Skip to content

Commit 1587280

Browse files
Tor Didriksendahlerlend
Tor Didriksen
authored andcommitted
Bug#37592337 Add cmake option ENABLE_HYPERGRAPH_OPTIMIZER
OPTIMIZER_SWITCH_HYPERGRAPH_OPTIMIZER is currently not part of OPTIMIZER_SWITCH_DEFAULT. Add a cmake option ENABLE_HYPERGRAPH_OPTIMIZER to enable adding it. Default value OFF, if set to ON it will also enable WITH_HYPERGRAPH_OPTIMIZER. We currently test the hypergraph optimizer with a special --hypergraph to mtr. This flag is passed on to mysqltest, which will do "SET @@session.optimizer_switch='hypergraph_optimizer=on', " "@@global.optimizer_switch='hypergraph_optimizer=on';"; for each connection. Handling of .result differences between traditional and hypergraph optimizer is based on special tags in the .mtr tests, environment variables and special diff handling of .result files. Extend mysqltest to also ask the server "is the hypergraph optimizer active"? If so, activate the special diff handling in mysqltest. Also for the mtr tests: ask the server rather than relying on a special environment variable HYPERGRAPH_TEST set by mtr. A few .mtr tests did SHOW STATUS LIKE 'Created_tmp_tables' and failed due to the extra "SHOW VARIABLES LIKE 'optimizer_switch'" from mysqltest. Fixed by doing "FLUSH STATUS" in each test. The patch also introduces a new option --hypergraph-off. With this option mysqltest will do "SET @@session.optimizer_switch='hypergraph_optimizer=off', " "@@global.optimizer_switch='hypergraph_optimizer=off';"; for each connection. This is implemented in order to be able to test the old optimizer when OPTIMIZER_SWITCH_HYPERGRAPH_OPTIMIZER is part of OPTIMIZER_SWITCH_DEFAULT. To summarize the options: --hypergraph : mysqltest turns hypergraph ON --hypergraph-off : mysqltest turns hypergraph OFF both options given : illegal, mtr aborts none of them given : mysqltest asks server whether hypergraph is ON/OFF A few mtr tests will explicitly turn hypergraph ON themselves, by doing --source include/have_hypergraph.inc This will re-enable hypergraph for that particular test even when --hypergraph-off is given. For test suites which have not been prepared for running with --hypergraph, running against a server built with ENABLE_HYPERGRAPH_OPTIMIZER, the new --hypergraph-off option will revert back to the original behaviour, e.g: ./mtr --mem --force --parallel=8 --with-ndb-only --hypergraph-off Change-Id: I3f53eec974a0b40d58a97420e1f0a75aceb265ce
1 parent 033523b commit 1587280

29 files changed

+183
-48
lines changed

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2258,6 +2258,13 @@ ELSE()
22582258
# Do not initialize the option, set it ON for $<CONFIG:Debug>
22592259
SET(WITH_HYPERGRAPH_OPTIMIZER_DEFAULT "default")
22602260
ENDIF()
2261+
OPTION(ENABLE_HYPERGRAPH_OPTIMIZER
2262+
"Enable hypergraph optimizer in OPTIMIZER_SWITCH_DEFAULT" OFF
2263+
)
2264+
IF(ENABLE_HYPERGRAPH_OPTIMIZER)
2265+
SET(WITH_HYPERGRAPH_OPTIMIZER ON)
2266+
SET(WITH_HYPERGRAPH_OPTIMIZER ON CACHE BOOL "" FORCE)
2267+
ENDIF()
22612268

22622269
# Allow SHOW PARSE_TREE on debug build by default.
22632270
IF(CMAKE_BUILD_TYPE_UPPER STREQUAL "DEBUG" OR WITH_DEBUG)

