Skip to content

Commit

Permalink
[enhance](mtmv)support replace materialized view (#36749)
Browse files Browse the repository at this point in the history
- support alter MATERIALIZED VIEW mv1 replace with MATERIALIZED VIEW mv2 PROPERTIES('swap' = 'false');
- fix rename MATERIALIZED VIEW not change state of high level MATERIALIZED VIEW

Logic is the same as ALTER-TABLE-REPLACE. more detail pelase read doris document.
The difference is that this statement can only operate on materialized views
  • Loading branch information
zddr authored Jul 2, 2024
1 parent 2e63fef commit 9223349
Show file tree
Hide file tree
Showing 12 changed files with 501 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ statementBase
| REFRESH MATERIALIZED VIEW mvName=multipartIdentifier (partitionSpec | COMPLETE | AUTO) #refreshMTMV
| ALTER MATERIALIZED VIEW mvName=multipartIdentifier ((RENAME newName=identifier)
| (REFRESH (refreshMethod | refreshTrigger | refreshMethod refreshTrigger))
| REPLACE WITH MATERIALIZED VIEW newName=identifier propertyClause?
| (SET LEFT_PAREN fileProperties=propertyItemList RIGHT_PAREN)) #alterMTMV
| DROP MATERIALIZED VIEW (IF EXISTS)? mvName=multipartIdentifier #dropMTMV
| PAUSE MATERIALIZED VIEW JOB ON mvName=multipartIdentifier #pauseMTMV
Expand Down
8 changes: 8 additions & 0 deletions fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,11 @@ private void processReplaceTable(Database db, OlapTable origTable, List<AlterCla
ReplaceTableClause clause = (ReplaceTableClause) alterClauses.get(0);
String newTblName = clause.getTblName();
boolean swapTable = clause.isSwapTable();
processReplaceTable(db, origTable, newTblName, swapTable);
}

public void processReplaceTable(Database db, OlapTable origTable, String newTblName, boolean swapTable)
throws UserException {
db.writeLockOrDdlException();
try {
List<TableType> tableTypes = Lists.newArrayList(TableType.OLAP, TableType.MATERIALIZED_VIEW);
Expand Down Expand Up @@ -604,6 +609,9 @@ private void replaceTableInternal(Database db, OlapTable origTable, OlapTable ne
} else {
// not swap, the origin table is not used anymore, need to drop all its tablets.
Env.getCurrentEnv().onEraseOlapTable(origTable, isReplay);
if (origTable.getType() == TableType.MATERIALIZED_VIEW) {
Env.getCurrentEnv().getMtmvService().deregisterMTMV((MTMV) origTable);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@
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.AlterMTMVReplaceInfo;
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;
Expand Down Expand Up @@ -853,6 +854,11 @@ public AlterMTMVCommand visitAlterMTMV(AlterMTMVContext ctx) {
} else if (ctx.SET() != null) {
alterMTMVInfo = new AlterMTMVPropertyInfo(mvName,
Maps.newHashMap(visitPropertyItemList(ctx.fileProperties)));
} else if (ctx.REPLACE() != null) {
String newName = ctx.newName.getText();
Map<String, String> properties = ctx.propertyClause() != null
? Maps.newHashMap(visitPropertyClause(ctx.propertyClause())) : Maps.newHashMap();
alterMTMVInfo = new AlterMTMVReplaceInfo(mvName, newName, properties);
}
return new AlterMTMVCommand(alterMTMVInfo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package org.apache.doris.nereids.trees.plans.commands.info;

import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.TableIf.TableType;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.UserException;
import org.apache.doris.mysql.privilege.PrivPredicate;
Expand Down Expand Up @@ -51,6 +53,14 @@ public void analyze(ConnectContext ctx) throws AnalysisException {
mvName.getDb() + ": " + mvName.getTbl());
throw new AnalysisException(message);
}
// check mv exist
try {
Env.getCurrentInternalCatalog().getDbOrAnalysisException(mvName.getDb())
.getTableOrDdlException(mvName.getTbl(),
TableType.MATERIALIZED_VIEW);
} catch (DdlException | org.apache.doris.common.AnalysisException e) {
throw new AnalysisException(e.getMessage(), e);
}
}

public abstract void run() throws UserException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,6 @@ public void run() throws DdlException {
Database db = Env.getCurrentInternalCatalog().getDbOrDdlException(mvName.getDb());
Table table = db.getTableOrDdlException(mvName.getTbl());
Env.getCurrentEnv().renameTable(db, table, newName);
Env.getCurrentEnv().getMtmvService().alterTable(table);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// 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.catalog.Database;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.MTMV;
import org.apache.doris.catalog.TableIf.TableType;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.PropertyAnalyzer;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.qe.ConnectContext;

import java.util.Map;
import java.util.Objects;

/**
* replace
*/
public class AlterMTMVReplaceInfo extends AlterMTMVInfo {
protected final String newName;
private final Map<String, String> properties;

// parsed from properties.
// if false, after replace, there will be only one table exist with.
// if true, the new table and the old table will be exchanged.
// default is true.
private boolean swapTable;

/**
* constructor for alter MTMV
*/
public AlterMTMVReplaceInfo(TableNameInfo mvName, String newName, Map<String, String> properties) {
super(mvName);
this.newName = Objects.requireNonNull(newName, "require newName object");
this.properties = Objects.requireNonNull(properties, "require properties object");
}

/**
* analyze
*
* @param ctx ctx
* @throws AnalysisException AnalysisException
*/
public void analyze(ConnectContext ctx) throws AnalysisException {
super.analyze(ctx);
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, mvName.getCtl(), mvName.getDb(),
newName, PrivPredicate.ALTER)) {
String message = ErrorCode.ERR_TABLEACCESS_DENIED_ERROR.formatErrorMsg("ALTER",
ctx.getQualifiedUser(), ctx.getRemoteIP(),
mvName.getDb() + ": " + newName);
throw new AnalysisException(message);
}
this.swapTable = PropertyAnalyzer.analyzeBooleanProp(properties, PropertyAnalyzer.PROPERTIES_SWAP_TABLE, true);

if (properties != null && !properties.isEmpty()) {
throw new AnalysisException("Unknown properties: " + properties.keySet());
}
// check new mv exist
try {
Env.getCurrentInternalCatalog().getDbOrAnalysisException(mvName.getDb())
.getTableOrDdlException(newName,
TableType.MATERIALIZED_VIEW);
} catch (DdlException | org.apache.doris.common.AnalysisException e) {
throw new AnalysisException(e.getMessage(), e);
}
}

@Override
public void run() throws UserException {
Database db = Env.getCurrentInternalCatalog().getDbOrDdlException(mvName.getDb());
MTMV mtmv = (MTMV) db.getTableOrDdlException(mvName.getTbl(), TableType.MATERIALIZED_VIEW);
MTMV newMtmv = (MTMV) db.getTableOrDdlException(newName, TableType.MATERIALIZED_VIEW);
Env.getCurrentEnv().getAlterInstance().processReplaceTable(db, mtmv, newName, swapTable);
Env.getCurrentEnv().getMtmvService().alterTable(newMtmv);
if (swapTable) {
Env.getCurrentEnv().getMtmvService().alterTable(mtmv);
} else {
Env.getCurrentEnv().getMtmvService().dropMTMV(mtmv);
Env.getCurrentEnv().getMtmvService().dropTable(mtmv);
}
}
}
4 changes: 4 additions & 0 deletions regression-test/data/mtmv_p0/test_multi_level_rename_mtmv.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- This file is automatically generated. You should know what you did if you want to edit this
-- !status --
test_multi_level_rename_mtmv_mv2 SCHEMA_CHANGE

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- This file is automatically generated. You should know what you did if you want to edit this
-- !status --
test_multi_level_replace_mtmv_mv2 SCHEMA_CHANGE

25 changes: 25 additions & 0 deletions regression-test/data/mtmv_p0/test_replace_mtmv.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- This file is automatically generated. You should know what you did if you want to edit this
-- !mv1 --
1 1

-- !mv2 --
2 2

-- !mv1_replace --
2 2

-- !mv2_replace --
1 1

-- !mv1_refresh --
2 2
4 4

-- !mv2_refresh --
1 1
3 3

-- !mv1_replace_not_swap --
1 1
3 3

88 changes: 88 additions & 0 deletions regression-test/suites/mtmv_p0/test_multi_level_rename_mtmv.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// 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.

import org.junit.Assert;

suite("test_multi_level_rename_mtmv","mtmv") {
String dbName = context.config.getDbNameByFile(context.file)
String suiteName = "test_multi_level_rename_mtmv"
String tableName1 = "${suiteName}_table1"
String tableName2 = "${suiteName}_table2"
String mvName1 = "${suiteName}_mv1"
String mvName1_rename = "${suiteName}_mv1_rename"
String mvName2 = "${suiteName}_mv2"
sql """drop table if exists `${tableName1}`"""
sql """drop table if exists `${tableName2}`"""
sql """drop materialized view if exists ${mvName1};"""
sql """drop materialized view if exists ${mvName1_rename};"""
sql """drop materialized view if exists ${mvName2};"""

sql """
CREATE TABLE ${tableName1}
(
k1 TINYINT,
k2 INT not null
)
DISTRIBUTED BY HASH(k2) BUCKETS 2
PROPERTIES (
"replication_num" = "1"
);
"""
sql """
CREATE TABLE ${tableName2}
(
k3 TINYINT,
k4 INT not null
)
DISTRIBUTED BY HASH(k4) BUCKETS 2
PROPERTIES (
"replication_num" = "1"
);
"""
sql """
CREATE MATERIALIZED VIEW ${mvName1}
BUILD DEFERRED REFRESH AUTO ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
PROPERTIES (
'replication_num' = '1'
)
AS
SELECT * from ${tableName1};
"""
sql """
CREATE MATERIALIZED VIEW ${mvName2}
BUILD DEFERRED REFRESH AUTO ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
PROPERTIES (
'replication_num' = '1'
)
AS
SELECT * from ${mvName1};
"""

sql """
alter MATERIALIZED VIEW ${mvName1} rename ${mvName1_rename};
"""

order_qt_status "select Name,State from mv_infos('database'='${dbName}') where Name='${mvName2}'"

sql """drop table if exists `${tableName1}`"""
sql """drop table if exists `${tableName2}`"""
sql """drop materialized view if exists ${mvName1};"""
sql """drop materialized view if exists ${mvName1_rename};"""
sql """drop materialized view if exists ${mvName2};"""
}
Loading

0 comments on commit 9223349

Please sign in to comment.