Skip to content

Commit 8569f65

Browse files
committed
[test](mtmv)Add mtmv up and down with drop table test case
1 parent 884d615 commit 8569f65

File tree

3 files changed

+294
-10
lines changed

3 files changed

+294
-10
lines changed

regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,12 +2057,45 @@ class Suite implements GroovyInterceptable {
20572057
}
20582058
}
20592059

2060+
def get_follower_ip = {
2061+
def result = sql """show frontends;"""
2062+
logger.info("result:" + result)
2063+
for (int i = 0; i < result.size(); i++) {
2064+
if (result[i][7] == "FOLLOWER" && result[i][8] == "false" && result[i][11] == "true") {
2065+
return result[i][1]
2066+
}
2067+
}
2068+
return "null"
2069+
}
2070+
2071+
def get_follower_conn = { def explainSelectSql ->
2072+
def switch_ip = get_follower_ip()
2073+
if (switch_ip != "null") {
2074+
def tokens = context.config.jdbcUrl.split('/')
2075+
def url_tmp = tokens[0] + "//" + tokens[2] + "/" + "information_schema" + "?"
2076+
def new_jdbc_url = url_tmp.replaceAll(/\/\/[0-9.]+:/, "//${switch_ip}:")
2077+
logger.info("new_jdbc_url: " + new_jdbc_url)
2078+
2079+
def user = context.config.jdbcUser
2080+
def password = context.config.jdbcPassword
2081+
def explainRes = connect(user, password, new_jdbc_url) {
2082+
sql explainSelectSql
2083+
}
2084+
return explainRes
2085+
}
2086+
logger.info("This cluster not exists follower node")
2087+
return null
2088+
}
2089+
20602090
// mv part in rewrite process, rewrte success and chosen by cbo
20612091
// sync_cbo_rewrite is the bool value which control sync mv is use cbo based mv rewrite
20622092
// is_partition_statistics_ready is the bool value which identifying if partition row count is valid or not
20632093
// if true, check if chosen by cbo or doesn't check
2094+
// The default parameter of curConn is 0, which means there is no limitation on the FE role for the connection;
2095+
// when it is 1, it indicates that the operation is to be executed by connecting to the master; when it is 2,
2096+
// it means the operation is to be executed by connecting to a follower.
20642097
void mv_rewrite_success(query_sql, mv_name, sync_cbo_rewrite = enable_sync_mv_cost_based_rewrite(),
2065-
is_partition_statistics_ready = true) {
2098+
is_partition_statistics_ready = true, curConn = 0) {
20662099
logger.info("query_sql = " + query_sql + ", mv_name = " + mv_name + ", sync_cbo_rewrite = " +sync_cbo_rewrite
20672100
+ ", is_partition_statistics_ready = " + is_partition_statistics_ready)
20682101
if (!is_partition_statistics_ready) {
@@ -2077,10 +2110,23 @@ class Suite implements GroovyInterceptable {
20772110
}
20782111
return
20792112
}
2080-
explain {
2081-
sql(" memo plan ${query_sql}")
2082-
contains("${mv_name} chose")
2113+
if (curConn == 1) {
2114+
explain {
2115+
master_sql(" memo plan ${query_sql}")
2116+
contains("${mv_name} chose")
2117+
}
2118+
} else if (curConn == 2) {
2119+
explain {
2120+
get_follower_conn(" memo plan ${query_sql}")
2121+
contains("${mv_name} chose")
2122+
}
2123+
} else {
2124+
explain {
2125+
sql(" memo plan ${query_sql}")
2126+
contains("${mv_name} chose")
2127+
}
20832128
}
2129+
20842130
}
20852131

20862132
// multi mv part in rewrite process, all rewrte success and chosen by cbo
@@ -2250,8 +2296,11 @@ class Suite implements GroovyInterceptable {
22502296

22512297
// multi mv part in rewrite process, rewrte success without check if chosen by cbo or not
22522298
// sync_cbo_rewrite is the bool value which control sync mv is use cbo based mv rewrite
2299+
// The default parameter of curConn is 0, which means there is no limitation on the FE role for the connection;
2300+
// when it is 1, it indicates that the operation is to be executed by connecting to the master; when it is 2,
2301+
// it means the operation is to be executed by connecting to a follower.
22532302
void mv_rewrite_success_without_check_chosen(query_sql, mv_name,
2254-
sync_cbo_rewrite = enable_sync_mv_cost_based_rewrite()) {
2303+
sync_cbo_rewrite = enable_sync_mv_cost_based_rewrite(), curConn = 0) {
22552304
logger.info("query_sql = " + query_sql + ", mv_name = " + mv_name)
22562305
if (!sync_cbo_rewrite) {
22572306
explain {
@@ -2263,10 +2312,26 @@ class Suite implements GroovyInterceptable {
22632312
}
22642313
return
22652314
}
2266-
explain {
2267-
sql(" memo plan ${query_sql}")
2268-
check { result ->
2269-
result.contains("${mv_name} chose") || result.contains("${mv_name} not chose")
2315+
if (curConn == 1) {
2316+
explain {
2317+
master_sql(" memo plan ${query_sql}")
2318+
check { result ->
2319+
result.contains("${mv_name} chose") || result.contains("${mv_name} not chose")
2320+
}
2321+
}
2322+
} else if (curConn == 2) {
2323+
explain {
2324+
get_follower_conn(" memo plan ${query_sql}")
2325+
check { result ->
2326+
result.contains("${mv_name} chose") || result.contains("${mv_name} not chose")
2327+
}
2328+
}
2329+
} else {
2330+
explain {
2331+
sql(" memo plan ${query_sql}")
2332+
check { result ->
2333+
result.contains("${mv_name} chose") || result.contains("${mv_name} not chose")
2334+
}
22702335
}
22712336
}
22722337
}

regression-test/suites/mtmv_up_down_olap_p0/load.groovy

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,26 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
/*
19+
Build the basic information. When conceiving upgrade and downgrade test cases, you should firmly grasp the object
20+
representation of the function in the FE meta.
21+
Taking MTMV as an example, the main function points are creation, refresh, and rewriting, and the involved entities
22+
are the base table and MTMV.
23+
1.When creating an MTMV, check if the rewriting meets the expectations.
24+
2.When refreshing an MTMV, check if the rewriting meets the expectations.
25+
3.When deleting an MTMV, check if the rewriting meets the expectations.
26+
4.When deleting a base table, check if the rewriting meets the expectations; then trigger a refresh and check if the
27+
rewriting meets the expectations.
28+
5.When deleting a partition of a base table, check if the rewriting meets the expectations; then trigger a refresh and
29+
check if the rewriting meets the expectations.
30+
6.Design a slightly more complex scenario. For example: Build an MTMV with two base tables. When deleting one of the
31+
base tables, check if the refresh of the MTMV meets the expectations and if the rewriting meets the expectations;
32+
create an MTMV with the undeleted base table and check if it can be created and refreshed normally, and if the
33+
corresponding rewriting meets the expectations.
34+
*/
1835
suite("test_upgrade_downgrade_prepare_olap_mtmv","p0,mtmv,restart_fe") {
1936
String suiteName = "mtmv_up_down_olap"
37+
String dbName = context.config.getDbNameByFile(context.file)
2038
String mvName = "${suiteName}_mtmv"
2139
String tableName = "${suiteName}_table"
2240
String tableName2 = "${suiteName}_table2"
@@ -68,4 +86,123 @@ suite("test_upgrade_downgrade_prepare_olap_mtmv","p0,mtmv,restart_fe") {
6886
SELECT a.* FROM ${tableName} a inner join ${tableName2} b on a.user_id=b.user_id;
6987
"""
7088
waitingMTMVTaskFinishedByMvName(mvName)
89+
90+
91+
String dropTableName1 = """${suiteName}_DropTableName1"""
92+
String dropTableName2 = """${suiteName}_DropTableName2"""
93+
String dropTableName4 = """${suiteName}_DropTableName4"""
94+
String dropMtmvName1 = """${suiteName}_dropMtmvName1"""
95+
String dropMtmvName2 = """${suiteName}_dropMtmvName2"""
96+
String dropMtmvName3 = """${suiteName}_dropMtmvName3"""
97+
98+
sql """drop materialized view if exists ${dropMtmvName1};"""
99+
sql """drop materialized view if exists ${dropMtmvName2};"""
100+
sql """drop materialized view if exists ${dropMtmvName3};"""
101+
sql """drop table if exists `${dropTableName1}`"""
102+
sql """drop table if exists `${dropTableName2}`"""
103+
sql """drop table if exists `${dropTableName4}`"""
104+
105+
106+
sql """
107+
CREATE TABLE `${dropTableName1}` (
108+
`user_id` LARGEINT NOT NULL COMMENT '\"用户id\"',
109+
`date` DATE NOT NULL COMMENT '\"数据灌入日期时间\"',
110+
`num` SMALLINT NOT NULL COMMENT '\"数量\"'
111+
) ENGINE=OLAP
112+
DUPLICATE KEY(`user_id`, `date`, `num`)
113+
COMMENT 'OLAP'
114+
PARTITION BY RANGE(`date`)
115+
(PARTITION p201701_1000 VALUES [('0000-01-01'), ('2017-02-01')),
116+
PARTITION p201702_2000 VALUES [('2017-02-01'), ('2017-03-01')),
117+
PARTITION p201703_3000 VALUES [('2017-03-01'), ('2017-04-01')),
118+
PARTITION p201704_4000 VALUES [('2017-04-01'), ('2017-05-01')),
119+
PARTITION p201705_5000 VALUES [('2017-05-01'), ('2017-06-01')),
120+
PARTITION p201706_6000 VALUES [('2017-06-01'), ('2017-07-01')),
121+
PARTITION p201707_7000 VALUES [('2017-07-01'), ('2017-08-01')),
122+
PARTITION p201708_8000 VALUES [('2017-08-01'), ('2017-09-01')),
123+
PARTITION p201709_9000 VALUES [('2017-09-01'), ('2017-10-01')),
124+
PARTITION p201710_1000 VALUES [('2017-10-01'), ('2017-11-01')),
125+
PARTITION p201711_1100 VALUES [('2017-11-01'), ('2017-12-01')),
126+
PARTITION p201712_1200 VALUES [('2017-12-01'), ('2018-01-01')))
127+
DISTRIBUTED BY HASH(`user_id`) BUCKETS 2
128+
PROPERTIES ('replication_num' = '1') ;
129+
"""
130+
sql """
131+
insert into ${dropTableName1} values(1,"2017-01-15",1),(2,"2017-02-15",2),(3,"2017-03-15",3),(4,"2017-04-15",4),(5,"2017-05-15",5),(6,"2017-06-15",6),(7,"2017-07-15",7),(8,"2017-08-15",8),(9,"2017-09-15",9),(10,"2017-10-15",10),(11,"2017-11-15",11),(12,"2017-12-15",12);
132+
"""
133+
134+
sql """
135+
CREATE TABLE `${dropTableName2}` (
136+
`user_id` LARGEINT NOT NULL COMMENT '\"用户id\"',
137+
`date` DATE NOT NULL COMMENT '\"数据灌入日期时间\"',
138+
`num` SMALLINT NOT NULL COMMENT '\"数量\"'
139+
) ENGINE=OLAP
140+
DUPLICATE KEY(`user_id`, `date`, `num`)
141+
COMMENT 'OLAP'
142+
PARTITION BY RANGE(`date`)
143+
(PARTITION p201701_1000 VALUES [('0000-01-01'), ('2017-02-01')),
144+
PARTITION p201702_2000 VALUES [('2017-02-01'), ('2017-03-01')),
145+
PARTITION p201703_3000 VALUES [('2017-03-01'), ('2017-04-01')),
146+
PARTITION p201704_4000 VALUES [('2017-04-01'), ('2017-05-01')),
147+
PARTITION p201705_5000 VALUES [('2017-05-01'), ('2017-06-01')),
148+
PARTITION p201706_6000 VALUES [('2017-06-01'), ('2017-07-01')),
149+
PARTITION p201707_7000 VALUES [('2017-07-01'), ('2017-08-01')),
150+
PARTITION p201708_8000 VALUES [('2017-08-01'), ('2017-09-01')),
151+
PARTITION p201709_9000 VALUES [('2017-09-01'), ('2017-10-01')),
152+
PARTITION p201710_1000 VALUES [('2017-10-01'), ('2017-11-01')),
153+
PARTITION p201711_1100 VALUES [('2017-11-01'), ('2017-12-01')),
154+
PARTITION p201712_1200 VALUES [('2017-12-01'), ('2018-01-01')))
155+
DISTRIBUTED BY HASH(`user_id`) BUCKETS 2
156+
PROPERTIES ('replication_num' = '1') ;
157+
"""
158+
sql """
159+
insert into ${dropTableName2} values(1,"2017-01-15",1),(2,"2017-02-15",2),(3,"2017-03-15",3),(4,"2017-04-15",4),(5,"2017-05-15",5),(6,"2017-06-15",6),(7,"2017-07-15",7),(8,"2017-08-15",8),(9,"2017-09-15",9),(10,"2017-10-15",10),(11,"2017-11-15",11),(12,"2017-12-15",12);
160+
"""
161+
162+
sql """
163+
CREATE TABLE `${dropTableName4}` (
164+
`user_id` LARGEINT NOT NULL COMMENT '\"用户id\"',
165+
`age` SMALLINT NOT NULL COMMENT '\"年龄\"'
166+
) ENGINE=OLAP
167+
DUPLICATE KEY(`user_id`, `age`)
168+
COMMENT 'OLAP'
169+
DISTRIBUTED BY HASH(`user_id`) BUCKETS 2
170+
PROPERTIES ('replication_num' = '1') ;
171+
"""
172+
sql """
173+
insert into ${dropTableName4} values(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12);
174+
"""
175+
176+
177+
sql """
178+
CREATE MATERIALIZED VIEW ${dropMtmvName1}
179+
REFRESH AUTO ON MANUAL
180+
partition by(`date`)
181+
DISTRIBUTED BY RANDOM BUCKETS 2
182+
PROPERTIES ('replication_num' = '1')
183+
AS
184+
SELECT a.* FROM ${dropTableName1} a inner join ${dropTableName4} b on a.user_id=b.user_id;
185+
"""
186+
waitingMTMVTaskFinishedByMvName(dropMtmvName1)
187+
188+
sql """
189+
CREATE MATERIALIZED VIEW ${dropMtmvName2}
190+
REFRESH AUTO ON MANUAL
191+
partition by(`date`)
192+
DISTRIBUTED BY RANDOM BUCKETS 2
193+
PROPERTIES ('replication_num' = '1')
194+
AS
195+
SELECT a.* FROM ${dropTableName2} a inner join ${dropTableName4} b on a.user_id=b.user_id;
196+
"""
197+
waitingMTMVTaskFinishedByMvName(dropMtmvName2)
198+
199+
def state_mtmv1 = sql """select State,RefreshState,SyncWithBaseTables from mv_infos('database'='${dbName}') where Name = '${dropMtmvName1}';"""
200+
assertTrue(state_mtmv1[0][0] == "NORMAL")
201+
assertTrue(state_mtmv1[0][1] == "SUCCESS")
202+
assertTrue(state_mtmv1[0][2] == true)
203+
def state_mtmv2 = sql """select State,RefreshState,SyncWithBaseTables from mv_infos('database'='${dbName}') where Name = '${dropMtmvName2}';"""
204+
assertTrue(state_mtmv2[0][0] == "NORMAL")
205+
assertTrue(state_mtmv2[0][1] == "SUCCESS")
206+
assertTrue(state_mtmv2[0][2] == true)
207+
71208
}

regression-test/suites/mtmv_up_down_olap_p0/test_upgrade_downgrade_olap_mtmv.groovy

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,95 @@ suite("test_upgrade_downgrade_olap_mtmv","p0,mtmv,restart_fe") {
2020
String dbName = context.config.getDbNameByFile(context.file)
2121
String mvName = "${suiteName}_mtmv"
2222
String tableName = "${suiteName}_table"
23+
2324
// test data is normal
2425
order_qt_refresh_init "SELECT * FROM ${mvName}"
2526
// test is sync
2627
order_qt_mtmv_sync "select SyncWithBaseTables from mv_infos('database'='${dbName}') where Name='${mvName}'"
27-
sql """
28+
sql """
2829
REFRESH MATERIALIZED VIEW ${mvName} complete
2930
"""
3031
// test can refresh success
3132
waitingMTMVTaskFinishedByMvName(mvName)
33+
34+
String dropTableName1 = """${suiteName}_DropTableName1"""
35+
String dropTableName2 = """${suiteName}_DropTableName2"""
36+
String dropTableName4 = """${suiteName}_DropTableName4"""
37+
String dropMtmvName1 = """${suiteName}_dropMtmvName1"""
38+
String dropMtmvName2 = """${suiteName}_dropMtmvName2"""
39+
String dropMtmvName3 = """${suiteName}_dropMtmvName3"""
40+
41+
// drop table
42+
sql """drop table if exists ${dropTableName1}"""
43+
def state_mtmv1 = sql """select State,RefreshState,SyncWithBaseTables from mv_infos('database'='${dbName}') where Name = '${dropMtmvName1}';"""
44+
assertTrue(state_mtmv1[0][0] == "SCHEMA_CHANGE")
45+
assertTrue(state_mtmv1[0][1] == "SUCCESS" || state_mtmv1[0][1] == "INIT")
46+
assertTrue(state_mtmv1[0][2] == false)
47+
48+
// drop partition
49+
def parts_res = sql """show partitions from ${dropTableName2}"""
50+
sql """ALTER TABLE ${dropTableName2} DROP PARTITION ${parts_res[0][1]};"""
51+
def state_mtmv2 = sql """select State,RefreshState,SyncWithBaseTables from mv_infos('database'='${dbName}') where Name = '${dropMtmvName2}';"""
52+
assertTrue(state_mtmv2[0][0] == "NORMAL")
53+
assertTrue(state_mtmv2[0][1] == "SUCCESS")
54+
def mtmv_part_res = sql """show partitions from ${dropMtmvName2}"""
55+
logger.info("mtmv_part_res[0][18]: " + mtmv_part_res[0][18])
56+
logger.info("mtmv_part_res[0][19]: " + mtmv_part_res[0][19])
57+
logger.info("mtmv_part_res:" + mtmv_part_res)
58+
def part_1 = mtmv_part_res.size()
59+
def diff_part = 0
60+
for (int i = 0; i < mtmv_part_res.size(); i++) {
61+
if (mtmv_part_res[i][18] == "false" && mtmv_part_res[i][19] as String == "[${dropTableName2}]") {
62+
diff_part = diff_part + 1
63+
}
64+
}
65+
66+
def sql2 = "SELECT a.* FROM ${dropTableName2} a inner join ${dropTableName4} b on a.user_id=b.user_id;"
67+
mv_rewrite_success(sql2, dropMtmvName2)
68+
69+
// An error occurred when refreshing the partition individually, and the partition was not deleted after the refresh.
70+
try {
71+
sql """refresh MATERIALIZED VIEW ${dropMtmvName2} partition(${mtmv_part_res[0][1]})"""
72+
} catch (Exception e) {
73+
logger.info(e.getMessage())
74+
}
75+
76+
// When refreshing the entire MTMV, the partition will be deleted.
77+
sql """refresh MATERIALIZED VIEW ${dropMtmvName2} auto"""
78+
waitingMTMVTaskFinishedByMvName(dropMtmvName2)
79+
mtmv_part_res = sql """show partitions from ${dropMtmvName2}"""
80+
logger.info("mtmv_part_res:" + mtmv_part_res)
81+
def part_2 = mtmv_part_res.size()
82+
assertTrue(part_1 == part_2 + diff_part)
83+
84+
state_mtmv2 = sql """select State,RefreshState,SyncWithBaseTables from mv_infos('database'='${dbName}') where Name = '${dropMtmvName2}';"""
85+
logger.info("state_mtmv2:" + state_mtmv2)
86+
assertTrue(state_mtmv2[0][0] == "NORMAL")
87+
assertTrue(state_mtmv2[0][1] == "SUCCESS")
88+
assertTrue(state_mtmv2[0][2] == true)
89+
mv_rewrite_success(sql2, dropMtmvName2)
90+
def follower_ip = get_follower_ip()
91+
if (follower_ip != "null") {
92+
mv_rewrite_success(sql2, dropMtmvName2,
93+
enable_sync_mv_cost_based_rewrite(), is_partition_statistics_ready(dbName, [dropTableName2, dropTableName4]), 2)
94+
}
95+
96+
97+
// After deleting the table, you can create a new MTMV
98+
def cur_dropMtmvName3 = dropMtmvName3 + UUID.randomUUID().toString().replaceAll("-", "")
99+
sql """
100+
CREATE MATERIALIZED VIEW ${cur_dropMtmvName3}
101+
REFRESH AUTO ON MANUAL
102+
DISTRIBUTED BY RANDOM BUCKETS 2
103+
PROPERTIES ('replication_num' = '1')
104+
AS
105+
SELECT user_id, age FROM ${dropTableName4};
106+
"""
107+
waitingMTMVTaskFinishedByMvName(cur_dropMtmvName3)
108+
mv_rewrite_success_without_check_chosen("""SELECT user_id FROM ${dropTableName4}""", cur_dropMtmvName3)
109+
if (follower_ip != "null") {
110+
mv_rewrite_success_without_check_chosen("""SELECT user_id FROM ${dropTableName4}""", cur_dropMtmvName3,
111+
enable_sync_mv_cost_based_rewrite(), 2)
112+
}
113+
32114
}

0 commit comments

Comments
 (0)