Skip to content

Commit a9f6f3d

Browse files
committed
Fix a problem that alter database overwrites un-altered db options
Summary: db.opt file is always rewritten whenever any option changes. This is to fix a problem when `alter database` changes an option, it also resets other options to defaults. The db.opt file now also contains per db read_only options besides charset/collation. squash with 8194409 Per Database Read-Only (no need for the summary) Test Plan: New mtr test cases in t/db_read_only.test. The problem occured for the new test cases without this fix. Reviewers: jtolmer, santoshb Reviewed By: santoshb Subscribers: webscalesql-eng Differential Revision: https://reviews.facebook.net/D56013
1 parent 1091bee commit a9f6f3d

File tree

6 files changed

+116
-32
lines changed

6 files changed

+116
-32
lines changed

mysql-test/r/db_read_only.result

+33
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,39 @@ test CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 READ_ONLY */
758758
show create database test;
759759
Database Create Database
760760
test CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 READ_ONLY */
761+
create database test_db_opt;
762+
show create database test_db_opt;
763+
Database Create Database
764+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET latin1 */
765+
alter database test_db_opt read_only = true;
766+
show create database test_db_opt;
767+
Database Create Database
768+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET latin1 READ_ONLY */
769+
alter database test_db_opt default charset = utf8;
770+
show create database test_db_opt;
771+
Database Create Database
772+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET utf8 READ_ONLY */
773+
alter database test_db_opt default charset = default;
774+
show create database test_db_opt;
775+
Database Create Database
776+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET latin1 READ_ONLY */
777+
alter database test_db_opt default collate = utf8_general_ci;
778+
show create database test_db_opt;
779+
Database Create Database
780+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET utf8 READ_ONLY */
781+
alter database test_db_opt super_read_only = true;
782+
show create database test_db_opt;
783+
Database Create Database
784+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET utf8 SUPER_READ_ONLY */
785+
alter database test_db_opt super_read_only = false;
786+
show create database test_db_opt;
787+
Database Create Database
788+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET utf8 READ_ONLY */
789+
alter database test_db_opt default collate = default;
790+
show create database test_db_opt;
791+
Database Create Database
792+
test_db_opt CREATE DATABASE `test_db_opt` /*!40100 DEFAULT CHARACTER SET latin1 READ_ONLY */
793+
drop database test_db_opt;
761794
connection default;
762795
alter database test read_only = false;
763796
show create database test;

mysql-test/t/db_read_only.test

+21
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,27 @@ show create database test;
176176
--source include/restart_mysqld.inc
177177
show create database test;
178178

179+
#
180+
# Alter database options will not overwrite un-altered optinos
181+
#
182+
create database test_db_opt;
183+
show create database test_db_opt;
184+
alter database test_db_opt read_only = true;
185+
show create database test_db_opt;
186+
alter database test_db_opt default charset = utf8;
187+
show create database test_db_opt;
188+
alter database test_db_opt default charset = default;
189+
show create database test_db_opt;
190+
alter database test_db_opt default collate = utf8_general_ci;
191+
show create database test_db_opt;
192+
alter database test_db_opt super_read_only = true;
193+
show create database test_db_opt;
194+
alter database test_db_opt super_read_only = false;
195+
show create database test_db_opt;
196+
alter database test_db_opt default collate = default;
197+
show create database test_db_opt;
198+
drop database test_db_opt;
199+
179200
#
180201
# cleanup
181202
#

sql/handler.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -1071,10 +1071,19 @@ enum enum_stats_auto_recalc { HA_STATS_AUTO_RECALC_DEFAULT= 0,
10711071
HA_STATS_AUTO_RECALC_ON,
10721072
HA_STATS_AUTO_RECALC_OFF };
10731073

