This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch branch-2.1 in repository https://gitbox.apache.org/repos/asf/doris.git
commit 2f996a574f4a71330c02a9e7304a6e938c261a35 Author: feiniaofeiafei <53502832+feiniaofeia...@users.noreply.github.com> AuthorDate: Wed Apr 24 15:58:13 2024 +0800 [Feat](nereids) nereids add alter view (#33970) nereids support alter view stmt. e.g. ALTER VIEW example_db.example_view ( c1 COMMENT "column 1", c2 COMMENT "column 2", c3 COMMENT "column 3" ) AS SELECT k1, k2, SUM(v1) FROM example_table GROUP BY k1, k2 --- .../antlr4/org/apache/doris/nereids/DorisParser.g4 | 2 + .../org/apache/doris/analysis/AlterViewStmt.java | 9 + .../doris/nereids/parser/LogicalPlanBuilder.java | 13 ++ .../apache/doris/nereids/trees/plans/PlanType.java | 3 +- .../trees/plans/commands/AlterViewCommand.java | 49 +++++ .../trees/plans/commands/info/AlterViewInfo.java | 121 +++++++++++ .../{CreateViewInfo.java => BaseViewInfo.java} | 112 ++--------- .../trees/plans/commands/info/CreateViewInfo.java | 221 +-------------------- .../trees/plans/visitor/CommandVisitor.java | 5 + .../data/ddl_p0/test_alter_view_nereids.out | 17 ++ .../suites/ddl_p0/test_alter_view_nereids.groovy | 69 +++++++ 11 files changed, 310 insertions(+), 311 deletions(-) diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 74870648786..b84f2186b91 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -63,6 +63,8 @@ statementBase | CREATE VIEW (IF NOT EXISTS)? name=multipartIdentifier (LEFT_PAREN cols=simpleColumnDefs RIGHT_PAREN)? (COMMENT STRING_LITERAL)? AS query #createView + | ALTER VIEW name=multipartIdentifier (LEFT_PAREN cols=simpleColumnDefs RIGHT_PAREN)? + AS query #alterView | explain? INSERT (INTO | OVERWRITE TABLE) (tableName=multipartIdentifier | DORIS_INTERNAL_TABLE_ID LEFT_PAREN tableId=INTEGER_VALUE RIGHT_PAREN) partitionSpec? // partition define diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterViewStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterViewStmt.java index 355c9723c8b..39ea2ff1294 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterViewStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterViewStmt.java @@ -17,6 +17,7 @@ package org.apache.doris.analysis; +import org.apache.doris.catalog.Column; import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.TableIf; @@ -77,6 +78,14 @@ public class AlterViewStmt extends BaseViewStmt { createColumnAndViewDefs(analyzer); } + public void setInlineViewDef(String querySql) { + inlineViewDef = querySql; + } + + public void setFinalColumns(List<Column> columns) { + finalCols.addAll(columns); + } + @Override public String toSql() { StringBuilder sb = new StringBuilder(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 4739e74b262..239d898f02e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -48,6 +48,7 @@ import org.apache.doris.nereids.DorisParser.AggStateDataTypeContext; import org.apache.doris.nereids.DorisParser.AliasQueryContext; import org.apache.doris.nereids.DorisParser.AliasedQueryContext; import org.apache.doris.nereids.DorisParser.AlterMTMVContext; +import org.apache.doris.nereids.DorisParser.AlterViewContext; import org.apache.doris.nereids.DorisParser.ArithmeticBinaryContext; import org.apache.doris.nereids.DorisParser.ArithmeticUnaryContext; import org.apache.doris.nereids.DorisParser.ArrayLiteralContext; @@ -353,6 +354,7 @@ import org.apache.doris.nereids.trees.plans.algebra.Aggregate; import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier; import org.apache.doris.nereids.trees.plans.commands.AddConstraintCommand; import org.apache.doris.nereids.trees.plans.commands.AlterMTMVCommand; +import org.apache.doris.nereids.trees.plans.commands.AlterViewCommand; import org.apache.doris.nereids.trees.plans.commands.CallCommand; import org.apache.doris.nereids.trees.plans.commands.CancelMTMVTaskCommand; import org.apache.doris.nereids.trees.plans.commands.Command; @@ -382,6 +384,7 @@ import org.apache.doris.nereids.trees.plans.commands.info.AlterMTMVInfo; import org.apache.doris.nereids.trees.plans.commands.info.AlterMTMVPropertyInfo; import org.apache.doris.nereids.trees.plans.commands.info.AlterMTMVRefreshInfo; import org.apache.doris.nereids.trees.plans.commands.info.AlterMTMVRenameInfo; +import org.apache.doris.nereids.trees.plans.commands.info.AlterViewInfo; import org.apache.doris.nereids.trees.plans.commands.info.BulkLoadDataDesc; import org.apache.doris.nereids.trees.plans.commands.info.BulkStorageDesc; import org.apache.doris.nereids.trees.plans.commands.info.CancelMTMVTaskInfo; @@ -804,6 +807,16 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { return new AlterMTMVCommand(alterMTMVInfo); } + @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, + ctx.cols == null ? Lists.newArrayList() : visitSimpleColumnDefs(ctx.cols)); + return new AlterViewCommand(info); + } + @Override public LogicalPlan visitShowConstraint(ShowConstraintContext ctx) { List<String> parts = visitMultipartIdentifier(ctx.table); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java index 165dcd5e3ca..bf4741cff4e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java @@ -151,5 +151,6 @@ public enum PlanType { DROP_PROCEDURE_COMMAND, SHOW_PROCEDURE_COMMAND, SHOW_CREATE_PROCEDURE_COMMAND, - CREATE_VIEW_COMMAND + CREATE_VIEW_COMMAND, + ALTER_VIEW_COMMAND } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterViewCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterViewCommand.java new file mode 100644 index 00000000000..ebcbe280532 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterViewCommand.java @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.trees.plans.commands; + +import org.apache.doris.analysis.AlterViewStmt; +import org.apache.doris.catalog.Env; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.commands.info.AlterViewInfo; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.StmtExecutor; + +/**AlterViewCommand*/ +public class AlterViewCommand extends Command implements ForwardWithSync { + private final AlterViewInfo alterViewInfo; + + public AlterViewCommand(AlterViewInfo alterViewInfo) { + super(PlanType.ALTER_VIEW_COMMAND); + this.alterViewInfo = alterViewInfo; + } + + @Override + public void run(ConnectContext ctx, StmtExecutor executor) throws Exception { + alterViewInfo.init(ctx); + alterViewInfo.validate(ctx); + AlterViewStmt alterViewStmt = alterViewInfo.translateToLegacyStmt(ctx); + Env.getCurrentEnv().alterView(alterViewStmt); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitAlterViewCommand(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterViewInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterViewInfo.java new file mode 100644 index 00000000000..55798377145 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterViewInfo.java @@ -0,0 +1,121 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.trees.plans.commands.info; + +import org.apache.doris.analysis.AlterViewStmt; +import org.apache.doris.analysis.ColWithComment; +import org.apache.doris.analysis.TableName; +import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.DatabaseIf; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.TableIf; +import org.apache.doris.catalog.View; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.FeNameFormat; +import org.apache.doris.common.UserException; +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; +import com.google.common.collect.Sets; + +import java.util.List; +import java.util.Set; + +/** AlterViewInfo */ +public class AlterViewInfo extends BaseViewInfo { + /** constructor*/ + public AlterViewInfo(TableNameInfo viewName, LogicalPlan logicalQuery, + 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"); + } + } + + /** init */ + public void init(ConnectContext ctx) throws UserException { + if (viewName == null) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_TABLES_USED); + } + viewName.analyze(ctx); + FeNameFormat.checkTableName(viewName.getTbl()); + // disallow external catalog + Util.prohibitExternalCatalog(viewName.getCtl(), "AlterViewStmt"); + + DatabaseIf db = Env.getCurrentInternalCatalog().getDbOrAnalysisException(viewName.getDb()); + TableIf table = db.getTableOrAnalysisException(viewName.getTbl()); + if (!(table instanceof View)) { + throw new org.apache.doris.common.AnalysisException( + String.format("ALTER VIEW not allowed on a table:%s.%s", viewName.getDb(), viewName.getTbl())); + } + + // check privilege + if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, new TableName(viewName.getCtl(), viewName.getDb(), + viewName.getTbl()), PrivPredicate.ALTER)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLE_ACCESS_DENIED_ERROR, + PrivPredicate.ALTER.getPrivs().toString(), viewName.getTbl()); + } + analyzeAndFillRewriteSqlMap(querySql, ctx); + OutermostPlanFinderContext outermostPlanFinderContext = new OutermostPlanFinderContext(); + analyzedPlan.accept(OutermostPlanFinder.INSTANCE, outermostPlanFinderContext); + List<Slot> outputs = outermostPlanFinderContext.outermostPlan.getOutput(); + createFinalCols(outputs); + } + + /**validate*/ + public void validate(ConnectContext ctx) throws UserException { + NereidsPlanner planner = new NereidsPlanner(ctx.getStatementContext()); + planner.plan(new UnboundResultSink<>(logicalQuery), PhysicalProperties.ANY, ExplainLevel.NONE); + Set<String> colSets = Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER); + for (Column col : finalCols) { + if (!colSets.add(col.getName())) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_DUP_FIELDNAME, col.getName()); + } + } + } + + /**translateToLegacyStmt*/ + public AlterViewStmt translateToLegacyStmt(ConnectContext ctx) { + List<ColWithComment> cols = Lists.newArrayList(); + for (SimpleColumnDefinition def : simpleColumnDefinitions) { + cols.add(def.translateToColWithComment()); + } + AlterViewStmt alterViewStmt = new AlterViewStmt(viewName.transferToTableName(), cols, + null); + // expand star(*) in project list and replace table name with qualifier + String rewrittenSql = rewriteSql(ctx.getStatementContext().getIndexInSqlToString()); + + // rewrite project alias + rewrittenSql = rewriteProjectsToUserDefineAlias(rewrittenSql); + + alterViewStmt.setInlineViewDef(rewrittenSql); + alterViewStmt.setFinalColumns(finalCols); + return alterViewStmt; + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateViewInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/BaseViewInfo.java similarity index 67% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateViewInfo.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/BaseViewInfo.java index 084fe3af3f4..e0b00edf7fe 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateViewInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/BaseViewInfo.java @@ -17,27 +17,17 @@ package org.apache.doris.nereids.trees.plans.commands.info; -import org.apache.doris.analysis.ColWithComment; -import org.apache.doris.analysis.CreateViewStmt; -import org.apache.doris.analysis.TableName; import org.apache.doris.catalog.Column; -import org.apache.doris.catalog.Env; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; -import org.apache.doris.common.FeNameFormat; import org.apache.doris.common.Pair; -import org.apache.doris.common.UserException; -import org.apache.doris.common.util.Util; -import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.DorisParser; import org.apache.doris.nereids.DorisParser.NamedExpressionContext; import org.apache.doris.nereids.DorisParser.NamedExpressionSeqContext; import org.apache.doris.nereids.DorisParserBaseVisitor; -import org.apache.doris.nereids.NereidsPlanner; import org.apache.doris.nereids.StatementContext; import org.apache.doris.nereids.analyzer.UnboundResultSink; -import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.jobs.executor.AbstractBatchJobExecutor; import org.apache.doris.nereids.jobs.rewrite.RewriteJob; import org.apache.doris.nereids.parser.NereidsParser; @@ -49,16 +39,13 @@ import org.apache.doris.nereids.rules.analysis.CheckPolicy; import org.apache.doris.nereids.rules.analysis.EliminateLogicalSelectHint; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.Plan; -import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel; 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.LogicalPlan; import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor; import org.apache.doris.qe.ConnectContext; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.RuleNode; @@ -66,86 +53,25 @@ import org.apache.commons.lang3.StringUtils; import java.util.List; import java.util.Map; -import java.util.Set; -/** - * CreateViewInfo - */ -public class CreateViewInfo { - private final boolean ifNotExists; - private final TableNameInfo viewName; - private final String comment; - private final LogicalPlan logicalQuery; - private final String querySql; - private final List<SimpleColumnDefinition> simpleColumnDefinitions; - private final List<Column> finalCols = Lists.newArrayList(); - private Plan analyzedPlan; +/** BaseViewInfo */ +public class BaseViewInfo { + protected final TableNameInfo viewName; + protected final LogicalPlan logicalQuery; + protected final String querySql; + protected final List<SimpleColumnDefinition> simpleColumnDefinitions; + protected final List<Column> finalCols = Lists.newArrayList(); + protected Plan analyzedPlan; - /** constructor*/ - public CreateViewInfo(boolean ifNotExists, TableNameInfo viewName, String comment, LogicalPlan logicalQuery, + public BaseViewInfo(TableNameInfo viewName, LogicalPlan logicalQuery, String querySql, List<SimpleColumnDefinition> simpleColumnDefinitions) { - this.ifNotExists = ifNotExists; this.viewName = viewName; - this.comment = comment; - if (logicalQuery instanceof LogicalFileSink) { - throw new AnalysisException("Not support OUTFILE clause in CREATE VIEW statement"); - } this.logicalQuery = logicalQuery; this.querySql = querySql; this.simpleColumnDefinitions = simpleColumnDefinitions; } - /** init */ - public void init(ConnectContext ctx) throws UserException { - analyzeAndFillRewriteSqlMap(querySql, ctx); - OutermostPlanFinderContext outermostPlanFinderContext = new OutermostPlanFinderContext(); - analyzedPlan.accept(OutermostPlanFinder.INSTANCE, outermostPlanFinderContext); - List<Slot> outputs = outermostPlanFinderContext.outermostPlan.getOutput(); - createFinalCols(outputs); - } - - /**validate*/ - public void validate(ConnectContext ctx) throws UserException { - viewName.analyze(ctx); - FeNameFormat.checkTableName(viewName.getTbl()); - // disallow external catalog - Util.prohibitExternalCatalog(viewName.getCtl(), "CreateViewStmt"); - // check privilege - if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, new TableName(viewName.getCtl(), viewName.getDb(), - viewName.getTbl()), PrivPredicate.CREATE)) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLE_ACCESS_DENIED_ERROR, - PrivPredicate.CREATE.getPrivs().toString(), viewName.getTbl()); - } - NereidsPlanner planner = new NereidsPlanner(ctx.getStatementContext()); - planner.plan(new UnboundResultSink<>(logicalQuery), PhysicalProperties.ANY, ExplainLevel.NONE); - Set<String> colSets = Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER); - for (Column col : finalCols) { - if (!colSets.add(col.getName())) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_DUP_FIELDNAME, col.getName()); - } - } - } - - /**translateToLegacyStmt*/ - public CreateViewStmt translateToLegacyStmt(ConnectContext ctx) { - List<ColWithComment> cols = Lists.newArrayList(); - for (SimpleColumnDefinition def : simpleColumnDefinitions) { - cols.add(def.translateToColWithComment()); - } - CreateViewStmt createViewStmt = new CreateViewStmt(ifNotExists, viewName.transferToTableName(), cols, comment, - null); - // expand star(*) in project list and replace table name with qualifier - String rewrittenSql = rewriteSql(ctx.getStatementContext().getIndexInSqlToString()); - - // rewrite project alias - rewrittenSql = rewriteProjectsToUserDefineAlias(rewrittenSql); - - createViewStmt.setInlineViewDef(rewrittenSql); - createViewStmt.setFinalColumns(finalCols); - return createViewStmt; - } - - private void analyzeAndFillRewriteSqlMap(String sql, ConnectContext ctx) { + protected void analyzeAndFillRewriteSqlMap(String sql, ConnectContext ctx) { StatementContext stmtCtx = ctx.getStatementContext(); LogicalPlan parsedViewPlan = new NereidsParser().parseForCreateView(sql); if (parsedViewPlan instanceof UnboundResultSink) { @@ -158,7 +84,7 @@ public class CreateViewInfo { analyzedPlan = viewContextForStar.getRewritePlan(); } - private String rewriteSql(Map<Pair<Integer, Integer>, String> indexStringSqlMap) { + protected String rewriteSql(Map<Pair<Integer, Integer>, String> indexStringSqlMap) { StringBuilder builder = new StringBuilder(); int beg = 0; for (Map.Entry<Pair<Integer, Integer>, String> entry : indexStringSqlMap.entrySet()) { @@ -171,7 +97,7 @@ public class CreateViewInfo { return builder.toString(); } - private String rewriteProjectsToUserDefineAlias(String resSql) { + protected String rewriteProjectsToUserDefineAlias(String resSql) { IndexFinder finder = new IndexFinder(); ParserRuleContext tree = NereidsParser.toAst(resSql, DorisParser::singleStatement); finder.visit(tree); @@ -198,7 +124,7 @@ public class CreateViewInfo { finder.getIndex().second + 1); } - private void createFinalCols(List<Slot> outputs) throws org.apache.doris.common.AnalysisException { + protected void createFinalCols(List<Slot> outputs) throws org.apache.doris.common.AnalysisException { if (simpleColumnDefinitions.isEmpty()) { for (Slot output : outputs) { Column column = new Column(output.getName(), output.getDataType().toCatalogDataType()); @@ -217,12 +143,15 @@ public class CreateViewInfo { } } - private static class OutermostPlanFinderContext { + /**OutermostPlanFinderContext*/ + protected static class OutermostPlanFinderContext { public Plan outermostPlan = null; public boolean found = false; } - private static class OutermostPlanFinder extends DefaultPlanVisitor<Void, OutermostPlanFinderContext> { + /**OutermostPlanFinder*/ + protected static class OutermostPlanFinder extends + DefaultPlanVisitor<Void, OutermostPlanFinderContext> { public static final OutermostPlanFinder INSTANCE = new OutermostPlanFinder(); @Override @@ -252,7 +181,7 @@ public class CreateViewInfo { } /** traverse ast to find the outermost project list location information in sql*/ - private static class IndexFinder extends DorisParserBaseVisitor<Void> { + protected static class IndexFinder extends DorisParserBaseVisitor<Void> { private boolean found = false; private int startIndex; private int stopIndex; @@ -299,7 +228,8 @@ public class CreateViewInfo { } } - private static class AnalyzerForCreateView extends AbstractBatchJobExecutor { + /**AnalyzerForCreateView*/ + protected static class AnalyzerForCreateView extends AbstractBatchJobExecutor { private final List<RewriteJob> jobs; public AnalyzerForCreateView(CascadesContext cascadesContext) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateViewInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateViewInfo.java index 084fe3af3f4..e52f69954ba 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateViewInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateViewInfo.java @@ -25,74 +25,41 @@ import org.apache.doris.catalog.Env; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; import org.apache.doris.common.FeNameFormat; -import org.apache.doris.common.Pair; import org.apache.doris.common.UserException; import org.apache.doris.common.util.Util; import org.apache.doris.mysql.privilege.PrivPredicate; -import org.apache.doris.nereids.CascadesContext; -import org.apache.doris.nereids.DorisParser; -import org.apache.doris.nereids.DorisParser.NamedExpressionContext; -import org.apache.doris.nereids.DorisParser.NamedExpressionSeqContext; -import org.apache.doris.nereids.DorisParserBaseVisitor; import org.apache.doris.nereids.NereidsPlanner; -import org.apache.doris.nereids.StatementContext; import org.apache.doris.nereids.analyzer.UnboundResultSink; import org.apache.doris.nereids.exceptions.AnalysisException; -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.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.Slot; -import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel; -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.LogicalPlan; -import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor; import org.apache.doris.qe.ConnectContext; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.RuleNode; -import org.apache.commons.lang3.StringUtils; import java.util.List; -import java.util.Map; import java.util.Set; /** * CreateViewInfo */ -public class CreateViewInfo { +public class CreateViewInfo extends BaseViewInfo { private final boolean ifNotExists; - private final TableNameInfo viewName; private final String comment; - private final LogicalPlan logicalQuery; - private final String querySql; - private final List<SimpleColumnDefinition> simpleColumnDefinitions; - private final List<Column> finalCols = Lists.newArrayList(); - private Plan analyzedPlan; /** constructor*/ public CreateViewInfo(boolean ifNotExists, TableNameInfo viewName, String comment, LogicalPlan logicalQuery, String querySql, List<SimpleColumnDefinition> simpleColumnDefinitions) { + super(viewName, logicalQuery, querySql, simpleColumnDefinitions); this.ifNotExists = ifNotExists; - this.viewName = viewName; this.comment = comment; if (logicalQuery instanceof LogicalFileSink) { throw new AnalysisException("Not support OUTFILE clause in CREATE VIEW statement"); } - this.logicalQuery = logicalQuery; - this.querySql = querySql; - this.simpleColumnDefinitions = simpleColumnDefinitions; } /** init */ @@ -144,188 +111,4 @@ public class CreateViewInfo { createViewStmt.setFinalColumns(finalCols); return createViewStmt; } - - private void analyzeAndFillRewriteSqlMap(String sql, ConnectContext ctx) { - StatementContext stmtCtx = ctx.getStatementContext(); - LogicalPlan parsedViewPlan = new NereidsParser().parseForCreateView(sql); - if (parsedViewPlan instanceof UnboundResultSink) { - parsedViewPlan = (LogicalPlan) ((UnboundResultSink<?>) parsedViewPlan).child(); - } - CascadesContext viewContextForStar = CascadesContext.initContext( - stmtCtx, parsedViewPlan, PhysicalProperties.ANY); - AnalyzerForCreateView analyzerForStar = new AnalyzerForCreateView(viewContextForStar); - analyzerForStar.analyze(); - analyzedPlan = viewContextForStar.getRewritePlan(); - } - - private String rewriteSql(Map<Pair<Integer, Integer>, String> indexStringSqlMap) { - StringBuilder builder = new StringBuilder(); - int beg = 0; - for (Map.Entry<Pair<Integer, Integer>, String> entry : indexStringSqlMap.entrySet()) { - Pair<Integer, Integer> index = entry.getKey(); - builder.append(querySql, beg, index.first); - builder.append(entry.getValue()); - beg = index.second + 1; - } - builder.append(querySql, beg, querySql.length()); - return builder.toString(); - } - - private String rewriteProjectsToUserDefineAlias(String resSql) { - IndexFinder finder = new IndexFinder(); - ParserRuleContext tree = NereidsParser.toAst(resSql, DorisParser::singleStatement); - finder.visit(tree); - if (simpleColumnDefinitions.isEmpty()) { - return resSql; - } - List<NamedExpressionContext> namedExpressionContexts = finder.getNamedExpressionContexts(); - StringBuilder replaceWithColsBuilder = new StringBuilder(); - for (int i = 0; i < namedExpressionContexts.size(); ++i) { - NamedExpressionContext namedExpressionContext = namedExpressionContexts.get(i); - int start = namedExpressionContext.expression().start.getStartIndex(); - int stop = namedExpressionContext.expression().stop.getStopIndex(); - replaceWithColsBuilder.append(resSql, start, stop + 1); - replaceWithColsBuilder.append(" AS `"); - String escapeBacktick = finalCols.get(i).getName().replace("`", "``"); - replaceWithColsBuilder.append(escapeBacktick); - replaceWithColsBuilder.append('`'); - if (i != namedExpressionContexts.size() - 1) { - replaceWithColsBuilder.append(", "); - } - } - String replaceWithCols = replaceWithColsBuilder.toString(); - return StringUtils.overlay(resSql, replaceWithCols, finder.getIndex().first, - finder.getIndex().second + 1); - } - - private void createFinalCols(List<Slot> outputs) throws org.apache.doris.common.AnalysisException { - if (simpleColumnDefinitions.isEmpty()) { - for (Slot output : outputs) { - Column column = new Column(output.getName(), output.getDataType().toCatalogDataType()); - finalCols.add(column); - } - } else { - if (outputs.size() != simpleColumnDefinitions.size()) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_VIEW_WRONG_LIST); - } - for (int i = 0; i < simpleColumnDefinitions.size(); ++i) { - Column column = new Column(simpleColumnDefinitions.get(i).getName(), - outputs.get(i).getDataType().toCatalogDataType()); - column.setComment(simpleColumnDefinitions.get(i).getComment()); - finalCols.add(column); - } - } - } - - private static class OutermostPlanFinderContext { - public Plan outermostPlan = null; - public boolean found = false; - } - - private static class OutermostPlanFinder extends DefaultPlanVisitor<Void, OutermostPlanFinderContext> { - public static final OutermostPlanFinder INSTANCE = new OutermostPlanFinder(); - - @Override - public Void visit(Plan plan, OutermostPlanFinderContext ctx) { - if (ctx.found) { - return null; - } - ctx.outermostPlan = plan; - ctx.found = true; - return null; - } - - @Override - public Void visitLogicalCTEAnchor(LogicalCTEAnchor<? extends Plan, ? extends Plan> cteAnchor, - OutermostPlanFinderContext ctx) { - if (ctx.found) { - return null; - } - return super.visit(cteAnchor, ctx); - } - - @Override - public Void visitLogicalCTEProducer(LogicalCTEProducer<? extends Plan> cteProducer, - OutermostPlanFinderContext ctx) { - return null; - } - } - - /** traverse ast to find the outermost project list location information in sql*/ - private static class IndexFinder extends DorisParserBaseVisitor<Void> { - private boolean found = false; - private int startIndex; - private int stopIndex; - private List<NamedExpressionContext> namedExpressionContexts = Lists.newArrayList(); - - @Override - public Void visitChildren(RuleNode node) { - if (found) { - return null; - } - int n = node.getChildCount(); - for (int i = 0; i < n; ++i) { - ParseTree c = node.getChild(i); - c.accept(this); - } - return null; - } - - @Override - public Void visitCte(DorisParser.CteContext ctx) { - return null; - } - - @Override - public Void visitSelectColumnClause(DorisParser.SelectColumnClauseContext ctx) { - if (found) { - return null; - } - startIndex = ctx.getStart().getStartIndex(); - stopIndex = ctx.getStop().getStopIndex(); - found = true; - - NamedExpressionSeqContext namedExpressionSeqContext = ctx.namedExpressionSeq(); - namedExpressionContexts = namedExpressionSeqContext.namedExpression(); - return null; - } - - public Pair<Integer, Integer> getIndex() { - return Pair.of(startIndex, stopIndex); - } - - public List<NamedExpressionContext> getNamedExpressionContexts() { - return namedExpressionContexts; - } - } - - private static class AnalyzerForCreateView extends AbstractBatchJobExecutor { - private final List<RewriteJob> jobs; - - public AnalyzerForCreateView(CascadesContext cascadesContext) { - super(cascadesContext); - jobs = buildAnalyzeViewJobsForStar(); - } - - public void analyze() { - execute(); - } - - @Override - public List<RewriteJob> getJobs() { - return jobs; - } - - private static List<RewriteJob> buildAnalyzeViewJobsForStar() { - return jobs( - topDown(new EliminateLogicalSelectHint()), - topDown(new AnalyzeCTE()), - bottomUp( - new BindRelation(), - new CheckPolicy(), - new BindExpression() - ) - ); - } - } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java index 527ccb1ffe0..d23cb855af6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java @@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.plans.visitor; import org.apache.doris.nereids.trees.plans.commands.AddConstraintCommand; import org.apache.doris.nereids.trees.plans.commands.AlterMTMVCommand; +import org.apache.doris.nereids.trees.plans.commands.AlterViewCommand; import org.apache.doris.nereids.trees.plans.commands.CallCommand; import org.apache.doris.nereids.trees.plans.commands.CancelMTMVTaskCommand; import org.apache.doris.nereids.trees.plans.commands.Command; @@ -161,4 +162,8 @@ public interface CommandVisitor<R, C> { default R visitCreateViewCommand(CreateViewCommand createViewCommand, C context) { return visitCommand(createViewCommand, context); } + + default R visitAlterViewCommand(AlterViewCommand alterViewCommand, C context) { + return visitCommand(alterViewCommand, context); + } } diff --git a/regression-test/data/ddl_p0/test_alter_view_nereids.out b/regression-test/data/ddl_p0/test_alter_view_nereids.out new file mode 100644 index 00000000000..ef50a9c8801 --- /dev/null +++ b/regression-test/data/ddl_p0/test_alter_view_nereids.out @@ -0,0 +1,17 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select -- +1 1 +1 5 +2 1 +2 10 + +-- !select -- +1 60 +2 70 + +-- !sql -- +test_alter_view_view_nereids CREATE VIEW `test_alter_view_view_nereids` COMMENT 'test_view' AS SELECT c1 AS `k1`, sum(c3) AS `k2` FROM `internal`.`regression_test_ddl_p0`.`test_alter_view_table_nereids` GROUP BY c1; utf8mb4 utf8mb4_0900_bin + +-- !sql -- +test_alter_view_view_nereids CREATE VIEW `test_alter_view_view_nereids` COMMENT 'test_view' AS (select `internal`.`regression_test_ddl_p0`.`test_alter_view_table_nereids`.`c1`, `internal`.`regression_test_ddl_p0`.`test_alter_view_table_nereids`.`c2`, `internal`.`regression_test_ddl_p0`.`test_alter_view_table_nereids`.`c3` from `internal`.`regression_test_ddl_p0`.`test_alter_view_table_nereids`); utf8mb4 utf8mb4_0900_bin + diff --git a/regression-test/suites/ddl_p0/test_alter_view_nereids.groovy b/regression-test/suites/ddl_p0/test_alter_view_nereids.groovy new file mode 100644 index 00000000000..6b26d093e56 --- /dev/null +++ b/regression-test/suites/ddl_p0/test_alter_view_nereids.groovy @@ -0,0 +1,69 @@ +// 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. + +suite("test_alter_view_nereids") { + sql "SET enable_nereids_planner=true;" + sql "SET enable_fallback_to_original_planner=false;" + String tableName = "test_alter_view_table_nereids"; + String viewName = "test_alter_view_view_nereids"; + sql " DROP TABLE IF EXISTS ${tableName}" + sql """ + CREATE TABLE IF NOT EXISTS ${tableName} + ( + c1 BIGINT NOT NULL, + c2 BIGINT NOT NULL, + c3 BIGINT NOT NULL + ) + UNIQUE KEY (`c1`, `c2`) + DISTRIBUTED BY HASH(`c1`) BUCKETS 1 + PROPERTIES + ( + "replication_num" = "1" + ) + """ + sql """ + CREATE VIEW IF NOT EXISTS ${viewName} (k1, k2) + COMMENT "test_view" + AS + SELECT c1 as k1, c2 as k2 FROM ${tableName} + """ + + sql """ + INSERT INTO ${tableName} VALUES + (1, 1, 10), + (1, 5, 50), + (2, 1, 20), + (2, 10, 50) + """ + + qt_select " SELECT * FROM ${viewName} order by k1, k2 " + + sql """ + ALTER VIEW ${viewName} (k1, k2) + AS + SELECT c1 as k1, sum(c3) as k2 FROM ${tableName} GROUP BY c1 + """ + + qt_select " SELECT * FROM ${viewName} order by k1, k2 " + qt_sql "show create view ${viewName}" + + sql "alter view ${viewName} as (select * from ${tableName})" + qt_sql "show create view ${viewName}" + + sql "DROP VIEW ${viewName}" + sql "DROP TABLE ${tableName}" +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org