blob: f371f02653a8fcee52226f2526a24fbc4a471b2b [file] [log] [blame]
// 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.alter;
import org.apache.doris.analysis.AlterTableStmt;
import org.apache.doris.analysis.CreateDbStmt;
import org.apache.doris.analysis.CreateTableStmt;
import org.apache.doris.analysis.DateLiteral;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.catalog.DataProperty;
import org.apache.doris.catalog.Database;
import org.apache.doris.catalog.MaterializedIndex;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.Partition;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.catalog.Table;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.Config;
import org.apache.doris.common.FeConstants;
import org.apache.doris.common.util.TimeUtils;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.thrift.TStorageMedium;
import org.apache.doris.utframe.UtFrameUtils;
import com.google.common.collect.Lists;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class AlterTest {
private static String runningDir = "fe/mocked/AlterTest/" + UUID.randomUUID().toString() + "/";
private static ConnectContext connectContext;
@BeforeClass
public static void beforeClass() throws Exception {
FeConstants.runningUnitTest = true;
FeConstants.default_scheduler_interval_millisecond = 100;
Config.dynamic_partition_enable = true;
Config.dynamic_partition_check_interval_seconds = 1;
UtFrameUtils.createMinDorisCluster(runningDir);
// create connect context
connectContext = UtFrameUtils.createDefaultCtx();
// create database
String createDbStmtStr = "create database test;";
CreateDbStmt createDbStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createDbStmtStr, connectContext);
Catalog.getCurrentCatalog().createDb(createDbStmt);
createTable("CREATE TABLE test.tbl1\n" +
"(\n" +
" k1 date,\n" +
" k2 int,\n" +
" v1 int sum\n" +
")\n" +
"PARTITION BY RANGE(k1)\n" +
"(\n" +
" PARTITION p1 values less than('2020-02-01'),\n" +
" PARTITION p2 values less than('2020-03-01')\n" +
")\n" +
"DISTRIBUTED BY HASH(k2) BUCKETS 3\n" +
"PROPERTIES('replication_num' = '1');");
createTable("CREATE TABLE test.tbl2\n" +
"(\n" +
" k1 date,\n" +
" v1 int sum\n" +
")\n" +
"DISTRIBUTED BY HASH (k1) BUCKETS 3\n" +
"PROPERTIES('replication_num' = '1');");
createTable("CREATE TABLE test.tbl3\n" +
"(\n" +
" k1 date,\n" +
" k2 int,\n" +
" v1 int sum\n" +
")\n" +
"PARTITION BY RANGE(k1)\n" +
"(\n" +
" PARTITION p1 values less than('2020-02-01'),\n" +
" PARTITION p2 values less than('2020-03-01')\n" +
")\n" +
"DISTRIBUTED BY HASH(k2) BUCKETS 3\n" +
"PROPERTIES('replication_num' = '1');");
createTable("CREATE TABLE test.tbl4\n" +
"(\n" +
" k1 date,\n" +
" k2 int,\n" +
" v1 int sum\n" +
")\n" +
"PARTITION BY RANGE(k1)\n" +
"(\n" +
" PARTITION p1 values less than('2020-02-01'),\n" +
" PARTITION p2 values less than('2020-03-01'),\n" +
" PARTITION p3 values less than('2020-04-01'),\n" +
" PARTITION p4 values less than('2020-05-01')\n" +
")\n" +
"DISTRIBUTED BY HASH(k2) BUCKETS 3\n" +
"PROPERTIES" +
"(" +
" 'replication_num' = '1',\n" +
" 'in_memory' = 'false',\n" +
" 'storage_medium' = 'SSD',\n" +
" 'storage_cooldown_time' = '9999-12-31 00:00:00'\n" +
");");
createTable("CREATE TABLE test.tbl5\n" +
"(\n" +
" k1 date,\n" +
" k2 int,\n" +
" v1 int \n" +
") ENGINE=OLAP\n" +
"UNIQUE KEY (k1,k2)\n" +
"PARTITION BY RANGE(k1)\n" +
"(\n" +
" PARTITION p1 values less than('2020-02-01'),\n" +
" PARTITION p2 values less than('2020-03-01')\n" +
")\n" +
"DISTRIBUTED BY HASH(k2) BUCKETS 3\n" +
"PROPERTIES('replication_num' = '1');");
createTable("create external table test.odbc_table\n" +
"( `k1` bigint(20) COMMENT \"\",\n" +
" `k2` datetime COMMENT \"\",\n" +
" `k3` varchar(20) COMMENT \"\",\n" +
" `k4` varchar(100) COMMENT \"\",\n" +
" `k5` float COMMENT \"\"\n" +
")ENGINE=ODBC\n" +
"PROPERTIES (\n" +
"\"host\" = \"127.0.0.1\",\n" +
"\"port\" = \"3306\",\n" +
"\"user\" = \"root\",\n" +
"\"password\" = \"123\",\n" +
"\"database\" = \"db1\",\n" +
"\"table\" = \"tbl1\",\n" +
"\"driver\" = \"Oracle Driver\",\n" +
"\"odbc_type\" = \"oracle\"\n" +
");");
}
@AfterClass
public static void tearDown() {
File file = new File(runningDir);
file.delete();
}
private static void createTable(String sql) throws Exception {
CreateTableStmt createTableStmt = (CreateTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
Catalog.getCurrentCatalog().createTable(createTableStmt);
}
private static void alterTable(String sql, boolean expectedException) throws Exception {
AlterTableStmt alterTableStmt = (AlterTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
try {
Catalog.getCurrentCatalog().alterTable(alterTableStmt);
if (expectedException) {
Assert.fail();
}
} catch (Exception e) {
e.printStackTrace();
if (!expectedException) {
Assert.fail();
}
}
}
private static void alterTableWithExceptionMsg(String sql, String msg) throws Exception {
AlterTableStmt alterTableStmt = (AlterTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
try {
Catalog.getCurrentCatalog().alterTable(alterTableStmt);
} catch (Exception e) {
Assert.assertEquals(msg, e.getMessage());
}
}
@Test
public void alterTableWithEnableFeature() throws Exception {
String stmt = "alter table test.tbl5 enable feature \"SEQUENCE_LOAD\" with properties (\"function_column.sequence_type\" = \"int\") ";
alterTable(stmt, false);
stmt = "alter table test.tbl5 enable feature \"SEQUENCE_LOAD\" with properties (\"function_column.sequence_type\" = \"double\") ";
alterTable(stmt, true);
}
@Test
public void testConflictAlterOperations() throws Exception {
String stmt = "alter table test.tbl1 add partition p3 values less than('2020-04-01'), add partition p4 values less than('2020-05-01')";
alterTable(stmt, true);
stmt = "alter table test.tbl1 add partition p3 values less than('2020-04-01'), drop partition p4";
alterTable(stmt, true);
stmt = "alter table test.tbl1 drop partition p3, drop partition p4";
alterTable(stmt, true);
stmt = "alter table test.tbl1 drop partition p3, add column k3 int";
alterTable(stmt, true);
// no conflict
stmt = "alter table test.tbl1 add column k3 int, add column k4 int";
alterTable(stmt, false);
waitSchemaChangeJobDone(false);
stmt = "alter table test.tbl1 add rollup r1 (k1)";
alterTable(stmt, false);
waitSchemaChangeJobDone(true);
stmt = "alter table test.tbl1 add rollup r2 (k1), r3 (k1)";
alterTable(stmt, false);
waitSchemaChangeJobDone(true);
// enable dynamic partition
// not adding the `start` property so that it won't drop the origin partition p1, p2 and p3
stmt = "alter table test.tbl1 set (\n" +
"'dynamic_partition.enable' = 'true',\n" +
"'dynamic_partition.time_unit' = 'DAY',\n" +
"'dynamic_partition.end' = '3',\n" +
"'dynamic_partition.prefix' = 'p',\n" +
"'dynamic_partition.buckets' = '3'\n" +
" );";
alterTable(stmt, false);
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
OlapTable tbl = (OlapTable) db.getTable("tbl1");
Assert.assertTrue(tbl.getTableProperty().getDynamicPartitionProperty().getEnable());
Assert.assertEquals(4, tbl.getIndexIdToSchema().size());
// add partition when dynamic partition is enable
stmt = "alter table test.tbl1 add partition p3 values less than('2020-04-01') distributed by hash(k2) buckets 4 PROPERTIES ('replication_num' = '1')";
alterTable(stmt, true);
// add temp partition when dynamic partition is enable
stmt = "alter table test.tbl1 add temporary partition tp3 values less than('2020-04-01') distributed by hash(k2) buckets 4 PROPERTIES ('replication_num' = '1')";
alterTable(stmt, false);
Assert.assertEquals(1, tbl.getTempPartitions().size());
// disable the dynamic partition
stmt = "alter table test.tbl1 set ('dynamic_partition.enable' = 'false')";
alterTable(stmt, false);
Assert.assertFalse(tbl.getTableProperty().getDynamicPartitionProperty().getEnable());
// add partition when dynamic partition is disable
stmt = "alter table test.tbl1 add partition p3 values less than('2020-04-01') distributed by hash(k2) buckets 4";
alterTable(stmt, false);
// set table's default replication num
Assert.assertEquals(Short.valueOf("1"), tbl.getDefaultReplicationNum());
stmt = "alter table test.tbl1 set ('default.replication_num' = '3');";
alterTable(stmt, false);
Assert.assertEquals(Short.valueOf("3"), tbl.getDefaultReplicationNum());
// set range table's real replication num
Partition p1 = tbl.getPartition("p1");
Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl.getPartitionInfo().getReplicationNum(p1.getId())));
stmt = "alter table test.tbl1 set ('replication_num' = '3');";
alterTable(stmt, true);
Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl.getPartitionInfo().getReplicationNum(p1.getId())));
// set un-partitioned table's real replication num
OlapTable tbl2 = (OlapTable) db.getTable("tbl2");
Partition partition = tbl2.getPartition(tbl2.getName());
Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl2.getPartitionInfo().getReplicationNum(partition.getId())));
stmt = "alter table test.tbl2 set ('replication_num' = '3');";
alterTable(stmt, false);
Assert.assertEquals(Short.valueOf("3"), Short.valueOf(tbl2.getPartitionInfo().getReplicationNum(partition.getId())));
Thread.sleep(5000); // sleep to wait dynamic partition scheduler run
// add partition without set replication num
stmt = "alter table test.tbl1 add partition p4 values less than('2020-04-10')";
alterTable(stmt, true);
// add partition when dynamic partition is disable
stmt = "alter table test.tbl1 add partition p4 values less than('2020-04-10') ('replication_num' = '1')";
alterTable(stmt, false);
}
// test batch update range partitions' properties
@Test
public void testBatchUpdatePartitionProperties() throws Exception {
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
OlapTable tbl4 = (OlapTable) db.getTable("tbl4");
Partition p1 = tbl4.getPartition("p1");
Partition p2 = tbl4.getPartition("p2");
Partition p3 = tbl4.getPartition("p3");
Partition p4 = tbl4.getPartition("p4");
// batch update replication_num property
String stmt = "alter table test.tbl4 modify partition (p1, p2, p4) set ('replication_num' = '3')";
List<Partition> partitionList = Lists.newArrayList(p1, p2, p4);
for (Partition partition : partitionList) {
Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl4.getPartitionInfo().getReplicationNum(partition.getId())));
}
alterTable(stmt, false);
for (Partition partition : partitionList) {
Assert.assertEquals(Short.valueOf("3"), Short.valueOf(tbl4.getPartitionInfo().getReplicationNum(partition.getId())));
}
Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl4.getPartitionInfo().getReplicationNum(p3.getId())));
// batch update in_memory property
stmt = "alter table test.tbl4 modify partition (p1, p2, p3) set ('in_memory' = 'true')";
partitionList = Lists.newArrayList(p1, p2, p3);
for (Partition partition : partitionList) {
Assert.assertEquals(false, tbl4.getPartitionInfo().getIsInMemory(partition.getId()));
}
alterTable(stmt, false);
for (Partition partition : partitionList) {
Assert.assertEquals(true, tbl4.getPartitionInfo().getIsInMemory(partition.getId()));
}
Assert.assertEquals(false, tbl4.getPartitionInfo().getIsInMemory(p4.getId()));
// batch update storage_medium and storage_cool_down properties
stmt = "alter table test.tbl4 modify partition (p2, p3, p4) set ('storage_medium' = 'HDD')";
DateLiteral dateLiteral = new DateLiteral("9999-12-31 00:00:00", Type.DATETIME);
long coolDownTimeMs = dateLiteral.unixTimestamp(TimeUtils.getTimeZone());
DataProperty oldDataProperty = new DataProperty(TStorageMedium.SSD, coolDownTimeMs);
partitionList = Lists.newArrayList(p2, p3, p4);
for (Partition partition : partitionList) {
Assert.assertEquals(oldDataProperty, tbl4.getPartitionInfo().getDataProperty(partition.getId()));
}
alterTable(stmt, false);
DataProperty newDataProperty = new DataProperty(TStorageMedium.HDD, DataProperty.MAX_COOLDOWN_TIME_MS);
for (Partition partition : partitionList) {
Assert.assertEquals(newDataProperty, tbl4.getPartitionInfo().getDataProperty(partition.getId()));
}
Assert.assertEquals(oldDataProperty, tbl4.getPartitionInfo().getDataProperty(p1.getId()));
// batch update range partitions' properties with *
stmt = "alter table test.tbl4 modify partition (*) set ('replication_num' = '1')";
partitionList = Lists.newArrayList(p1, p2, p3, p4);
alterTable(stmt, false);
for (Partition partition : partitionList) {
Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl4.getPartitionInfo().getReplicationNum(partition.getId())));
}
}
@Test
public void testDynamicPartitionDropAndAdd() throws Exception {
// test day range
String stmt = "alter table test.tbl3 set (\n" +
"'dynamic_partition.enable' = 'true',\n" +
"'dynamic_partition.time_unit' = 'DAY',\n" +
"'dynamic_partition.start' = '-3',\n" +
"'dynamic_partition.end' = '3',\n" +
"'dynamic_partition.prefix' = 'p',\n" +
"'dynamic_partition.buckets' = '3'\n" +
" );";
alterTable(stmt, false);
Thread.sleep(5000); // sleep to wait dynamic partition scheduler run
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
OlapTable tbl = (OlapTable) db.getTable("tbl3");
Assert.assertEquals(4, tbl.getPartitionNames().size());
Assert.assertNull(tbl.getPartition("p1"));
Assert.assertNull(tbl.getPartition("p2"));
}
private void waitSchemaChangeJobDone(boolean rollupJob) throws InterruptedException {
Map<Long, AlterJobV2> alterJobs = Catalog.getCurrentCatalog().getSchemaChangeHandler().getAlterJobsV2();
if (rollupJob) {
alterJobs = Catalog.getCurrentCatalog().getRollupHandler().getAlterJobsV2();
}
for (AlterJobV2 alterJobV2 : alterJobs.values()) {
while (!alterJobV2.getJobState().isFinalState()) {
System.out.println("alter job " + alterJobV2.getJobId() + " is running. state: " + alterJobV2.getJobState());
Thread.sleep(1000);
}
System.out.println(alterJobV2.getType() + " alter job " + alterJobV2.getJobId() + " is done. state: " + alterJobV2.getJobState());
Assert.assertEquals(AlterJobV2.JobState.FINISHED, alterJobV2.getJobState());
Database db = Catalog.getCurrentCatalog().getDb(alterJobV2.getDbId());
OlapTable tbl = (OlapTable) db.getTable(alterJobV2.getTableId());
while (tbl.getState() != OlapTable.OlapTableState.NORMAL) {
Thread.sleep(1000);
}
}
}
@Test
public void testSetDynamicPropertiesInNormalTable() throws Exception {
String tableName = "no_dynamic_table";
String createOlapTblStmt = "CREATE TABLE test.`" + tableName + "` (\n" +
" `k1` date NULL COMMENT \"\",\n" +
" `k2` int NULL COMMENT \"\",\n" +
" `k3` smallint NULL COMMENT \"\",\n" +
" `v1` varchar(2048) NULL COMMENT \"\",\n" +
" `v2` datetime NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"DUPLICATE KEY(`k1`, `k2`, `k3`)\n" +
"COMMENT \"OLAP\"\n" +
"PARTITION BY RANGE (k1)\n" +
"(\n" +
"PARTITION p1 VALUES LESS THAN (\"2014-01-01\"),\n" +
"PARTITION p2 VALUES LESS THAN (\"2014-06-01\"),\n" +
"PARTITION p3 VALUES LESS THAN (\"2014-12-01\")\n" +
")\n" +
"DISTRIBUTED BY HASH(`k1`) BUCKETS 32\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\"\n" +
");";
createTable(createOlapTblStmt);
String alterStmt = "alter table test." + tableName + " set (\"dynamic_partition.enable\" = \"true\");";
String errorMsg = "errCode = 2, detailMessage = Table default_cluster:test.no_dynamic_table is not a dynamic partition table. " +
"Use command `HELP ALTER TABLE` to see how to change a normal table to a dynamic partition table.";
alterTableWithExceptionMsg(alterStmt, errorMsg);
// test set dynamic properties in a no dynamic partition table
String stmt = "alter table test." + tableName + " set (\n" +
"'dynamic_partition.enable' = 'true',\n" +
"'dynamic_partition.time_unit' = 'DAY',\n" +
"'dynamic_partition.start' = '-3',\n" +
"'dynamic_partition.end' = '3',\n" +
"'dynamic_partition.prefix' = 'p',\n" +
"'dynamic_partition.buckets' = '3'\n" +
" );";
alterTable(stmt, false);
}
@Test
public void testSetDynamicPropertiesInDynamicPartitionTable() throws Exception {
String tableName = "dynamic_table";
String createOlapTblStmt = "CREATE TABLE test.`" + tableName + "` (\n" +
" `k1` date NULL COMMENT \"\",\n" +
" `k2` int NULL COMMENT \"\",\n" +
" `k3` smallint NULL COMMENT \"\",\n" +
" `v1` varchar(2048) NULL COMMENT \"\",\n" +
" `v2` datetime NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"DUPLICATE KEY(`k1`, `k2`, `k3`)\n" +
"COMMENT \"OLAP\"\n" +
"PARTITION BY RANGE (k1)\n" +
"(\n" +
"PARTITION p1 VALUES LESS THAN (\"2014-01-01\"),\n" +
"PARTITION p2 VALUES LESS THAN (\"2014-06-01\"),\n" +
"PARTITION p3 VALUES LESS THAN (\"2014-12-01\")\n" +
")\n" +
"DISTRIBUTED BY HASH(`k1`) BUCKETS 32\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"dynamic_partition.enable\" = \"true\",\n" +
"\"dynamic_partition.start\" = \"-3\",\n" +
"\"dynamic_partition.end\" = \"3\",\n" +
"\"dynamic_partition.time_unit\" = \"day\",\n" +
"\"dynamic_partition.prefix\" = \"p\",\n" +
"\"dynamic_partition.buckets\" = \"1\"\n" +
");";
createTable(createOlapTblStmt);
String alterStmt1 = "alter table test." + tableName + " set (\"dynamic_partition.enable\" = \"false\");";
alterTable(alterStmt1, false);
String alterStmt2 = "alter table test." + tableName + " set (\"dynamic_partition.time_unit\" = \"week\");";
alterTable(alterStmt2, false);
String alterStmt3 = "alter table test." + tableName + " set (\"dynamic_partition.start\" = \"-10\");";
alterTable(alterStmt3, false);
String alterStmt4 = "alter table test." + tableName + " set (\"dynamic_partition.end\" = \"10\");";
alterTable(alterStmt4, false);
String alterStmt5 = "alter table test." + tableName + " set (\"dynamic_partition.prefix\" = \"pp\");";
alterTable(alterStmt5, false);
String alterStmt6 = "alter table test." + tableName + " set (\"dynamic_partition.buckets\" = \"5\");";
alterTable(alterStmt6, false);
}
@Test
public void testReplaceTable() throws Exception {
String stmt1 = "CREATE TABLE test.replace1\n" +
"(\n" +
" k1 int, k2 int, k3 int sum\n" +
")\n" +
"AGGREGATE KEY(k1, k2)\n" +
"DISTRIBUTED BY HASH(k1) BUCKETS 10\n" +
"rollup (\n" +
"r1(k1),\n" +
"r2(k2, k3)\n" +
")\n" +
"PROPERTIES(\"replication_num\" = \"1\");";
String stmt2 = "CREATE TABLE test.r1\n" +
"(\n" +
" k1 int, k2 int\n" +
")\n" +
"DISTRIBUTED BY HASH(k1) BUCKETS 11\n" +
"PROPERTIES(\"replication_num\" = \"1\");";
String stmt3 = "CREATE TABLE test.replace2\n" +
"(\n" +
" k1 int, k2 int\n" +
")\n" +
"DISTRIBUTED BY HASH(k1) BUCKETS 11\n" +
"PROPERTIES(\"replication_num\" = \"1\");";
String stmt4 = "CREATE TABLE test.replace3\n" +
"(\n" +
" k1 int, k2 int, k3 int sum\n" +
")\n" +
"PARTITION BY RANGE(k1)\n" +
"(\n" +
"\tPARTITION p1 values less than(\"100\"),\n" +
"\tPARTITION p2 values less than(\"200\")\n" +
")\n" +
"DISTRIBUTED BY HASH(k1) BUCKETS 1\n" +
"rollup (\n" +
"r3(k1),\n" +
"r4(k2, k3)\n" +
")\n" +
"PROPERTIES(\"replication_num\" = \"1\");";
createTable(stmt1);
createTable(stmt2);
createTable(stmt3);
createTable(stmt4);
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
// name conflict
String replaceStmt = "ALTER TABLE test.replace1 REPLACE WITH TABLE r1";
alterTable(replaceStmt, true);
// replace1 with replace2
replaceStmt = "ALTER TABLE test.replace1 REPLACE WITH TABLE replace2";
OlapTable replace1 = (OlapTable) db.getTable("replace1");
OlapTable replace2 = (OlapTable) db.getTable("replace2");
Assert.assertEquals(3, replace1.getPartition("replace1").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
Assert.assertEquals(1, replace2.getPartition("replace2").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
alterTable(replaceStmt, false);
replace1 = (OlapTable) db.getTable("replace1");
replace2 = (OlapTable) db.getTable("replace2");
Assert.assertEquals(1, replace1.getPartition("replace1").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
Assert.assertEquals(3, replace2.getPartition("replace2").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
Assert.assertEquals("replace1", replace1.getIndexNameById(replace1.getBaseIndexId()));
Assert.assertEquals("replace2", replace2.getIndexNameById(replace2.getBaseIndexId()));
// replace with no swap
replaceStmt = "ALTER TABLE test.replace1 REPLACE WITH TABLE replace2 properties('swap' = 'false')";
alterTable(replaceStmt, false);
replace1 = (OlapTable) db.getTable("replace1");
replace2 = (OlapTable) db.getTable("replace2");
Assert.assertNull(replace2);
Assert.assertEquals(3, replace1.getPartition("replace1").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
Assert.assertEquals("replace1", replace1.getIndexNameById(replace1.getBaseIndexId()));
replaceStmt = "ALTER TABLE test.replace1 REPLACE WITH TABLE replace3 properties('swap' = 'true')";
alterTable(replaceStmt, false);
replace1 = (OlapTable) db.getTable("replace1");
OlapTable replace3 = (OlapTable) db.getTable("replace3");
Assert.assertEquals(3, replace1.getPartition("p1").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
Assert.assertEquals(3, replace1.getPartition("p2").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
Assert.assertNotNull(replace1.getIndexIdByName("r3"));
Assert.assertNotNull(replace1.getIndexIdByName("r4"));
Assert.assertEquals(3, replace3.getPartition("replace3").getMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE).size());
Assert.assertNotNull(replace3.getIndexIdByName("r1"));
Assert.assertNotNull(replace3.getIndexIdByName("r2"));
}
@Test
public void testExternalTableAlterOperations() throws Exception {
// external table do not support partition operation
String stmt = "alter table test.odbc_table add partition p3 values less than('2020-04-01'), add partition p4 values less than('2020-05-01')";
alterTable(stmt, true);
// external table do not support rollup
stmt = "alter table test.odbc_table add rollup r1 (k1)";
alterTable(stmt, true);
// external table support add column
stmt = "alter table test.odbc_table add column k6 INT KEY after k1, add column k7 TINYINT KEY after k6";
alterTable(stmt, false);
Database db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
Table odbc_table = db.getTable("odbc_table");
Assert.assertEquals(odbc_table.getBaseSchema().size(), 7);
Assert.assertEquals(odbc_table.getBaseSchema().get(1).getDataType(), PrimitiveType.INT);
Assert.assertEquals(odbc_table.getBaseSchema().get(2).getDataType(), PrimitiveType.TINYINT);
// external table support drop column
stmt = "alter table test.odbc_table drop column k7";
alterTable(stmt, false);
db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
odbc_table = db.getTable("odbc_table");
Assert.assertEquals(odbc_table.getBaseSchema().size(), 6);
// external table support modify column
stmt = "alter table test.odbc_table modify column k6 bigint after k5";
alterTable(stmt, false);
db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
odbc_table = db.getTable("odbc_table");
Assert.assertEquals(odbc_table.getBaseSchema().size(), 6);
Assert.assertEquals(odbc_table.getBaseSchema().get(5).getDataType(), PrimitiveType.BIGINT);
// external table support reorder column
db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
odbc_table = db.getTable("odbc_table");
Assert.assertTrue(odbc_table.getBaseSchema().stream().
map(column -> column.getName()).
reduce("", (totalName, columnName) -> totalName + columnName).equals("k1k2k3k4k5k6"));
stmt = "alter table test.odbc_table order by (k6, k5, k4, k3, k2, k1)";
alterTable(stmt, false);
Assert.assertTrue(odbc_table.getBaseSchema().stream().
map(column -> column.getName()).
reduce("", (totalName, columnName) -> totalName + columnName).equals("k6k5k4k3k2k1"));
// external table support drop column
stmt = "alter table test.odbc_table drop column k6";
alterTable(stmt, false);
stmt = "alter table test.odbc_table drop column k5";
alterTable(stmt, false);
stmt = "alter table test.odbc_table drop column k4";
alterTable(stmt, false);
stmt = "alter table test.odbc_table drop column k3";
alterTable(stmt, false);
stmt = "alter table test.odbc_table drop column k2";
alterTable(stmt, false);
// do not allow drop last column
Assert.assertEquals(odbc_table.getBaseSchema().size(), 1);
stmt = "alter table test.odbc_table drop column k1";
alterTable(stmt, true);
Assert.assertEquals(odbc_table.getBaseSchema().size(), 1);
// external table support rename operation
stmt = "alter table test.odbc_table rename oracle_table";
alterTable(stmt, false);
db = Catalog.getCurrentCatalog().getDb("default_cluster:test");
odbc_table = db.getTable("oracle_table");
Assert.assertTrue(odbc_table != null);
odbc_table = db.getTable("odbc_table");
Assert.assertTrue(odbc_table == null);
}
}