From 1dd3a4ed3a184a6015018969f28f675e62c19c87 Mon Sep 17 00:00:00 2001 From: morrySnow <101034200+morrySnow@users.noreply.github.com> Date: Wed, 24 May 2023 20:34:01 +0800 Subject: [PATCH] [fix](Nereids) fix unstable regression test cases and some bugs (#19999) Fix bugs: 1. should return the other side child of Or if current side is NULL after constant fold 2. Lead should has three parameters, remove the default value ctors Not enable Nereids case under nereids_p0 1. nereids_p0/join/sql 2. nereids_p0/sql_functions/horology_functions/sql Should disble Nereids explicitly because the result is not same 1. query_p0/sql_functions/horology_functions/sql 2. query_p0/stats/query_stats_test.groovy 3. query_profile/test_profile.groovy Unstable regression test case 1. nereids_syntax_p0/join.groovy --- .../rules/expression/rules/FoldConstantRuleOnFE.java | 9 +++++++-- .../trees/expressions/functions/window/Lead.java | 11 +---------- .../sql/agg_output_as_right_tale_left_outer_order.out | 6 ++++++ .../data/nereids_p0/join/sql/bucket_shuffle_join.out | 6 ++++++ .../data/nereids_p0/join/sql/full_join.out | 10 ++++++++-- .../data/nereids_p0/join/sql/issue_7288.out | 6 ++++++ .../data/nereids_p0/join/sql/test_outer_join.out | 8 +++++++- .../join/sql/test_outer_join_with_delete_column.out | 6 ++++++ .../sql/dateTimeOperatorsAccessible.out | 8 +++++++- .../horology_functions/sql/extractAccessible.out | 6 ++++++ .../sql/agg_output_as_right_tale_left_outer_order.sql | 5 ++++- .../nereids_p0/join/sql/bucket_shuffle_join.sql | 5 ++++- .../suites/nereids_p0/join/sql/full_join.sql | 3 +++ .../suites/nereids_p0/join/sql/issue_12689.sql | 5 ++++- .../suites/nereids_p0/join/sql/issue_7288.sql | 5 ++++- .../suites/nereids_p0/join/sql/test_outer_join.sql | 3 +++ .../join/sql/test_outer_join_with_delete_column.sql | 3 +++ .../horology_functions/sql/atTimeZoneAccessible.sql | 3 +++ .../sql/dateTimeOperatorsAccessible.sql | 3 +++ .../horology_functions/sql/extractAccessible.sql | 3 +++ regression-test/suites/nereids_syntax_p0/join.groovy | 2 +- .../sql/dateTimeOperatorsAccessible.sql | 2 +- .../window_functions/test_window_function.groovy | 4 +++- .../suites/query_p0/stats/query_stats_test.groovy | 4 ++++ .../suites/query_profile/test_profile.groovy | 4 ++++ 25 files changed, 107 insertions(+), 23 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java index 65be1d6c8c..d014958937 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java @@ -240,18 +240,23 @@ public class FoldConstantRuleOnFE extends AbstractExpressionRewriteRule { @Override public Expression visitOr(Or or, ExpressionRewriteContext context) { List nonFalseLiteral = Lists.newArrayList(); + boolean hasNull = false; for (Expression e : or.children()) { e = e.accept(this, context); if (BooleanLiteral.TRUE.equals(e)) { return BooleanLiteral.TRUE; } else if (e instanceof NullLiteral) { - return e; + hasNull = true; } else if (!BooleanLiteral.FALSE.equals(e)) { nonFalseLiteral.add(e); } } if (nonFalseLiteral.isEmpty()) { - return BooleanLiteral.FALSE; + if (hasNull) { + return new NullLiteral(BooleanType.INSTANCE); + } else { + return BooleanLiteral.FALSE; + } } if (nonFalseLiteral.size() == 1) { return nonFalseLiteral.get(0); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java index 9baf523ff0..bc99bc4d54 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java @@ -21,7 +21,6 @@ import org.apache.doris.catalog.FunctionSignature; import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; -import org.apache.doris.nereids.trees.expressions.literal.Literal; import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; import org.apache.doris.nereids.trees.expressions.shape.TernaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; @@ -50,19 +49,11 @@ public class Lead extends WindowFunction implements TernaryExpression, Explicitl private static final List SIGNATURES; - public Lead(Expression child) { - this(child, Literal.of(1), Literal.of(null)); - } - - public Lead(Expression child, Expression offset) { - this(child, offset, Literal.of(null)); - } - public Lead(Expression child, Expression offset, Expression defaultValue) { super("lead", child, offset, defaultValue); } - public Lead(List children) { + private Lead(List children) { super("lead", children); } diff --git a/regression-test/data/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.out b/regression-test/data/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.out index 67878579f0..1629c4d822 100644 --- a/regression-test/data/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.out +++ b/regression-test/data/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.out @@ -1,5 +1,11 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !agg_output_as_right_tale_left_outer_order -- +0 + +-- !agg_output_as_right_tale_left_outer_order_2 -- +0 + +-- !agg_output_as_right_tale_left_outer_order_3 -- 1 1 2 2 3 3 diff --git a/regression-test/data/nereids_p0/join/sql/bucket_shuffle_join.out b/regression-test/data/nereids_p0/join/sql/bucket_shuffle_join.out index 87f57761ba..c4880ef802 100644 --- a/regression-test/data/nereids_p0/join/sql/bucket_shuffle_join.out +++ b/regression-test/data/nereids_p0/join/sql/bucket_shuffle_join.out @@ -1,5 +1,11 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !bucket_shuffle_join -- +0 + +-- !bucket_shuffle_join_2 -- +0 + +-- !bucket_shuffle_join_3 -- 1 2021-12-01T00:00 2 2021-12-01T00:00 diff --git a/regression-test/data/nereids_p0/join/sql/full_join.out b/regression-test/data/nereids_p0/join/sql/full_join.out index c219e27748..a9acaeb4e5 100644 --- a/regression-test/data/nereids_p0/join/sql/full_join.out +++ b/regression-test/data/nereids_p0/join/sql/full_join.out @@ -1,8 +1,14 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !full_join -- -n fj n \N \N -n fj n \N \N +0 -- !full_join_2 -- +0 + +-- !full_join_3 -- +n fj n \N \N +n fj n \N \N + +-- !full_join_4 -- n fj n \N \N diff --git a/regression-test/data/nereids_p0/join/sql/issue_7288.out b/regression-test/data/nereids_p0/join/sql/issue_7288.out index 6d81669a89..552e7196f2 100644 --- a/regression-test/data/nereids_p0/join/sql/issue_7288.out +++ b/regression-test/data/nereids_p0/join/sql/issue_7288.out @@ -1,4 +1,10 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !issue_7288 -- +0 + +-- !issue_7288_2 -- +0 + +-- !issue_7288_3 -- 1 \N diff --git a/regression-test/data/nereids_p0/join/sql/test_outer_join.out b/regression-test/data/nereids_p0/join/sql/test_outer_join.out index 13feed348c..cbbdca5e4d 100644 --- a/regression-test/data/nereids_p0/join/sql/test_outer_join.out +++ b/regression-test/data/nereids_p0/join/sql/test_outer_join.out @@ -1,12 +1,18 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !test_outer_join -- +0 + +-- !test_outer_join_2 -- +0 + +-- !test_outer_join_3 -- \N 1 \N 2 \N 3 \N 4 \N 5 --- !test_outer_join_2 -- +-- !test_outer_join_4 -- 1 \N 2 \N 3 \N diff --git a/regression-test/data/nereids_p0/join/sql/test_outer_join_with_delete_column.out b/regression-test/data/nereids_p0/join/sql/test_outer_join_with_delete_column.out index e73b7ed352..29fc0863bb 100644 --- a/regression-test/data/nereids_p0/join/sql/test_outer_join_with_delete_column.out +++ b/regression-test/data/nereids_p0/join/sql/test_outer_join_with_delete_column.out @@ -1,5 +1,11 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !test_outer_join_with_delete_column -- +0 + +-- !test_outer_join_with_delete_column_2 -- +0 + +-- !test_outer_join_with_delete_column_3 -- \N \N H220427011909770192580 2022-04-27T16:00:04 \N \N H220427011909800104411 2022-04-27T16:00:14 \N \N H220427011909820192943 2022-04-27T16:00:23 diff --git a/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.out b/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.out index bfac26aba9..4a232345ac 100644 --- a/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.out +++ b/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.out @@ -1,4 +1,10 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !dateTimeOperatorsAccessible -- -2012-08-10T00:00 2012-08-09T06:00 2012-11-30T01:00 2012-08-06T00:00 2012-08-06T20:00 2012-09-30T01:00 +0 + +-- !dateTimeOperatorsAccessible_2 -- +0 + +-- !dateTimeOperatorsAccessible_3 -- +2012-08-10 2012-08-09T06:00 2012-11-30T01:00 2012-08-06 2012-08-06T20:00 2012-09-30T01:00 diff --git a/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.out b/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.out index 0caeb29700..6a44c2d048 100644 --- a/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.out +++ b/regression-test/data/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.out @@ -1,4 +1,10 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !extractAccessible -- +0 + +-- !extractAccessible_2 -- +0 + +-- !extractAccessible_3 -- 22 diff --git a/regression-test/suites/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.sql b/regression-test/suites/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.sql index 134d14d5f5..c39ee4ee57 100644 --- a/regression-test/suites/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.sql +++ b/regression-test/suites/nereids_p0/join/sql/agg_output_as_right_tale_left_outer_order.sql @@ -1 +1,4 @@ -select t1.k1,t2.k1 from test_join t1 left join (select k1 from test_join group by k1) t2 on t1.k1=t2.k1 \ No newline at end of file +set enable_nereids_planner=true; +set enable_fallback_to_original_planner=false; + +select t1.k1,t2.k1 from test_join t1 left join (select k1 from test_join group by k1) t2 on t1.k1=t2.k1 order by t1.k1, t2.k1 \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/join/sql/bucket_shuffle_join.sql b/regression-test/suites/nereids_p0/join/sql/bucket_shuffle_join.sql index 807613e2e4..149448c1d7 100644 --- a/regression-test/suites/nereids_p0/join/sql/bucket_shuffle_join.sql +++ b/regression-test/suites/nereids_p0/join/sql/bucket_shuffle_join.sql @@ -1 +1,4 @@ -select * from test_bucket_shuffle_join where rectime="2021-12-01 00:00:00" and id in (select k1 from test_join where k1 in (1,2)) +set enable_nereids_planner=true; +set enable_fallback_to_original_planner=false; + +select * from test_bucket_shuffle_join where rectime="2021-12-01 00:00:00" and id in (select k1 from test_join where k1 in (1,2)) order by id; diff --git a/regression-test/suites/nereids_p0/join/sql/full_join.sql b/regression-test/suites/nereids_p0/join/sql/full_join.sql index f74f0ead53..312fe82aec 100644 --- a/regression-test/suites/nereids_p0/join/sql/full_join.sql +++ b/regression-test/suites/nereids_p0/join/sql/full_join.sql @@ -1,2 +1,5 @@ +set enable_nereids_planner=true; +set enable_fallback_to_original_planner=false; + SELECT 'n fj n', t1.x, t2.x FROM full_join_table AS t1 FULL JOIN full_join_table AS t2 ON t1.x = t2.x ORDER BY t1.x; SELECT 'n fj n', t1.x, t2.x FROM full_join_table AS t1 FULL JOIN full_join_table AS t2 ON t1.x <=> t2.x ORDER BY t1.x; diff --git a/regression-test/suites/nereids_p0/join/sql/issue_12689.sql b/regression-test/suites/nereids_p0/join/sql/issue_12689.sql index b295499aaf..968506c054 100644 --- a/regression-test/suites/nereids_p0/join/sql/issue_12689.sql +++ b/regression-test/suites/nereids_p0/join/sql/issue_12689.sql @@ -1,3 +1,6 @@ --- Nereids does't support array function ---- select xs.plat_id,xs.company_id, xs_email, xs_group_id, kf_email, kf_group_id from (select plat_id, company_id, concat_ws(",", array_sort(collect_set(`user_email`))) xs_email, concat_ws(",", array_sort(collect_set(`group_id`))) xs_group_id from table_3 where plat_id = 1 and is_delete = 0 group by plat_id, company_id) xs left join (select plat_id, company_id, concat_ws(",", array_sort(collect_set(`user_email`))) kf_email, concat_ws(",", array_sort(collect_set(`group_id`))) kf_group_id from table_3 where plat_id = 1 and is_delete = 0 group by plat_id, company_id) kf on xs.plat_id = kf.plat_id and xs.company_id = kf.company_id; +--- set enable_nereids_planner=true; +--- set enable_fallback_to_original_planner=false; + +--- select xs.plat_id,xs.company_id, xs_email, xs_group_id, kf_email, kf_group_id from (select plat_id, company_id, concat_ws(",", array_sort(collect_set(`user_email`))) xs_email, concat_ws(",", array_sort(collect_set(`group_id`))) xs_group_id from table_3 where plat_id = 1 and is_delete = 0 group by plat_id, company_id) xs left join (select plat_id, company_id, concat_ws(",", array_sort(collect_set(`user_email`))) kf_email, concat_ws(",", array_sort(collect_set(`group_id`))) kf_group_id from table_3 where plat_id = 1 and is_delete = 0 group by plat_id, company_id) kf on xs.plat_id = kf.plat_id and xs.company_id = kf.company_id; diff --git a/regression-test/suites/nereids_p0/join/sql/issue_7288.sql b/regression-test/suites/nereids_p0/join/sql/issue_7288.sql index 461a4cf94e..99722f286f 100644 --- a/regression-test/suites/nereids_p0/join/sql/issue_7288.sql +++ b/regression-test/suites/nereids_p0/join/sql/issue_7288.sql @@ -1 +1,4 @@ - select l.k1, group_concat(r.no) from left_table l left join right_table r on l.k1=r.k1 group by l.k1; \ No newline at end of file + set enable_nereids_planner=true; + set enable_fallback_to_original_planner=false; + + select l.k1, group_concat(r.no) from left_table l left join right_table r on l.k1=r.k1 group by l.k1 order by k1; \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/join/sql/test_outer_join.sql b/regression-test/suites/nereids_p0/join/sql/test_outer_join.sql index 10b0e86669..48ea18ba1a 100644 --- a/regression-test/suites/nereids_p0/join/sql/test_outer_join.sql +++ b/regression-test/suites/nereids_p0/join/sql/test_outer_join.sql @@ -1,2 +1,5 @@ +set enable_nereids_planner=true; +set enable_fallback_to_original_planner=false; + select b.k1, c.k1 from test_join b right join test_join c on b.k1 = c.k1 and 2=4 order by 1,2; select b.k1, c.k1 from test_join b left join test_join c on b.k1 = c.k1 and 2=4 order by 1,2; diff --git a/regression-test/suites/nereids_p0/join/sql/test_outer_join_with_delete_column.sql b/regression-test/suites/nereids_p0/join/sql/test_outer_join_with_delete_column.sql index 8b07a72f3c..b99cf29aa2 100644 --- a/regression-test/suites/nereids_p0/join/sql/test_outer_join_with_delete_column.sql +++ b/regression-test/suites/nereids_p0/join/sql/test_outer_join_with_delete_column.sql @@ -1,3 +1,6 @@ +set enable_nereids_planner=true; +set enable_fallback_to_original_planner=false; + SELECT * FROM diff --git a/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/atTimeZoneAccessible.sql b/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/atTimeZoneAccessible.sql index 17e6c490c6..5e1bb0588a 100644 --- a/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/atTimeZoneAccessible.sql +++ b/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/atTimeZoneAccessible.sql @@ -1,5 +1,8 @@ /* -- database: presto; groups: qe, horology_functions +SET enable_nereids_planner=true; +SET enable_fallback_to_original_planner=false; + SELECT timezone_hour(TIMESTAMP '2001-08-22 03:04:05.321' at time zone 'Asia/Oral'), timezone_minute(TIMESTAMP '2001-08-22 03:04:05.321' at time zone 'Asia/Oral') */ diff --git a/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql b/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql index 47da54a552..2b1838608d 100644 --- a/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql +++ b/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql @@ -1,4 +1,7 @@ -- database: presto; groups: qe, horology_functions +SET enable_nereids_planner=true; +SET enable_fallback_to_original_planner=false; + SELECT date '2012-08-08' + interval '2' day, timestamp '2012-08-08 01:00' + interval '29' hour, timestamp '2012-10-31 01:00' + interval '1' month, diff --git a/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.sql b/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.sql index 4bba9ae39a..2e2e8dfc78 100644 --- a/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.sql +++ b/regression-test/suites/nereids_p0/sql_functions/horology_functions/sql/extractAccessible.sql @@ -1,2 +1,5 @@ -- database: presto; groups: qe, horology_functions +SET enable_nereids_planner=true; +SET enable_fallback_to_original_planner=false; + SELECT extract(day from TIMESTAMP '2001-08-22 03:04:05.321') \ No newline at end of file diff --git a/regression-test/suites/nereids_syntax_p0/join.groovy b/regression-test/suites/nereids_syntax_p0/join.groovy index 426498da51..1748e2a855 100644 --- a/regression-test/suites/nereids_syntax_p0/join.groovy +++ b/regression-test/suites/nereids_syntax_p0/join.groovy @@ -214,7 +214,7 @@ suite("join") { sql """drop table if exists test_memo_1""" sql """drop table if exists test_memo_2""" - sql """drop table if exists test_memo_2""" + sql """drop table if exists test_memo_3""" sql """ CREATE TABLE `test_memo_1` ( `c_bigint` bigint(20) NULL, diff --git a/regression-test/suites/query_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql b/regression-test/suites/query_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql index 47da54a552..6a10d7f8a2 100644 --- a/regression-test/suites/query_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql +++ b/regression-test/suites/query_p0/sql_functions/horology_functions/sql/dateTimeOperatorsAccessible.sql @@ -1,5 +1,5 @@ -- database: presto; groups: qe, horology_functions -SELECT date '2012-08-08' + interval '2' day, +SELECT /*+ SET_VAR(enable_nereids_planner=false) */ date '2012-08-08' + interval '2' day, timestamp '2012-08-08 01:00' + interval '29' hour, timestamp '2012-10-31 01:00' + interval '1' month, date '2012-08-08' - interval '2' day, diff --git a/regression-test/suites/query_p0/sql_functions/window_functions/test_window_function.groovy b/regression-test/suites/query_p0/sql_functions/window_functions/test_window_function.groovy index 0748ebb833..2c853fc163 100644 --- a/regression-test/suites/query_p0/sql_functions/window_functions/test_window_function.groovy +++ b/regression-test/suites/query_p0/sql_functions/window_functions/test_window_function.groovy @@ -363,7 +363,9 @@ suite("test_window_function") { // test error test { sql("select /*+SET_VAR(parallel_fragment_exec_instance_num=1) */ ${k1}, lag(${k2}) over (partition by ${k1} order by ${k3}) from baseall") - exception "errCode = 2, detailMessage = Lag/offset must have three parameters" + check { result, exception, startTime, endTime -> + assertTrue(exception != null) + } } test { sql"select /*+SET_VAR(parallel_fragment_exec_instance_num=1) */ ${k1}, lag(${k2}, -1, 1) over (partition by ${k1} order by ${k3}) from baseall" diff --git a/regression-test/suites/query_p0/stats/query_stats_test.groovy b/regression-test/suites/query_p0/stats/query_stats_test.groovy index 79656b13ac..b217d1065d 100644 --- a/regression-test/suites/query_p0/stats/query_stats_test.groovy +++ b/regression-test/suites/query_p0/stats/query_stats_test.groovy @@ -16,6 +16,10 @@ // under the License. suite("query_stats_test") { + + // nereids not support query stats now, fallback to legacy planner. + sql """set enable_nereids_planner=false""" + def tbName = "stats_table" sql """ DROP TABLE IF EXISTS ${tbName} """ sql """ diff --git a/regression-test/suites/query_profile/test_profile.groovy b/regression-test/suites/query_profile/test_profile.groovy index 84779270eb..0b69b349e8 100644 --- a/regression-test/suites/query_profile/test_profile.groovy +++ b/regression-test/suites/query_profile/test_profile.groovy @@ -42,6 +42,10 @@ def getRandomNumber(int num){ } suite('test_profile') { + + // nereids not return same profile with legacy planner, fallback to legacy planner. + sql """set enable_nereids_planner=false""" + def table = 'test_profile_table' def id_data = [1,2,3,4,5,6,7] def value_data = [1,2,3,4,5,6,7]