From: Tatjana A Nuernberg Date: November 25 2007 6:05pm Subject: bk commit into 5.0 tree (tnurnberg:1.2557) BUG#31177 List-Archive: http://lists.mysql.com/commits/38449 X-Bug: 31177 Message-Id: <200711251805.lAPI5A7Y002965@white.intern.koehntopp.de> Below is the list of changes that have just been committed into a local 5.0 repository of tnurnberg. When tnurnberg does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2007-11-25 19:05:07+01:00, tnurnberg@stripped +7 -0 Bug#31177: Server variables can't be set to their current values Default values of variables were not subject to upper/lower bounds and step, while setting variables was. Bounds and step are also applied to defaults now; defaults are corrected quietly, values given by the user are corrected, and a correction-warning is printed to the log as needed. Lastly, very large values could wrap around, starting from 0 again. They are bounded at the maximum value for the respective data-type now if no lower maximum is specific in the variable's definition. client/mysqltest.c@stripped, 2007-11-25 19:05:05+01:00, tnurnberg@stripped +1 -1 adjust minimum for "sleep" option so default value is no longer out of bounds. include/m_string.h@stripped, 2007-11-25 19:05:05+01:00, tnurnberg@stripped +1 -0 ullstr() - the unsigned brother of llstr() mysql-test/r/variables.result@stripped, 2007-11-25 19:05:05+01:00, tnurnberg@stripped +2 -2 correct results: bounds and step apply to variables' default values, too mysql-test/t/variables.test@stripped, 2007-11-25 19:05:05+01:00, tnurnberg@stripped +1 -1 correct results: bounds and step apply to variables' default values, too mysys/my_getopt.c@stripped, 2007-11-25 19:05:05+01:00, tnurnberg@stripped +127 -34 - apply bounds/step to default values of variables (based on work by serg) - print complaints about incorrect values for variables (truncation etc., by requestion of consulting) - if no lower maximum is specified in variable definition, bound unsigned values at their maximum to prevent wrap-around sql/mysqld.cc@stripped, 2007-11-25 19:05:06+01:00, tnurnberg@stripped +1 -1 minimum value for max-user-connections was higher than default strings/llstr.c@stripped, 2007-11-25 19:05:06+01:00, tnurnberg@stripped +6 -0 ullstr() - the unsigned brother of llstr() diff -Nrup a/client/mysqltest.c b/client/mysqltest.c --- a/client/mysqltest.c 2007-10-05 18:18:47 +02:00 +++ b/client/mysqltest.c 2007-11-25 19:05:05 +01:00 @@ -4986,7 +4986,7 @@ static struct my_option my_long_options[ "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"sleep", 'T', "Sleep always this many seconds on sleep commands.", - (gptr*) &opt_sleep, (gptr*) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, 0, 0, + (gptr*) &opt_sleep, (gptr*) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", (gptr*) &unix_sock, (gptr*) &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, diff -Nrup a/include/m_string.h b/include/m_string.h --- a/include/m_string.h 2007-05-30 20:47:50 +02:00 +++ b/include/m_string.h 2007-11-25 19:05:05 +01:00 @@ -219,6 +219,7 @@ double my_strtod(const char *str, char * double my_atof(const char *nptr); extern char *llstr(longlong value,char *buff); +extern char *ullstr(longlong value,char *buff); #ifndef HAVE_STRTOUL extern long strtol(const char *str, char **ptr, int base); extern ulong strtoul(const char *str, char **ptr, int base); diff -Nrup a/mysql-test/r/variables.result b/mysql-test/r/variables.result --- a/mysql-test/r/variables.result 2007-10-29 08:25:37 +01:00 +++ b/mysql-test/r/variables.result 2007-11-25 19:05:05 +01:00 @@ -238,7 +238,7 @@ show variables like '%alloc%'; Variable_name Value query_alloc_block_size 8192 query_prealloc_size 8192 -range_alloc_block_size 2048 +range_alloc_block_size 4096 transaction_alloc_block_size 8192 transaction_prealloc_size 4096 set @@range_alloc_block_size=1024*16; @@ -263,7 +263,7 @@ show variables like '%alloc%'; Variable_name Value query_alloc_block_size 8192 query_prealloc_size 8192 -range_alloc_block_size 2048 +range_alloc_block_size 4096 transaction_alloc_block_size 8192 transaction_prealloc_size 4096 SELECT @@version LIKE 'non-existent'; diff -Nrup a/mysql-test/t/variables.test b/mysql-test/t/variables.test --- a/mysql-test/t/variables.test 2007-10-29 08:25:37 +01:00 +++ b/mysql-test/t/variables.test 2007-11-25 19:05:05 +01:00 @@ -126,7 +126,7 @@ set GLOBAL query_cache_size=100000; set GLOBAL myisam_max_sort_file_size=2000000; show global variables like 'myisam_max_sort_file_size'; set GLOBAL myisam_max_sort_file_size=default; ---replace_result 2147483647 FILE_SIZE 9223372036854775807 FILE_SIZE +--replace_result 2147482624 FILE_SIZE 2146435072 FILE_SIZE show variables like 'myisam_max_sort_file_size'; set global net_retry_count=10, session net_retry_count=10; diff -Nrup a/mysys/my_getopt.c b/mysys/my_getopt.c --- a/mysys/my_getopt.c 2007-10-04 10:33:56 +02:00 +++ b/mysys/my_getopt.c 2007-11-25 19:05:05 +01:00 @@ -22,6 +22,7 @@ #include static void default_reporter(enum loglevel level, const char *format, ...); +static void null_reporter(enum loglevel level, const char *format, ...); my_error_reporter my_getopt_error_reporter= &default_reporter; static int findopt(char *optpat, uint length, @@ -31,6 +32,7 @@ my_bool getopt_compare_strings(const cha const char *t, uint length); static longlong getopt_ll(char *arg, const struct my_option *optp, int *err); +static longlong getopt_ll_limit_value(longlong, const struct my_option *); static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err); static void init_variables(const struct my_option *options); @@ -59,6 +61,13 @@ char *disabled_my_option= (char*) "0"; my_bool my_getopt_print_errors= 1; +/* + This is a flag that can be set in client programs. 1 means that + my_getopt will skip over options it does not know how to handle. +*/ + +my_bool my_getopt_skip_unknown= 0; + static void default_reporter(enum loglevel level, const char *format, ...) { @@ -73,6 +82,11 @@ static void default_reporter(enum loglev fflush(stderr); } +static void null_reporter(enum loglevel level, + const char *format, ...) +{ +} + /* function: handle_options @@ -105,12 +119,17 @@ int handle_options(int *argc, char ***ar int error; LINT_INIT(opt_found); + + /* handle_options() assumes arg0 (program name) always exists */ + DBUG_ASSERT(argc && *argc >= 1); + DBUG_ASSERT(argv && *argv); (*argc)--; /* Skip the program name */ (*argv)++; /* --- || ---- */ init_variables(longopts); for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) { + char **first= pos; char *cur_arg= *pos; if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */ { @@ -217,12 +236,11 @@ int handle_options(int *argc, char ***ar /* We were called with a special prefix, we can reuse opt_found */ - opt_str+= (special_opt_prefix_lengths[i] + 1); + opt_str+= special_opt_prefix_lengths[i] + 1; + length-= special_opt_prefix_lengths[i] + 1; if (i == OPT_LOOSE) option_is_loose= 1; - if ((opt_found= findopt(opt_str, length - - (special_opt_prefix_lengths[i] + 1), - &optp, &prev_found))) + if ((opt_found= findopt(opt_str, length, &optp, &prev_found))) { if (opt_found > 1) { @@ -255,11 +273,25 @@ int handle_options(int *argc, char ***ar } break; /* break from the inner loop, main loop continues */ } + i= -1; /* restart the loop */ } } } if (!opt_found) { + if (my_getopt_skip_unknown) + { + /* + preserve all the components of this unknown option, this may + occurr when the user provides options like: "-O foo" or + "--set-variable foo" (note that theres a space in there) + Generally, these kind of options are to be avoided + */ + do { + (*argv)[argvpos++]= *first++; + } while (first <= pos); + continue; + } if (must_be_var) { if (my_getopt_print_errors) @@ -492,7 +524,7 @@ invalid value '%s'\n", } get_one_option(optp->id, optp, argument); - (*argc)--; /* option handled (short or long), decrease argument count */ + (*argc)--; /* option handled (short or long), decrease argument count */ } else /* non-option found */ (*argv)[argvpos++]= cur_arg; @@ -575,13 +607,17 @@ static int setval(const struct my_option *((my_bool*) result_pos)= (my_bool) atoi(argument) != 0; break; case GET_INT: - case GET_UINT: /* fall through */ *((int*) result_pos)= (int) getopt_ll(argument, opts, &err); break; + case GET_UINT: + *((uint*) result_pos)= (uint) getopt_ull(argument, opts, &err); + break; case GET_LONG: - case GET_ULONG: /* fall through */ *((long*) result_pos)= (long) getopt_ll(argument, opts, &err); break; + case GET_ULONG: + *((long*) result_pos)= (long) getopt_ull(argument, opts, &err); + break; case GET_LL: *((longlong*) result_pos)= getopt_ll(argument, opts, &err); break; @@ -733,23 +769,40 @@ static longlong eval_num_suffix (char *a static longlong getopt_ll(char *arg, const struct my_option *optp, int *err) { - longlong num; + longlong num=eval_num_suffix(arg, err, (char*) optp->name); + return getopt_ll_limit_value(num, optp); +} + +/* + function: getopt_ll_limit_value + + Applies min/max/block_size to a numeric value of an option. + Returns "fixed" value. +*/ + +static longlong getopt_ll_limit_value(longlong num, + const struct my_option *optp) +{ + longlong old= num; + char buf1[255] __attribute__((unused)), buf2[255] __attribute__((unused)); ulonglong block_size= (optp->block_size ? (ulonglong) optp->block_size : 1L); - - num= eval_num_suffix(arg, err, (char*) optp->name); + if (num > 0 && (ulonglong) num > (ulonglong) optp->max_value && optp->max_value) /* if max value is not set -> no upper limit */ - { - char buf[22]; - my_getopt_error_reporter(WARNING_LEVEL, - "Truncated incorrect %s value: '%s'", - optp->name, llstr(num, buf)); - num= (ulonglong) optp->max_value; - } + num= ((num - optp->sub_size) / block_size); num= (longlong) (num * block_size); - return max(num, optp->min_value); + + num= max(num, optp->min_value); + + if (num != old) + my_getopt_error_reporter(WARNING_LEVEL, + "option '%s' (type %d): " + "signed value '%s' adjusted to '%s'", + optp->name, optp->var_type & GET_TYPE_MASK, + llstr(old, buf1), llstr(num, buf2)); + return num; } /* @@ -761,18 +814,33 @@ static longlong getopt_ll(char *arg, con static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err) { - ulonglong num; - - num= eval_num_suffix(arg, err, (char*) optp->name); + ulonglong num= eval_num_suffix(arg, err, (char*) optp->name); return getopt_ull_limit_value(num, optp); } ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp) { + ulonglong old= num; + char buf1[255] __attribute__((unused)), buf2[255] __attribute__((unused)); + if ((ulonglong) num > (ulonglong) optp->max_value && optp->max_value) /* if max value is not set -> no upper limit */ num= (ulonglong) optp->max_value; + + switch ((optp->var_type & GET_TYPE_MASK)) { + case GET_UINT: + if (num > (ulonglong) ~(uint) 0) + num= ((ulonglong) ~(uint) 0); + break; +#if SIZEOF_LONG < SIZEOF_LONG_LONG + case GET_ULONG: + if (num > (ulonglong) ~(ulong) 0) + num= ((ulonglong) ~(ulong) 0); + break; +#endif + } + if (optp->block_size > 1) { num/= (ulonglong) optp->block_size; @@ -780,6 +848,13 @@ ulonglong getopt_ull_limit_value(ulonglo } if (num < (ulonglong) optp->min_value) num= (ulonglong) optp->min_value; + + if (num != old) + my_getopt_error_reporter(WARNING_LEVEL, + "option '%s' (type %d): " + "unsigned value '%s' adjusted to '%s'", + optp->name, optp->var_type & GET_TYPE_MASK, + ullstr(old, buf1), ullstr(num, buf2)); return num; } @@ -789,38 +864,53 @@ ulonglong getopt_ull_limit_value(ulonglo SYNOPSIS init_one_value() - option Option to initialize - value Pointer to variable + optp Option to initialize + value Pointer to variable */ -static void init_one_value(const struct my_option *option, gptr *variable, +static void init_one_value(const struct my_option *optp, gptr *variable, longlong value) { - switch ((option->var_type & GET_TYPE_MASK)) { + /* + Gag reporter (which isn't default_reporter when we're mysqld) + while setting defaults - we'll apply step-size and bounds even + to defaults, but silently. + */ + my_error_reporter save_reporter= my_getopt_error_reporter; + + DBUG_ENTER("init_one_value"); + + my_getopt_error_reporter= null_reporter; + + switch ((optp->var_type & GET_TYPE_MASK)) { case GET_BOOL: *((my_bool*) variable)= (my_bool) value; break; case GET_INT: - *((int*) variable)= (int) value; + *((int*) variable)= (int) getopt_ll_limit_value(value, optp); break; case GET_UINT: - *((uint*) variable)= (uint) value; + *((uint*) variable)= (uint) getopt_ull_limit_value(value, optp); break; case GET_LONG: - *((long*) variable)= (long) value; + *((long*) variable)= (long) getopt_ll_limit_value(value, optp); break; case GET_ULONG: - *((ulong*) variable)= (ulong) value; + *((ulong*) variable)= (ulong) getopt_ull_limit_value(value, optp); break; case GET_LL: - *((longlong*) variable)= (longlong) value; + *((longlong*) variable)= (longlong) getopt_ll_limit_value(value, optp); break; case GET_ULL: - *((ulonglong*) variable)= (ulonglong) value; + *((ulonglong*) variable)= (ulonglong) getopt_ull_limit_value(value, optp); break; default: /* dummy default to avoid compiler warnings */ break; } + + my_getopt_error_reporter= save_reporter; + + DBUG_VOID_RETURN; } @@ -839,9 +929,11 @@ static void init_one_value(const struct static void init_variables(const struct my_option *options) { + DBUG_ENTER("init_variables"); for (; options->name; options++) { gptr *variable; + DBUG_PRINT("options", ("name: '%s'", options->name)); /* We must set u_max_value first as for some variables options->u_max_value == options->value and in this case we want to @@ -855,6 +947,7 @@ static void init_variables(const struct (variable= (*getopt_get_addr)("", 0, options))) init_one_value(options, variable, options->def_value); } + DBUG_VOID_RETURN; } @@ -957,8 +1050,8 @@ void my_print_variables(const struct my_ (*getopt_get_addr)("", 0, optp) : optp->value); if (value) { - printf("%s", optp->name); - length= (uint) strlen(optp->name); + printf("%s ", optp->name); + length= (uint) strlen(optp->name)+1; for (; length < name_space; length++) putchar(' '); switch ((optp->var_type & GET_TYPE_MASK)) { @@ -977,7 +1070,7 @@ void my_print_variables(const struct my_ printf("%d\n", *((uint*) value)); break; case GET_LONG: - printf("%lu\n", *((long*) value)); + printf("%ld\n", *((long*) value)); break; case GET_ULONG: printf("%lu\n", *((ulong*) value)); diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc --- a/sql/mysqld.cc 2007-10-29 09:52:39 +01:00 +++ b/sql/mysqld.cc 2007-11-25 19:05:06 +01:00 @@ -5982,7 +5982,7 @@ The minimum value for this variable is 4 {"max_user_connections", OPT_MAX_USER_CONNECTIONS, "The maximum number of active connections for a single user (0 = no limit).", (gptr*) &max_user_connections, (gptr*) &max_user_connections, 0, GET_UINT, - REQUIRED_ARG, 0, 1, ~0, 0, 1, 0}, + REQUIRED_ARG, 0, 0, ~0, 0, 1, 0}, {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT, "After this many write locks, allow some read locks to run in between.", (gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG, diff -Nrup a/strings/llstr.c b/strings/llstr.c --- a/strings/llstr.c 2006-12-23 20:04:30 +01:00 +++ b/strings/llstr.c 2007-11-25 19:05:06 +01:00 @@ -32,3 +32,9 @@ char *llstr(longlong value,char *buff) longlong10_to_str(value,buff,-10); return buff; } + +char *ullstr(longlong value,char *buff) +{ + longlong10_to_str(value,buff,10); + return buff; +}