Commit 4474cc84 authored by unknown's avatar unknown

Bug#22645 LC_TIME_NAMES: Statement not replicated

Problem: replication of LC_TIME_NAMES didn't work.
Thus, INSERTS or UPDATES using date_format() always
worked with en_US on the slave side.
Fix: adding ONE_SHOT implementation for LC_TIME_NAMES.


mysql-test/r/variables.result:
  Adding various tests with LC_TIME_NAMES and
  string and numeric constants and expressions.
mysql-test/t/variables.test:
  Adding various tests with LC_TIME_NAMES and
  string and numeric constants and expressions.
sql/log.cc:
  Adding ONE_SHOT trick for lc_time_names.
sql/mysql_priv.h:
  Adding new member "number" - for unique locale IDs.
  Adding prototype for my_locale_by_number().
sql/set_var.cc:
  Modifying lc_time_names variable to understand both:
  - string valyes (using locale name)
  - number values (using locale IDs)
sql/set_var.h:
  - Marking lc_time_names as ONE_SHOT capable.
  - Marking lc_time_names as INT_RESULT compatible.
sql/sql_locale.cc:
  - adding local IDs
  - better layout for locale data declarations
    (splitting long lines into short ones)
  - adding DBUG_ASSERT into my_locale_by_name()
    and moving this function towards the end of file -
    after "my_locales" declaration
  - adding my_locale_by_number() implementation
sql/sql_parse.cc:
  Adding initialization of lc_time_names
  to its default value (en_US)
mysql-test/r/rpl_locale.result:
  Adding test case
mysql-test/t/rpl_locale.test:
  Adding test case