1074+
enum enum_db_read_only { DB_READ_ONLY_NO = 0,
1075+
DB_READ_ONLY_YES = 1,
1076+
DB_READ_ONLY_SUPER = 2,
1077+
DB_READ_ONLY_NULL = 255 };
1078+
10741079
typedef struct st_ha_create_information
10751080
{
10761081
const CHARSET_INFO *table_charset, *default_table_charset;
1077-
uchar db_read_only;
1082+
bool alter_default_table_charset; /* This is to differentiate whether the
1083+
null value for default_table_charset
1084+
means it is explicitly set to default or
1085+
it is not specified in alter */
1086+
enum enum_db_read_only db_read_only;
10781087
LEX_STRING connect_string;
10791088
const char *password, *tablespace;
10801089
LEX_STRING comment;
@@ -1111,7 +1120,7 @@ typedef struct st_ha_create_information
11111120
in Table_map_log_events */
11121121

11131122
/* initialize db_read_only parameter */
1114-
st_ha_create_information() : db_read_only(0) {}
1123+
st_ha_create_information() : db_read_only(DB_READ_ONLY_NO) {}
11151124
} HA_CREATE_INFO;
11161125

11171126
/**

sql/share/errmsg-utf8.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -7218,8 +7218,9 @@ ER_UUID_NOT_IN_EXECUTED_GTID_SET
72187218
ER_DB_FAILED_TO_LOCK_REC_NOWAIT
72197219
eng "Failed to lock a record and didn't wait"
72207220

7221-
ER_PLACE_HOLDER_1922
7222-
eng "PLACE HOLDER."
7221+
ER_UNKNOWN_DB_READ_ONLY
7222+
eng "Unknown db read ony option: '%-.64s'"
7223+
72237224
ER_PLACE_HOLDER_1923
72247225
eng "PLACE HOLDER."
72257226
ER_PLACE_HOLDER_1924

sql/sql_db.cc

+33-22
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ typedef struct my_dbopt_st
7777
char *name; /* Database name */
7878
uint name_length; /* Database length name */
7979
const CHARSET_INFO *charset; /* Database default character set */
80-
uchar db_read_only;
80+
enum enum_db_read_only db_read_only;
8181
} my_dbopt_t;
8282

8383

@@ -414,21 +414,6 @@ void init_thd_db_read_only(THD *thd)
414414
DBUG_VOID_RETURN;
415415
}
416416

417-
/**
418-
* Return db_read_only value in the dbopt
419-
*
420-
* Similar logic here as in get_default_db_collation() -
421-
* In case load_db_opt_by_name() fails (e.g. db.opt file
422-
* doesn't exist), db_read_only will be false (0) by default.
423-
*/
424-
static uchar get_db_read_only(THD *thd, const char *path)
425-
{
426-
HA_CREATE_INFO db_info;
427-
428-
load_db_opt(thd, path, &db_info);
429-
return db_info.db_read_only;
430-
}
431-
432417
/* Update db_ops in all threads' local hash map */
433418
static void update_thd_db_read_only(const char *path, uchar db_read_only)
434419
{
@@ -496,10 +481,23 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
496481
char buf[512]; // Should be enough for options
497482
bool error=1;
498483

484+
/* If db.opt doesn't exist, defaults will be loaded */
485+
HA_CREATE_INFO db_info;
486+
load_db_opt(thd, path, &db_info);
487+
499488
if (!create->default_table_charset)
500-
create->default_table_charset= thd->variables.collation_server;
489+
{
490+
if (!create->alter_default_table_charset)
491+
/* if we are not explicitly setting charset to default,
492+
* use the current value */
493+
create->default_table_charset = db_info.default_table_charset;
494+
else
495+
create->default_table_charset= thd->variables.collation_server;
496+
}
501497

502-
uchar prev_db_read_only= get_db_read_only(thd, path);
498+
/* if db_read_only is not specified, use the current value */
499+
if (create->db_read_only == enum_db_read_only::DB_READ_ONLY_NULL)
500+
create->db_read_only = db_info.db_read_only;
503501

504502
if (put_dbopt(path, create))
505503
return 1;
@@ -513,8 +511,10 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
513511
"\ndefault-collation=",
514512
create->default_table_charset->name,
515513
"\ndb-read-only=",
516-
create->db_read_only==0? "0":
517-
create->db_read_only==1? "1":"2",
514+
create->db_read_only==
515+
enum_db_read_only::DB_READ_ONLY_YES? "1":
516+
create->db_read_only==
517+
enum_db_read_only::DB_READ_ONLY_SUPER? "2":"0",
518518
"\n", NullS) - buf);
519519