client/mysqltest.cc

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ enum {
172172
OPT_CURSOR_PROTOCOL,
173173
OPT_EXPLAIN_PROTOCOL,
174174
OPT_HYPERGRAPH,
175+
OPT_HYPERGRAPH_OFF,
175176
OPT_JSON_EXPLAIN_PROTOCOL,
176177
OPT_LOG_DIR,
177178
OPT_MARK_PROGRESS,
@@ -239,6 +240,10 @@ static const char *load_default_groups[] = {"mysqltest", "client", nullptr};
239240
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos = line_buffer;
240241
static bool can_handle_expired_passwords = true;
241242
static bool opt_hypergraph = false;
243+
static bool opt_hypergraph_off = false;
244+
static bool hypergraph_enabled = false;
245+
246+
bool hypergraph_is_active() { return opt_hypergraph || hypergraph_enabled; }
242247

243248
/*
244249
These variables control the behavior of the asynchronous operations for
@@ -1311,7 +1316,7 @@ void handle_error(struct st_command *command, std::uint32_t err_errno,
13111316
const char *interpolated_query = nullptr) {
13121317
DBUG_TRACE;
13131318

1314-
if (opt_hypergraph && err_errno == ER_HYPERGRAPH_NOT_SUPPORTED_YET) {
1319+
if (hypergraph_is_active() && err_errno == ER_HYPERGRAPH_NOT_SUPPORTED_YET) {
13151320
const char errstr[] = "<ignored hypergraph optimizer error: ";
13161321
dynstr_append_mem(ds, errstr, sizeof(errstr) - 1);
13171322
replace_dynstr_append(ds, err_error);
@@ -2082,7 +2087,7 @@ static bool show_diff(DYNAMIC_STRING *ds, const char *filename1,
20822087
"2>&1", nullptr);
20832088
if (exit_code > 1) diff_name = nullptr;
20842089
}
2085-
} else if (exit_code == 1 && opt_hypergraph &&
2090+
} else if (exit_code == 1 && hypergraph_is_active() &&
20862091
is_diff_clean_except_hypergraph(&ds_diff)) {
20872092
dynstr_free(&ds_diff);
20882093
return true;
@@ -6631,6 +6636,18 @@ static bool enable_hypergraph_optimizer(st_connection *con) {
66316636
return mysql_query_wrapper(&con->mysql, set_stmt) != 0;
66326637
}
66336638

6639+
/**
6640+
Disable the hypergraph optimizer in a connection. This allows you to test
6641+
the traditional optimizer in a mysqld server configured with
6642+
hypergraph_optimizer default ON.
6643+
*/
6644+
static bool disable_hypergraph_optimizer(st_connection *con) {
6645+
const char *set_stmt =
6646+
"SET @@session.optimizer_switch='hypergraph_optimizer=off', "
6647+
"@@global.optimizer_switch='hypergraph_optimizer=off';";
6648+
return mysql_query_wrapper(&con->mysql, set_stmt) != 0;
6649+
}
6650+
66346651
/*
66356652
Open a new connection to MySQL Server with the parameters
66366653
specified. Make the new connection the current connection.
@@ -6741,6 +6758,8 @@ static void do_connect(struct st_command *command) {
67416758
assert(con_slot != next_con);
67426759
if (opt_hypergraph) {
67436760
enable_hypergraph_optimizer(con_slot);
6761+
} else if (opt_hypergraph_off) {
6762+
disable_hypergraph_optimizer(con_slot);
67446763
}
67456764
}
67466765
/* mysql_reconnect changes this setting to true. We really want it to be
@@ -7870,9 +7889,15 @@ static struct my_option my_long_options[] = {
78707889
{"host", 'h', "Connect to host.", &opt_host, &opt_host, nullptr, GET_STR,
78717890
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
78727891
{"hypergraph", OPT_HYPERGRAPH,
7873-
"Force all queries to be run under the hypergraph optimizer.",
7892+
"Force all queries to be run under the hypergraph optimizer. "
7893+
"SET @@optimizer_switch='hypergraph_optimizer=ON",
78747894
&opt_hypergraph, &opt_hypergraph, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
78757895
nullptr, 0, nullptr},
7896+
{"hypergraph-off", OPT_HYPERGRAPH_OFF,
7897+
"Force all queries to be run under the old optimizer. "
7898+
"SET @@optimizer_switch='hypergraph_optimizer=OFF",
7899+
&opt_hypergraph_off, &opt_hypergraph_off, nullptr, GET_BOOL, NO_ARG, 0, 0,
7900+
0, nullptr, 0, nullptr},
78767901
{"include", 'i', "Include SQL before each test case.", &opt_include,
78777902
&opt_include, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
78787903
nullptr},
@@ -9161,7 +9186,7 @@ static void run_query(struct st_connection *cn, struct st_command *command,
91619186
dynstr_append_mem(ds, "\n", 1);
91629187
}
91639188

9164-
if (skip_if_hypergraph && opt_hypergraph) {
9189+
if (skip_if_hypergraph && hypergraph_is_active()) {
91659190
constexpr char message[] =
91669191
"<ignored hypergraph optimizer error: statement skipped by "
91679192
"test>\n";
@@ -9699,6 +9724,10 @@ int main(int argc, char **argv) {
96999724

97009725
parse_args(argc, argv);
97019726

9727+
if (opt_hypergraph && opt_hypergraph_off) {
9728+
die("Cannot specify both hypergraph and hypergraph-off");
9729+
}
9730+
97029731
#ifdef _WIN32
97039732
// Create an event to request stack trace when timeout occurs
97049733
if (opt_safe_process_pid) create_stacktrace_collector_event();
@@ -9855,6 +9884,28 @@ int main(int argc, char **argv) {
98559884
"hypergraph optimizer. (errno=%d)",
98569885
my_errno());
98579886
}
9887+
} else if (opt_hypergraph_off) {
9888+
if (disable_hypergraph_optimizer(con)) {
9889+
die("--hypergraph-off was given, (errno=%d)", my_errno());
9890+
}
9891+
} else {
9892+
// No explicit hypergraph option? Ask the server hypergraph is enabled.
9893+
std::string optimizer_switch;
9894+
if (query_get_string(&con->mysql, "SHOW VARIABLES LIKE 'optimizer_switch'",
9895+
1, &optimizer_switch)) {
9896+
die("Failed to get optimizer_switch from server");
9897+
}
9898+
// It is tempting to FLUSH STATUS, but this modifies the database, and will
9899+
// cause misc tests (with implicit assumptions about database state)
9900+
// to fail. The query above will create a temporary table, so mtr tests
9901+
// making assumptions about 'Created_tmp_tables' must FLUSH STATUS.
9902+
// if (mysql_query(&con->mysql, "FLUSH STATUS")) {
9903+
// die("Failed to FLUSH STATUS");
9904+
// }
9905+
const size_t found_hyper = optimizer_switch.find("hypergraph_optimizer=on");
9906+
if (found_hyper != std::string::npos) {
9907+
hypergraph_enabled = true;
9908+
}
98589909
}
98599910

98609911
if (opt_include) {

mysql-test/include/disable_hypergraph.inc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
# including include/have_hypergraph.inc.
33

44
--disable_query_log
5-
SET @@session.optimizer_switch = 'hypergraph_optimizer=off',
6-
@@global.optimizer_switch = 'hypergraph_optimizer=off';
5+
if(!$hypergraph_was_active) {
6+
SET @@session.optimizer_switch = 'hypergraph_optimizer=off',
7+
@@global.optimizer_switch = 'hypergraph_optimizer=off';
8+
}
79
--enable_query_log

mysql-test/include/have_hypergraph.inc

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
# --source include/disable_hypergraph.inc
1111

1212
--disable_query_log
13-
--error 0, ER_HYPERGRAPH_NOT_SUPPORTED_YET
14-
SET @@session.optimizer_switch = 'hypergraph_optimizer=on',
15-
@@global.optimizer_switch = 'hypergraph_optimizer=on';
16-
if (`SELECT NOT FIND_IN_SET('hypergraph_optimizer=on', @@optimizer_switch)`) {
17-
--skip Test requires binaries built with WITH_HYPERGRAPH_OPTIMIZER=ON
13+
--source include/hypergraph_is_active.inc
14+
--let $hypergraph_was_active=$hypergraph_is_active;
15+
if(!$hypergraph_is_active) {
16+
--error 0, ER_HYPERGRAPH_NOT_SUPPORTED_YET
17+
SET @@session.optimizer_switch = 'hypergraph_optimizer=on',
18+
@@global.optimizer_switch = 'hypergraph_optimizer=on';
19+
if (`SELECT NOT FIND_IN_SET('hypergraph_optimizer=on', @@optimizer_switch)`) {
20+
--skip Test requires binaries built with WITH_HYPERGRAPH_OPTIMIZER=ON
21+
}
1822
}
1923
--enable_query_log
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# include/hypergraph_is_active.inc
2+
#
3+
# Ask the server whether hypergraph_optimizer is ON
4+
#
5+
--let $hypergraph_is_active= 0
6+
if (`select locate('hypergraph_optimizer=on', @@optimizer_switch) > 0`)
7+
{
8+
--let $hypergraph_is_active= 1
9+
}

mysql-test/include/mysqld--help.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ perl;
6868
s/\b286720\b/262144/;
6969
s/\b442368\b/262144/;
7070
s/\b221184\b/262144/;
71+
s/hypergraph_optimizer=on/hypergraph_optimizer=off/;
7172
# Replacing port number with string
7273
s/^port \d+/port ####/;
7374
# log-tc-size varies by platform

mysql-test/include/not_hypergraph.inc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# include/not_hypergraph.inc
22
#
3-
# Skip the test if we are forcing the hypergraph optimizer. This is typically
3+
# Skip the test if we are using the hypergraph optimizer. This is typically
44
# because the test expects some given query plan, or more generally expects
55
# certain debug/non-critical input that will differ. Tests that give the wrong
66
# answer or crash under the hypergraph optimizer should not be using this file;
77
# instead, the optimizer should error out with ER_HYPERGRAPH_NOT_SUPPORTED_YET.
88
#
99

10-
if ($HYPERGRAPH_TEST) {
11-
--skip Not supported under '--hypergraph'
10+
if (`select locate('hypergraph_optimizer=on', @@optimizer_switch) > 0`)
11+
{
12+
--skip server has hypergraph_optimizer ON
1213
}
13-
14-

mysql-test/include/subquery_sj.inc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Nested Loops semi-join subquery evaluation tests
33
#
44
--source include/elide_costs.inc
5+
--source include/hypergraph_is_active.inc
56

67
# This portion of the file vas developed when subquery materialization
78
# was rule-based; to preserve the intended test scenarios, we switch
@@ -4351,12 +4352,12 @@ WHERE col_varchar_10_latin1_key IN (
43514352
WHERE alias1.pk AND alias1.pk < 3 OR alias1.pk AND alias3.pk);
43524353
ANALYZE TABLE t1, t2, t3;
43534354
eval EXPLAIN $query;
4354-
if ($HYPERGRAPH_TEST) {
4355+
if ($hypergraph_is_active) {
43554356
# Different warnings with hypergraph than with old optimizer.
43564357
--disable_warnings
43574358
}
43584359
eval $query;
4359-
if ($HYPERGRAPH_TEST) {
4360+
if ($hypergraph_is_active) {
43604361
--enable_warnings
43614362
}
43624363

mysql-test/mysql-test-run.pl

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@
299299
our $opt_gcov_exe = "gcov";
300300
our $opt_gcov_msg = "mysql-test-gcov.msg";
301301
our $opt_hypergraph = 0;
302+
our $opt_hypergraph_off = 0;
302303
our $opt_keep_ndbfs = 0;
303304
our $opt_mem = $ENV{'MTR_MEM'} ? 1 : 0;
304305
our $opt_only_big_test = 0;
@@ -1675,6 +1676,7 @@ sub print_global_resfile {
16751676
resfile_global("gprof", $opt_gprof ? 1 : 0);
16761677
resfile_global("helgrind", $opt_helgrind ? 1 : 0);
16771678
resfile_global("hypergraph", $opt_hypergraph ? 1 : 0);
1679+
resfile_global("hypergraph-off", $opt_hypergraph_off ? 1 : 0);
16781680
resfile_global("initialize", \@opt_extra_bootstrap_opt);
16791681
resfile_global("max-connections", $opt_max_connections);
16801682
resfile_global("mem", $opt_mem ? 1 : 0);
@@ -1733,6 +1735,7 @@ sub command_line_setup {
17331735
'cursor-protocol' => \$opt_cursor_protocol,
17341736
'explain-protocol' => \$opt_explain_protocol,
17351737
'hypergraph' => \$opt_hypergraph,
1738+
'hypergraph-off' => \$opt_hypergraph_off,
17361739
'json-explain-protocol' => \$opt_json_explain_protocol,
17371740
'opt-trace-protocol' => \$opt_trace_protocol,
17381741
'ps-protocol' => \$opt_ps_protocol,
@@ -3582,10 +3585,6 @@ sub environment_setup {
35823585
mtr_exe_exists("$path_client_bindir/mysql_tzinfo_to_sql");
35833586
$ENV{'MYSQL_TZINFO_TO_SQL'} = native_path($exe_mysql_tzinfo_to_sql);
35843587

3585-
# Create an environment variable to make it possible
3586-
# to detect that the hypergraph optimizer is being used from test cases
3587-
$ENV{'HYPERGRAPH_TEST'} = $opt_hypergraph;
3588-
35893588
# Create an environment variable to make it possible
35903589
# to detect that valgrind is being used from test cases
35913590
$ENV{'VALGRIND_TEST'} = $opt_valgrind;
@@ -7637,9 +7636,15 @@ ($$$)
76377636
mtr_add_arg($args, "--verbose");
76387637
mtr_add_arg($args, "--logdir=%s/tmp", $opt_vardir);
76397638

7639+
if ($opt_hypergraph && $opt_hypergraph_off) {
7640+
die "Cannot specify both hypergraph and hypergraph-off";
7641+
}
76407642
if ($opt_hypergraph) {
76417643
mtr_add_arg($args, "--hypergraph");
76427644
}
7645+
if ($opt_hypergraph_off) {
7646+
mtr_add_arg($args, "--hypergraph-off");
7647+
}
76437648

76447649
if (IS_WINDOWS) {
76457650
mtr_add_arg($args, "--protocol=pipe");
@@ -7765,9 +7770,15 @@ ($)
77657770
mtr_add_arg($args, "--colored-diff", $opt_colored_diff);
77667771
}
77677772

7773+
if ($opt_hypergraph && $opt_hypergraph_off) {
7774+
die "Cannot specify both hypergraph and hypergraph-off";
7775+
}
77687776
if ($opt_hypergraph) {
77697777
mtr_add_arg($args, "--hypergraph");
77707778
}
7779+
if ($opt_hypergraph_off) {
7780+
mtr_add_arg($args, "--hypergraph-off");
7781+
}
77717782

77727783
foreach my $arg (@opt_extra_mysqltest_opt) {
77737784
mtr_add_arg($args, $arg);
@@ -8357,6 +8368,7 @@ ($)
83578368
explain-protocol Run 'EXPLAIN EXTENDED' on all SELECT, INSERT,
83588369
REPLACE, UPDATE and DELETE queries.
83598370
hypergraph Set the 'hypergraph_optimizer=on' optimizer switch.
8371+
hypergraph-off Set the 'hypergraph_optimizer=off' optimizer switch.
83608372
json-explain-protocol Run 'EXPLAIN FORMAT=JSON' on all SELECT, INSERT,
83618373
REPLACE, UPDATE and DELETE queries.
83628374
opt-trace-protocol Print optimizer trace.

mysql-test/r/temptable_basic.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
FLUSH STATUS;
12
SET @@GLOBAL.internal_tmp_mem_storage_engine = TempTable;
23
CREATE TABLE t_int (c INT);
34
CREATE TABLE t_char (c CHAR(20));

mysql-test/r/temptable_fallback.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
FLUSH STATUS;
12
# Disable sorting by addon fields, as that will enable the
23
# StreamingIterator in many of the test cases, resulting in
34
# fewer materializations.

mysql-test/r/temptable_no_pad_collation.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#
22
# Prepare
33
#
4+
FLUSH STATUS;
45
SET @big_tables_saved = @@big_tables;
56
SET @optimizer_switch_saved = @@optimizer_switch;
67
#

mysql-test/r/using_hypergraph_optimizer.result

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ COUNT(*)
8080
SET optimizer_switch = 'hypergraph_optimizer=off';
8181
PREPARE ps_set FROM 'SET @x = (SELECT COUNT(*) FROM t)';
8282
PREPARE ps_select FROM 'SELECT COUNT(*) FROM t';
83+
SET optimizer_switch = 'hypergraph_optimizer=on';
8384
EXECUTE ps_set;
8485
SELECT COUNT(*) FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE
8586
WHERE TRACE LIKE '%Constructed hypergraph%';
@@ -117,6 +118,7 @@ SELECT @x;
117118
3
118119
# Clean up for Bug #33296454
119120
DROP TABLE t;
121+
SET optimizer_switch = 'hypergraph_optimizer=on';
120122
# Bug #33296454 done
121123
#
122124
# Bug #33296504: Use the hypergraph optimizer for subqueries in INSERT statements
@@ -171,6 +173,7 @@ COUNT(*)
171173
0
172174
# Clean up for Bug #33296504
173175
DROP TABLE t1, t2, t3;
176+
SET optimizer_switch = 'hypergraph_optimizer=on';
174177
# Bug #33296504 done
175178
#
176179
# WL#14673: Enable the hypergraph optimizer for DELETE

mysql-test/suite/binlog_gtid/t/binlog_gtid_myisam.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
--source include/force_myisam_default.inc
22
--source include/have_myisam.inc
33
--source include/have_log_bin.inc
4+
--source include/hypergraph_is_active.inc
45

56
#
67
# Bug#27716 multi-update did partially and has not binlogged
@@ -22,7 +23,7 @@ CREATE TABLE `t2` (
2223
insert into t1 values (1,1),(2,2);
2324
insert into t2 values (1,1),(4,4);
2425
reset binary logs and gtids;
25-
if ($HYPERGRAPH_TEST) {
26+
if ($hypergraph_is_active) {
2627
# Hypergraph uses hash join and updates the rows in a different order.
2728
--replace_result "'4'" "'3'"
2829
}

mysql-test/suite/binlog_nogtid/t/binlog_myisam.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
--source include/have_myisam.inc
33
--source include/have_log_bin.inc
44
--source common/binlog/innodb.inc
5+
--source include/hypergraph_is_active.inc
56
#
67
# Bug#27716 multi-update did partially and has not binlogged
78
#
@@ -22,7 +23,7 @@ CREATE TABLE `t2` (
2223
insert into t1 values (1,1),(2,2);
2324
insert into t2 values (1,1),(4,4);
2425
reset binary logs and gtids;
25-
if ($HYPERGRAPH_TEST) {
26+
if ($hypergraph_is_active) {
2627
# Hypergraph uses hash join and updates the rows in a different order.
2728
--replace_result "'4'" "'3'"
2829
}

0 commit comments

Comments
 (0)