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
The following commit(s) were added to refs/heads/branch-2.1 by this push: new 84f0b1fbfea [feature](view) support create or replace view stmt (#40715) (#40915) 84f0b1fbfea is described below commit 84f0b1fbfea8bd1d52aedf10b6e209f4c8be421c Author: camby <camby...@tencent.com> AuthorDate: Thu Sep 19 01:10:43 2024 +0800 [feature](view) support create or replace view stmt (#40715) (#40915) pick #40715 to branch-2.1 --- .../antlr4/org/apache/doris/nereids/DorisParser.g4 | 2 +- fe/fe-core/src/main/cup/sql_parser.cup | 15 +++- .../org/apache/doris/analysis/BaseViewStmt.java | 11 +++ .../org/apache/doris/analysis/CreateViewStmt.java | 13 +++- .../main/java/org/apache/doris/catalog/Env.java | 48 ++++++++----- .../doris/nereids/parser/LogicalPlanBuilder.java | 6 +- .../trees/plans/commands/info/CreateViewInfo.java | 8 ++- .../data/ddl_p0/test_create_or_replace_view.out | 10 +++ .../ddl_p0/test_create_or_replace_view.groovy | 80 ++++++++++++++++++++++ 9 files changed, 169 insertions(+), 24 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 275c934f7d5..a0e3a4582d9 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 @@ -60,7 +60,7 @@ statementBase properties=propertyClause? (BROKER extProperties=propertyClause)? (AS query)? #createTable - | CREATE VIEW (IF NOT EXISTS)? name=multipartIdentifier + | CREATE (OR REPLACE)? 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)? diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index a7f43260472..90a22ac2506 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -961,6 +961,7 @@ nonterminal List<Map<String, String>> opt_with_analysis_properties; nonterminal String opt_db, procedure_or_function, opt_comment, opt_comment_null, opt_engine; nonterminal ColumnDef.DefaultValue opt_default_value; +nonterminal Boolean opt_or_replace; nonterminal Boolean opt_if_exists, opt_if_not_exists; nonterminal Boolean opt_external; nonterminal Boolean opt_force; @@ -1892,10 +1893,10 @@ create_stmt ::= {: RESULT = new CreateUserStmt(ifNotExists, user, userRole, passwdOptions, comment); :} - | KW_CREATE KW_VIEW opt_if_not_exists:ifNotExists table_name:viewName + | KW_CREATE opt_or_replace:orReplace KW_VIEW opt_if_not_exists:ifNotExists table_name:viewName opt_col_with_comment_list:columns opt_comment:comment KW_AS query_stmt:view_def {: - RESULT = new CreateViewStmt(ifNotExists, viewName, columns, comment, view_def); + RESULT = new CreateViewStmt(ifNotExists, orReplace, viewName, columns, comment, view_def); :} | KW_CREATE opt_read_only:isReadOnly KW_REPOSITORY ident:repoName KW_WITH storage_backend:storage {: @@ -3865,6 +3866,16 @@ opt_index_type ::= :} ; +opt_or_replace ::= + {: + RESULT = false; + :} + | KW_OR KW_REPLACE + {: + RESULT = true; + :} + ; + opt_if_exists ::= {: RESULT = false; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/BaseViewStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/BaseViewStmt.java index 545d7c1c57a..e265703128d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/BaseViewStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/BaseViewStmt.java @@ -68,11 +68,22 @@ public class BaseViewStmt extends DdlStmt { return tableName.getTbl(); } + public TableName getTableName() { + return tableName; + } public List<Column> getColumns() { return finalCols; } + public List<ColWithComment> getColWithComments() { + return cols; + } + + public QueryStmt getViewDefStmt() { + return viewDefStmt; + } + public String getInlineViewDef() { return inlineViewDef; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateViewStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateViewStmt.java index 2029b464100..50b658a48aa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateViewStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateViewStmt.java @@ -25,6 +25,7 @@ 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.exceptions.AnalysisException; import org.apache.doris.qe.ConnectContext; import com.google.common.base.Strings; @@ -37,12 +38,14 @@ public class CreateViewStmt extends BaseViewStmt { private static final Logger LOG = LogManager.getLogger(CreateViewStmt.class); private final boolean ifNotExists; + private final boolean orReplace; private final String comment; - public CreateViewStmt(boolean ifNotExists, TableName tableName, List<ColWithComment> cols, + public CreateViewStmt(boolean ifNotExists, boolean orReplace, TableName tableName, List<ColWithComment> cols, String comment, QueryStmt queryStmt) { super(tableName, cols, queryStmt); this.ifNotExists = ifNotExists; + this.orReplace = orReplace; this.comment = Strings.nullToEmpty(comment); } @@ -50,6 +53,10 @@ public class CreateViewStmt extends BaseViewStmt { return ifNotExists; } + public boolean isSetOrReplace() { + return orReplace; + } + public String getComment() { return comment; } @@ -63,6 +70,10 @@ public class CreateViewStmt extends BaseViewStmt { // disallow external catalog Util.prohibitExternalCatalog(tableName.getCtl(), this.getClass().getSimpleName()); + if (orReplace && ifNotExists) { + throw new AnalysisException("[OR REPLACE] and [IF NOT EXISTS] cannot used at the same time"); + } + // check privilege if (!Env.getCurrentEnv().getAccessManager() .checkTblPriv(ConnectContext.get(), tableName.getCtl(), tableName.getDb(), diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java index 8d9ec6f1d21..b7209ba550d 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java @@ -5317,33 +5317,49 @@ public class Env { Database db = getInternalCatalog().getDbOrDdlException(dbName); // check if table exists in db + boolean replace = false; if (db.getTable(tableName).isPresent()) { if (stmt.isSetIfNotExists()) { LOG.info("create view[{}] which already exists", tableName); return; + } else if (stmt.isSetOrReplace()) { + replace = true; + LOG.info("view[{}] already exists, need to replace it", tableName); } else { ErrorReport.reportDdlException(ErrorCode.ERR_TABLE_EXISTS_ERROR, tableName); } } - List<Column> columns = stmt.getColumns(); - - long tableId = Env.getCurrentEnv().getNextId(); - View newView = new View(tableId, tableName, columns); - newView.setComment(stmt.getComment()); - newView.setInlineViewDefWithSqlMode(stmt.getInlineViewDef(), - ConnectContext.get().getSessionVariable().getSqlMode()); - // init here in case the stmt string from view.toSql() has some syntax error. - try { - newView.init(); - } catch (UserException e) { - throw new DdlException("failed to init view stmt, reason=" + e.getMessage()); - } + if (replace) { + AlterViewStmt alterViewStmt = new AlterViewStmt(stmt.getTableName(), stmt.getColWithComments(), + stmt.getViewDefStmt()); + alterViewStmt.setInlineViewDef(stmt.getInlineViewDef()); + try { + alterView(alterViewStmt); + } catch (UserException e) { + throw new DdlException("failed to replace view[" + tableName + "], reason=" + e.getMessage()); + } + LOG.info("successfully replace view[{}]", tableName); + } else { + List<Column> columns = stmt.getColumns(); + + long tableId = Env.getCurrentEnv().getNextId(); + View newView = new View(tableId, tableName, columns); + newView.setComment(stmt.getComment()); + newView.setInlineViewDefWithSqlMode(stmt.getInlineViewDef(), + ConnectContext.get().getSessionVariable().getSqlMode()); + // init here in case the stmt string from view.toSql() has some syntax error. + try { + newView.init(); + } catch (UserException e) { + throw new DdlException("failed to init view stmt, reason=" + e.getMessage()); + } - if (!((Database) db).createTableWithLock(newView, false, stmt.isSetIfNotExists()).first) { - throw new DdlException("Failed to create view[" + tableName + "]."); + if (!((Database) db).createTableWithLock(newView, false, stmt.isSetIfNotExists()).first) { + throw new DdlException("Failed to create view[" + tableName + "]."); + } + LOG.info("successfully create view[" + tableName + "-" + newView.getId() + "]"); } - LOG.info("successfully create view[" + tableName + "-" + newView.getId() + "]"); } public FunctionRegistry getFunctionRegistry() { 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 32cfe310f1e..fae6ddb137b 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 @@ -2529,7 +2529,11 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { String comment = ctx.STRING_LITERAL() == null ? "" : LogicalPlanBuilderAssistant.escapeBackSlash( ctx.STRING_LITERAL().getText().substring(1, ctx.STRING_LITERAL().getText().length() - 1)); String querySql = getOriginSql(ctx.query()); - CreateViewInfo info = new CreateViewInfo(ctx.EXISTS() != null, new TableNameInfo(nameParts), + if (ctx.REPLACE() != null && ctx.EXISTS() != null) { + throw new AnalysisException("[OR REPLACE] and [IF NOT EXISTS] cannot used at the same time"); + } + CreateViewInfo info = new CreateViewInfo(ctx.EXISTS() != null, ctx.REPLACE() != null, + new TableNameInfo(nameParts), comment, querySql, ctx.cols == null ? Lists.newArrayList() : visitSimpleColumnDefs(ctx.cols)); return new CreateViewCommand(info); 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 8279a311030..81c12baebfd 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 @@ -46,13 +46,15 @@ import java.util.Set; */ public class CreateViewInfo extends BaseViewInfo { private final boolean ifNotExists; + private final boolean orReplace; private final String comment; /** constructor*/ - public CreateViewInfo(boolean ifNotExists, TableNameInfo viewName, String comment, + public CreateViewInfo(boolean ifNotExists, boolean orReplace, TableNameInfo viewName, String comment, String querySql, List<SimpleColumnDefinition> simpleColumnDefinitions) { super(viewName, querySql, simpleColumnDefinitions); this.ifNotExists = ifNotExists; + this.orReplace = orReplace; this.comment = comment; } @@ -93,8 +95,8 @@ public class CreateViewInfo extends BaseViewInfo { for (SimpleColumnDefinition def : simpleColumnDefinitions) { cols.add(def.translateToColWithComment()); } - CreateViewStmt createViewStmt = new CreateViewStmt(ifNotExists, viewName.transferToTableName(), cols, comment, - null); + CreateViewStmt createViewStmt = new CreateViewStmt(ifNotExists, orReplace, viewName.transferToTableName(), cols, + comment, null); // expand star(*) in project list and replace table name with qualifier String rewrittenSql = rewriteSql(ctx.getStatementContext().getIndexInSqlToString()); diff --git a/regression-test/data/ddl_p0/test_create_or_replace_view.out b/regression-test/data/ddl_p0/test_create_or_replace_view.out new file mode 100644 index 00000000000..9cccca77283 --- /dev/null +++ b/regression-test/data/ddl_p0/test_create_or_replace_view.out @@ -0,0 +1,10 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql_1 -- +1 1 1 + +-- !sql_2 -- +2 2 2 + +-- !sql_3 -- +1 1 1 + diff --git a/regression-test/suites/ddl_p0/test_create_or_replace_view.groovy b/regression-test/suites/ddl_p0/test_create_or_replace_view.groovy new file mode 100644 index 00000000000..bd689802119 --- /dev/null +++ b/regression-test/suites/ddl_p0/test_create_or_replace_view.groovy @@ -0,0 +1,80 @@ +// 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_create_or_replace_view") { + sql "SET enable_nereids_planner=true" + + // create two test tables and insert some data + sql """DROP TABLE IF EXISTS test_create_or_replace_view_tbl1""" + sql """ + CREATE TABLE IF NOT EXISTS test_create_or_replace_view_tbl1 + (k1 int, k2 int, v int) + DUPLICATE KEY(k1) DISTRIBUTED BY HASH(k1) BUCKETS 1 + PROPERTIES( "replication_num" = "1"); + """ + sql """DROP TABLE IF EXISTS test_create_or_replace_view_tbl2""" + sql """ + CREATE TABLE IF NOT EXISTS test_create_or_replace_view_tbl2 + (k1 int, k2 int, v int) + DUPLICATE KEY(k1) DISTRIBUTED BY HASH(k1) BUCKETS 1 + PROPERTIES( "replication_num" = "1"); + """ + sql """INSERT INTO test_create_or_replace_view_tbl1 VALUES(1,1,1)""" + sql """INSERT INTO test_create_or_replace_view_tbl2 VALUES(2,2,2)""" + sql "sync" + + // create view + sql "drop view if exists view_test_create_or_replace_view" + sql """ + CREATE VIEW IF NOT EXISTS view_test_create_or_replace_view + AS SELECT * FROM test_create_or_replace_view_tbl1; + """ + qt_sql_1 """select * from view_test_create_or_replace_view""" + + // create or replace view in nereids + sql """ + CREATE OR REPLACE VIEW view_test_create_or_replace_view + AS SELECT * FROM test_create_or_replace_view_tbl2; + """ + qt_sql_2 """select * from view_test_create_or_replace_view""" + test { + sql """ + CREATE OR REPLACE VIEW IF NOT EXISTS view_test_create_or_replace_view + AS SELECT * FROM test_create_or_replace_view_tbl1; + """ + exception "[OR REPLACE] and [IF NOT EXISTS] cannot used at the same time" + } + + // create or replace view in non-nereids + sql "SET enable_nereids_planner=false" + sql """ + CREATE OR REPLACE VIEW view_test_create_or_replace_view + AS SELECT * FROM test_create_or_replace_view_tbl1; + """ + qt_sql_3 """select * from view_test_create_or_replace_view""" + test { + sql """ + CREATE OR REPLACE VIEW IF NOT EXISTS view_test_create_or_replace_view + AS SELECT * FROM test_create_or_replace_view_tbl1; + """ + exception "[OR REPLACE] and [IF NOT EXISTS] cannot used at the same time" + } + + sql """drop view if exists view_test_create_or_replace_view""" + sql """DROP TABLE IF EXISTS test_create_or_replace_view_tbl1""" + sql """DROP TABLE IF EXISTS test_create_or_replace_view_tbl2""" +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org