pick #40715 to branch-2.1
This commit is contained in:
@ -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)?
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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();
|
||||
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());
|
||||
}
|
||||
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() {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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());
|
||||
|
||||
|
||||
10
regression-test/data/ddl_p0/test_create_or_replace_view.out
Normal file
10
regression-test/data/ddl_p0/test_create_or_replace_view.out
Normal file
@ -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
|
||||
|
||||
@ -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"""
|
||||
}
|
||||
Reference in New Issue
Block a user