summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqlcheck.c25
-rw-r--r--client/mysqltest.c4
-rw-r--r--libmysql/client_settings.h4
-rw-r--r--libmysql/libmysql.c30
-rw-r--r--mysql-test/include/mix1.inc34
-rw-r--r--mysql-test/r/create.result22
-rw-r--r--mysql-test/r/delayed.result29
-rw-r--r--mysql-test/r/innodb_mysql.result36
-rw-r--r--mysql-test/r/query_cache.result49
-rw-r--r--mysql-test/r/renamedb.result43
-rw-r--r--mysql-test/r/sp-code.result4
-rw-r--r--mysql-test/r/sp-error.result13
-rw-r--r--mysql-test/r/sp.result50
-rw-r--r--mysql-test/r/upgrade.result25
-rw-r--r--mysql-test/t/create.test44
-rw-r--r--mysql-test/t/delayed.test31
-rw-r--r--mysql-test/t/mysql_client_test.test4
-rw-r--r--mysql-test/t/query_cache.test80
-rw-r--r--mysql-test/t/renamedb.test71
-rw-r--r--mysql-test/t/sp-error.test28
-rw-r--r--mysql-test/t/sp.test84
-rw-r--r--mysql-test/t/upgrade.test31
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_db.cc122
-rw-r--r--sql/sql_insert.cc37
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc159
-rw-r--r--sql/sql_prepare.cc13
-rw-r--r--sql/sql_select.cc30
-rw-r--r--sql/sql_yacc.yy67
-rw-r--r--tests/mysql_client_test.c377
34 files changed, 1191 insertions, 374 deletions
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index 316412d7df9..6d85e30c033 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -539,13 +539,13 @@ static int process_all_tables_in_db(char *database)
-static int fix_object_name(const char *obj, const char *name)
+static int fix_table_storage_name(const char *name)
{
char qbuf[100 + NAME_LEN*4];
int rc= 0;
if (strncmp(name, "#mysql50#", 9))
return 1;
- sprintf(qbuf, "RENAME %s `%s` TO `%s`", obj, name, name + 9);
+ sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9);
if (mysql_query(sock, qbuf))
{
fprintf(stderr, "Failed to %s\n", qbuf);
@@ -557,6 +557,23 @@ static int fix_object_name(const char *obj, const char *name)
return rc;
}
+static int fix_database_storage_name(const char *name)
+{
+ char qbuf[100 + NAME_LEN*4];
+ int rc= 0;
+ if (strncmp(name, "#mysql50#", 9))
+ return 1;
+ sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name);
+ if (mysql_query(sock, qbuf))
+ {
+ fprintf(stderr, "Failed to %s\n", qbuf);
+ fprintf(stderr, "Error: %s\n", mysql_error(sock));
+ rc= 1;
+ }
+ if (verbose)
+ printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
+ return rc;
+}
static int process_one_db(char *database)
{
@@ -565,7 +582,7 @@ static int process_one_db(char *database)
int rc= 0;
if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9))
{
- rc= fix_object_name("DATABASE", database);
+ rc= fix_database_storage_name(database);
database+= 9;
}
if (rc || !opt_fix_table_names)
@@ -620,7 +637,7 @@ static int handle_request_for_tables(char *tables, uint length)
op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG";
break;
case DO_UPGRADE:
- return fix_object_name("TABLE", tables);
+ return fix_table_storage_name(tables);
}
if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME))))
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 979c8de3656..702eab0078f 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -1507,7 +1507,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
die("Failed to create temporary file for ds");
/* Write ds to temporary file and set file pos to beginning*/
- if (my_write(fd, ds->str, ds->length,
+ if (my_write(fd, (uchar *) ds->str, ds->length,
MYF(MY_FNABP | MY_WME)) ||
my_seek(fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
{
@@ -1986,7 +1986,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
const struct command_arg query_get_value_args[] = {
"query", ARG_STRING, TRUE, &ds_query, "Query to run",
"column name", ARG_STRING, TRUE, &ds_col, "Name of column",
- "row number", ARG_STRING, TRUE, &ds_row, "Number for row",
+ "row number", ARG_STRING, TRUE, &ds_row, "Number for row"
};
DBUG_ENTER("var_set_query_get_value");
diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h
index a803ff8372f..f87e625771f 100644
--- a/libmysql/client_settings.h
+++ b/libmysql/client_settings.h
@@ -63,3 +63,7 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd);
int init_embedded_server(int argc, char **argv, char **groups);
void end_embedded_server();
#endif /*EMBEDDED_LIBRARY*/
+
+C_MODE_START
+extern int mysql_init_character_set(MYSQL *mysql);
+C_MODE_END
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 74435a1eb57..4153bd773d5 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -685,14 +685,25 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
return 0;
}
-
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db)
{
char buff[512],*end=buff;
int rc;
+ CHARSET_INFO *saved_cs= mysql->charset;
+
DBUG_ENTER("mysql_change_user");
+ /* Get the connection-default character set. */
+
+ if (mysql_init_character_set(mysql))
+ {
+ mysql->charset= saved_cs;
+ DBUG_RETURN(TRUE);
+ }
+
+ /* Use an empty string instead of NULL. */
+
if (!user)
user="";
if (!passwd)
@@ -721,6 +732,14 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
/* Add database if needed */
end= strmov(end, db ? db : "") + 1;
+ /* Add character set number. */
+
+ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
+ {
+ int2store(end, (ushort) mysql->charset->number);
+ end+= 2;
+ }
+
/* Write authentication package */
simple_command(mysql,COM_CHANGE_USER, (uchar*) buff, (ulong) (end-buff), 1);
@@ -743,6 +762,11 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
}
+ else
+ {
+ mysql->charset= saved_cs;
+ }
+
DBUG_RETURN(rc);
}
@@ -2502,7 +2526,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
5 /* execution flags */];
my_bool res;
DBUG_ENTER("execute");
- DBUG_DUMP("packet", packet, length);
+ DBUG_DUMP("packet", (uchar *) packet, length);
mysql->last_used_con= mysql;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
@@ -4679,7 +4703,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt)
NET *net;
DBUG_ENTER("cli_read_binary_rows");
-
+
if (!mysql)
{
set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc
index e2a22303d9d..aee5613ff35 100644
--- a/mysql-test/include/mix1.inc
+++ b/mysql-test/include/mix1.inc
@@ -1146,4 +1146,38 @@ select @b:=f2 from t1;
select if(@a=@b,"ok","wrong");
drop table t1;
+#
+# Bug#30747 Create table with identical constraint names behaves incorrectly
+#
+
+if ($test_foreign_keys)
+{
+ CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) engine=innodb;
+ --error ER_WRONG_FK_DEF
+ CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+ CONSTRAINT c2 FOREIGN KEY f2 (c) REFERENCES t1 (a,b) ON UPDATE NO ACTION) engine=innodb;
+ --error ER_WRONG_FK_DEF
+ CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+ CONSTRAINT c2 FOREIGN KEY (c) REFERENCES t1 (a,b) ON UPDATE NO ACTION) engine=innodb;
+ CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+ CONSTRAINT c1 FOREIGN KEY c2 (c) REFERENCES t1 (a) ON DELETE NO ACTION,
+ CONSTRAINT c2 FOREIGN KEY (c) REFERENCES t1 (a) ON UPDATE NO ACTION) engine=innodb;
+ ALTER TABLE t2 DROP FOREIGN KEY c2;
+ DROP TABLE t2;
+ --error ER_WRONG_FK_DEF
+ CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+ FOREIGN KEY (c) REFERENCES t1 (a,k) ON UPDATE NO ACTION) engine=innodb;
+ --error ER_WRONG_FK_DEF
+ CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+ FOREIGN KEY f1 (c) REFERENCES t1 (a,k) ON UPDATE NO ACTION) engine=innodb;
+ CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+ CONSTRAINT c1 FOREIGN KEY f1 (c) REFERENCES t1 (a) ON DELETE NO ACTION,
+ CONSTRAINT c2 FOREIGN KEY (c) REFERENCES t1 (a) ON UPDATE NO ACTION,
+ FOREIGN KEY f3 (c) REFERENCES t1 (a) ON UPDATE NO ACTION,
+ FOREIGN KEY (c) REFERENCES t1 (a) ON UPDATE NO ACTION) engine=innodb;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+ DROP TABLE t1;
+}
+
--echo End of 5.1 tests
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index b370fbf6fbe..e79a255967b 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -1588,14 +1588,6 @@ CREATE DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
DROP DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
-RENAME DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa TO a;
-ERROR 42000: Unknown database 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
-RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
-ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
-create database mysqltest;
-RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
-ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
-drop database mysqltest;
USE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
SHOW CREATE DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
@@ -1699,4 +1691,18 @@ ERROR 42000: Identifier name 'очень_очень_очень_очень_оче
drop view имя_вью_кодировке_утф8_длиной_больше_чем_42;
drop table имя_таблицы_в_кодировке_утф8_длиной_больше_чем_48;
set names default;
+drop table if exists t1,t2,t3;
+drop function if exists f1;
+create function f1() returns int
+begin
+declare res int;
+create temporary table t3 select 1 i;
+set res:= (select count(*) from t1);
+drop temporary table t3;
+return res;
+end|
+create table t1 as select 1;
+create table t2 as select f1() from t1;
+drop table t1,t2;
+drop function f1;
End of 5.1 tests
diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result
index fb8dc9af71a..c520ab52ab3 100644
--- a/mysql-test/r/delayed.result
+++ b/mysql-test/r/delayed.result
@@ -255,3 +255,32 @@ CREATE TABLE t2(c1 INT) ENGINE=MERGE UNION=(t1);
INSERT DELAYED INTO t2 VALUES(1);
ERROR HY000: Table storage engine for 't2' doesn't have this option
DROP TABLE t1, t2;
+DROP TABLE IF EXISTS t1,t2;
+SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
+CREATE TABLE `t1` (
+`id` int(11) PRIMARY KEY auto_increment,
+`f1` varchar(10) NOT NULL UNIQUE
+);
+INSERT DELAYED INTO t1 VALUES(0,"test1");
+SELECT * FROM t1;
+id f1
+0 test1
+SET SQL_MODE='PIPES_AS_CONCAT';
+INSERT DELAYED INTO t1 VALUES(0,'a' || 'b');
+SELECT * FROM t1;
+id f1
+0 test1
+1 ab
+SET SQL_MODE='ERROR_FOR_DIVISION_BY_ZERO,STRICT_ALL_TABLES';
+INSERT DELAYED INTO t1 VALUES(mod(1,0),"test3");
+ERROR 22012: Division by 0
+CREATE TABLE t2 (
+`id` int(11) PRIMARY KEY auto_increment,
+`f1` date
+);
+SET SQL_MODE='NO_ZERO_DATE,STRICT_ALL_TABLES,NO_ZERO_IN_DATE';
+INSERT DELAYED INTO t2 VALUES (0,'0000-00-00');
+ERROR 22007: Incorrect date value: '0000-00-00' for column 'f1' at row 1
+INSERT DELAYED INTO t2 VALUES (0,'2007-00-00');
+ERROR 22007: Incorrect date value: '2007-00-00' for column 'f1' at row 1
+DROP TABLE t1,t2;
diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result
index 0757936a8f7..3a6758b38f4 100644
--- a/mysql-test/r/innodb_mysql.result
+++ b/mysql-test/r/innodb_mysql.result
@@ -1419,4 +1419,40 @@ select if(@a=@b,"ok","wrong");
if(@a=@b,"ok","wrong")
ok
drop table t1;
+CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) engine=innodb;
+CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+CONSTRAINT c2 FOREIGN KEY f2 (c) REFERENCES t1 (a,b) ON UPDATE NO ACTION) engine=innodb;
+ERROR 42000: Incorrect foreign key definition for 'f2': Key reference and table reference don't match
+CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+CONSTRAINT c2 FOREIGN KEY (c) REFERENCES t1 (a,b) ON UPDATE NO ACTION) engine=innodb;
+ERROR 42000: Incorrect foreign key definition for 'c2': Key reference and table reference don't match
+CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+CONSTRAINT c1 FOREIGN KEY c2 (c) REFERENCES t1 (a) ON DELETE NO ACTION,
+CONSTRAINT c2 FOREIGN KEY (c) REFERENCES t1 (a) ON UPDATE NO ACTION) engine=innodb;
+ALTER TABLE t2 DROP FOREIGN KEY c2;
+DROP TABLE t2;
+CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+FOREIGN KEY (c) REFERENCES t1 (a,k) ON UPDATE NO ACTION) engine=innodb;
+ERROR 42000: Incorrect foreign key definition for 'foreign key without name': Key reference and table reference don't match
+CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+FOREIGN KEY f1 (c) REFERENCES t1 (a,k) ON UPDATE NO ACTION) engine=innodb;
+ERROR 42000: Incorrect foreign key definition for 'f1': Key reference and table reference don't match
+CREATE TABLE t2 (c INT NOT NULL, d INT NOT NULL, PRIMARY KEY (c,d),
+CONSTRAINT c1 FOREIGN KEY f1 (c) REFERENCES t1 (a) ON DELETE NO ACTION,
+CONSTRAINT c2 FOREIGN KEY (c) REFERENCES t1 (a) ON UPDATE NO ACTION,
+FOREIGN KEY f3 (c) REFERENCES t1 (a) ON UPDATE NO ACTION,
+FOREIGN KEY (c) REFERENCES t1 (a) ON UPDATE NO ACTION) engine=innodb;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c` int(11) NOT NULL,
+ `d` int(11) NOT NULL,
+ PRIMARY KEY (`c`,`d`),
+ CONSTRAINT `c1` FOREIGN KEY (`c`) REFERENCES `t1` (`a`) ON DELETE NO ACTION,
+ CONSTRAINT `c2` FOREIGN KEY (`c`) REFERENCES `t1` (`a`) ON UPDATE NO ACTION,
+ CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`c`) REFERENCES `t1` (`a`) ON UPDATE NO ACTION,
+ CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`c`) REFERENCES `t1` (`a`) ON UPDATE NO ACTION
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
End of 5.1 tests
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 321b08628ee..5a15a87bd3c 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -1684,52 +1684,3 @@ set GLOBAL query_cache_limit=default;
set GLOBAL query_cache_min_res_unit=default;
set GLOBAL query_cache_size=default;
End of 5.0 tests
-drop database if exists db1;
-drop database if exists db2;
-set GLOBAL query_cache_size=15*1024*1024;
-create database db1;
-use db1;
-create table t1(c1 int)engine=myisam;
-insert into t1(c1) values (1);
-select * from db1.t1 f;
-c1
-1
-show status like 'Qcache_queries_in_cache';
-Variable_name Value
-Qcache_queries_in_cache 1
-rename schema db1 to db2;
-show status like 'Qcache_queries_in_cache';
-Variable_name Value
-Qcache_queries_in_cache 0
-drop database db2;
-set global query_cache_size=default;
-drop database if exists db1;
-drop database if exists db3;
-set GLOBAL query_cache_size=15*1024*1024;
-create database db1;
-create database db3;
-use db1;
-create table t1(c1 int) engine=myisam;
-use db3;
-create table t1(c1 int) engine=myisam;
-use db1;
-insert into t1(c1) values (1);
-use mysql;
-select * from db1.t1;
-c1
-1
-select c1+1 from db1.t1;
-c1+1
-2
-select * from db3.t1;
-c1
-show status like 'Qcache_queries_in_cache';
-Variable_name Value
-Qcache_queries_in_cache 3
-rename schema db1 to db2;
-show status like 'Qcache_queries_in_cache';
-Variable_name Value
-Qcache_queries_in_cache 1
-drop database db2;
-drop database db3;
-End of 5.1 tests
diff --git a/mysql-test/r/renamedb.result b/mysql-test/r/renamedb.result
index b22322fbe8d..ff8f89592fc 100644
--- a/mysql-test/r/renamedb.result
+++ b/mysql-test/r/renamedb.result
@@ -1,33 +1,12 @@
-drop database if exists testdb1;
-create database testdb1 default character set latin2;
-use testdb1;
-create table t1 (a int);
-insert into t1 values (1),(2),(3);
-show create database testdb1;
-Database Create Database
-testdb1 CREATE DATABASE `testdb1` /*!40100 DEFAULT CHARACTER SET latin2 */
-show tables;
-Tables_in_testdb1
-t1
rename database testdb1 to testdb2;
-show create database testdb1;
-ERROR 42000: Unknown database 'testdb1'
-show create database testdb2;
-Database Create Database
-testdb2 CREATE DATABASE `testdb2` /*!40100 DEFAULT CHARACTER SET latin2 */
-select database();
-database()
-testdb2
-show tables;
-Tables_in_testdb2
-t1
-select a from t1 order by a;
-a
-1
-2
-3
-drop database testdb2;
-create database testdb1;
-rename database testdb1 to testdb1;
-ERROR HY000: Can't create database 'testdb1'; database exists
-drop database testdb1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'database testdb1 to testdb2' at line 1
+ALTER DATABASE wrong UPGRADE DATA DIRECTORY NAME;
+ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name
+ALTER DATABASE `#mysql41#not-supported` UPGRADE DATA DIRECTORY NAME;
+ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name
+ALTER DATABASE `#mysql51#not-yet` UPGRADE DATA DIRECTORY NAME;
+ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name
+ALTER DATABASE `#mysql50#` UPGRADE DATA DIRECTORY NAME;
+ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name
+ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME;
+ERROR 42000: Unknown database '#mysql50#upgrade-me'
diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result
index b2bcfff0fdb..018173e723d 100644
--- a/mysql-test/r/sp-code.result
+++ b/mysql-test/r/sp-code.result
@@ -155,11 +155,11 @@ Pos Instruction
0 stmt 9 "drop temporary table if exists sudoku..."
1 stmt 1 "create temporary table sudoku_work ( ..."
2 stmt 1 "create temporary table sudoku_schedul..."
-3 stmt 95 "call sudoku_init()"
+3 stmt 94 "call sudoku_init()"
4 jump_if_not 7(8) p_naive@0
5 stmt 4 "update sudoku_work set cnt = 0 where ..."
6 jump 8
-7 stmt 95 "call sudoku_count()"
+7 stmt 94 "call sudoku_count()"
8 stmt 6 "insert into sudoku_schedule (row,col)..."
9 set v_scounter@2 0
10 set v_i@3 1
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 2e0d437aeb6..bfcd64e89d3 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -1478,3 +1478,16 @@ end
until true end repeat retry;
end//
ERROR 42000: LEAVE with no matching label: retry
+drop procedure if exists proc_28360;
+drop function if exists func_28360;
+CREATE PROCEDURE proc_28360()
+BEGIN
+ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME;
+END//
+ERROR HY000: Can't drop or alter a DATABASE from within another stored routine
+CREATE FUNCTION func_28360() RETURNS int
+BEGIN
+ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME;
+RETURN 0;
+END//
+ERROR HY000: Can't drop or alter a DATABASE from within another stored routine
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 55b27b0a733..21af61d39f6 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -4914,7 +4914,7 @@ create table t3 as select * from v1|
show create table t3|
Table Create Table
t3 CREATE TABLE `t3` (
- `j` bigint(11) DEFAULT NULL
+ `j` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t3|
j
@@ -6621,3 +6621,51 @@ DROP TABLE t1;
DROP PROCEDURE p1;
DROP PROCEDURE p2;
End of 5.0 tests
+
+#
+# Bug#20550.
+#
+
+#
+# - Prepare.
+#
+
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+
+#
+# - Create required objects.
+#
+
+CREATE FUNCTION f1() RETURNS VARCHAR(65525) RETURN 'Hello';
+
+CREATE FUNCTION f2() RETURNS TINYINT RETURN 1;
+
+CREATE VIEW v1 AS SELECT f1();
+
+CREATE VIEW v2 AS SELECT f2();
+
+#
+# - Check.
+#
+
+SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'v1';
+DATA_TYPE
+varchar
+
+SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'v2';
+DATA_TYPE
+tinyint
+
+#
+# - Cleanup.
+#
+
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP VIEW v1;
+DROP VIEW v2;
+
+End of 5.1 tests
diff --git a/mysql-test/r/upgrade.result b/mysql-test/r/upgrade.result
index 76e0359c405..adf81efe8e3 100644
--- a/mysql-test/r/upgrade.result
+++ b/mysql-test/r/upgrade.result
@@ -59,3 +59,28 @@ drop table `txu@0023p@0023p1`;
drop table `txu#p#p1`;
truncate t1;
drop table t1;
+drop database if exists `tabc`;
+drop database if exists `a-b-c`;
+create database `tabc` default character set latin2;
+create table tabc.t1 (a int);
+FLUSH TABLES;
+show databases like '%a-b-c%';
+Database (%a-b-c%)
+#mysql50#a-b-c
+ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME;
+show databases like '%a-b-c%';
+Database (%a-b-c%)
+a-b-c
+show create database `a-b-c`;
+Database Create Database
+a-b-c CREATE DATABASE `a-b-c` /*!40100 DEFAULT CHARACTER SET latin2 */
+show tables in `a-b-c`;
+Tables_in_a-b-c
+t1
+show create table `a-b-c`.`t1`;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin2
+drop database `a-b-c`;
+drop database `tabc`;
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 341c019af6e..023e55ea418 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -1197,14 +1197,17 @@ drop table t1,t2;
CREATE DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
--error 1102
DROP DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
---error 1049
-RENAME DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa TO a;
---error 1102
-RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
-create database mysqltest;
---error 1102
-RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
-drop database mysqltest;
+
+# TODO: enable these tests when RENAME DATABASE is implemented.
+# --error 1049
+# RENAME DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa TO a;
+# --error 1102
+# RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+# create database mysqltest;
+# --error 1102
+# RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+# drop database mysqltest;
+
--error 1102
USE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
--error 1102
@@ -1300,4 +1303,29 @@ return 0;
drop view имя_вью_кодировке_утф8_длиной_больше_чем_42;
drop table имя_таблицы_в_кодировке_утф8_длиной_больше_чем_48;
set names default;
+
+#
+# Bug#21136 CREATE TABLE SELECT within CREATE TABLE SELECT causes server crash
+#
+
+--disable_warnings
+drop table if exists t1,t2,t3;
+drop function if exists f1;
+--enable_warnings
+
+--delimiter |
+create function f1() returns int
+begin
+ declare res int;
+ create temporary table t3 select 1 i;
+ set res:= (select count(*) from t1);
+ drop temporary table t3;
+ return res;
+end|
+--delimiter ;
+create table t1 as select 1;
+create table t2 as select f1() from t1;
+drop table t1,t2;
+drop function f1;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test
index 396c06f43e7..03b4f8b3013 100644
--- a/mysql-test/t/delayed.test
+++ b/mysql-test/t/delayed.test
@@ -251,4 +251,35 @@ CREATE TABLE t2(c1 INT) ENGINE=MERGE UNION=(t1);
--error 1031
INSERT DELAYED INTO t2 VALUES(1);
DROP TABLE t1, t2;
+#
+# Bug#27358 INSERT DELAYED does not honour SQL_MODE of the client
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2;
+--enable_warnings
+SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
+CREATE TABLE `t1` (
+ `id` int(11) PRIMARY KEY auto_increment,
+ `f1` varchar(10) NOT NULL UNIQUE
+);
+INSERT DELAYED INTO t1 VALUES(0,"test1");
+sleep 1;
+SELECT * FROM t1;
+SET SQL_MODE='PIPES_AS_CONCAT';
+INSERT DELAYED INTO t1 VALUES(0,'a' || 'b');
+sleep 1;
+SELECT * FROM t1;
+SET SQL_MODE='ERROR_FOR_DIVISION_BY_ZERO,STRICT_ALL_TABLES';
+--error 1365
+INSERT DELAYED INTO t1 VALUES(mod(1,0),"test3");
+CREATE TABLE t2 (
+ `id` int(11) PRIMARY KEY auto_increment,
+ `f1` date
+);
+SET SQL_MODE='NO_ZERO_DATE,STRICT_ALL_TABLES,NO_ZERO_IN_DATE';
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT DELAYED INTO t2 VALUES (0,'0000-00-00');
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT DELAYED INTO t2 VALUES (0,'2007-00-00');
+DROP TABLE t1,t2;
diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test
index 66a27abd61a..7667522feaf 100644
--- a/mysql-test/t/mysql_client_test.test
+++ b/mysql-test/t/mysql_client_test.test
@@ -8,8 +8,8 @@
# server or run mysql-test-run --debug mysql_client_test and check
# var/log/mysql_client_test.trace
---exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1
---exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1
+--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1
+--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1
# End of 4.1 tests
echo ok;
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index d06698cdb17..2cfe1ff4ccc 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -1293,44 +1293,42 @@ set GLOBAL query_cache_size=default;
#
# Bug #28211 RENAME DATABASE and query cache don't play nicely together
-#
---disable_warnings
-drop database if exists db1;
-drop database if exists db2;
---enable_warnings
-set GLOBAL query_cache_size=15*1024*1024;
-create database db1;
-use db1;
-create table t1(c1 int)engine=myisam;
-insert into t1(c1) values (1);
-select * from db1.t1 f;
-show status like 'Qcache_queries_in_cache';
-rename schema db1 to db2;
-show status like 'Qcache_queries_in_cache';
-drop database db2;
-set global query_cache_size=default;
-
---disable_warnings
-drop database if exists db1;
-drop database if exists db3;
---enable_warnings
-set GLOBAL query_cache_size=15*1024*1024;
-create database db1;
-create database db3;
-use db1;
-create table t1(c1 int) engine=myisam;
-use db3;
-create table t1(c1 int) engine=myisam;
-use db1;
-insert into t1(c1) values (1);
-use mysql;
-select * from db1.t1;
-select c1+1 from db1.t1;
-select * from db3.t1;
-show status like 'Qcache_queries_in_cache';
-rename schema db1 to db2;
-show status like 'Qcache_queries_in_cache';
-drop database db2;
-drop database db3;
-
---echo End of 5.1 tests
+# TODO: enable these tests when RENAME DATABASE is implemented.
+# --disable_warnings
+# drop database if exists db1;
+# drop database if exists db2;
+# --enable_warnings
+# set GLOBAL query_cache_size=15*1024*1024;
+# create database db1;
+# use db1;
+# create table t1(c1 int)engine=myisam;
+# insert into t1(c1) values (1);
+# select * from db1.t1 f;
+# show status like 'Qcache_queries_in_cache';
+# rename schema db1 to db2;
+# show status like 'Qcache_queries_in_cache';
+# drop database db2;
+# set global query_cache_size=default;
+#
+# --disable_warnings
+# drop database if exists db1;
+# drop database if exists db3;
+# --enable_warnings
+# set GLOBAL query_cache_size=15*1024*1024;
+# create database db1;
+# create database db3;
+# use db1;
+# create table t1(c1 int) engine=myisam;
+# use db3;
+# create table t1(c1 int) engine=myisam;
+# use db1;
+# insert into t1(c1) values (1);
+# use mysql;
+# select * from db1.t1;
+# select c1+1 from db1.t1;
+# select * from db3.t1;
+# show status like 'Qcache_queries_in_cache';
+# rename schema db1 to db2;
+# show status like 'Qcache_queries_in_cache';
+# drop database db2;
+# drop database db3;
diff --git a/mysql-test/t/renamedb.test b/mysql-test/t/renamedb.test
index 1e71adb3bf3..84315090b7a 100644
--- a/mysql-test/t/renamedb.test
+++ b/mysql-test/t/renamedb.test
@@ -1,26 +1,53 @@
---disable_warnings
-drop database if exists testdb1;
---enable_warnings
-
-create database testdb1 default character set latin2;
-use testdb1;
-create table t1 (a int);
-insert into t1 values (1),(2),(3);
-show create database testdb1;
-show tables;
-rename database testdb1 to testdb2;
---error 1049
-show create database testdb1;
-show create database testdb2;
-select database();
-show tables;
-select a from t1 order by a;
-drop database testdb2;
+# TODO: enable these tests when RENAME DATABASE is implemented.
+#
+# --disable_warnings
+# drop database if exists testdb1;
+# --enable_warnings
+#
+# create database testdb1 default character set latin2;
+# use testdb1;
+# create table t1 (a int);
+# insert into t1 values (1),(2),(3);
+# show create database testdb1;
+# show tables;
+# rename database testdb1 to testdb2;
+# --error 1049
+# show create database testdb1;
+# show create database testdb2;
+# select database();
+# show tables;
+# select a from t1 order by a;
+# drop database testdb2;
+#
#
# Bug#19392 Rename Database: Crash if case change
#
-create database testdb1;
---error 1007
-rename database testdb1 to testdb1;
-drop database testdb1;
+# create database testdb1;
+# --error 1007
+# rename database testdb1 to testdb1;
+# drop database testdb1;
+
+#
+# WL#4030 (Deprecate RENAME DATABASE: replace with ALTER DATABASE <name> UPGRADE)
+#
+
+--error ER_PARSE_ERROR
+rename database testdb1 to testdb2;
+
+--error ER_WRONG_USAGE
+ALTER DATABASE wrong UPGRADE DATA DIRECTORY NAME;
+
+--error ER_WRONG_USAGE
+ALTER DATABASE `#mysql41#not-supported` UPGRADE DATA DIRECTORY NAME;
+
+--error ER_WRONG_USAGE
+ALTER DATABASE `#mysql51#not-yet` UPGRADE DATA DIRECTORY NAME;
+
+--error ER_WRONG_USAGE
+ALTER DATABASE `#mysql50#` UPGRADE DATA DIRECTORY NAME;
+
+--error ER_BAD_DB_ERROR
+ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME;
+
+
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 012f2b33225..c9145859405 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -2150,6 +2150,34 @@ end//
delimiter ;//
+
+#
+# Bug#28360 (RENAME DATABASE destroys routines)
+#
+
+--disable_warnings
+drop procedure if exists proc_28360;
+drop function if exists func_28360;
+--enable_warnings
+
+delimiter //;
+
+--error ER_SP_NO_DROP_SP
+CREATE PROCEDURE proc_28360()
+BEGIN
+ ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME;
+END//
+
+--error ER_SP_NO_DROP_SP
+CREATE FUNCTION func_28360() RETURNS int
+BEGIN
+ ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME;
+ RETURN 0;
+END//
+
+delimiter ;//
+
+
#
# BUG#NNNN: New bug synopsis
#
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 4e4102dd1ef..78ac419e451 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -7582,3 +7582,87 @@ DROP PROCEDURE p1;
DROP PROCEDURE p2;
--echo End of 5.0 tests
+
+###########################################################################
+
+#
+# Bug#20550: Stored function: wrong RETURN type metadata when used in a VIEW.
+#
+
+###########################################################################
+
+--echo
+
+--echo #
+--echo # Bug#20550.
+--echo #
+
+--echo
+
+--echo #
+--echo # - Prepare.
+--echo #
+
+--echo
+
+--disable_warnings
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+--enable_warnings
+
+--echo
+
+--echo #
+--echo # - Create required objects.
+--echo #
+
+--echo
+
+CREATE FUNCTION f1() RETURNS VARCHAR(65525) RETURN 'Hello';
+
+--echo
+
+CREATE FUNCTION f2() RETURNS TINYINT RETURN 1;
+
+--echo
+
+CREATE VIEW v1 AS SELECT f1();
+
+--echo
+
+CREATE VIEW v2 AS SELECT f2();
+
+--echo
+
+--echo #
+--echo # - Check.
+--echo #
+
+--echo
+
+SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'v1';
+
+--echo
+
+SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'v2';
+
+--echo
+
+--echo #
+--echo # - Cleanup.
+--echo #
+
+--echo
+
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP VIEW v1;
+DROP VIEW v2;
+
+--echo
+
+###########################################################################
+
+--echo End of 5.1 tests
diff --git a/mysql-test/t/upgrade.test b/mysql-test/t/upgrade.test
index f517c7787f8..40bd17fc3a5 100644
--- a/mysql-test/t/upgrade.test
+++ b/mysql-test/t/upgrade.test
@@ -56,3 +56,34 @@ system cp $MYSQL_TEST_DIR/std_data/old_table-323.frm $MYSQLTEST_VARDIR/master-da
truncate t1;
drop table t1;
+#
+# Bug#28360 (RENAME DATABASE destroys routines)
+#
+
+
+--disable_warnings
+drop database if exists `tabc`;
+drop database if exists `a-b-c`;
+--enable_warnings
+
+create database `tabc` default character set latin2;
+create table tabc.t1 (a int);
+FLUSH TABLES;
+
+# Manually make a 5.0 database from the template
+--exec mkdir $MYSQLTEST_VARDIR/master-data/a-b-c
+--copy_file $MYSQLTEST_VARDIR/master-data/tabc/db.opt $MYSQLTEST_VARDIR/master-data/a-b-c/db.opt
+--copy_file $MYSQLTEST_VARDIR/master-data/tabc/t1.frm $MYSQLTEST_VARDIR/master-data/a-b-c/t1.frm
+--copy_file $MYSQLTEST_VARDIR/master-data/tabc/t1.MYD $MYSQLTEST_VARDIR/master-data/a-b-c/t1.MYD
+--copy_file $MYSQLTEST_VARDIR/master-data/tabc/t1.MYI $MYSQLTEST_VARDIR/master-data/a-b-c/t1.MYI
+
+show databases like '%a-b-c%';
+ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME;
+# The physical directory name is now a@002db@002dc, the logical name still a-b-c
+show databases like '%a-b-c%';
+show create database `a-b-c`;
+show tables in `a-b-c`;
+show create table `a-b-c`.`t1`;
+drop database `a-b-c`;
+drop database `tabc`;
+
diff --git a/sql/item_func.h b/sql/item_func.h
index ea22e35773d..66a417f31fa 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1535,6 +1535,11 @@ public:
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec(void);
bool is_expensive() { return 1; }
+
+ inline Field *get_sp_result_field()
+ {
+ return sp_result_field;
+ }
};
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 47a42354423..6a7e3e00f6f 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -923,7 +923,7 @@ void end_connection(THD *thd);
bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
-bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db);
+bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db);
void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
void mysql_client_binlog_statement(THD *thd);
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 828517011d5..7de230bba78 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2699,7 +2699,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
query= thd->query;
query_length= thd->query_length;
- if (!(res= alloc_query(thd, m_query.str, m_query.length+1)) &&
+ if (!(res= alloc_query(thd, m_query.str, m_query.length)) &&
!(res=subst_spvars(thd, this, &m_query)))
{
/*
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 7875870bd1a..97a63ed9448 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2133,6 +2133,10 @@ class select_create: public select_insert {
TABLE_LIST *select_tables;
Alter_info *alter_info;
Field **field;
+ /* lock data for tmp table */
+ MYSQL_LOCK *m_lock;
+ /* m_lock or thd->extra_lock */
+ MYSQL_LOCK **m_plock;
public:
select_create (TABLE_LIST *table_arg,
HA_CREATE_INFO *create_info_par,
@@ -2143,7 +2147,8 @@ public:
create_table(table_arg),
create_info(create_info_par),
select_tables(select_tables_arg),
- alter_info(alter_info_arg)
+ alter_info(alter_info_arg),
+ m_plock(NULL)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index cd7ad048802..abbf2131957 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1727,41 +1727,21 @@ lock_databases(THD *thd, const char *db1, uint length1,
}
-/*
- Rename database.
-
- SYNOPSIS
- mysql_rename_db()
- thd Thread handler
- olddb Old database name
- newdb New database name
-
- DESCRIPTION
- This function is invoked whenever a RENAME DATABASE query is executed:
-
- RENAME DATABASE 'olddb' TO 'newdb'.
-
- NOTES
-
- If we have managed to rename (move) tables to the new database
- but something failed on a later step, then we store the
- RENAME DATABASE event in the log. mysql_rename_db() is atomic in
- the sense that it will rename all or none of the tables.
-
- TODO:
- - Better trigger, stored procedure, event, grant handling,
- see the comments below.
- NOTE: It's probably a good idea to call wait_if_global_read_lock()
- once in mysql_rename_db(), instead of locking inside all
- the required functions for renaming triggerts, SP, events, grants, etc.
-
- RETURN VALUES
- 0 ok
- 1 error
+/**
+ Upgrade a 5.0 database.
+ This function is invoked whenever an ALTER DATABASE UPGRADE query is executed:
+ ALTER DATABASE 'olddb' UPGRADE DATA DIRECTORY NAME.
+
+ If we have managed to rename (move) tables to the new database
+ but something failed on a later step, then we store the
+ RENAME DATABASE event in the log. mysql_rename_db() is atomic in
+ the sense that it will rename all or none of the tables.
+
+ @param thd Current thread
+ @param old_db 5.0 database name, in #mysql50#name format
+ @return 0 on success, 1 on error
*/
-
-
-bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
+bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
{
int error= 0, change_to_newdb= 0;
char path[FN_REFLEN+16];
@@ -1770,11 +1750,27 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
MY_DIR *dirp;
TABLE_LIST *table_list;
SELECT_LEX *sl= thd->lex->current_select;
- DBUG_ENTER("mysql_rename_db");
+ LEX_STRING new_db;
+ DBUG_ENTER("mysql_upgrade_db");
+
+ if ((old_db->length <= MYSQL50_TABLE_NAME_PREFIX_LENGTH) ||
+ (strncmp(old_db->str,
+ MYSQL50_TABLE_NAME_PREFIX,
+ MYSQL50_TABLE_NAME_PREFIX_LENGTH) != 0))
+ {
+ my_error(ER_WRONG_USAGE, MYF(0),
+ "ALTER DATABASE UPGRADE DATA DIRECTORY NAME",
+ "name");
+ DBUG_RETURN(1);
+ }
+
+ /* `#mysql50#<name>` converted to encoded `<name>` */
+ new_db.str= old_db->str + MYSQL50_TABLE_NAME_PREFIX_LENGTH;
+ new_db.length= old_db->length - MYSQL50_TABLE_NAME_PREFIX_LENGTH;
if (lock_databases(thd, old_db->str, old_db->length,
- new_db->str, new_db->length))
- return 1;
+ new_db.str, new_db.length))
+ DBUG_RETURN(1);
/*
Let's remember if we should do "USE newdb" afterwards.
@@ -1798,7 +1794,7 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
}
/* Step1: Create the new database */
- if ((error= mysql_create_db(thd, new_db->str, &create_info, 1)))
+ if ((error= mysql_create_db(thd, new_db.str, &create_info, 1)))
goto exit;
/* Step2: Move tables to the new database */
@@ -1819,12 +1815,12 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
/* A frm file found, add the table info rename list */
*extension= '\0';
-
+
table_str.length= filename_to_tablename(file->name,
tname, sizeof(tname)-1);
table_str.str= (char*) sql_memdup(tname, table_str.length + 1);
Table_ident *old_ident= new Table_ident(thd, *old_db, table_str, 0);
- Table_ident *new_ident= new Table_ident(thd, *new_db, table_str, 0);
+ Table_ident *new_ident= new Table_ident(thd, new_db, table_str, 0);
if (!old_ident || !new_ident ||
!sl->add_table_to_list(thd, old_ident, NULL,
TL_OPTION_UPDATING, TL_IGNORE) ||
@@ -1854,9 +1850,9 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
It garantees we never loose any tables.
*/
build_table_filename(path, sizeof(path)-1,
- new_db->str,"",MY_DB_OPT_FILE, 0);
+ new_db.str,"",MY_DB_OPT_FILE, 0);
my_delete(path, MYF(MY_WME));
- length= build_table_filename(path, sizeof(path)-1, new_db->str, "", "", 0);
+ length= build_table_filename(path, sizeof(path)-1, new_db.str, "", "", 0);
if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\'
rmdir(path);
@@ -1910,47 +1906,13 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
build_table_filename(oldname, sizeof(oldname)-1,
old_db->str, "", file->name, 0);
build_table_filename(newname, sizeof(newname)-1,
- new_db->str, "", file->name, 0);
+ new_db.str, "", file->name, 0);
my_rename(oldname, newname, MYF(MY_WME));
}
- my_dirend(dirp);
+ my_dirend(dirp);
}
/*
- Step4: TODO: moving stored procedures in the 'proc' system table
- We need a new function: sp_move_db_routines(thd, olddb, newdb)
- Which will basically have the same effect with:
- UPDATE proc SET db='newdb' WHERE db='olddb'
- Note, for 5.0 to 5.1 upgrade purposes we don't really need it.
-
- The biggest problem here is that we can't have a lock on LOCK_open() while
- calling open_table() for 'proc'.
-
- Two solutions:
- - Start by opening the 'event' and 'proc' (and other) tables for write
- even before creating the 'to' database. (This will have the nice
- effect of blocking another 'rename database' while the lock is active).
- - Use the solution "Disable create of new tables during lock table"
-
- For an example of how to read through all rows, see:
- sql_help.cc::search_topics()
- */
-
- /*
- Step5: TODO: moving events in the 'event' system table
- We need a new function evex_move_db_events(thd, olddb, newdb)
- Which will have the same effect with:
- UPDATE event SET db='newdb' WHERE db='olddb'
- Note, for 5.0 to 5.1 upgrade purposes we don't really need it.
- */
-
- /*
- Step6: TODO: moving grants in the 'db', 'tables_priv', 'columns_priv'.
- Update each grant table, doing the same with:
- UPDATE system_table SET db='newdb' WHERE db='olddb'
- */
-
- /*
Step7: drop the old database.
remove_db_from_cache(olddb) and query_cache_invalidate(olddb)
are done inside mysql_rm_db(), no needs to execute them again.
@@ -1968,13 +1930,13 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
/* Step9: Let's do "use newdb" if we renamed the current database */
if (change_to_newdb)
- error|= mysql_change_db(thd, new_db, FALSE);
+ error|= mysql_change_db(thd, & new_db, FALSE);
exit:
pthread_mutex_lock(&LOCK_lock_db);
/* Remove the databases from db lock cache */
lock_db_delete(old_db->str, old_db->length);
- lock_db_delete(new_db->str, new_db->length);
+ lock_db_delete(new_db.str, new_db.length);
creating_database--;
/* Signal waiting CREATE TABLE's to continue */
pthread_cond_signal(&COND_refresh);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index ebbf4cafb19..b4f2d8c65f2 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1639,6 +1639,8 @@ public:
char *record;
enum_duplicates dup;
time_t start_time;
+ ulong sql_mode;
+ bool auto_increment_field_not_null;
bool query_start_used, ignore, log_query;
bool stmt_depends_on_first_successful_insert_id_in_prev_stmt;
ulonglong first_successful_insert_id_in_prev_stmt;
@@ -2141,6 +2143,9 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
/* Copy session variables. */
row->auto_increment_increment= thd->variables.auto_increment_increment;
row->auto_increment_offset= thd->variables.auto_increment_offset;
+ row->sql_mode= thd->variables.sql_mode;
+ row->auto_increment_field_not_null= table->auto_increment_field_not_null;
+
/* Copy the next forced auto increment value, if any. */
if ((forced_auto_inc= thd->auto_inc_intervals_forced.get_next()))
{
@@ -2555,10 +2560,13 @@ bool Delayed_insert::handle_inserts(void)
thd.stmt_depends_on_first_successful_insert_id_in_prev_stmt=
row->stmt_depends_on_first_successful_insert_id_in_prev_stmt;
table->timestamp_field_type= row->timestamp_field_type;
+ table->auto_increment_field_not_null= row->auto_increment_field_not_null;
/* Copy the session variables. */
thd.variables.auto_increment_increment= row->auto_increment_increment;
thd.variables.auto_increment_offset= row->auto_increment_offset;
+ thd.variables.sql_mode= row->sql_mode;
+
/* Copy a forced insert_id, if any. */
if (row->forced_insert_id)
{
@@ -3419,6 +3427,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
int
select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
+ MYSQL_LOCK *extra_lock= NULL;
DBUG_ENTER("select_create::prepare");
TABLEOP_HOOKS *hook_ptr= NULL;
@@ -3488,9 +3497,21 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (!(table= create_table_from_items(thd, create_info, create_table,
alter_info, &values,
- &thd->extra_lock, hook_ptr)))
+ &extra_lock, hook_ptr)))
DBUG_RETURN(-1); // abort() deletes table
+ if (extra_lock)
+ {
+ DBUG_ASSERT(m_plock == NULL);
+
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ m_plock= &m_lock;
+ else
+ m_plock= &thd->extra_lock;
+
+ *m_plock= extra_lock;
+ }
+
if (table->s->fields < values.elements)
{
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1);
@@ -3629,10 +3650,11 @@ bool select_create::send_eof()
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- if (thd->extra_lock)
+ if (m_plock)
{
- mysql_unlock_tables(thd, thd->extra_lock);
- thd->extra_lock=0;
+ mysql_unlock_tables(thd, *m_plock);
+ *m_plock= NULL;
+ m_plock= NULL;
}
}
return tmp;
@@ -3667,10 +3689,11 @@ void select_create::abort()
if (thd->current_stmt_binlog_row_based)
ha_rollback_stmt(thd);
- if (thd->extra_lock)
+ if (m_plock)
{
- mysql_unlock_tables(thd, thd->extra_lock);
- thd->extra_lock=0;
+ mysql_unlock_tables(thd, *m_plock);
+ *m_plock= NULL;
+ m_plock= NULL;
}
if (table)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 08104769704..90ee7aaac4f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -78,7 +78,6 @@ enum enum_sql_command {
SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
SQLCOM_GRANT,
SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB,
- SQLCOM_RENAME_DB,
SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
@@ -117,6 +116,7 @@ enum enum_sql_command {
SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
SQLCOM_SHOW_CREATE_TRIGGER,
+ SQLCOM_ALTER_DB_UPGRADE,
/* This should be the last !!! */
@@ -1550,7 +1550,6 @@ typedef struct st_lex : public Query_tables_list
required a local context, the parser pops the top-most context.
*/
List<Name_resolution_context> context_stack;
- List<LEX_STRING> db_list;
SQL_LIST proc_list, auxiliary_table_list, save_list;
Create_field *last_field;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ae347bebb47..10c59d6a374 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -321,8 +321,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
values of init_command_var can't be changed
*/
rw_rdlock(var_mutex);
- thd->query= init_command_var->value;
- thd->query_length= init_command_var->value_length;
save_client_capabilities= thd->client_capabilities;
thd->client_capabilities|= CLIENT_MULTI_QUERIES;
/*
@@ -332,7 +330,9 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
save_vio= thd->net.vio;
thd->net.vio= 0;
thd->net.no_send_error= 0;
- dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
+ dispatch_command(COM_QUERY, thd,
+ init_command_var->value,
+ init_command_var->value_length);
rw_unlock(var_mutex);
thd->client_capabilities= save_client_capabilities;
thd->net.vio= save_vio;
@@ -691,30 +691,39 @@ bool do_command(THD *thd)
net->error= 0;
DBUG_RETURN(FALSE);
}
- else
+
+ packet= (char*) net->read_pos;
+ /*
+ 'packet_length' contains length of data, as it was stored in packet
+ header. In case of malformed header, my_net_read returns zero.
+ If packet_length is not zero, my_net_read ensures that the returned
+ number of bytes was actually read from network.
+ There is also an extra safety measure in my_net_read:
+ it sets packet[packet_length]= 0, but only for non-zero packets.
+ */
+ if (packet_length == 0) /* safety */
{
- packet=(char*) net->read_pos;
- command = (enum enum_server_command) (uchar) packet[0];
- if (command >= COM_END)
- command= COM_END; // Wrong command
- DBUG_PRINT("info",("Command on %s = %d (%s)",
- vio_description(net->vio), command,
- command_name[command].str));
+ /* Initialize with COM_SLEEP packet */
+ packet[0]= (uchar) COM_SLEEP;
+ packet_length= 1;
}
+ /* Do not rely on my_net_read, extra safety against programming errors. */
+ packet[packet_length]= '\0'; /* safety */
+
+ command= (enum enum_server_command) (uchar) packet[0];
+
+ if (command >= COM_END)
+ command= COM_END; // Wrong command
+
+ DBUG_PRINT("info",("Command on %s = %d (%s)",
+ vio_description(net->vio), command,
+ command_name[command].str));
/* Restore read timeout value */
my_net_set_read_timeout(net, thd->variables.net_read_timeout);
- /*
- packet_length contains length of data, as it was stored in packet
- header. In case of malformed header, packet_length can be zero.
- If packet_length is not zero, my_net_read ensures that this number
- of bytes was actually read from network. Additionally my_net_read
- sets packet[packet_length]= 0 (thus if packet_length == 0,
- command == packet[0] == COM_SLEEP).
- In dispatch_command packet[packet_length] points beyond the end of packet.
- */
- DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
+ DBUG_ASSERT(packet_length);
+ DBUG_RETURN(dispatch_command(command, thd, packet+1, (uint) (packet_length-1)));
}
#endif /* EMBEDDED_LIBRARY */
@@ -727,9 +736,7 @@ bool do_command(THD *thd)
thd connection handle
command type of command to perform
packet data for the command, packet is always null-terminated
- packet_length length of packet + 1 (to show that data is
- null-terminated) except for COM_SLEEP, where it
- can be zero.
+ packet_length length of packet. Can be zero, e.g. in case of COM_SLEEP.
RETURN VALUE
0 ok
1 request of thread shutdown, i. e. if command is
@@ -773,7 +780,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
LEX_STRING tmp;
status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]);
thd->convert_string(&tmp, system_charset_info,
- packet, packet_length-1, thd->charset());
+ packet, packet_length, thd->charset());
if (!mysql_change_db(thd, &tmp, FALSE))
{
general_log_print(thd, command, "%s",thd->db);
@@ -793,14 +800,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *tbl_name;
LEX_STRING db;
+ /* Safe because there is always a trailing \0 at the end of the packet */
uint db_len= *(uchar*) packet;
- if (db_len >= packet_length || db_len > NAME_LEN)
+ if (db_len + 1 > packet_length || db_len > NAME_LEN)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
+ /* Safe because there is always a trailing \0 at the end of the packet */
uint tbl_len= *(uchar*) (packet + db_len + 1);
- if (db_len+tbl_len+2 > packet_length || tbl_len > NAME_LEN)
+ if (db_len + tbl_len + 2 > packet_length || tbl_len > NAME_LEN)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
@@ -823,7 +832,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CHANGE_USER:
{
status_var_increment(thd->status_var.com_other);
- char *user= (char*) packet, *packet_end= packet+ packet_length;
+ char *user= (char*) packet, *packet_end= packet + packet_length;
+ /* Safe because there is always a trailing \0 at the end of the packet */
char *passwd= strend(user)+1;
thd->change_user();
@@ -840,6 +850,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char db_buff[NAME_LEN+1]; // buffer to store db in utf8
char *db= passwd;
char *save_db;
+ /*
+ If there is no password supplied, the packet must contain '\0',
+ in any type of handshake (4.1 or pre-4.1).
+ */
+ if (passwd >= packet_end)
+ {
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ break;
+ }
uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
(uchar)(*passwd++) : strlen(passwd));
uint dummy_errors, save_db_length, db_length;
@@ -848,22 +867,32 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
USER_CONN *save_user_connect;
db+= passwd_len + 1;
-#ifndef EMBEDDED_LIBRARY
- /* Small check for incoming packet */
- if ((uint) ((uchar*) db - net->read_pos) > packet_length)
+ /*
+ Database name is always NUL-terminated, so in case of empty database
+ the packet must contain at least the trailing '\0'.
+ */
+ if (db >= packet_end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
-#endif
+ db_length= strlen(db);
+
+ char *ptr= db + db_length + 1;
+ uint cs_number= 0;
+
+ if (ptr < packet_end)
+ {
+ if (ptr + 2 > packet_end)
+ {
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ break;
+ }
+
+ cs_number= uint2korr(ptr);
+ }
+
/* Convert database name to utf8 */
- /*
- Handle problem with old bug in client protocol where db had an extra
- \0
- */
- db_length= (packet_end - db);
- if (db_length > 0 && db[db_length-1] == 0)
- db_length--;
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
system_charset_info, db, db_length,
thd->charset(), &dummy_errors)]= 0;
@@ -907,6 +936,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
x_free((uchar*) save_db);
x_free((uchar*) save_security_ctx.user);
+
+ if (cs_number)
+ {
+ thd_init_client_charset(thd, cs_number);
+ thd->update_charset();
+ }
}
break;
}
@@ -999,7 +1034,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
#else
{
- char *fields, *packet_end= packet + packet_length - 1, *arg_end;
+ char *fields, *packet_end= packet + packet_length, *arg_end;
/* Locked closure of all tables */
TABLE_LIST table_list;
LEX_STRING conv_name;
@@ -1073,7 +1108,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
HA_CREATE_INFO create_info;
status_var_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB]);
- if (thd->make_lex_string(&db, packet, packet_length - 1, FALSE) ||
+ if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
thd->make_lex_string(&alias, db.str, db.length, FALSE) ||
check_db_name(&db))
{
@@ -1094,7 +1129,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
status_var_increment(thd->status_var.com_stat[SQLCOM_DROP_DB]);
LEX_STRING db;
- if (thd->make_lex_string(&db, packet, packet_length - 1, FALSE) ||
+ if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
check_db_name(&db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
@@ -1163,7 +1198,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break; /* purecov: inspected */
/*
If the client is < 4.1.3, it is going to send us no argument; then
- packet_length is 1, packet[0] is the end 0 of the packet. Note that
+ packet_length is 0, packet[0] is the end 0 of the packet. Note that
SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
packet[0].
*/
@@ -1521,9 +1556,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
bool alloc_query(THD *thd, const char *packet, uint packet_length)
{
- packet_length--; // Remove end null
/* Remove garbage at start and end of query */
- while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
+ while (packet_length > 0 && my_isspace(thd->charset(), packet[0]))
{
packet++;
packet_length--;
@@ -3173,12 +3207,9 @@ end_with_restore_list:
res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
break;
}
- case SQLCOM_RENAME_DB:
+ case SQLCOM_ALTER_DB_UPGRADE:
{
- LEX_STRING *olddb, *newdb;
- List_iterator <LEX_STRING> db_list(lex->db_list);
- olddb= db_list++;
- newdb= db_list++;
+ LEX_STRING *db= & lex->name;
if (end_active_trans(thd))
{
res= 1;
@@ -3186,24 +3217,22 @@ end_with_restore_list:
}
#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
- (!rpl_filter->db_ok(olddb->str) ||
- !rpl_filter->db_ok(newdb->str) ||
- !rpl_filter->db_ok_with_wild_table(olddb->str) ||
- !rpl_filter->db_ok_with_wild_table(newdb->str)))
+ (!rpl_filter->db_ok(db->str) ||
+ !rpl_filter->db_ok_with_wild_table(db->str)))
{
res= 1;
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
- if (check_db_name(newdb))
+ if (check_db_name(db))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), newdb->str);
+ my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
break;
}
- if (check_access(thd,ALTER_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
- check_access(thd,DROP_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
- check_access(thd,CREATE_ACL,newdb->str,0,1,0,is_schema_db(newdb->str)))
+ if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)) ||
+ check_access(thd, DROP_ACL, db->str, 0, 1, 0, is_schema_db(db->str)) ||
+ check_access(thd, CREATE_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
{
res= 1;
break;
@@ -3215,7 +3244,8 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res= mysql_rename_db(thd, olddb, newdb);
+
+ res= mysql_upgrade_db(thd, db);
if (!res)
send_ok(thd);
break;
@@ -7242,7 +7272,12 @@ bool parse_sql(THD *thd,
/* Parse the query. */
- bool err_status= MYSQLparse(thd) != 0 || thd->is_fatal_error;
+ bool mysql_parse_status= MYSQLparse(thd) != 0;
+
+ /* Check that if MYSQLparse() failed, thd->net.report_error is set. */
+
+ DBUG_ASSERT(!mysql_parse_status ||
+ mysql_parse_status && thd->net.report_error);
/* Reset Lex_input_stream. */
@@ -7255,7 +7290,7 @@ bool parse_sql(THD *thd,
/* That's it. */
- return err_status;
+ return mysql_parse_status || thd->is_fatal_error;
}
/**
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 9337a2aa329..05743b6dfe3 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1799,7 +1799,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_UNINSTALL_PLUGIN:
case SQLCOM_CREATE_DB:
case SQLCOM_DROP_DB:
- case SQLCOM_RENAME_DB:
+ case SQLCOM_ALTER_DB_UPGRADE:
case SQLCOM_CHECKSUM:
case SQLCOM_CREATE_USER:
case SQLCOM_RENAME_USER:
@@ -2107,7 +2107,7 @@ void mysql_sql_stmt_prepare(THD *thd)
DBUG_VOID_RETURN;
}
- if (stmt->prepare(query, query_len+1))
+ if (stmt->prepare(query, query_len))
{
/* Statement map deletes the statement on erase */
thd->stmt_map.erase(stmt);
@@ -2270,7 +2270,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
/* Query text for binary, general or slow log, if any of them is open */
String expanded_query;
#ifndef EMBEDDED_LIBRARY
- uchar *packet_end= packet + packet_length - 1;
+ uchar *packet_end= packet + packet_length;
#endif
Prepared_statement *stmt;
bool error;
@@ -2585,14 +2585,14 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
Prepared_statement *stmt;
Item_param *param;
#ifndef EMBEDDED_LIBRARY
- char *packet_end= packet + packet_length - 1;
+ char *packet_end= packet + packet_length;
#endif
DBUG_ENTER("mysql_stmt_get_longdata");
status_var_increment(thd->status_var.com_stmt_send_long_data);
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
- if (packet_length <= MYSQL_LONG_DATA_HEADER)
+ if (packet_length < MYSQL_LONG_DATA_HEADER)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
DBUG_VOID_RETURN;
@@ -2866,6 +2866,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
error= parse_sql(thd, &lip, NULL) ||
thd->net.report_error ||
init_param_array(this);
+
lex->set_trg_event_type_for_tables();
/* Remember the current database. */
@@ -3059,7 +3060,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (expanded_query->length() &&
alloc_query(thd, (char*) expanded_query->ptr(),
- expanded_query->length()+1))
+ expanded_query->length()))
{
my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
goto error;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b77bb719e1e..1e024c81a26 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -9343,6 +9343,36 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
}
/* Fall through */
case Item::FUNC_ITEM:
+ if (((Item_func *) item)->functype() == Item_func::FUNC_SP)
+ {
+ Item_func_sp *item_func_sp= (Item_func_sp *) item;
+ Field *sp_result_field= item_func_sp->get_sp_result_field();
+
+ if (make_copy_field)
+ {
+ DBUG_ASSERT(item_func_sp->result_field);
+ *from_field= item_func_sp->result_field;
+ }
+ else
+ {
+ *((*copy_func)++)= item;
+ }
+
+ Field *result_field=
+ create_tmp_field_from_field(thd,
+ sp_result_field,
+ item_func_sp->name,
+ table,
+ NULL,
+ convert_blob_length);
+
+ if (modify_item)
+ item->set_result_field(result_field);
+
+ return result_field;
+ }
+
+ /* Fall through */
case Item::COND_ITEM:
case Item::FIELD_AVG_ITEM:
case Item::FIELD_STD_ITEM:
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 68680addc58..39175297753 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1261,7 +1261,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
clear_privileges flush_options flush_option
equal optional_braces
opt_mi_check_type opt_to mi_check_types normal_join
- db_to_db table_to_table_list table_to_table opt_table_list opt_as
+ table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
union_clause union_list
@@ -3362,7 +3362,6 @@ change_ts_option:
;
tablespace_option_list:
- /* empty */ {}
tablespace_options
;
@@ -3384,7 +3383,6 @@ tablespace_option:
;
alter_tablespace_option_list:
- /* empty */ {}
alter_tablespace_options
;
@@ -3403,7 +3401,6 @@ alter_tablespace_option:
;
logfile_group_option_list:
- /* empty */ {}
logfile_group_options
;
@@ -3424,7 +3421,6 @@ logfile_group_option:
;
alter_logfile_group_option_list:
- /* empty */ {}
alter_logfile_group_options
;
@@ -3669,7 +3665,7 @@ size_number:
create2:
'(' create2a {}
| opt_create_table_options
- opt_partitioning {}
+ opt_partitioning
create3 {}
| LIKE table_ident
{
@@ -3693,19 +3689,22 @@ create2:
create2a:
field_list ')' opt_create_table_options
- opt_partitioning {}
+ opt_partitioning
create3 {}
- | opt_partitioning {}
+ | opt_partitioning
create_select ')'
- { Select->set_braces(1);} union_opt {}
+ { Select->set_braces(1);}
+ union_opt {}
;
create3:
/* empty */ {}
| opt_duplicate opt_as create_select
- { Select->set_braces(0);} union_clause {}
+ { Select->set_braces(0);}
+ union_clause {}
| opt_duplicate opt_as '(' create_select ')'
- { Select->set_braces(1);} union_opt {}
+ { Select->set_braces(1);}
+ union_opt {}
;
/*
@@ -3787,7 +3786,7 @@ partition_entry:
;
partition:
- BY part_type_def opt_no_parts {} opt_sub_part {} part_defs
+ BY part_type_def opt_no_parts opt_sub_part part_defs
;
part_type_def:
@@ -3988,10 +3987,11 @@ part_definition:
part_info->use_default_partitions= FALSE;
part_info->use_default_no_partitions= FALSE;
}
- part_name {}
- opt_part_values {}
- opt_part_options {}
- opt_sub_partition {}
+ part_name
+ opt_part_values
+ opt_part_options
+ opt_sub_partition
+ {}
;
part_name:
@@ -4657,8 +4657,9 @@ key_def:
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
LEX *lex=Lex;
- const char *key_name= $4 ? $4 : $1;
- Key *key= new Foreign_key(key_name, lex->col_list,
+ const char *key_name= $1 ? $1 : $4;
+ const char *fkey_name = $4 ? $4 : key_name;
+ Key *key= new Foreign_key(fkey_name, lex->col_list,
$8,
lex->ref_list,
lex->fk_delete_opt,
@@ -5401,6 +5402,17 @@ alter:
lex->copy_db_to(&lex->name.str, &lex->name.length))
MYSQL_YYABORT;
}
+ | ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
+ {
+ LEX *lex= Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "DATABASE");
+ MYSQL_YYABORT;
+ }
+ lex->sql_command= SQLCOM_ALTER_DB_UPGRADE;
+ lex->name= $3;
+ }
| ALTER PROCEDURE sp_name
{
LEX *lex= Lex;
@@ -6185,13 +6197,6 @@ rename:
}
table_to_table_list
{}
- | RENAME DATABASE
- {
- Lex->db_list.empty();
- Lex->sql_command= SQLCOM_RENAME_DB;
- }
- db_to_db
- {}
| RENAME USER clear_privileges rename_list
{
Lex->sql_command = SQLCOM_RENAME_USER;
@@ -6229,18 +6234,6 @@ table_to_table:
}
;
-db_to_db:
- ident TO_SYM ident
- {
- LEX *lex=Lex;
- if (lex->db_list.push_back((LEX_STRING*)
- sql_memdup(&$1, sizeof(LEX_STRING))) ||
- lex->db_list.push_back((LEX_STRING*)
- sql_memdup(&$3, sizeof(LEX_STRING))))
- MYSQL_YYABORT;
- }
- ;
-
keycache:
CACHE_SYM INDEX_SYM keycache_list IN_SYM key_cache_name
{
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 7f0289d93db..eff8df8109a 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -119,6 +119,8 @@ static void client_disconnect(void);
#define DIE_UNLESS(expr) \
((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0)))
+#define DIE_IF(expr) \
+ ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0))
#define DIE(expr) \
die(__FILE__, __LINE__, #expr)
@@ -177,8 +179,8 @@ if (stmt == 0) \
DIE_UNLESS(stmt == 0);\
}
-#define mytest(x) if (!x) {myerror(NULL);DIE_UNLESS(FALSE);}
-#define mytest_r(x) if (x) {myerror(NULL);DIE_UNLESS(FALSE);}
+#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);}
+#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);}
/* A workaround for Sun Forte 5.6 on Solaris x86 */
@@ -13534,7 +13536,7 @@ static void test_bug9478()
{
char buff[8];
- /* Fill in the fethc packet */
+ /* Fill in the fetch packet */
int4store(buff, stmt->stmt_id);
buff[4]= 1; /* prefetch rows */
rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
@@ -16214,6 +16216,204 @@ static void test_bug28934()
myquery(mysql_query(mysql, "drop table t1"));
}
+/*
+ Test mysql_change_user() C API and COM_CHANGE_USER
+*/
+
+static void test_change_user()
+{
+ char buff[256];
+ const char *user_pw= "mysqltest_pw";
+ const char *user_no_pw= "mysqltest_no_pw";
+ const char *pw= "password";
+ const char *db= "mysqltest_user_test_database";
+ int rc;
+
+ DBUG_ENTER("test_change_user");
+ myheader("test_change_user");
+
+ /* Prepare environment */
+ sprintf(buff, "drop database if exists %s", db);
+ rc= mysql_query(mysql, buff);
+ myquery(rc);
+
+ sprintf(buff, "create database %s", db);
+ rc= mysql_query(mysql, buff);
+ myquery(rc);
+
+ sprintf(buff,
+ "grant select on %s.* to %s@'%%' identified by '%s'",
+ db,
+ user_pw,
+ pw);
+ rc= mysql_query(mysql, buff);
+ myquery(rc);
+
+ sprintf(buff,
+ "grant select on %s.* to %s@'%%'",
+ db,
+ user_no_pw);
+ rc= mysql_query(mysql, buff);
+ myquery(rc);
+
+
+ /* Try some combinations */
+ rc= mysql_change_user(mysql, NULL, NULL, NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+
+ rc= mysql_change_user(mysql, "", NULL, NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, "", "", NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, "", "", "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, NULL, "", "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+
+ rc= mysql_change_user(mysql, NULL, NULL, "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, "", NULL, "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_pw, NULL, "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_pw, "", "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_pw, "", NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_pw, NULL, NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_pw, "", db);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_pw, NULL, db);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_pw, pw, db);
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, user_pw, pw, NULL);
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, user_pw, pw, "");
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, user_no_pw, pw, db);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_no_pw, pw, "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_no_pw, pw, NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, user_no_pw, "", NULL);
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, user_no_pw, "", "");
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, user_no_pw, "", db);
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, user_no_pw, NULL, db);
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, "", pw, db);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, "", pw, "");
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, "", pw, NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, NULL, pw, NULL);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, NULL, NULL, db);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, NULL, "", db);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ rc= mysql_change_user(mysql, "", "", db);
+ DIE_UNLESS(rc);
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+
+ /* Cleanup the environment */
+
+ mysql_change_user(mysql, opt_user, opt_password, current_db);
+
+ sprintf(buff, "drop database %s", db);
+ rc= mysql_query(mysql, buff);
+ myquery(rc);
+
+ sprintf(buff, "drop user %s@'%%'", user_pw);
+ rc= mysql_query(mysql, buff);
+ myquery(rc);
+
+ sprintf(buff, "drop user %s@'%%'", user_no_pw);
+ rc= mysql_query(mysql, buff);
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
/*
Bug#27592 (stack overrun when storing datetime value using prepared statements)
@@ -16452,6 +16652,175 @@ static void test_bug29306()
DBUG_VOID_RETURN;
}
/*
+ Bug#30472: libmysql doesn't reset charset, insert_id after succ.
+ mysql_change_user() call row insertions.
+*/
+
+static void bug30472_retrieve_charset_info(MYSQL *con,
+ char *character_set_name,
+ char *character_set_client,
+ char *character_set_results,
+ char *collation_connection)
+{
+ MYSQL_RES *rs;
+ MYSQL_ROW row;
+
+ /* Get the cached client character set name. */
+
+ strcpy(character_set_name, mysql_character_set_name(con));
+
+ /* Retrieve server character set information. */
+
+ DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'"));
+ DIE_UNLESS(rs= mysql_store_result(con));
+ DIE_UNLESS(row= mysql_fetch_row(rs));
+ strcpy(character_set_client, row[1]);
+ mysql_free_result(rs);
+
+ DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'"));
+ DIE_UNLESS(rs= mysql_store_result(con));
+ DIE_UNLESS(row= mysql_fetch_row(rs));
+ strcpy(character_set_results, row[1]);
+ mysql_free_result(rs);
+
+ DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'"));
+ DIE_UNLESS(rs= mysql_store_result(con));
+ DIE_UNLESS(row= mysql_fetch_row(rs));
+ strcpy(collation_connection, row[1]);
+ mysql_free_result(rs);
+}
+
+static void test_bug30472()
+{
+ MYSQL con;
+
+ char character_set_name_1[MY_CS_NAME_SIZE];
+ char character_set_client_1[MY_CS_NAME_SIZE];
+ char character_set_results_1[MY_CS_NAME_SIZE];
+ char collation_connnection_1[MY_CS_NAME_SIZE];
+
+ char character_set_name_2[MY_CS_NAME_SIZE];
+ char character_set_client_2[MY_CS_NAME_SIZE];
+ char character_set_results_2[MY_CS_NAME_SIZE];
+ char collation_connnection_2[MY_CS_NAME_SIZE];
+
+ char character_set_name_3[MY_CS_NAME_SIZE];
+ char character_set_client_3[MY_CS_NAME_SIZE];
+ char character_set_results_3[MY_CS_NAME_SIZE];
+ char collation_connnection_3[MY_CS_NAME_SIZE];
+
+ char character_set_name_4[MY_CS_NAME_SIZE];
+ char character_set_client_4[MY_CS_NAME_SIZE];
+ char character_set_results_4[MY_CS_NAME_SIZE];
+ char collation_connnection_4[MY_CS_NAME_SIZE];
+
+ /* Create a new connection. */
+
+ DIE_UNLESS(mysql_init(&con));
+
+ DIE_UNLESS(mysql_real_connect(&con,
+ opt_host,
+ opt_user,
+ opt_password,
+ opt_db ? opt_db : "test",
+ opt_port,
+ opt_unix_socket,
+ CLIENT_FOUND_ROWS));
+
+ /* Retrieve character set information. */
+
+ bug30472_retrieve_charset_info(&con,
+ character_set_name_1,
+ character_set_client_1,
+ character_set_results_1,
+ collation_connnection_1);
+
+ /* Switch client character set. */
+
+ DIE_IF(mysql_set_character_set(&con, "utf8"));
+
+ /* Retrieve character set information. */
+
+ bug30472_retrieve_charset_info(&con,
+ character_set_name_2,
+ character_set_client_2,
+ character_set_results_2,
+ collation_connnection_2);
+
+ /*
+ Check that
+ 1) character set has been switched and
+ 2) new character set is different from the original one.
+ */
+
+ DIE_UNLESS(strcmp(character_set_name_2, "utf8") == 0);
+ DIE_UNLESS(strcmp(character_set_client_2, "utf8") == 0);
+ DIE_UNLESS(strcmp(character_set_results_2, "utf8") == 0);
+ DIE_UNLESS(strcmp(collation_connnection_2, "utf8_general_ci") == 0);
+
+ DIE_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0);
+ DIE_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0);
+ DIE_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0);
+ DIE_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0);
+
+ /* Call mysql_change_user() with the same username, password, database. */
+
+ DIE_IF(mysql_change_user(&con,
+ opt_user,
+ opt_password,
+ opt_db ? opt_db : "test"));
+
+ /* Retrieve character set information. */
+
+ bug30472_retrieve_charset_info(&con,
+ character_set_name_3,
+ character_set_client_3,
+ character_set_results_3,
+ collation_connnection_3);
+
+ /* Check that character set information has been reset. */
+
+ DIE_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0);
+ DIE_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0);
+ DIE_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0);
+ DIE_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0);
+
+ /* Change connection-default character set in the client. */
+
+ con.options.charset_name= my_strdup("utf8", MYF(MY_FAE));
+
+ /*
+ Call mysql_change_user() in order to check that new connection will
+ have UTF8 character set on the client and on the server.
+ */
+
+ DIE_IF(mysql_change_user(&con,
+ opt_user,
+ opt_password,
+ opt_db ? opt_db : "test"));
+
+ /* Retrieve character set information. */
+
+ bug30472_retrieve_charset_info(&con,
+ character_set_name_4,
+ character_set_client_4,
+ character_set_results_4,
+ collation_connnection_4);
+
+ /* Check that we have UTF8 on the server and on the client. */
+
+ DIE_UNLESS(strcmp(character_set_name_4, "utf8") == 0);
+ DIE_UNLESS(strcmp(character_set_client_4, "utf8") == 0);
+ DIE_UNLESS(strcmp(character_set_results_4, "utf8") == 0);
+ DIE_UNLESS(strcmp(collation_connnection_4, "utf8_general_ci") == 0);
+
+ /* That's it. Cleanup. */
+
+ mysql_close(&con);
+}
+
+
+/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -16744,6 +17113,8 @@ static struct my_tests_st my_tests[]= {
{ "test_bug29687", test_bug29687 },
{ "test_bug29692", test_bug29692 },
{ "test_bug29306", test_bug29306 },
+ { "test_change_user", test_change_user },
+ { "test_bug30472", test_bug30472 },
{ 0, 0 }
};