520520
/* Error is written by mysql_file_write */
@@ -525,7 +525,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
525525

526526
/* If the read_only option is not changed,
527527
* don't need to update it across all sessions */
528-
if (prev_db_read_only != create->db_read_only)
528+
if (db_info.db_read_only != create->db_read_only)
529529
update_thd_db_read_only(path, create->db_read_only);
530530

531531
return error;
@@ -611,7 +611,18 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
611611
}
612612
else if (!strncmp(buf,"db-read-only", (pos-buf)))
613613
{
614-
create->db_read_only = (*(pos+1) - '0');
614+
if (!strcmp((pos+1), "0"))
615+
create->db_read_only = DB_READ_ONLY_NO;
616+
else if (!strcmp((pos+1), "1"))
617+
create->db_read_only = DB_READ_ONLY_YES;
618+
else if (!strcmp((pos+1), "2"))
619+
create->db_read_only = DB_READ_ONLY_SUPER;
620+
else
621+
{
622+
sql_print_error("Error while loading database options: '%s':",path);
623+
sql_print_error(ER(ER_UNKNOWN_DB_READ_ONLY),pos+1);
624+
create->db_read_only = DB_READ_ONLY_NO;
625+
}
615626
}
616627
}
617628
}

sql/sql_yacc.yy

+15-6
Original file line numberDiff line numberDiff line change
@@ -2739,7 +2739,8 @@ create:
27392739
{
27402740
Lex->create_info.default_table_charset= NULL;
27412741
Lex->create_info.used_fields= 0;
2742-
Lex->create_info.db_read_only= 0;
2742+
Lex->create_info.db_read_only=
2743+
enum_db_read_only::DB_READ_ONLY_NULL;
27432744
}
27442745
opt_create_database_options
27452746
{
@@ -6468,6 +6469,7 @@ default_charset:
64686469
"CHARACTER SET ", $4->csname);
64696470
MYSQL_YYABORT;
64706471
}
6472+
Lex->create_info.alter_default_table_charset = true;
64716473
Lex->create_info.default_table_charset= $4;
64726474
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
64736475
}
@@ -6485,6 +6487,7 @@ default_collation:
64856487
MYSQL_YYABORT;
64866488
}
64876489

6490+
Lex->create_info.alter_default_table_charset = true;
64886491
Lex->create_info.default_table_charset= $4;
64896492
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
64906493
}
@@ -6493,15 +6496,19 @@ default_collation:
64936496
db_read_only:
64946497
read_only_opt equal boolean_val
64956498
{
6496-
Lex->create_info.db_read_only= 0; /* read_only = false */
6499+
/* read_only = false */
6500+
Lex->create_info.db_read_only= enum_db_read_only::DB_READ_ONLY_NO;
64976501
if (($1 == 0 && $3 == 1) || ($1 == 1 && $3 == 0))
64986502
{
6499-
Lex->create_info.db_read_only= 1; /* read_only = true */
6500-
/* super_read_only = false */
6503+
/* read_only = true and super_read_only = false */
6504+
Lex->create_info.db_read_only=
6505+
enum_db_read_only::DB_READ_ONLY_YES;
65016506
}
65026507
else if ($1 == 1 && $3 == 1)
65036508
{
6504-
Lex->create_info.db_read_only= 2; /* super_read_only = true */
6509+
/* super_read_only = true */
6510+
Lex->create_info.db_read_only=
6511+
enum_db_read_only::DB_READ_ONLY_SUPER;
65056512
}
65066513
}
65076514
;
@@ -7715,8 +7722,10 @@ alter:
77157722
| ALTER DATABASE ident_or_empty
77167723
{
77177724
Lex->create_info.default_table_charset= NULL;
7725+
Lex->create_info.alter_default_table_charset = false;
77187726
Lex->create_info.used_fields= 0;
7719-
Lex->create_info.db_read_only= 0;
7727+
Lex->create_info.db_read_only=
7728+
enum_db_read_only::DB_READ_ONLY_NULL;
77207729
}
77217730
create_database_options
77227731
{

0 commit comments

Comments
 (0)