parent 248ab7c7
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
create table t1 (s1 char(10));
set lc_time_names= 'de_DE';
insert into t1 values (date_format('2001-01-01','%W'));
select * from t1;
s1
Montag
select * from t1;
s1
Montag
drop table t1;
......@@ -499,6 +499,63 @@ set names latin1;
select @@have_innodb;
@@have_innodb
#
*** Various tests with LC_TIME_NAMES
*** LC_TIME_NAMES: testing case insensitivity
set @@lc_time_names='ru_ru';
select @@lc_time_names;
@@lc_time_names
ru_RU
*** LC_TIME_NAMES: testing with a user variable
set @lc='JA_JP';
set @@lc_time_names=@lc;
select @@lc_time_names;
@@lc_time_names
ja_JP
*** LC_TIME_NAMES: testing with string expressions
set lc_time_names=concat('de','_','DE');
select @@lc_time_names;
@@lc_time_names
de_DE
set lc_time_names=concat('de','+','DE');
ERROR HY000: Unknown locale: 'de+DE'
select @@lc_time_names;
@@lc_time_names
de_DE
LC_TIME_NAMES: testing with numeric expressions
set @@lc_time_names=1+2;
select @@lc_time_names;
@@lc_time_names
sv_SE
set @@lc_time_names=1/0;
ERROR 42000: Incorrect argument type to variable 'lc_time_names'
select @@lc_time_names;
@@lc_time_names
sv_SE
set lc_time_names=en_US;
LC_TIME_NAMES: testing NULL and a negative number:
set lc_time_names=NULL;
ERROR 42000: Variable 'lc_time_names' can't be set to the value of 'NULL'
set lc_time_names=-1;
ERROR HY000: Unknown locale: '-1'
select @@lc_time_names;
@@lc_time_names
en_US
LC_TIME_NAMES: testing locale with the last ID:
set lc_time_names=108;
select @@lc_time_names;
@@lc_time_names
zh_HK
LC_TIME_NAMES: testing a number beyond the valid ID range:
set lc_time_names=109;
ERROR HY000: Unknown locale: '109'
select @@lc_time_names;
@@lc_time_names
zh_HK
LC_TIME_NAMES: testing that 0 is en_US:
set lc_time_names=0;
select @@lc_time_names;
@@lc_time_names
en_US
set @test = @@query_prealloc_size;
set @@query_prealloc_size = @test;
select @@query_prealloc_size = @test;
......
# Replication of locale variables
source include/master-slave.inc;
#
# Bug#22645 LC_TIME_NAMES: Statement not replicated
#
connection master;
create table t1 (s1 char(10));
set lc_time_names= 'de_DE';
insert into t1 values (date_format('2001-01-01','%W'));
select * from t1;
sync_slave_with_master;
connection slave;
select * from t1;
connection master;
drop table t1;
sync_slave_with_master;
# End of 4.1 tests
......@@ -396,6 +396,50 @@ set names latin1;
--replace_column 1 #
select @@have_innodb;
#
# Tests for lc_time_names
# Note, when adding new locales, please fix ID accordingly:
# - to test the last ID (currently 108)
# - and the next after the last (currently 109)
#
--echo *** Various tests with LC_TIME_NAMES
--echo *** LC_TIME_NAMES: testing case insensitivity
set @@lc_time_names='ru_ru';
select @@lc_time_names;
--echo *** LC_TIME_NAMES: testing with a user variable
set @lc='JA_JP';
set @@lc_time_names=@lc;
select @@lc_time_names;
--echo *** LC_TIME_NAMES: testing with string expressions
set lc_time_names=concat('de','_','DE');
select @@lc_time_names;
--error 1105
set lc_time_names=concat('de','+','DE');
select @@lc_time_names;
--echo LC_TIME_NAMES: testing with numeric expressions
set @@lc_time_names=1+2;
select @@lc_time_names;
--error 1232
set @@lc_time_names=1/0;
select @@lc_time_names;
set lc_time_names=en_US;
--echo LC_TIME_NAMES: testing NULL and a negative number:
--error 1231
set lc_time_names=NULL;
--error 1105
set lc_time_names=-1;
select @@lc_time_names;
--echo LC_TIME_NAMES: testing locale with the last ID:
set lc_time_names=108;
select @@lc_time_names;
--echo LC_TIME_NAMES: testing a number beyond the valid ID range:
--error 1105
set lc_time_names=109;
select @@lc_time_names;
--echo LC_TIME_NAMES: testing that 0 is en_US:
set lc_time_names=0;
select @@lc_time_names;
#
# Bug #13334: query_prealloc_size default less than minimum
#
......
......@@ -1350,6 +1350,21 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
if (e.write(file))
goto err;
}
/*
Use the same ONE_SHOT trick for making replication of lc_time_names.
*/
if (thd->variables.lc_time_names->number) // Not en_US
{
char buf[32];
uint length= my_snprintf(buf, sizeof(buf),
"SET ONE_SHOT LC_TIME_NAMES=%u",
(uint) thd->variables.lc_time_names->number);
Query_log_event e(thd, buf, length, 0, FALSE);
e.set_log_pos(this);
e.error_code= 0; // This statement cannot fail (see [1]).
if (e.write(file))
goto err;
}
#endif
if (thd->last_insert_id_used)
......
......@@ -71,6 +71,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
typedef struct my_locale_st
{
uint number;
const char *name;
const char *description;
const bool is_ascii;
......@@ -84,6 +85,7 @@ extern MY_LOCALE my_locale_en_US;
extern MY_LOCALE *my_locales[];
MY_LOCALE *my_locale_by_name(const char *name);
MY_LOCALE *my_locale_by_number(uint number);
/***************************************************************************
Configuration parameters
......
......@@ -2576,19 +2576,38 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var)
{
char *locale_str =var->value->str_value.c_ptr();
MY_LOCALE *locale_match= my_locale_by_name(locale_str);
MY_LOCALE *locale_match;
if(locale_match == NULL)
if (var->value->result_type() == INT_RESULT)
{
my_printf_error(ER_UNKNOWN_ERROR, "Unknown locale: '%s'", MYF(0), locale_str);
return 1;
if (!(locale_match= my_locale_by_number((uint) var->value->val_int())))
{
char buf[20];
int10_to_str((int) var->value->val_int(), buf, -10);
my_printf_error(ER_UNKNOWN_ERROR, "Unknown locale: '%s'", MYF(0), buf);
return 1;
}
}
else
else // STRING_RESULT
{
var->save_result.locale_value= locale_match;
return 0;
char buff[6];
String str(buff, sizeof(buff), &my_charset_latin1), *res;
if (!(res=var->value->val_str(&str)))
{
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
return 1;
}
const char *locale_str= res->c_ptr();
if (!(locale_match= my_locale_by_name(locale_str)))
{
my_printf_error(ER_UNKNOWN_ERROR,
"Unknown locale: '%s'", MYF(0), locale_str);
return 1;
}
}
var->save_result.locale_value= locale_match;
return 0;
}
......
......@@ -764,12 +764,16 @@ class sys_var_thd_lc_time_names :public sys_var_thd
public:
sys_var_thd_lc_time_names(const char *name_arg):
sys_var_thd(name_arg)
{}
{
#if MYSQL_VERSION_ID < 50000
no_support_one_shot= 0;
#endif
}
bool check(THD *thd, set_var *var);
SHOW_TYPE type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
return ((type != STRING_RESULT) && (type != INT_RESULT));
}
bool check_default(enum_var_type type) { return 0; }
bool update(THD *thd, set_var *var);
......
This diff is collapsed.
......@@ -1958,6 +1958,7 @@ static void reset_one_shot_variables(THD *thd)
thd->update_charset();
thd->variables.time_zone=
global_system_variables.time_zone;
thd->variables.lc_time_names= &my_locale_en_US;
thd->one_shot_set= 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment