diff options
author | Marc Alff <marc.alff@oracle.com> | 2010-08-25 18:59:28 -0600 |
---|---|---|
committer | Marc Alff <marc.alff@oracle.com> | 2010-08-25 18:59:28 -0600 |
commit | 47c6b6a6cf0fba56f42380f5be7529da9773bb7c (patch) | |
tree | f649b6b130d90c3fdaa4e043bca118a69c38828f | |
parent | 3592489cae0115c245ef3e692bf0ec276a3e010d (diff) | |
download | mariadb-git-47c6b6a6cf0fba56f42380f5be7529da9773bb7c.tar.gz |
Bug#55873 short startup options do not work in 5.5
Before this fix, the server did not recognize 'short' (as in -a)
options but only 'long' (as in --ansi) options
in the startup command line, due to earlier changes in 5.5
introduced for the performance schema.
The root cause is that handle_options() did not honor the
my_getopt_skip_unknown flag when parsing 'short' options.
The fix changes handle_options(), so that my_getopt_skip_unknown is
honored in all cases.
Note that there are limitations to this,
see the added doxygen documentation in handle_options().
The current usage of handle_options() by the server to
parse early performance schema options fits within the limitations.
This has been enforced by an assert for PARSE_EARLY options, for safety.
-rw-r--r-- | mysql-test/suite/perfschema/r/bad_option_3.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/r/bad_option_4.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/r/bad_option_5.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/r/short_option_1.result | 27 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/r/short_option_2.result | 9 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/bad_option_3.test | 49 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/bad_option_4.test | 49 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/bad_option_5.test | 52 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/short_option_1-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/short_option_1.test | 35 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/short_option_2-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/short_option_2.test | 29 | ||||
-rw-r--r-- | mysys/my_getopt.c | 100 | ||||
-rw-r--r-- | sql/set_var.cc | 11 |
14 files changed, 362 insertions, 7 deletions
diff --git a/mysql-test/suite/perfschema/r/bad_option_3.result b/mysql-test/suite/perfschema/r/bad_option_3.result new file mode 100644 index 00000000000..ec717d6f7d2 --- /dev/null +++ b/mysql-test/suite/perfschema/r/bad_option_3.result @@ -0,0 +1,2 @@ +Found: unknown option '-x' +Found: Aborting diff --git a/mysql-test/suite/perfschema/r/bad_option_4.result b/mysql-test/suite/perfschema/r/bad_option_4.result new file mode 100644 index 00000000000..812ee546200 --- /dev/null +++ b/mysql-test/suite/perfschema/r/bad_option_4.result @@ -0,0 +1,2 @@ +Found: Can't change dir to.*bad_option_h_param +Found: Aborting diff --git a/mysql-test/suite/perfschema/r/bad_option_5.result b/mysql-test/suite/perfschema/r/bad_option_5.result new file mode 100644 index 00000000000..b318b6e0482 --- /dev/null +++ b/mysql-test/suite/perfschema/r/bad_option_5.result @@ -0,0 +1,2 @@ +Found: unknown option '-X' +Found: Aborting diff --git a/mysql-test/suite/perfschema/r/short_option_1.result b/mysql-test/suite/perfschema/r/short_option_1.result new file mode 100644 index 00000000000..ad48fe05ad9 --- /dev/null +++ b/mysql-test/suite/perfschema/r/short_option_1.result @@ -0,0 +1,27 @@ +select 'Ok, the server started' as result; +result +Ok, the server started +select @@SQL_MODE; +@@SQL_MODE +REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI +show variables like 'sql_mode'; +Variable_name Value +sql_mode REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI +select @@character_set_server; +@@character_set_server +utf8 +show variables like 'character_set_system'; +Variable_name Value +character_set_system utf8 +show variables like 'log'; +Variable_name Value +log ON +show variables like 'general_log'; +Variable_name Value +general_log ON +show variables like 'new'; +Variable_name Value +new ON +show variables like 'log_warnings'; +Variable_name Value +log_warnings 3 diff --git a/mysql-test/suite/perfschema/r/short_option_2.result b/mysql-test/suite/perfschema/r/short_option_2.result new file mode 100644 index 00000000000..0587fdef73b --- /dev/null +++ b/mysql-test/suite/perfschema/r/short_option_2.result @@ -0,0 +1,9 @@ +select 'Ok, the server started' as result; +result +Ok, the server started +select @@SQL_MODE; +@@SQL_MODE +REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI +select @@log_warnings; +@@log_warnings +5 diff --git a/mysql-test/suite/perfschema/t/bad_option_3.test b/mysql-test/suite/perfschema/t/bad_option_3.test new file mode 100644 index 00000000000..1a9efb61fdf --- /dev/null +++ b/mysql-test/suite/perfschema/t/bad_option_3.test @@ -0,0 +1,49 @@ +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + +# Tests for PERFORMANCE_SCHEMA +# Check error handling for invalid server start options + +--source include/not_embedded.inc +--source include/have_perfschema.inc + +let $outfile= $MYSQLTEST_VARDIR/tmp/bad_option_3.txt; +--error 0,1 +--remove_file $outfile +--error 2 +--exec $MYSQLD_BOOTSTRAP_CMD --loose-console -a -x > $outfile 2>&1 + +perl; + use strict; + use warnings; + my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/bad_option_3.txt"; + open(FILE, "<", $fname) or die; + my @lines= <FILE>; + # those must be in the file for the test to pass + my @patterns= + ("unknown option '-x'", + "Aborting"); + foreach my $one_line (@lines) + { + foreach my $one_pattern (@patterns) + { + # print pattern, not line, to get a stable output + print "Found: $one_pattern\n" if ($one_line =~ /$one_pattern/); + } + } + close FILE; +EOF +--remove_file $outfile + diff --git a/mysql-test/suite/perfschema/t/bad_option_4.test b/mysql-test/suite/perfschema/t/bad_option_4.test new file mode 100644 index 00000000000..c13df1b614d --- /dev/null +++ b/mysql-test/suite/perfschema/t/bad_option_4.test @@ -0,0 +1,49 @@ +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + +# Tests for PERFORMANCE_SCHEMA +# Check error handling for invalid server start options + +--source include/not_embedded.inc +--source include/have_perfschema.inc + +let $outfile= $MYSQLTEST_VARDIR/tmp/bad_option_4.txt; +--error 0,1 +--remove_file $outfile +--error 1 +--exec $MYSQLD_BOOTSTRAP_CMD --loose-console -a -h bad_option_h_param > $outfile 2>&1 + +perl; + use strict; + use warnings; + my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/bad_option_4.txt"; + open(FILE, "<", $fname) or die; + my @lines= <FILE>; + # those must be in the file for the test to pass + my @patterns= + ("Can't change dir to.*bad_option_h_param", + "Aborting"); + foreach my $one_line (@lines) + { + foreach my $one_pattern (@patterns) + { + # print pattern, not line, to get a stable output + print "Found: $one_pattern\n" if ($one_line =~ /$one_pattern/); + } + } + close FILE; +EOF +--remove_file $outfile + diff --git a/mysql-test/suite/perfschema/t/bad_option_5.test b/mysql-test/suite/perfschema/t/bad_option_5.test new file mode 100644 index 00000000000..d0ae1370859 --- /dev/null +++ b/mysql-test/suite/perfschema/t/bad_option_5.test @@ -0,0 +1,52 @@ +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + +# Tests for PERFORMANCE_SCHEMA +# Check error handling for invalid server start options + +--source include/not_embedded.inc +--source include/have_perfschema.inc + +let $outfile= $MYSQLTEST_VARDIR/tmp/bad_option_5.txt; +--error 0,1 +--remove_file $outfile +--error 2 +--exec $MYSQLD_BOOTSTRAP_CMD --loose-console -aXbroken > $outfile 2>&1 + +# -aXbroken should be parsed as -a -Xbroken, or --ansi -Xbroken, +# therefore the -X option is what the server should complain about + +perl; + use strict; + use warnings; + my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/bad_option_5.txt"; + open(FILE, "<", $fname) or die; + my @lines= <FILE>; + # those must be in the file for the test to pass + my @patterns= + ("unknown option '-X'", + "Aborting"); + foreach my $one_line (@lines) + { + foreach my $one_pattern (@patterns) + { + # print pattern, not line, to get a stable output + print "Found: $one_pattern\n" if ($one_line =~ /$one_pattern/); + } + } + close FILE; +EOF +--remove_file $outfile + diff --git a/mysql-test/suite/perfschema/t/short_option_1-master.opt b/mysql-test/suite/perfschema/t/short_option_1-master.opt new file mode 100644 index 00000000000..6a6e8d4c5ca --- /dev/null +++ b/mysql-test/suite/perfschema/t/short_option_1-master.opt @@ -0,0 +1 @@ +-a -n -Cutf8 --collation=utf8_bin -l -T12 -W3 diff --git a/mysql-test/suite/perfschema/t/short_option_1.test b/mysql-test/suite/perfschema/t/short_option_1.test new file mode 100644 index 00000000000..1d3e0835188 --- /dev/null +++ b/mysql-test/suite/perfschema/t/short_option_1.test @@ -0,0 +1,35 @@ +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + +# Tests for PERFORMANCE_SCHEMA +# Check server start for short server start options + +select 'Ok, the server started' as result; + +# See the associated -master.opt file. + +select @@SQL_MODE; +show variables like 'sql_mode'; + +select @@character_set_server; +show variables like 'character_set_system'; + +show variables like 'log'; +show variables like 'general_log'; + +show variables like 'new'; + +show variables like 'log_warnings'; + diff --git a/mysql-test/suite/perfschema/t/short_option_2-master.opt b/mysql-test/suite/perfschema/t/short_option_2-master.opt new file mode 100644 index 00000000000..5cf7590a1c8 --- /dev/null +++ b/mysql-test/suite/perfschema/t/short_option_2-master.opt @@ -0,0 +1 @@ +-aW5 diff --git a/mysql-test/suite/perfschema/t/short_option_2.test b/mysql-test/suite/perfschema/t/short_option_2.test new file mode 100644 index 00000000000..eb528dfcf72 --- /dev/null +++ b/mysql-test/suite/perfschema/t/short_option_2.test @@ -0,0 +1,29 @@ +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + +# Tests for PERFORMANCE_SCHEMA +# Check server start for short server start options + +select 'Ok, the server started' as result; + +# See the associated -master.opt file. +# -aW5 should be parsed as -a -W5, which are two separate short options +# stuffed inside a single argv[i] argument. + +# Should contain ANSI, since we started the server with -a (stands for --ansi) +select @@SQL_MODE; + +# Should be 5, since we started the server with -W5 +select @@log_warnings; diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 1c5bf0b6b1c..5689e0bafb5 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -98,6 +98,49 @@ void my_getopt_register_get_addr(my_getopt_value func_addr) matches with one of the options in struct 'my_option'. Check that option was given an argument if it requires one Call the optional 'get_one_option()' function once for each option. + + Note that handle_options() can be invoked multiple times to + parse a command line in several steps. + In this case, use the global flag @c my_getopt_skip_unknown to indicate + that options unknown in the current step should be preserved in the + command line for later parsing in subsequent steps. + + For 'long' options (--a_long_option), @c my_getopt_skip_unknown is + fully supported. Command line parameters such as: + - "--a_long_option" + - "--a_long_option=value" + - "--a_long_option value" + will be preserved as is when the option is not known. + + For 'short' options (-S), support for @c my_getopt_skip_unknown + comes with some limitation, because several short options + can also be specified together in the same command line argument, + as in "-XYZ". + + The first use case supported is: all short options are declared. + handle_options() will be able to interpret "-XYZ" as one of: + - an unknown X option + - "-X -Y -Z", three short options with no arguments + - "-X -YZ", where Y is a short option with argument Z + - "-XYZ", where X is a short option with argument YZ + based on the full short options specifications. + + The second use case supported is: no short option is declared. + handle_options() will reject "-XYZ" as unknown, to be parsed later. + + The use case that is explicitly not supported is to provide + only a partial list of short options to handle_options(). + This function can not be expected to extract some option Y + in the middle of the string "-XYZ" in these conditions, + without knowing if X will be declared an option later. + + Note that this limitation only impacts parsing of several + short options from the same command line argument, + as in "mysqld -anW5". + When each short option is properly separated out in the command line + argument, for example in "mysqld -a -n -w5", the code would actually + work even with partial options specs given at each stage. + @param [in, out] argc command line options (count) @param [in, out] argv command line options (values) @param [in] longopts descriptor of all valid options @@ -464,14 +507,57 @@ int handle_options(int *argc, char ***argv, } if (!opt_found) { - if (my_getopt_print_errors) - my_getopt_error_reporter(ERROR_LEVEL, - "%s: unknown option '-%c'", - my_progname, *optend); - return EXIT_UNKNOWN_OPTION; + if (my_getopt_skip_unknown) + { + /* + We are currently parsing a single argv[] argument + of the form "-XYZ", and parsing is done in multiple phases. + One or the argument found is not an option. + */ + if (optend == cur_arg) + { + /* + The first argument, "-X", is not an option + In this case, the entire argument "-XYZ" is rejected + from this phase, and preserved as is for later parsing. + */ + (*argv)[argvpos++]= *pos; + } + else + { + /* + We are in the middle of an "-XYZ" string already, + "-X" has already been parsed, and "Y" (pointed by optend) + is not an option. + Hack the string "-XYZ" to make a "-YZ" substring in it, + and push that to the next parsing phase. + */ + DBUG_ASSERT(optend > *pos); + DBUG_ASSERT(optend > cur_arg); + DBUG_ASSERT(optend <= *pos + strlen(*pos)); + DBUG_ASSERT(*optend); + optend--; + optend[0]= '-'; /* replace 'X' by '-' */ + (*argv)[argvpos++]= optend; + } + /* + Do not continue to parse at the current "-XYZ" argument, + skip to the next argv[] argument instead. + */ + optend= (char*) " "; + } + else + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: unknown option '-%c'", + my_progname, *optend); + return EXIT_UNKNOWN_OPTION; + } } } - (*argc)--; /* option handled (short), decrease argument count */ + if (opt_found) + (*argc)--; /* option handled (short), decrease argument count */ continue; } if ((error= setval(optp, value, argument, set_maximum_value))) @@ -479,7 +565,7 @@ int handle_options(int *argc, char ***argv, if (get_one_option && get_one_option(optp->id, optp, argument)) return EXIT_UNSPECIFIED_ERROR; - (*argc)--; /* option handled (short or long), decrease argument count */ + (*argc)--; /* option handled (long), decrease argument count */ } else /* non-option found */ (*argv)[argvpos++]= cur_arg; diff --git a/sql/set_var.cc b/sql/set_var.cc index 9daaf883ea8..501c6382056 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -153,6 +153,17 @@ sys_var::sys_var(sys_var_chain *chain, const char *name_arg, guard(lock), offset(off), on_check(on_check_func), on_update(on_update_func), is_os_charset(FALSE) { + /* + There is a limitation in handle_options() related to short options: + - either all short options should be declared when parsing in multiple stages, + - or none should be declared. + Because a lot of short options are used in the normal parsing phase + for mysqld, we enforce here that no short option is present + in the first (PARSE_EARLY) stage. + See handle_options() for details. + */ + DBUG_ASSERT(parse_flag == PARSE_NORMAL || getopt_id <= 0 || getopt_id >= 255); + name.str= name_arg; name.length= strlen(name_arg); DBUG_ASSERT(name.length <= NAME_CHAR_LEN); |