From b1b2108275d8737b8381ccd0bd64dbaaef04530c Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Thu, 23 Aug 2007 10:22:20 +0200 Subject: [PATCH 01/55] Bug#27358 INSERT DELAYED does not honour SQL_MODE of the client SQL_MODE was ignored when a client issued INSERT DELAYED. Some system settings weren't copied as intended when a record was saved for a delayed insert. --- mysql-test/r/bdb_notembedded.result | 35 -------------------------- mysql-test/r/delayed.result | 29 ++++++++++++++++++++++ mysql-test/t/bdb_notembedded.test | 38 ----------------------------- mysql-test/t/delayed.test | 31 +++++++++++++++++++++++ sql/sql_insert.cc | 8 ++++++ 5 files changed, 68 insertions(+), 73 deletions(-) delete mode 100644 mysql-test/r/bdb_notembedded.result delete mode 100644 mysql-test/t/bdb_notembedded.test diff --git a/mysql-test/r/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result deleted file mode 100644 index 14cb5fad915..00000000000 --- a/mysql-test/r/bdb_notembedded.result +++ /dev/null @@ -1,35 +0,0 @@ -set autocommit=1; -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; insert into bug16206 values(2) -drop table bug16206; -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb -f n Query 1 n use `test`; insert into bug16206 values(0) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; BEGIN -f n Query 1 n use `test`; insert into bug16206 values(2) -f n Query 1 n use `test`; COMMIT -f n Query 1 n use `test`; insert into bug16206 values(3) -drop table bug16206; -set autocommit=0; -End of 5.0 tests diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index b37679847be..5b56a6e27bc 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/t/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test deleted file mode 100644 index 24e64ebbfb2..00000000000 --- a/mysql-test/t/bdb_notembedded.test +++ /dev/null @@ -1,38 +0,0 @@ --- source include/not_embedded.inc --- source include/have_bdb.inc - -# -# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode -# -set autocommit=1; - -let $VERSION=`select version()`; - -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -set autocommit=0; - - ---echo End of 5.0 tests diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test index 13615c8c269..505556998be 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/sql/sql_insert.cc b/sql/sql_insert.cc index 5edce08e481..07f2ed8694e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1587,6 +1587,8 @@ public: ulonglong next_insert_id; ulong auto_increment_increment; ulong auto_increment_offset; + ulong sql_mode; + bool auto_increment_field_not_null; timestamp_auto_set_type timestamp_field_type; uint query_length; @@ -2048,6 +2050,9 @@ int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool ignore, /* The session variable settings can always be copied. */ 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; + /* Next insert id must be set for the first value in a multi-row insert only. So clear it after the first use. Assume a multi-row insert. @@ -2436,10 +2441,13 @@ bool Delayed_insert::handle_inserts(void) thd.last_insert_id_used=row->last_insert_id_used; thd.insert_id_used=row->insert_id_used; table->timestamp_field_type= row->timestamp_field_type; + table->auto_increment_field_not_null= row->auto_increment_field_not_null; /* The session variable settings can always be copied. */ 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; + /* Next insert id must be used only if non-zero. */ if (row->next_insert_id) thd.next_insert_id= row->next_insert_id; From 18300001c1dbbfddf9a0adcbaeea68956102bdd0 Mon Sep 17 00:00:00 2001 From: "malff@lambda.weblab" <> Date: Mon, 10 Sep 2007 16:10:37 -0600 Subject: [PATCH 02/55] WL#4030 (Deprecate RENAME DATABASE: replace with ALTER DATABASE UPGRADE) Bug 17565 (RENAME DATABASE destroys events) Bug#28360 (RENAME DATABASE destroys routines) Removed the RENAME DATABASE db1 TO db2 statement. Implemented the ALTER DATABASE db UPGRADE DATA DIRECTORY NAME statement, which has the same function. --- client/mysqlcheck.c | 25 +++++-- mysql-test/r/create.result | 8 --- mysql-test/r/query_cache.result | 49 ------------- mysql-test/r/renamedb.result | 43 +++--------- mysql-test/r/sp-code.result | 4 +- mysql-test/r/sp-error.result | 13 ++++ mysql-test/r/upgrade.result | 25 +++++++ mysql-test/t/create.test | 19 ++--- mysql-test/t/query_cache.test | 80 +++++++++++----------- mysql-test/t/renamedb.test | 71 +++++++++++++------ mysql-test/t/sp-error.test | 28 ++++++++ mysql-test/t/upgrade.test | 31 +++++++++ sql/mysql_priv.h | 2 +- sql/sql_db.cc | 118 +++++++++++--------------------- sql/sql_lex.h | 3 +- sql/sql_parse.cc | 26 +++---- sql/sql_prepare.cc | 2 +- sql/sql_yacc.yy | 32 ++++----- 18 files changed, 296 insertions(+), 283 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/mysql-test/r/create.result b/mysql-test/r/create.result index 84a620336dc..82bcc68f319 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; 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/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..d4feeebe4b1 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 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 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/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/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/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. +/** + Upgrade a 5.0 database. + This function is invoked whenever an ALTER DATABASE UPGRADE query is executed: + ALTER DATABASE 'olddb' UPGRADE DATA DIRECTORY NAME. - SYNOPSIS - mysql_rename_db() - thd Thread handler - olddb Old database name - newdb New database 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. - 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 + @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#` converted to encoded `` */ + 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,46 +1906,12 @@ 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) @@ -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_lex.h b/sql/sql_lex.h index da0134a7f72..ae689be263e 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 context_stack; - List 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 bbd6cb16d11..6002d7545ba 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3175,12 +3175,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 db_list(lex->db_list); - olddb= db_list++; - newdb= db_list++; + LEX_STRING *db= & lex->name; if (end_active_trans(thd)) { res= 1; @@ -3188,24 +3185,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; @@ -3217,7 +3212,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; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9337a2aa329..c576a9dba1d 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: diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index efd8c20e6d7..864d838c183 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1260,7 +1260,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 @@ -5400,6 +5400,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; @@ -6184,13 +6195,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; @@ -6228,18 +6232,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 { From 8b2435c9b50e36ed05769f2063d28804cfbf60ab Mon Sep 17 00:00:00 2001 From: "malff@lambda.weblab" <> Date: Wed, 12 Sep 2007 12:42:02 -0600 Subject: [PATCH 03/55] Cleanup of sql_yacc.yy --- sql/sql_yacc.yy | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index efd8c20e6d7..ce6e06bbc35 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3361,7 +3361,6 @@ change_ts_option: ; tablespace_option_list: - /* empty */ {} tablespace_options ; @@ -3383,7 +3382,6 @@ tablespace_option: ; alter_tablespace_option_list: - /* empty */ {} alter_tablespace_options ; @@ -3402,7 +3400,6 @@ alter_tablespace_option: ; logfile_group_option_list: - /* empty */ {} logfile_group_options ; @@ -3423,7 +3420,6 @@ logfile_group_option: ; alter_logfile_group_option_list: - /* empty */ {} alter_logfile_group_options ; @@ -3668,7 +3664,7 @@ size_number: create2: '(' create2a {} | opt_create_table_options - opt_partitioning {} + opt_partitioning create3 {} | LIKE table_ident { @@ -3692,19 +3688,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 {} ; /* @@ -3786,7 +3785,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: @@ -3987,10 +3986,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: From ef3bcaf3dd46d6a4bc7a38d7a50924eb970148c1 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Thu, 13 Sep 2007 17:30:44 +0400 Subject: [PATCH 04/55] Bug#16918: Aborted_clients > Connections. The problem was that aborted_threads variable was updated twice when a client connection had been aborted. The fix is to refactor a code to have aborted_threads updated only in one place. --- sql/mysql_priv.h | 1 - sql/sql_parse.cc | 27 +++++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 44eb5590a28..24d02ee6948 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -726,7 +726,6 @@ pthread_handler_t handle_bootstrap(void *arg); void end_thread(THD *thd,bool put_in_cache); void flush_thread_cache(); bool mysql_execute_command(THD *thd); -bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); void log_slow_statement(THD *thd); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 58f5ffc5235..99a61d95619 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -93,6 +93,8 @@ const char *xa_state_names[]={ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" }; +static bool do_command(THD *thd); + #ifdef __WIN__ static void test_signal(int sig_ptr) { @@ -1199,23 +1201,28 @@ pthread_handler_t handle_one_connection(void *arg) } if (thd->user_connect) decrease_user_connections(thd->user_connect); + + if (thd->killed || + net->vio && net->error && net->report_error) + { + statistic_increment(aborted_threads, &LOCK_status); + } + if (net->error && net->vio != 0 && net->report_error) { if (!thd->killed && thd->variables.log_warnings > 1) - sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), + { + sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), thd->thread_id,(thd->db ? thd->db : "unconnected"), sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, (net->last_errno ? ER(net->last_errno) : ER(ER_UNKNOWN_ERROR))); + } + net_send_error(thd, net->last_errno, NullS); - statistic_increment(aborted_threads,&LOCK_status); } - else if (thd->killed) - { - statistic_increment(aborted_threads,&LOCK_status); - } - + end_thread: close_connection(thd, 0, 1); end_thread(thd,1); @@ -1550,12 +1557,12 @@ bool do_command(THD *thd) DBUG_PRINT("info",("Got error %d reading command from socket %s", net->error, vio_description(net->vio))); + /* Check if we can continue without closing the connection */ + if (net->error != 3) - { - statistic_increment(aborted_threads,&LOCK_status); DBUG_RETURN(TRUE); // We have to close it. - } + net_send_error(thd, net->last_errno, NullS); net->error= 0; DBUG_RETURN(FALSE); From 2a70d6fa97d40c708b033c8eaee57f1f3ac5ad0d Mon Sep 17 00:00:00 2001 From: "davi@moksha.local" <> Date: Thu, 13 Sep 2007 19:22:08 -0300 Subject: [PATCH 05/55] Bug#30747 Create table with identical constraint names behaves incorrectly MySQL provides what appears to be a non standard extension to the FOREIGN KEY syntax which let users name (label/tag) a foreign key to more easily identify a specific foreign key if any problems show up later during the query parsing or execution. But the foreign key name was not being properly set to the right key, possible leaving the foreign key with no name. --- mysql-test/include/mix1.inc | 34 ++++++++++++++++++++++++++++++ mysql-test/r/innodb_mysql.result | 36 ++++++++++++++++++++++++++++++++ sql/sql_yacc.yy | 5 +++-- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 5e6a535fce5..0e1bdd1e0b8 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1096,4 +1096,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/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 32c692501ad..cc1a0cc61ab 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1273,4 +1273,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/sql/sql_yacc.yy b/sql/sql_yacc.yy index b5b451cfe3e..1f6ea170a10 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4656,8 +4656,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, From e452c06438f82dbf8e0f6366dddf8e7dd26fa774 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Fri, 28 Sep 2007 15:42:37 +0400 Subject: [PATCH 06/55] Prerequisite patch for BUG#30472: libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call. Supply a correct packet length to dispatch command. --- sql/sp_head.cc | 2 +- sql/sql_parse.cc | 112 ++++++++++++--------- sql/sql_prepare.cc | 11 ++- tests/mysql_client_test.c | 201 +++++++++++++++++++++++++++++++++++++- 4 files changed, 272 insertions(+), 54 deletions(-) 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_parse.cc b/sql/sql_parse.cc index 6002d7545ba..3dbcfe6d2bc 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,17 @@ 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= packet_end - db - 1; /* do not count the trailing '\0' */ /* 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; @@ -999,7 +1013,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; @@ -1074,7 +1088,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)) { @@ -1095,7 +1109,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"); @@ -1164,7 +1178,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]. */ @@ -1522,9 +1536,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--; @@ -7238,7 +7251,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. */ @@ -7251,7 +7269,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 c576a9dba1d..05743b6dfe3 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -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/tests/mysql_client_test.c b/tests/mysql_client_test.c index 7f0289d93db..93a85f44919 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13534,7 +13534,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 +16214,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) @@ -16744,6 +16942,7 @@ 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 }, { 0, 0 } }; From 8051b7568db48a845e1af8fa924c809ef4ca9641 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Fri, 28 Sep 2007 23:30:54 +0400 Subject: [PATCH 07/55] Patch for BUG#30472: libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call. See also WL 4066. This bug reveals two problems: - the problem on the client side which was described originally; - the problem in protocol / the server side: connection context on client and server should be like after mysql_real_connect() and be consistent. The server however just resets character set variables to the global defaults. The fix seems to be as follows: - extend the protocol so that the client be able to send character set information in COM_CHANGE_USER command; - change the server so that it understands client character set in the command; - change the client: - reset character set to the default value (which has been read from the configuration); - send character set in COM_CHANGE_USER command. --- client/client_priv.h | 4 + libmysql/libmysql.c | 26 +++- mysql-test/t/mysql_client_test.test | 4 +- sql/sql_parse.cc | 14 ++- tests/mysql_client_test.c | 176 +++++++++++++++++++++++++++- 5 files changed, 218 insertions(+), 6 deletions(-) diff --git a/client/client_priv.h b/client/client_priv.h index a2f61b9e9ca..4bc275e6630 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -82,3 +82,7 @@ enum options_client OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, OPT_WRITE_BINLOG, OPT_MAX_CLIENT_OPTION }; + +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 c8e2d48873f..e2e481fdd21 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) + { + *end= (uchar) mysql->charset->number; + ++end; + } + /* 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); } 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/sql/sql_parse.cc b/sql/sql_parse.cc index 3dbcfe6d2bc..923fd1b2bfe 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -876,7 +876,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } - db_length= packet_end - db - 1; /* do not count the trailing '\0' */ + db_length= strlen(db); + + uint cs_number= 0; + + if (db + db_length < packet_end) + cs_number= (uchar) *(db + db_length + 1); + /* Convert database name to utf8 */ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info, db, db_length, @@ -921,6 +927,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; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 93a85f44919..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 */ @@ -16649,6 +16651,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 */ @@ -16943,6 +17114,7 @@ static struct my_tests_st my_tests[]= { { "test_bug29692", test_bug29692 }, { "test_bug29306", test_bug29306 }, { "test_change_user", test_change_user }, + { "test_bug30472", test_bug30472 }, { 0, 0 } }; From 040e520d55598170fa80d53936812f14a5d9f4fd Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Fri, 28 Sep 2007 17:10:14 -0400 Subject: [PATCH 08/55] Bug #29772 Error compiling with option --without-geometry Added #ifdef HAVE_SPATIAL around geometry related code. --- sql/item.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/item.cc b/sql/item.cc index 66379d5dcf9..b44927f8da6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4357,12 +4357,14 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) return new Field_blob(max_length, maybe_null, name, table, collation.collation); break; // Blob handled outside of case +#ifdef HAVE_SPATIAL case MYSQL_TYPE_GEOMETRY: return new Field_geom(max_length, maybe_null, name, table, (Field::geometry_type) ((type() == Item::TYPE_HOLDER) ? ((Item_type_holder *)this)->get_geometry_type() : ((Item_geometry_func *)this)->get_geometry_type())); +#endif /* HAVE_SPATIAL */ } } @@ -6482,10 +6484,12 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) if (Field::result_merge_type(fld_type) == INT_RESULT) decimals= 0; prev_decimal_int_part= item->decimal_int_part(); +#ifdef HAVE_SPATIAL if (item->field_type() == MYSQL_TYPE_GEOMETRY) geometry_type= (item->type() == Item::FIELD_ITEM) ? ((Item_field *)item)->get_geometry_type() : (Field::geometry_type)((Item_geometry_func *)item)->get_geometry_type(); +#endif /* HAVE_SPATIAL */ } From 93fd4e200ce1541d20afa711693a626549577274 Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Fri, 28 Sep 2007 17:13:35 -0400 Subject: [PATCH 09/55] Bug #29589 sys_innodb_max_purge_lag is defined twice in sys_variables Removed duplicate innodb variable from sys_variables array. --- sql/set_var.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index e1246617d84..305370e6569 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -784,7 +784,6 @@ sys_var *sys_variables[]= &sys_innodb_max_purge_lag, &sys_innodb_table_locks, &sys_innodb_support_xa, - &sys_innodb_max_purge_lag, &sys_innodb_autoextend_increment, &sys_innodb_sync_spin_loops, &sys_innodb_concurrency_tickets, From ae079ec427c2a5d50940b7c20f45e0c92f01e450 Mon Sep 17 00:00:00 2001 From: "davi@moksha.local" <> Date: Fri, 28 Sep 2007 18:25:47 -0300 Subject: [PATCH 10/55] Bug#21136 CREATE TABLE SELECT within CREATE TABLE SELECT causes server crash When CREATE TEMPORARY TABLE .. SELECT is invoked from a stored function which in turn is called from CREATE TABLE SELECT causes a memory leak because the inner create temporary table overrides the outter extra_lock reference when locking the table. The solution is to simply not overrride the extra_lock by only using the extra_lock for a non-temporary table lock. --- mysql-test/r/create.result | 14 ++++++++++++++ mysql-test/t/create.test | 25 +++++++++++++++++++++++++ sql/sql_insert.cc | 27 ++++++++++++++++++++------- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 82bcc68f319..800a3f9cece 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1691,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/t/create.test b/mysql-test/t/create.test index d4feeebe4b1..023e55ea418 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1303,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/sql/sql_insert.cc b/sql/sql_insert.cc index 7679401b459..fedda29c249 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3427,6 +3427,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, int select_create::prepare(List &values, SELECT_LEX_UNIT *u) { + MYSQL_LOCK *extra_lock= NULL; DBUG_ENTER("select_create::prepare"); TABLEOP_HOOKS *hook_ptr= NULL; @@ -3496,9 +3497,21 @@ select_create::prepare(List &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); @@ -3637,10 +3650,10 @@ 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= 0; } } return tmp; @@ -3675,10 +3688,10 @@ 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= 0; } if (table) From 9c6d75e85d8249c3d853aab3a1b6a4e2cbbd1f98 Mon Sep 17 00:00:00 2001 From: "davi@moksha.local" <> Date: Fri, 28 Sep 2007 19:11:26 -0300 Subject: [PATCH 11/55] Post-merge fix for Bug 21136, initial merge missed the modifications for the sql_class.h file. --- sql/sql_class.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 &list, SELECT_LEX_UNIT *u); From f3b6d56fb2eb8ff2b0c98336339ceeffdfc6c26e Mon Sep 17 00:00:00 2001 From: "davi@moksha.local" <> Date: Sat, 29 Sep 2007 16:04:31 -0300 Subject: [PATCH 12/55] The fix for BUG 21136 (ChangeSet@1.2611.1.1) introduced a regression that caused a few tests to fail because the thd->extra_lock wasn't being set to NULL after the table was unlocked. This poses a serious problem because later attempts to access thd->extra_lock (now a dangling pointer) will probably result in a crash (undefined behavior) -- and that's what actually happens in some test cases. The solution is to set the select_create::m_plock pointee to NULL, which means that thd->extra_lock is set to NULL when the lock data is not for a temporary table. --- sql/sql_insert.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index fedda29c249..b4f2d8c65f2 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3653,7 +3653,8 @@ bool select_create::send_eof() if (m_plock) { mysql_unlock_tables(thd, *m_plock); - m_plock= 0; + *m_plock= NULL; + m_plock= NULL; } } return tmp; @@ -3691,7 +3692,8 @@ void select_create::abort() if (m_plock) { mysql_unlock_tables(thd, *m_plock); - m_plock= 0; + *m_plock= NULL; + m_plock= NULL; } if (table) From 95e01d44536bf6bbee869b063c8c0cabbfff54b9 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Sat, 29 Sep 2007 23:31:08 +0400 Subject: [PATCH 13/55] Fix compile warnings. --- client/client_priv.h | 4 ---- client/mysqltest.c | 10 ++++++---- libmysql/client_settings.h | 4 ++++ libmysql/libmysql.c | 6 +++--- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/client/client_priv.h b/client/client_priv.h index 4bc275e6630..a2f61b9e9ca 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -82,7 +82,3 @@ enum options_client OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, OPT_WRITE_BINLOG, OPT_MAX_CLIENT_OPTION }; - -C_MODE_START -extern int mysql_init_character_set(MYSQL *mysql); -C_MODE_END diff --git a/client/mysqltest.c b/client/mysqltest.c index 979c8de3656..0e45b2ac1d8 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) { @@ -1984,9 +1984,11 @@ void var_set_query_get_value(struct st_command *command, VAR *var) static DYNAMIC_STRING ds_col; static DYNAMIC_STRING ds_row; 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", + { + "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" + } }; 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 e2e481fdd21..adac6c7cd48 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2526,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 */ @@ -4702,14 +4702,14 @@ int cli_read_binary_rows(MYSQL_STMT *stmt) MYSQL_ROWS *cur, **prev_ptr= &result->data; NET *net; + DBUG_ENTER("cli_read_binary_rows"); + if (!mysql) { set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); return 1; } - DBUG_ENTER("cli_read_binary_rows"); - net = &mysql->net; mysql= mysql->last_used_con; From 0635a75f4a1deabd18d30e3b4873da62b4082c9b Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Mon, 1 Oct 2007 00:16:50 +0400 Subject: [PATCH 14/55] Fix compilation warnings. --- client/mysqltest.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 0e45b2ac1d8..702eab0078f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1984,11 +1984,9 @@ void var_set_query_get_value(struct st_command *command, VAR *var) static DYNAMIC_STRING ds_col; static DYNAMIC_STRING ds_row; 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" - } + "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" }; DBUG_ENTER("var_set_query_get_value"); From 7f554deb956f645982fe3b1ba0d505a002f11cb2 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Mon, 1 Oct 2007 15:41:18 +0400 Subject: [PATCH 15/55] BUG#30472: libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call. Use 2 bytes for character set number. --- libmysql/libmysql.c | 4 ++-- sql/sql_parse.cc | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index adac6c7cd48..f2c16eb85de 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -736,8 +736,8 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) { - *end= (uchar) mysql->charset->number; - ++end; + int2store(end, (ushort) mysql->charset->number); + end+= 2; } /* Write authentication package */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 923fd1b2bfe..ab9cace7a17 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -878,10 +878,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } db_length= strlen(db); + char *ptr= db + db_length + 1; uint cs_number= 0; - if (db + db_length < packet_end) - cs_number= (uchar) *(db + db_length + 1); + 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 */ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, From 5dad55cd24e8a82ae8e4b2e63186af57204ef571 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Mon, 1 Oct 2007 15:11:15 +0200 Subject: [PATCH 16/55] BUG#30992 (Wrong implementation of pthread_mutex_trylock()): Adding support for correct handling of pthread_mutex_trylock() on Win32 systems as well as when using the safe mutexes. --- include/my_pthread.h | 9 ++++---- mysys/my_winthread.c | 25 ++++++++++++++++++++++ mysys/thr_mutex.c | 49 +++++++++++++++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/include/my_pthread.h b/include/my_pthread.h index d64b5348666..e28bb9df1f3 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -135,6 +135,7 @@ struct timespec { void win_pthread_init(void); int win_pthread_setspecific(void *A,void *B,uint length); +int win_pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *); int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); @@ -195,7 +196,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *); #else #define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) #define pthread_mutex_lock(A) (EnterCriticalSection(A),0) -#define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT) +#define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A)) #define pthread_mutex_unlock(A) LeaveCriticalSection(A) #define pthread_mutex_destroy(A) DeleteCriticalSection(A) #define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B)) @@ -593,7 +594,7 @@ typedef struct st_safe_mutex_info_t int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, const char *file, uint line); -int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line); +int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line); int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, @@ -616,12 +617,12 @@ void safe_mutex_end(FILE *file); #undef pthread_cond_timedwait #undef pthread_mutex_trylock #define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__) -#define pthread_mutex_lock(A) safe_mutex_lock((A),__FILE__,__LINE__) +#define pthread_mutex_lock(A) safe_mutex_lock((A), FALSE, __FILE__, __LINE__) #define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__) #define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) #define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) #define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) -#define pthread_mutex_trylock(A) pthread_mutex_lock(A) +#define pthread_mutex_trylock(A) safe_mutex_lock((A), TRUE, __FILE__, __LINE__) #define pthread_mutex_t safe_mutex_t #define safe_mutex_assert_owner(mp) \ DBUG_ASSERT((mp)->count > 0 && \ diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c index 27ccaef4f23..e9fface0521 100644 --- a/mysys/my_winthread.c +++ b/mysys/my_winthread.c @@ -40,6 +40,31 @@ void win_pthread_init(void) pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST); } +/** + Adapter to @c pthread_mutex_trylock() + + @retval 0 Mutex was acquired + @retval EBUSY Mutex was already locked by a thread + @retval EINVAL Mutex could not be acquired due to other error + */ +int +win_pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + switch (WaitForSingleObject(mutex, 0)) { + case WAIT_TIMEOUT: + return EBUSY; + + default: + case WAIT_FAILURE: + return EINVAL; + + case WAIT_OBJECT_0: + case WAIT_ABANDONED: /* The mutex was acquired because it was + * abandoned */ + return 0; + } +} + /* ** We have tried to use '_beginthreadex' instead of '_beginthread' here ** but in this case the program leaks about 512 characters for each diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index 425e5fce459..53ee907e0a3 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -91,7 +91,7 @@ int safe_mutex_init(safe_mutex_t *mp, } -int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line) +int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line) { int error; if (!mp->file) @@ -104,15 +104,50 @@ int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line) } pthread_mutex_lock(&mp->global); - if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread)) + if (mp->count > 0) { - fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d in thread %s\n", - file,line,mp->file, mp->line, my_thread_name()); - fflush(stderr); - abort(); + if (try_lock) + { + pthread_mutex_unlock(&mp->global); + return EBUSY; + } + else if (pthread_equal(pthread_self(),mp->thread)) + { + fprintf(stderr, + "safe_mutex: Trying to lock mutex at %s, line %d, when the" + " mutex was already locked at %s, line %d in thread %s\n", + file,line,mp->file, mp->line, my_thread_name()); + fflush(stderr); + abort(); + } } pthread_mutex_unlock(&mp->global); - error=pthread_mutex_lock(&mp->mutex); + + /* + If we are imitating trylock(), we need to take special + precautions. + + - We cannot use pthread_mutex_lock() only since another thread can + overtake this thread and take the lock before this thread + causing pthread_mutex_trylock() to hang. In this case, we should + just return EBUSY. Hence, we use pthread_mutex_trylock() to be + able to return immediately. + + - We cannot just use trylock() and continue execution below, since + this would generate an error and abort execution if the thread + was overtaken and trylock() returned EBUSY . In this case, we + instead just return EBUSY, since this is the expected behaviour + of trylock(). + */ + if (try_lock) + { + error= pthread_mutex_trylock(&mp->mutex); + if (error == EBUSY) + return error; + } + else + error= pthread_mutex_lock(&mp->mutex); + if (error || (error=pthread_mutex_lock(&mp->global))) { fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n", From 18c6118911f1f98c80a9a06af50a8c5ed02aef32 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Wed, 3 Oct 2007 21:38:32 +0200 Subject: [PATCH 17/55] Bug#30992 Wrong implementation of pthread_mutex_trylock() It's not possible to use WaitForSingleObject to wait on a CRITICAL_SECTION, instead use the TryEnterCriticalSection function. - if "mutex" was already taken => return EBUSY - if "mutex" was aquired => return 0 --- include/config-win.h | 3 +++ mysys/my_winthread.c | 22 ++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 279be7aa5e4..f0804a368bc 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -19,6 +19,9 @@ /* We have to do this define before including windows.h to get the AWE API functions */ #define _WIN32_WINNT 0x0500 +#else +/* Get NT 4.0 functions */ +#define _WIN32_WINNT 0x0400 #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c index e9fface0521..e94369bec32 100644 --- a/mysys/my_winthread.c +++ b/mysys/my_winthread.c @@ -40,31 +40,29 @@ void win_pthread_init(void) pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST); } + /** Adapter to @c pthread_mutex_trylock() @retval 0 Mutex was acquired @retval EBUSY Mutex was already locked by a thread - @retval EINVAL Mutex could not be acquired due to other error */ int win_pthread_mutex_trylock(pthread_mutex_t *mutex) { - switch (WaitForSingleObject(mutex, 0)) { - case WAIT_TIMEOUT: - return EBUSY; - - default: - case WAIT_FAILURE: - return EINVAL; - - case WAIT_OBJECT_0: - case WAIT_ABANDONED: /* The mutex was acquired because it was - * abandoned */ + if (TryEnterCriticalSection(mutex)) + { + /* Don't allow recursive lock */ + if (mutex->RecursionCount > 1){ + LeaveCriticalSection(mutex); + return EBUSY; + } return 0; } + return EBUSY; } + /* ** We have tried to use '_beginthreadex' instead of '_beginthread' here ** but in this case the program leaks about 512 characters for each From 707f067446939f8e00ac22fc1c07d62846737193 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Thu, 4 Oct 2007 17:19:14 +0400 Subject: [PATCH 18/55] Fix for BUG#31035: select from function, group by result crasher. This actually, fix for the patch for bug-27354. The problem with the patch was that Item_func_sp::used_tables() was updated, but Item_func_sp::const_item() was not. So, for Item_func_sp, we had the following inconsistency: - used_tables() returned RAND_TABLE, which means that the item can produce "random" results; - but const_item() returned TRUE, which means that the item is a constant one. The fix is to change Item_func_sp::const_item() behaviour: it must return TRUE (an item is a constant one) only if a stored function is deterministic and each of its arguments (if any) is a constant item. --- mysql-test/r/sp.result | 176 +++++++++++++++++++++++++ mysql-test/t/sp.test | 290 +++++++++++++++++++++++++++++++++++++++++ sql/item_func.cc | 13 +- 3 files changed, 477 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index a6c429a31fb..efc12b402ce 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6367,4 +6367,180 @@ DROP TABLE t1; DROP PROCEDURE p1; DROP PROCEDURE p2; + +# +# Bug#31035. +# + +# +# - Prepare. +# + +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; + +# +# - Create required objects. +# + +CREATE TABLE t1(c1 INT); + +INSERT INTO t1 VALUES (1), (2), (3); + +CREATE FUNCTION f1() +RETURNS INT +NOT DETERMINISTIC +RETURN 1; + +CREATE FUNCTION f2(p INT) +RETURNS INT +NOT DETERMINISTIC +RETURN 1; + +CREATE FUNCTION f3() +RETURNS INT +DETERMINISTIC +RETURN 1; + +CREATE FUNCTION f4(p INT) +RETURNS INT +DETERMINISTIC +RETURN 1; + +# +# - Check. +# + +SELECT f1() AS a FROM t1 GROUP BY a; +a +1 + +SELECT f2(@a) AS a FROM t1 GROUP BY a; +a +1 + +SELECT f3() AS a FROM t1 GROUP BY a; +a +1 + +SELECT f4(0) AS a FROM t1 GROUP BY a; +a +1 + +SELECT f4(@a) AS a FROM t1 GROUP BY a; +a +1 + +# +# - Cleanup. +# + +DROP TABLE t1; +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP FUNCTION f3; +DROP FUNCTION f4; + +# +# Bug#31191. +# + +# +# - Prepare. +# + +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP FUNCTION IF EXISTS f1; + +# +# - Create required objects. +# + +CREATE TABLE t1 ( +id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +barcode INT(8) UNSIGNED ZEROFILL nOT NULL, +PRIMARY KEY (id), +UNIQUE KEY barcode (barcode) +); + +INSERT INTO t1 (id, barcode) VALUES (1, 12345678); +INSERT INTO t1 (id, barcode) VALUES (2, 12345679); + +CREATE TABLE test.t2 ( +id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +barcode BIGINT(11) UNSIGNED ZEROFILL NOT NULL, +PRIMARY KEY (id) +); + +INSERT INTO test.t2 (id, barcode) VALUES (1, 12345106708); +INSERT INTO test.t2 (id, barcode) VALUES (2, 12345106709); + +CREATE FUNCTION f1(p INT(8)) +RETURNS BIGINT(11) UNSIGNED +READS SQL DATA +RETURN FLOOR(p/1000)*1000000 + 100000 + FLOOR((p MOD 1000)/10)*100 + (p MOD 10); + +# +# - Check. +# + +SELECT DISTINCT t1.barcode, f1(t1.barcode) +FROM t1 +INNER JOIN t2 +ON f1(t1.barcode) = t2.barcode +WHERE t1.barcode=12345678; +barcode f1(t1.barcode) +12345678 12345106708 + +# +# - Cleanup. +# + +DROP TABLE t1; +DROP TABLE t2; +DROP FUNCTION f1; + +# +# Bug#31226. +# + +# +# - Prepare. +# + +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; + +# +# - Create required objects. +# + +CREATE TABLE t1(id INT); + +INSERT INTO t1 VALUES (1), (2), (3); + +CREATE FUNCTION f1() +RETURNS DATETIME +NOT DETERMINISTIC NO SQL +RETURN NOW(); + +# +# - Check. +# + +SELECT f1() FROM t1 GROUP BY 1; +f1() + + +# +# - Cleanup. +# + +DROP TABLE t1; +DROP FUNCTION f1; + End of 5.0 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 8dd99c2b2f1..6413cf2e89d 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7354,4 +7354,294 @@ DROP TABLE t1; DROP PROCEDURE p1; DROP PROCEDURE p2; +########################################################################### + +# +# Bug#31035: select from function, group by result crasher. +# + +########################################################################### + +--echo + +--echo # +--echo # Bug#31035. +--echo # + +--echo + +--echo # +--echo # - Prepare. +--echo # + +--echo + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +--enable_warnings + +--echo + +--echo # +--echo # - Create required objects. +--echo # + +--echo + +CREATE TABLE t1(c1 INT); + +--echo + +INSERT INTO t1 VALUES (1), (2), (3); + +--echo + +CREATE FUNCTION f1() + RETURNS INT + NOT DETERMINISTIC + RETURN 1; + +--echo + +CREATE FUNCTION f2(p INT) + RETURNS INT + NOT DETERMINISTIC + RETURN 1; + +--echo + +CREATE FUNCTION f3() + RETURNS INT + DETERMINISTIC + RETURN 1; + +--echo + +CREATE FUNCTION f4(p INT) + RETURNS INT + DETERMINISTIC + RETURN 1; + +--echo + +--echo # +--echo # - Check. +--echo # + +--echo + +# Not deterministic function, no arguments. + +SELECT f1() AS a FROM t1 GROUP BY a; + +--echo + +# Not deterministic function, non-constant argument. + +SELECT f2(@a) AS a FROM t1 GROUP BY a; + +--echo + +# Deterministic function, no arguments. + +SELECT f3() AS a FROM t1 GROUP BY a; + +--echo + +# Deterministic function, constant argument. + +SELECT f4(0) AS a FROM t1 GROUP BY a; + +--echo + +# Deterministic function, non-constant argument. + +SELECT f4(@a) AS a FROM t1 GROUP BY a; + +--echo + +--echo # +--echo # - Cleanup. +--echo # + +--echo + +DROP TABLE t1; +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP FUNCTION f3; +DROP FUNCTION f4; + +--echo + +########################################################################### + +# +# Bug#31191: JOIN in combination with stored function crashes the server. +# + +########################################################################### + +--echo # +--echo # Bug#31191. +--echo # + +--echo + +--echo # +--echo # - Prepare. +--echo # + +--echo + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +--echo + +--echo # +--echo # - Create required objects. +--echo # + +--echo + +CREATE TABLE t1 ( + id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + barcode INT(8) UNSIGNED ZEROFILL nOT NULL, + PRIMARY KEY (id), + UNIQUE KEY barcode (barcode) +); + +--echo + +INSERT INTO t1 (id, barcode) VALUES (1, 12345678); +INSERT INTO t1 (id, barcode) VALUES (2, 12345679); + +--echo + +CREATE TABLE test.t2 ( + id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + barcode BIGINT(11) UNSIGNED ZEROFILL NOT NULL, + PRIMARY KEY (id) +); + +--echo + +INSERT INTO test.t2 (id, barcode) VALUES (1, 12345106708); +INSERT INTO test.t2 (id, barcode) VALUES (2, 12345106709); + +--echo + +CREATE FUNCTION f1(p INT(8)) + RETURNS BIGINT(11) UNSIGNED + READS SQL DATA + RETURN FLOOR(p/1000)*1000000 + 100000 + FLOOR((p MOD 1000)/10)*100 + (p MOD 10); + +--echo + +--echo # +--echo # - Check. +--echo # + +--echo + +SELECT DISTINCT t1.barcode, f1(t1.barcode) +FROM t1 +INNER JOIN t2 +ON f1(t1.barcode) = t2.barcode +WHERE t1.barcode=12345678; + +--echo + +--echo # +--echo # - Cleanup. +--echo # + +--echo + +DROP TABLE t1; +DROP TABLE t2; +DROP FUNCTION f1; + +--echo + +########################################################################### + +# +# Bug#31226: Group by function crashes mysql. +# + +########################################################################### + +--echo # +--echo # Bug#31226. +--echo # + +--echo + +--echo # +--echo # - Prepare. +--echo # + +--echo + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +--echo + +--echo # +--echo # - Create required objects. +--echo # + +--echo + +CREATE TABLE t1(id INT); + +--echo + +INSERT INTO t1 VALUES (1), (2), (3); + +--echo + +CREATE FUNCTION f1() + RETURNS DATETIME + NOT DETERMINISTIC NO SQL + RETURN NOW(); + +--echo + +--echo # +--echo # - Check. +--echo # + +--echo + +--replace_column 1 +SELECT f1() FROM t1 GROUP BY 1; + +--echo + +--echo # +--echo # - Cleanup. +--echo # + +--echo + +DROP TABLE t1; +DROP FUNCTION f1; + +--echo + +########################################################################### + --echo End of 5.0 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index d03d497dfd0..f7103c22581 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5583,8 +5583,13 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) #endif /* ! NO_EMBEDDED_ACCESS_CHECKS */ } + if (!m_sp->m_chistics->detistic) - used_tables_cache |= RAND_TABLE_BIT; + { + used_tables_cache |= RAND_TABLE_BIT; + const_item_cache= FALSE; + } + DBUG_RETURN(res); } @@ -5592,6 +5597,10 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) void Item_func_sp::update_used_tables() { Item_func::update_used_tables(); + if (!m_sp->m_chistics->detistic) - used_tables_cache |= RAND_TABLE_BIT; + { + used_tables_cache |= RAND_TABLE_BIT; + const_item_cache= FALSE; + } } From 305ebc1e21d72c54a2c3e7714b884b847da06efc Mon Sep 17 00:00:00 2001 From: "davi@moksha.local" <> Date: Thu, 4 Oct 2007 17:34:41 -0300 Subject: [PATCH 19/55] Bug#21587 FLUSH TABLES causes server crash when used with HANDLER statements This bug is a symptom of the way handler's tables are managed. The most different aspect, compared to the conventional behavior, is that the handler's tables are long lived, meaning that their lifetimes are not bounded by the duration of the command that opened them. For this effect the handler code uses its own list (handler_tables instead of open_tables) to hold open handler tables so that the tables won't be closed at the end of the command/statement. Besides the handler_tables list, there is a hash (handler_tables_hash) which is used to associate handler aliases to tables and to refresh the tables upon demand (flush tables). The current implementation doesn't work properly with refreshed tables -- more precisely when flush commands are issued by other initiators. This happens because when a handler open or read statement is being processed, the associated table has to be opened or locked and, for this matter, the open_tables and handler_tables lists are swapped so that the new table being opened is inserted into the handler_tables list. But when opening or locking the table, if the refresh version is different from the thread refresh version then all used tables in the open_tables list (now handler_tables) are refreshed. In the "refreshing" process the handler tables are flushed (closed) without being properly unlinked from the handler hash. The current implementation also fails to properly discard handlers of dropped tables, but this and other problems are going to be addressed in the fixes for bugs 31397 and 31409. The chosen approach tries to properly save and restore the table state so that no table is flushed during the table open and lock operations. The logic is almost the same as before with the list swapping, but with a working glue code. The test case for this bug is going to be committed into 5.1 because it requires a test feature only avaiable in 5.1 (wait_condition). --- sql/sql_handler.cc | 53 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 9aefa71647e..89090c9fa63 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -65,11 +65,6 @@ static enum enum_ha_read_modes rkey_to_rnext[]= { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV }; -#define HANDLER_TABLES_HACK(thd) { \ - TABLE *tmp=thd->open_tables; \ - thd->open_tables=thd->handler_tables; \ - thd->handler_tables=tmp; } - static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags); @@ -187,6 +182,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) char *db, *name, *alias; uint dblen, namelen, aliaslen, counter; int error; + TABLE *backup_open_tables, *backup_handler_tables; DBUG_ENTER("mysql_ha_open"); DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d", tables->db, tables->table_name, tables->alias, @@ -215,18 +211,31 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) } } + /* save open_ and handler_ tables state */ + backup_open_tables= thd->open_tables; + backup_handler_tables= thd->handler_tables; + + /* no pre-opened tables */ + thd->open_tables= NULL; + /* to avoid flushes */ + thd->handler_tables= NULL; + /* open_tables() will set 'tables->table' if successful. It must be NULL for a real open when calling open_tables(). */ DBUG_ASSERT(! tables->table); - HANDLER_TABLES_HACK(thd); /* for now HANDLER can be used only for real TABLES */ tables->required_type= FRMTYPE_TABLE; error= open_tables(thd, &tables, &counter, 0); - HANDLER_TABLES_HACK(thd); + /* restore the state and merge the opened table into handler_tables list */ + thd->handler_tables= thd->open_tables ? + thd->open_tables->next= backup_handler_tables, + thd->open_tables : backup_handler_tables; + thd->open_tables= backup_open_tables; + if (error) goto err; @@ -351,7 +360,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ha_rows select_limit_cnt, ha_rows offset_limit_cnt) { TABLE_LIST *hash_tables; - TABLE *table; + TABLE *table, *backup_open_tables, *backup_handler_tables; MYSQL_LOCK *lock; List list; Protocol *protocol= thd->protocol; @@ -361,7 +370,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, uint num_rows; byte *key; uint key_len; - bool not_used; + bool need_reopen; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", tables->db, tables->table_name, tables->alias)); @@ -375,6 +384,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, List_iterator it(list); it++; +retry: if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, (byte*) tables->alias, strlen(tables->alias) + 1))) @@ -427,9 +437,28 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; - HANDLER_TABLES_HACK(thd); - lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used); - HANDLER_TABLES_HACK(thd); + /* save open_ and handler_ tables state */ + backup_open_tables= thd->open_tables; + backup_handler_tables= thd->handler_tables; + + /* no pre-opened tables */ + thd->open_tables= NULL; + /* to avoid flushes */ + thd->handler_tables= NULL; + + lock= mysql_lock_tables(thd, &tables->table, 1, + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen); + + /* restore previous context */ + thd->handler_tables= backup_handler_tables; + thd->open_tables= backup_open_tables; + + if (need_reopen) + { + mysql_ha_close_table(thd, tables); + hash_tables->table= NULL; + goto retry; + } if (!lock) goto err0; // mysql_lock_tables() printed error message already From ac875690f74b52c093d6e3760445598044ef148f Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Fri, 5 Oct 2007 16:35:01 +0400 Subject: [PATCH 20/55] Fix for BUG#20550: Stored function: wrong RETURN type metadata when used in a VIEW. The problem was that wrong function (create_tmp_from_item()) was used to create a temporary field for Item_func_sp. The fix is to use create_tmp_from_field(). --- mysql-test/r/sp.result | 50 ++++++++++++++++++++++++- mysql-test/t/sp.test | 84 ++++++++++++++++++++++++++++++++++++++++++ sql/item_func.h | 5 +++ sql/sql_select.cc | 30 +++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index fd09701c125..2274a9103e8 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 @@ -6599,3 +6599,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/t/sp.test b/mysql-test/t/sp.test index 27e559f4463..938bbc27777 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7549,3 +7549,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/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/sql_select.cc b/sql/sql_select.cc index fd3be1aef08..9b79b706438 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9301,6 +9301,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: From 128772ba1ffc3ef29cb3dae718b89cc5bf5a1902 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Mon, 8 Oct 2007 17:09:28 +0400 Subject: [PATCH 21/55] Fix compilation warning. --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0aa9591e95d..c3565dd9b17 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1527,7 +1527,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) 1 request of thread shutdown (see dispatch_command() description) */ -bool do_command(THD *thd) +static bool do_command(THD *thd) { char *packet= 0; ulong packet_length; From 2885d0df1556653706ee0dd70e029e6cfdb476ce Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Mon, 8 Oct 2007 17:59:23 +0400 Subject: [PATCH 22/55] Get rid of compilation warning. --- sql/sql_parse.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c3565dd9b17..8c61243e3c5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -93,7 +93,9 @@ const char *xa_state_names[]={ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" }; +#ifndef EMBEDDED_LIBRARY static bool do_command(THD *thd); +#endif // EMBEDDED_LIBRARY #ifdef __WIN__ static void test_signal(int sig_ptr) From 437fdeaa16c42979a79743520a46e311235c604c Mon Sep 17 00:00:00 2001 From: "malff@lambda.hsd1.co.comcast.net." <> Date: Mon, 8 Oct 2007 12:37:57 -0600 Subject: [PATCH 23/55] Test cleanup, the upgrade test script assumes a unix like environment --- mysql-test/t/upgrade.test | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/upgrade.test b/mysql-test/t/upgrade.test index 40bd17fc3a5..05f430b087b 100644 --- a/mysql-test/t/upgrade.test +++ b/mysql-test/t/upgrade.test @@ -1,5 +1,10 @@ -- source include/not_embedded.inc +# Temporary disabled on windows, +# because of --exec mkdir +# TODO: implement Bug#31004 and remove this limitation +--source include/not_windows.inc + --disable_warnings drop database if exists `mysqltest1`; drop database if exists `mysqltest-1`; @@ -60,7 +65,6 @@ drop table t1; # Bug#28360 (RENAME DATABASE destroys routines) # - --disable_warnings drop database if exists `tabc`; drop database if exists `a-b-c`; From 27ee6db9db2128f4b2d34c1ea00da2d88b2748ec Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Tue, 9 Oct 2007 14:53:15 +0400 Subject: [PATCH 24/55] Fix merge. --- sql/mysql_priv.h | 1 + sql/sql_connect.cc | 16 ++++++++++++---- sql/sql_parse.cc | 2 -- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9b1578280e4..6a7e3e00f6f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -965,6 +965,7 @@ void init_update_queries(void); void free_max_user_conn(void); pthread_handler_t handle_bootstrap(void *arg); bool mysql_execute_command(THD *thd); +bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); void log_slow_statement(THD *thd); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 6bb0f62d843..9785b30ea00 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -973,21 +973,29 @@ void end_connection(THD *thd) plugin_thdvar_cleanup(thd); if (thd->user_connect) decrease_user_connections(thd->user_connect); + + if (thd->killed || + net->error && net->vio != 0 && net->report_error) + { + statistic_increment(aborted_threads,&LOCK_status); + } + if (net->error && net->vio != 0 && net->report_error) { - Security_context *sctx= thd->security_ctx; if (!thd->killed && thd->variables.log_warnings > 1) + { + Security_context *sctx= thd->security_ctx; + sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), thd->thread_id,(thd->db ? thd->db : "unconnected"), sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, (net->last_errno ? ER(net->last_errno) : ER(ER_UNKNOWN_ERROR))); + } + net_send_error(thd, net->last_errno, NullS); - statistic_increment(aborted_threads,&LOCK_status); } - else if (thd->killed) - statistic_increment(aborted_threads,&LOCK_status); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 91eaadb0d9f..695e923e816 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -86,8 +86,6 @@ const char *xa_state_names[]={ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" }; -static bool do_command(THD *thd); - static void unlock_locked_tables(THD *thd) { if (thd->locked_tables) From 7252cbe1e0e48c8497fac35c99b113294095217e Mon Sep 17 00:00:00 2001 From: "davi@moksha.local" <> Date: Tue, 9 Oct 2007 12:02:59 -0300 Subject: [PATCH 25/55] Bug#31409 RENAME TABLE causes server crash or deadlock when used with HANDLER statements This deadlock occurs when a client issues a HANDLER ... OPEN statement that tries to open a table that has a pending name-lock on it by another client that also needs a name-lock on some other table which is already open and associated to a HANDLER instance owned by the first client. The deadlock happens because the open_table() function will back-off and wait until the name-lock goes away, causing a circular wait if some other name-lock is also pending for one of the open HANDLER tables. Such situation, for example, can be easily repeated by issuing a RENAME TABLE command in such a way that the existing table is already open as a HANDLER table by another client and this client tries to open a HANDLER to the new table name. The solution is to allow handler tables with older versions (marked for flush) to be closed before waiting for the name-lock completion. This is safe because no other name-lock can be issued between the flush and the check for pending name-locks. The test case for this bug is going to be committed into 5.1 because it requires a test feature only avaiable in 5.1 (wait_condition). --- sql/sql_base.cc | 12 +++++++++++- sql/sql_handler.cc | 47 +++++++++++++++++++++++++++------------------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 289924ff418..905190cb9cd 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1745,7 +1745,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, DBUG_RETURN(0); } - /* close handler tables which are marked for flush */ + /* + In order for the back off and re-start process to work properly, + handler tables having old versions (due to FLUSH TABLES or pending + name-lock) MUST be closed. This is specially important if a name-lock + is pending for any table of the handler_tables list, otherwise a + deadlock may occur. + */ if (thd->handler_tables) mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); @@ -1810,6 +1816,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->db_stat == 0 signals wait_for_locked_table_names that the tables in question are not used any more. See table_is_used call for details. + + Notice that HANDLER tables were already taken care of by + the earlier call to mysql_ha_flush() in this same critical + section. */ close_old_data_files(thd,thd->open_tables,0,0); /* diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 89090c9fa63..e87381dd49c 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -182,7 +182,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) char *db, *name, *alias; uint dblen, namelen, aliaslen, counter; int error; - TABLE *backup_open_tables, *backup_handler_tables; + TABLE *backup_open_tables; DBUG_ENTER("mysql_ha_open"); DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d", tables->db, tables->table_name, tables->alias, @@ -211,14 +211,20 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) } } - /* save open_ and handler_ tables state */ - backup_open_tables= thd->open_tables; - backup_handler_tables= thd->handler_tables; + /* + Save and reset the open_tables list so that open_tables() won't + be able to access (or know about) the previous list. And on return + from open_tables(), thd->open_tables will contain only the opened + table. - /* no pre-opened tables */ + The thd->handler_tables list is kept as-is to avoid deadlocks if + open_table(), called by open_tables(), needs to back-off because + of a pending name-lock on the table being opened. + + See open_table() back-off comments for more details. + */ + backup_open_tables= thd->open_tables; thd->open_tables= NULL; - /* to avoid flushes */ - thd->handler_tables= NULL; /* open_tables() will set 'tables->table' if successful. @@ -231,9 +237,12 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) error= open_tables(thd, &tables, &counter, 0); /* restore the state and merge the opened table into handler_tables list */ - thd->handler_tables= thd->open_tables ? - thd->open_tables->next= backup_handler_tables, - thd->open_tables : backup_handler_tables; + if (thd->open_tables) + { + thd->open_tables->next= thd->handler_tables; + thd->handler_tables= thd->open_tables; + } + thd->open_tables= backup_open_tables; if (error) @@ -360,7 +369,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ha_rows select_limit_cnt, ha_rows offset_limit_cnt) { TABLE_LIST *hash_tables; - TABLE *table, *backup_open_tables, *backup_handler_tables; + TABLE *table, *backup_open_tables; MYSQL_LOCK *lock; List list; Protocol *protocol= thd->protocol; @@ -437,20 +446,20 @@ retry: } tables->table=table; - /* save open_ and handler_ tables state */ + /* save open_tables state */ backup_open_tables= thd->open_tables; - backup_handler_tables= thd->handler_tables; - - /* no pre-opened tables */ - thd->open_tables= NULL; - /* to avoid flushes */ - thd->handler_tables= NULL; + /* + mysql_lock_tables() needs thd->open_tables to be set correctly to + be able to handle aborts properly. When the abort happens, it's + safe to not protect thd->handler_tables because it won't close any + tables. + */ + thd->open_tables= thd->handler_tables; lock= mysql_lock_tables(thd, &tables->table, 1, MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen); /* restore previous context */ - thd->handler_tables= backup_handler_tables; thd->open_tables= backup_open_tables; if (need_reopen) From fd3c6b185515bc6a0ea8598e98531c5f8b326502 Mon Sep 17 00:00:00 2001 From: "davi@virtua-cwbas201-21-158-74.ctb.virtua.com.br" <> Date: Tue, 9 Oct 2007 20:46:33 -0300 Subject: [PATCH 26/55] Bug#28318 CREATE FUNCTION (UDF) requires a schema Bug#29816 Syntactically wrong query fails with misleading error message The core problem is that an SQL-invoked function name can be a that contains no , but the mysql parser insists that all stored procedures (function, procedures and triggers) must have a , which is not true for functions. This problem is especially visible when trying to create a function or when a query contains a syntax error after a function call (in the same query), both will fail with a "No database selected" message if the session is not attached to a particular schema, but the first one should succeed and the second fail with a "syntax error" message. Part of the fix is to revamp the sp name handling so that a schema name may be omitted for functions -- this means that the internal function name representation may not have a dot, which represents that the function doesn't have a schema name. The other part is to place schema checks after the type (function, trigger or procedure) of the routine is known. --- mysql-test/r/sp-error.result | 13 +++++++++++++ mysql-test/r/udf.result | 7 +++++++ mysql-test/t/sp-error.test | 20 ++++++++++++++++++++ mysql-test/t/udf.test | 14 ++++++++++++++ sql/sp.cc | 13 +++---------- sql/sp_head.cc | 31 ++++++++++++++++++++++++++++--- sql/sp_head.h | 11 +---------- sql/sql_yacc.yy | 31 ++++++++++++++++++++++++++----- 8 files changed, 112 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index bd0640b2b14..cc217ecd093 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1452,3 +1452,16 @@ end until true end repeat retry; end// ERROR 42000: LEAVE with no matching label: retry +DROP DATABASE IF EXISTS mysqltest; +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +SELECT inexistent(), 1 + ,; +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 '' at line 1 +SELECT inexistent(); +ERROR 42000: FUNCTION inexistent does not exist +SELECT .inexistent(); +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 '()' at line 1 +SELECT ..inexistent(); +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 '.inexistent()' at line 1 +USE test; diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 2e9cf217ed6..3e29c780ca8 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -296,4 +296,11 @@ Qcache_queries_in_cache 0 drop table t1; drop function metaphon; set GLOBAL query_cache_size=default; +DROP DATABASE IF EXISTS mysqltest; +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +DROP FUNCTION metaphon; +USE test; End of 5.0 tests. diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 240cda67edc..a1abf4852b0 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2089,6 +2089,26 @@ end// delimiter ;// +# +# Bug#29816 Syntactically wrong query fails with misleading error message +# + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest; +--enable_warnings +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +--error ER_PARSE_ERROR +SELECT inexistent(), 1 + ,; +--error ER_SP_DOES_NOT_EXIST +SELECT inexistent(); +--error ER_PARSE_ERROR +SELECT .inexistent(); +--error ER_PARSE_ERROR +SELECT ..inexistent(); +USE test; + # # BUG#NNNN: New bug synopsis # diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 75af1f4be4b..6a516a29534 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -311,5 +311,19 @@ drop table t1; drop function metaphon; set GLOBAL query_cache_size=default; +# +# Bug#28318 CREATE FUNCTION (UDF) requires a schema +# + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest; +--enable_warnings +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; +DROP FUNCTION metaphon; +USE test; --echo End of 5.0 tests. diff --git a/sql/sp.cc b/sql/sp.cc index 75d6fa4618f..0b84e1ad07f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1405,12 +1405,12 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, { Sroutine_hash_entry *rn= (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) + - key->length); + key->length + 1); if (!rn) // OOM. Error will be reported using fatal_error(). return FALSE; rn->key.length= key->length; rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry); - memcpy(rn->key.str, key->str, key->length); + memcpy(rn->key.str, key->str, key->length + 1); my_hash_insert(&lex->sroutines, (byte *)rn); lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next); rn->belong_to_view= belong_to_view; @@ -1595,7 +1595,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, for (Sroutine_hash_entry *rt= start; rt; rt= rt->next) { - sp_name name(rt->key.str, rt->key.length); + sp_name name(thd, rt->key.str, rt->key.length); int type= rt->key.str[0]; sp_head *sp; @@ -1603,13 +1603,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, &thd->sp_func_cache : &thd->sp_proc_cache), &name))) { - name.m_name.str= strchr(name.m_qname.str, '.'); - name.m_db.length= name.m_name.str - name.m_qname.str; - name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str, - name.m_db.length); - name.m_name.str+= 1; - name.m_name.length= name.m_qname.length - name.m_db.length - 1; - switch ((ret= db_find_routine(thd, type, &name, &sp))) { case SP_OK: diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 5ad6625efb8..69dda9ec1e8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -369,17 +369,42 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) * */ +sp_name::sp_name(THD *thd, char *key, uint key_len) +{ + m_sroutines_key.str= key; + m_sroutines_key.length= key_len; + m_qname.str= ++key; + m_qname.length= key_len - 1; + if ((m_name.str= strchr(m_qname.str, '.'))) + { + m_db.length= m_name.str - key; + m_db.str= strmake_root(thd->mem_root, key, m_db.length); + m_name.str++; + m_name.length= m_qname.length - m_db.length - 1; + } + else + { + m_name.str= m_qname.str; + m_name.length= m_qname.length; + m_db.str= 0; + m_db.length= 0; + } + m_explicit_name= false; +} + void sp_name::init_qname(THD *thd) { - m_sroutines_key.length= m_db.length + m_name.length + 2; + const uint dot= !!m_db.length; + /* m_sroutines format: m_type + [database + dot] + name + nul */ + m_sroutines_key.length= 1 + m_db.length + dot + m_name.length; if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1))) return; m_qname.length= m_sroutines_key.length - 1; m_qname.str= m_sroutines_key.str + 1; - sprintf(m_qname.str, "%.*s.%.*s", + sprintf(m_qname.str, "%.*s%.*s%.*s", m_db.length, (m_db.length ? m_db.str : ""), - m_name.length, m_name.str); + dot, ".", m_name.length, m_name.str); } diff --git a/sql/sp_head.h b/sql/sp_head.h index ebe40ce9c87..7d042367985 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -72,16 +72,7 @@ public: Creates temporary sp_name object from key, used mainly for SP-cache lookups. */ - sp_name(char *key, uint key_len) - { - m_sroutines_key.str= key; - m_sroutines_key.length= key_len; - m_name.str= m_qname.str= key + 1; - m_name.length= m_qname.length= key_len - 1; - m_db.str= 0; - m_db.length= 0; - m_explicit_name= false; - } + sp_name(THD *thd, char *key, uint key_len); // Init. the qualified name from the db and name. void init_qname(THD *thd); // thd for memroot allocation diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e0b9ab28594..7e3c11b5122 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1569,13 +1569,15 @@ sp_name: | ident { LEX *lex= Lex; - LEX_STRING db; + LEX_STRING db= {0,0}; + THD *thd= YYTHD; + if (check_routine_name($1)) { my_error(ER_SP_WRONG_NAME, MYF(0), $1.str); MYSQL_YYABORT; } - if (lex->copy_db_to(&db.str, &db.length)) + if (thd->db && thd->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; $$= new sp_name(db, $1, false); if ($$) @@ -1625,6 +1627,13 @@ create_function_tail: my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION"); MYSQL_YYABORT; } + + if (!lex->spname->m_db.length) + { + my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); + MYSQL_YYABORT; + } + /* Order is important here: new - reset - init */ sp= new sp_head(); sp->reset_thd_mem_root(thd); @@ -5194,8 +5203,8 @@ simple_expr: #endif /* HAVE_DLOPEN */ { THD *thd= lex->thd; - LEX_STRING db; - if (lex->copy_db_to(&db.str, &db.length)) + LEX_STRING db= {0,0}; + if (thd->db && thd->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; sp_name *name= new sp_name(db, $1, false); if (name) @@ -9730,7 +9739,13 @@ trigger_tail: my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER"); MYSQL_YYABORT; } - + + if (!$3->m_db.length) + { + my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); + MYSQL_YYABORT; + } + if (!(sp= new sp_head())) MYSQL_YYABORT; sp->reset_thd_mem_root(thd); @@ -9813,6 +9828,12 @@ sp_tail: MYSQL_YYABORT; } + if (!$3->m_db.length) + { + my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); + MYSQL_YYABORT; + } + lex->stmt_definition_begin= $2; /* Order is important here: new - reset - init */ From 190bb6bf4c812ca053524565ef2f2cceeedef05d Mon Sep 17 00:00:00 2001 From: "malff@lambda.hsd1.co.comcast.net." <> Date: Tue, 9 Oct 2007 18:12:13 -0600 Subject: [PATCH 27/55] Fixed packet length for embedded tests --- libmysqld/lib_sql.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 9c26febe627..4e525f8447f 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -111,7 +111,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, } thd->net.no_send_error= 0; - result= dispatch_command(command, thd, (char *) arg, arg_length + 1); + result= dispatch_command(command, thd, (char *) arg, arg_length); thd->cur_data= 0; if (!skip_check) From c6c419f91974676fd453d8a412a14e41f886671e Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Wed, 10 Oct 2007 13:53:24 +0400 Subject: [PATCH 28/55] Fix automerge. --- mysql-test/r/sp.result | 176 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 21af61d39f6..4641866bb43 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6620,6 +6620,182 @@ DROP TABLE t1; DROP PROCEDURE p1; DROP PROCEDURE p2; + +# +# Bug#31035. +# + +# +# - Prepare. +# + +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; + +# +# - Create required objects. +# + +CREATE TABLE t1(c1 INT); + +INSERT INTO t1 VALUES (1), (2), (3); + +CREATE FUNCTION f1() +RETURNS INT +NOT DETERMINISTIC +RETURN 1; + +CREATE FUNCTION f2(p INT) +RETURNS INT +NOT DETERMINISTIC +RETURN 1; + +CREATE FUNCTION f3() +RETURNS INT +DETERMINISTIC +RETURN 1; + +CREATE FUNCTION f4(p INT) +RETURNS INT +DETERMINISTIC +RETURN 1; + +# +# - Check. +# + +SELECT f1() AS a FROM t1 GROUP BY a; +a +1 + +SELECT f2(@a) AS a FROM t1 GROUP BY a; +a +1 + +SELECT f3() AS a FROM t1 GROUP BY a; +a +1 + +SELECT f4(0) AS a FROM t1 GROUP BY a; +a +1 + +SELECT f4(@a) AS a FROM t1 GROUP BY a; +a +1 + +# +# - Cleanup. +# + +DROP TABLE t1; +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP FUNCTION f3; +DROP FUNCTION f4; + +# +# Bug#31191. +# + +# +# - Prepare. +# + +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP FUNCTION IF EXISTS f1; + +# +# - Create required objects. +# + +CREATE TABLE t1 ( +id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +barcode INT(8) UNSIGNED ZEROFILL nOT NULL, +PRIMARY KEY (id), +UNIQUE KEY barcode (barcode) +); + +INSERT INTO t1 (id, barcode) VALUES (1, 12345678); +INSERT INTO t1 (id, barcode) VALUES (2, 12345679); + +CREATE TABLE test.t2 ( +id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +barcode BIGINT(11) UNSIGNED ZEROFILL NOT NULL, +PRIMARY KEY (id) +); + +INSERT INTO test.t2 (id, barcode) VALUES (1, 12345106708); +INSERT INTO test.t2 (id, barcode) VALUES (2, 12345106709); + +CREATE FUNCTION f1(p INT(8)) +RETURNS BIGINT(11) UNSIGNED +READS SQL DATA +RETURN FLOOR(p/1000)*1000000 + 100000 + FLOOR((p MOD 1000)/10)*100 + (p MOD 10); + +# +# - Check. +# + +SELECT DISTINCT t1.barcode, f1(t1.barcode) +FROM t1 +INNER JOIN t2 +ON f1(t1.barcode) = t2.barcode +WHERE t1.barcode=12345678; +barcode f1(t1.barcode) +12345678 12345106708 + +# +# - Cleanup. +# + +DROP TABLE t1; +DROP TABLE t2; +DROP FUNCTION f1; + +# +# Bug#31226. +# + +# +# - Prepare. +# + +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; + +# +# - Create required objects. +# + +CREATE TABLE t1(id INT); + +INSERT INTO t1 VALUES (1), (2), (3); + +CREATE FUNCTION f1() +RETURNS DATETIME +NOT DETERMINISTIC NO SQL +RETURN NOW(); + +# +# - Check. +# + +SELECT f1() FROM t1 GROUP BY 1; +f1() + + +# +# - Cleanup. +# + +DROP TABLE t1; +DROP FUNCTION f1; + End of 5.0 tests # From 05cf10bdf6b803e943a3348af05fa2a5a76362c4 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Wed, 10 Oct 2007 14:42:29 +0400 Subject: [PATCH 29/55] Cleanup sp.test. --- mysql-test/r/sp.result | 6 +++--- mysql-test/t/sp.test | 10 +++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index b1120a22dfd..ef173b9661f 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -5667,7 +5667,6 @@ t3_id_1 t3_id_2 t4_id DROP PROCEDURE p1| DROP VIEW v1, v2| DROP TABLE t3, t4| -End of 5.0 tests DROP TABLE IF EXISTS bug23760| DROP TABLE IF EXISTS bug23760_log| DROP PROCEDURE IF EXISTS bug23760_update_log| @@ -6145,7 +6144,6 @@ Procedure sql_mode Create Procedure proc_21513 CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_21513`() `my_label`:BEGIN END drop procedure proc_21513| -End of 5.0 tests. drop table t1,t2; CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM; CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb; @@ -6565,4 +6563,6 @@ f1() DROP TABLE t1; DROP FUNCTION f1; -End of 5.0 tests +# ------------------------------------------------------------------ +# -- End of 5.0 tests +# ------------------------------------------------------------------ diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 465585a693e..501d96c842a 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -6642,9 +6642,6 @@ DROP VIEW v1, v2| DROP TABLE t3, t4| ---echo End of 5.0 tests - - # # BUG#23760: ROW_COUNT() and store procedure not owrking together # @@ -7076,9 +7073,6 @@ show create procedure proc_21513| drop procedure proc_21513| -### ---echo End of 5.0 tests. - # # BUG#NNNN: New bug synopsis # @@ -7677,4 +7671,6 @@ DROP FUNCTION f1; ########################################################################### ---echo End of 5.0 tests +--echo # ------------------------------------------------------------------ +--echo # -- End of 5.0 tests +--echo # ------------------------------------------------------------------ From ac83b3122c32e84c2ec526760273d3a9b1176b49 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Wed, 10 Oct 2007 17:57:01 +0400 Subject: [PATCH 30/55] Fix for BUG#20023: mysql_change_user() resets the value of SQL_BIG_SELECTS. The bug was that SQL_BIG_SELECTS was not properly set in COM_CHANGE_USER. The fix is to update SQL_BIG_SELECTS properly. --- sql/mysql_priv.h | 1 - sql/sql_class.cc | 6 ++ sql/sql_connect.cc | 4 +- tests/mysql_client_test.c | 171 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 3 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6a7e3e00f6f..79d4c16f9c1 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -917,7 +917,6 @@ void decrease_user_connections(USER_CONN *uc); void thd_init_client_charset(THD *thd, uint cs_number); bool setup_connection_thread_globals(THD *thd); bool login_connection(THD *thd); -void prepare_new_connection_state(THD* thd); void end_connection(THD *thd); bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 66a51d5bb00..490aedad0ef 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -585,6 +585,12 @@ void THD::init(void) if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; options= thd_startup_options; + + if (variables.max_join_size == HA_POS_ERROR) + options |= OPTION_BIG_SELECTS; + else + options &= ~OPTION_BIG_SELECTS; + transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE; open_options=ha_open_options; update_lock_default= (variables.low_priority_updates ? diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 9785b30ea00..094bef9324e 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -933,7 +933,7 @@ bool login_connection(THD *thd) NET *net= &thd->net; Security_context *sctx= thd->security_ctx; DBUG_ENTER("login_connection"); - DBUG_PRINT("info", ("handle_one_connection called by thread %lu", + DBUG_PRINT("info", ("login_connection called by thread %lu", thd->thread_id)); net->no_send_error= 0; @@ -1003,7 +1003,7 @@ void end_connection(THD *thd) Initialize THD to handle queries */ -void prepare_new_connection_state(THD* thd) +static void prepare_new_connection_state(THD* thd) { Security_context *sctx= thd->security_ctx; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index eff8df8109a..9505340c24f 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -16819,6 +16819,176 @@ static void test_bug30472() mysql_close(&con); } +static void bug20023_change_user(MYSQL *con) +{ + DIE_IF(mysql_change_user(con, + opt_user, + opt_password, + opt_db ? opt_db : "test")); +} + +static void bug20023_query_int_variable(MYSQL *con, + const char *var_name, + int *var_value) +{ + MYSQL_RES *rs; + MYSQL_ROW row; + + char query_buffer[MAX_TEST_QUERY_LENGTH]; + + my_snprintf(query_buffer, + sizeof (query_buffer), + "SELECT @@%s", + (const char *) var_name); + + DIE_IF(mysql_query(con, query_buffer)); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + *var_value= atoi(row[0]); + mysql_free_result(rs); +} + +static void test_bug20023() +{ + MYSQL con; + + int sql_big_selects_orig; + int max_join_size_orig; + + int sql_big_selects_2; + int sql_big_selects_3; + int sql_big_selects_4; + int sql_big_selects_5; + + char query_buffer[MAX_TEST_QUERY_LENGTH]; + + /* 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)); + + /*********************************************************************** + Remember original SQL_BIG_SELECTS, MAX_JOIN_SIZE values. + ***********************************************************************/ + + bug20023_query_int_variable(&con, + "session.sql_big_selects", + &sql_big_selects_orig); + + bug20023_query_int_variable(&con, + "global.max_join_size", + &max_join_size_orig); + + /*********************************************************************** + Test that COM_CHANGE_USER resets the SQL_BIG_SELECTS to the initial value. + ***********************************************************************/ + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + bug20023_query_int_variable(&con, + "session.sql_big_selects", + &sql_big_selects_2); + + /* Check that SQL_BIG_SELECTS is reset properly. */ + + DIE_UNLESS(sql_big_selects_orig == sql_big_selects_2); + + /*********************************************************************** + Test that if MAX_JOIN_SIZE set to non-default value, + SQL_BIG_SELECTS will be 0. + ***********************************************************************/ + + /* Set MAX_JOIN_SIZE to some non-default value. */ + + DIE_IF(mysql_query(&con, "SET @@global.max_join_size = 10000")); + DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + bug20023_query_int_variable(&con, + "session.sql_big_selects", + &sql_big_selects_3); + + /* Check that SQL_BIG_SELECTS is 0. */ + + DIE_UNLESS(sql_big_selects_3 == 0); + + /*********************************************************************** + Test that if MAX_JOIN_SIZE set to default value, + SQL_BIG_SELECTS will be 1. + ***********************************************************************/ + + /* Set MAX_JOIN_SIZE to the default value (-1). */ + + DIE_IF(mysql_query(&con, "SET @@global.max_join_size = -1")); + DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + bug20023_query_int_variable(&con, + "session.sql_big_selects", + &sql_big_selects_4); + + /* Check that SQL_BIG_SELECTS is 1. */ + + DIE_UNLESS(sql_big_selects_4 == 1); + + /*********************************************************************** + Restore MAX_JOIN_SIZE. + Check that SQL_BIG_SELECTS will be the original one. + ***********************************************************************/ + + /* Restore MAX_JOIN_SIZE. */ + + my_snprintf(query_buffer, + sizeof (query_buffer), + "SET @@global.max_join_size = %d", + (int) max_join_size_orig); + + DIE_IF(mysql_query(&con, query_buffer)); + DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + bug20023_query_int_variable(&con, + "session.sql_big_selects", + &sql_big_selects_5); + + /* Check that SQL_BIG_SELECTS is 1. */ + + DIE_UNLESS(sql_big_selects_5 == sql_big_selects_orig); + + /*********************************************************************** + That's it. Cleanup. + ***********************************************************************/ + + mysql_close(&con); +} + /* Read and parse arguments and MySQL options from my.cnf @@ -17115,6 +17285,7 @@ static struct my_tests_st my_tests[]= { { "test_bug29306", test_bug29306 }, { "test_change_user", test_change_user }, { "test_bug30472", test_bug30472 }, + { "test_bug20023", test_bug20023 }, { 0, 0 } }; From ae462f3e772cb75abc2d64ae83d2f39c88c19fef Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Wed, 10 Oct 2007 19:06:53 -0300 Subject: [PATCH 31/55] Post-merge test case for Bug 21587 --- mysql-test/include/handler.inc | 35 ++++++++++++++++++++++++++++++ mysql-test/r/handler_innodb.result | 22 +++++++++++++++++++ mysql-test/r/handler_myisam.result | 22 +++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index 437dd6ced4d..c957fa81040 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -498,3 +498,38 @@ handler t1_alias read a next; handler t1_alias READ a next where inexistent > 0; handler t1_alias close; drop table t1; + +# +# Bug#21587 FLUSH TABLES causes server crash when used with HANDLER statements +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +create table t1 (c1 int); +create table t2 (c1 int); +insert into t1 values (1); +insert into t2 values (2); +--echo connection: default +handler t1 open; +handler t1 read first; +connect (flush,localhost,root,,); +connection flush; +--echo connection: flush +--send flush tables; +connection default; +--echo connection: default +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Flushing tables"; +--source include/wait_condition.inc +handler t2 open; +handler t2 read first; +handler t1 read next; +handler t1 close; +handler t2 close; +connection flush; +reap; +connection default; +drop table t1,t2; +disconnect flush; diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index 98b8922bc5f..45a6218585d 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -535,3 +535,25 @@ handler t1_alias READ a next where inexistent > 0; ERROR 42S22: Unknown column 'inexistent' in 'field list' handler t1_alias close; drop table t1; +drop table if exists t1,t2; +create table t1 (c1 int); +create table t2 (c1 int); +insert into t1 values (1); +insert into t2 values (2); +connection: default +handler t1 open; +handler t1 read first; +c1 +1 +connection: flush +flush tables;; +connection: default +handler t2 open; +handler t2 read first; +c1 +2 +handler t1 read next; +c1 +handler t1 close; +handler t2 close; +drop table t1,t2; diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index 464b775b795..bc4a8e9081a 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -535,3 +535,25 @@ handler t1_alias READ a next where inexistent > 0; ERROR 42S22: Unknown column 'inexistent' in 'field list' handler t1_alias close; drop table t1; +drop table if exists t1,t2; +create table t1 (c1 int); +create table t2 (c1 int); +insert into t1 values (1); +insert into t2 values (2); +connection: default +handler t1 open; +handler t1 read first; +c1 +1 +connection: flush +flush tables;; +connection: default +handler t2 open; +handler t2 read first; +c1 +2 +handler t1 read next; +c1 +handler t1 close; +handler t2 close; +drop table t1,t2; From 2f946efda79ce6de0c113a86a39094f641cf7ef0 Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Wed, 10 Oct 2007 21:07:23 -0300 Subject: [PATCH 32/55] Mismerge broken 5.1-runtime compilation because do_command was defined static but it's still used by another compilation unit. Remove static qualifier from do_command definition. --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3104f77d013..695e923e816 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -650,7 +650,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) 1 request of thread shutdown (see dispatch_command() description) */ -static bool do_command(THD *thd) +bool do_command(THD *thd) { char *packet= 0; ulong packet_length; From 4515ccf7c074c7044c9ddf681bbc8a70821d46d5 Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Wed, 10 Oct 2007 21:39:22 -0300 Subject: [PATCH 33/55] Post-merge test case for Bug 31409 --- mysql-test/include/handler.inc | 33 ++++++++++++++++++++++++++++++ mysql-test/r/handler_innodb.result | 18 ++++++++++++++++ mysql-test/r/handler_myisam.result | 18 ++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index c957fa81040..71647112126 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -533,3 +533,36 @@ reap; connection default; drop table t1,t2; disconnect flush; + +# +# Bug#31409 RENAME TABLE causes server crash or deadlock when used with HANDLER statements +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +create table t1 (c1 int); +--echo connection: default +handler t1 open; +handler t1 read first; +connect (flush,localhost,root,,); +connection flush; +--echo connection: flush +--send rename table t1 to t2; +connection default; +--echo connection: default +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table" and info = "rename table t1 to t2"; +--source include/wait_condition.inc +handler t2 open; +handler t2 read first; +--error ER_NO_SUCH_TABLE +handler t1 read next; +handler t1 close; +handler t2 close; +connection flush; +reap; +connection default; +drop table t2; +disconnect flush; diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index 45a6218585d..e9e5c7dbdd5 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -554,6 +554,24 @@ c1 2 handler t1 read next; c1 +1 handler t1 close; handler t2 close; drop table t1,t2; +drop table if exists t1,t2; +create table t1 (c1 int); +connection: default +handler t1 open; +handler t1 read first; +c1 +connection: flush +rename table t1 to t2;; +connection: default +handler t2 open; +handler t2 read first; +c1 +handler t1 read next; +ERROR 42S02: Table 'test.t1' doesn't exist +handler t1 close; +handler t2 close; +drop table t2; diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index bc4a8e9081a..715e5ab03d6 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -554,6 +554,24 @@ c1 2 handler t1 read next; c1 +1 handler t1 close; handler t2 close; drop table t1,t2; +drop table if exists t1,t2; +create table t1 (c1 int); +connection: default +handler t1 open; +handler t1 read first; +c1 +connection: flush +rename table t1 to t2;; +connection: default +handler t2 open; +handler t2 read first; +c1 +handler t1 read next; +ERROR 42S02: Table 'test.t1' doesn't exist +handler t1 close; +handler t2 close; +drop table t2; From 7237c31698176cd732923cca811e701391ccd217 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Thu, 11 Oct 2007 17:11:12 +0400 Subject: [PATCH 34/55] A patch for BUG#31418: User locks misfunctioning after mysql_change_user(). The problem was that THD::ull was not reset in THD::cleanup(). The fix is to reset it. --- sql/sql_class.cc | 1 + tests/mysql_client_test.c | 164 +++++++++++++++++++++++++++++++------- 2 files changed, 134 insertions(+), 31 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 490aedad0ef..09c8a79c15e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -698,6 +698,7 @@ void THD::cleanup(void) pthread_mutex_lock(&LOCK_user_locks); item_user_lock_release(ull); pthread_mutex_unlock(&LOCK_user_locks); + ull= NULL; } cleanup_done=1; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9505340c24f..801f2896107 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -16827,25 +16827,34 @@ static void bug20023_change_user(MYSQL *con) opt_db ? opt_db : "test")); } -static void bug20023_query_int_variable(MYSQL *con, - const char *var_name, - int *var_value) +static bool query_int_variable(MYSQL *con, + const char *var_name, + int *var_value) { MYSQL_RES *rs; MYSQL_ROW row; char query_buffer[MAX_TEST_QUERY_LENGTH]; + bool is_null; + my_snprintf(query_buffer, sizeof (query_buffer), - "SELECT @@%s", + "SELECT %s", (const char *) var_name); DIE_IF(mysql_query(con, query_buffer)); DIE_UNLESS(rs= mysql_store_result(con)); DIE_UNLESS(row= mysql_fetch_row(rs)); - *var_value= atoi(row[0]); + + is_null= row[0] == NULL; + + if (!is_null) + *var_value= atoi(row[0]); + mysql_free_result(rs); + + return is_null; } static void test_bug20023() @@ -16876,19 +16885,19 @@ static void test_bug20023() CLIENT_FOUND_ROWS)); /*********************************************************************** - Remember original SQL_BIG_SELECTS, MAX_JOIN_SIZE values. + Remember original SQL_BIG_SELECTS, MAX_JOIN_SIZE values. ***********************************************************************/ - bug20023_query_int_variable(&con, - "session.sql_big_selects", - &sql_big_selects_orig); + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_orig); - bug20023_query_int_variable(&con, - "global.max_join_size", - &max_join_size_orig); + query_int_variable(&con, + "@@global.max_join_size", + &max_join_size_orig); /*********************************************************************** - Test that COM_CHANGE_USER resets the SQL_BIG_SELECTS to the initial value. + Test that COM_CHANGE_USER resets the SQL_BIG_SELECTS to the initial value. ***********************************************************************/ /* Issue COM_CHANGE_USER. */ @@ -16897,17 +16906,17 @@ static void test_bug20023() /* Query SQL_BIG_SELECTS. */ - bug20023_query_int_variable(&con, - "session.sql_big_selects", - &sql_big_selects_2); + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_2); /* Check that SQL_BIG_SELECTS is reset properly. */ DIE_UNLESS(sql_big_selects_orig == sql_big_selects_2); /*********************************************************************** - Test that if MAX_JOIN_SIZE set to non-default value, - SQL_BIG_SELECTS will be 0. + Test that if MAX_JOIN_SIZE set to non-default value, + SQL_BIG_SELECTS will be 0. ***********************************************************************/ /* Set MAX_JOIN_SIZE to some non-default value. */ @@ -16921,17 +16930,17 @@ static void test_bug20023() /* Query SQL_BIG_SELECTS. */ - bug20023_query_int_variable(&con, - "session.sql_big_selects", - &sql_big_selects_3); + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_3); /* Check that SQL_BIG_SELECTS is 0. */ DIE_UNLESS(sql_big_selects_3 == 0); /*********************************************************************** - Test that if MAX_JOIN_SIZE set to default value, - SQL_BIG_SELECTS will be 1. + Test that if MAX_JOIN_SIZE set to default value, + SQL_BIG_SELECTS will be 1. ***********************************************************************/ /* Set MAX_JOIN_SIZE to the default value (-1). */ @@ -16945,17 +16954,17 @@ static void test_bug20023() /* Query SQL_BIG_SELECTS. */ - bug20023_query_int_variable(&con, - "session.sql_big_selects", - &sql_big_selects_4); + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_4); /* Check that SQL_BIG_SELECTS is 1. */ DIE_UNLESS(sql_big_selects_4 == 1); /*********************************************************************** - Restore MAX_JOIN_SIZE. - Check that SQL_BIG_SELECTS will be the original one. + Restore MAX_JOIN_SIZE. + Check that SQL_BIG_SELECTS will be the original one. ***********************************************************************/ /* Restore MAX_JOIN_SIZE. */ @@ -16974,14 +16983,95 @@ static void test_bug20023() /* Query SQL_BIG_SELECTS. */ - bug20023_query_int_variable(&con, - "session.sql_big_selects", - &sql_big_selects_5); + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_5); /* Check that SQL_BIG_SELECTS is 1. */ DIE_UNLESS(sql_big_selects_5 == sql_big_selects_orig); + /*********************************************************************** + That's it. Cleanup. + ***********************************************************************/ + + mysql_close(&con); +} + +static void bug31418_impl() +{ + MYSQL con; + + bool is_null; + int rc; + + /* 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)); + + /*********************************************************************** + Check that lock is free: + - IS_FREE_LOCK() should return 1; + - IS_USED_LOCK() should return NULL; + ***********************************************************************/ + + is_null= query_int_variable(&con, + "IS_FREE_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && rc); + + is_null= query_int_variable(&con, + "IS_USED_LOCK('bug31418')", + &rc); + DIE_UNLESS(is_null); + + /*********************************************************************** + Acquire lock and check the lock status (the lock must be in use): + - IS_FREE_LOCK() should return 0; + - IS_USED_LOCK() should return non-zero thread id; + ***********************************************************************/ + + query_int_variable(&con, "GET_LOCK('bug31418', 1)", &rc); + DIE_UNLESS(rc); + + is_null= query_int_variable(&con, + "IS_FREE_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && !rc); + + is_null= query_int_variable(&con, + "IS_USED_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && rc); + + /*********************************************************************** + Issue COM_CHANGE_USER command and check the lock status + (the lock must be free): + - IS_FREE_LOCK() should return 1; + - IS_USED_LOCK() should return NULL; + **********************************************************************/ + + bug20023_change_user(&con); + + is_null= query_int_variable(&con, + "IS_FREE_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && rc); + + is_null= query_int_variable(&con, + "IS_USED_LOCK('bug31418')", + &rc); + DIE_UNLESS(is_null); + /*********************************************************************** That's it. Cleanup. ***********************************************************************/ @@ -16989,6 +17079,17 @@ static void test_bug20023() mysql_close(&con); } +static void test_bug31418() +{ + /* Run test case for BUG#31418 for three different connections. */ + + bug31418_impl(); + + bug31418_impl(); + + bug31418_impl(); +} + /* Read and parse arguments and MySQL options from my.cnf @@ -17286,6 +17387,7 @@ static struct my_tests_st my_tests[]= { { "test_change_user", test_change_user }, { "test_bug30472", test_bug30472 }, { "test_bug20023", test_bug20023 }, + { "test_bug31418", test_bug31418 }, { 0, 0 } }; From 2adf38c12e80b942ef3728d7f68ce044c15d1758 Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Thu, 11 Oct 2007 17:38:40 -0300 Subject: [PATCH 35/55] Bug#29223 declare cursor c for SHOW ..... "DECLARE CURSOR FOR SHOW ..." is a syntax that currently appears to work, but is untested for some SHOW commands and does not work for other SHOW commands. Since this is an un-intended feature that leaked as a result of a coding bug (in the parser grammar), the correct fix is to fix the grammar to not accept this construct. In other words, "DECLARE CURSOR FOR SHOW " is not considered a bug, and we will not implement other features to make all the SHOW commands usable inside a cursor just because someone exploited a bug. --- mysql-test/r/sp-error.result | 21 ++++++++++++++++++++- mysql-test/t/information_schema.test | 2 +- mysql-test/t/sp-error.test | 23 ++++++++++++++++++++++- sql/sql_yacc.yy | 18 +++--------------- 4 files changed, 46 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index bfcd64e89d3..46b8adb85b8 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -142,7 +142,10 @@ declare c cursor for insert into test.t1 values ("foo", 42); open c; close c; end| -ERROR 42000: Cursor statement must be a SELECT +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 'insert into test.t1 values ("foo", 42); +open c; +close c; +end' at line 3 create procedure p() begin declare x int; @@ -1491,3 +1494,19 @@ 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 +DROP PROCEDURE IF EXISTS p1; +CREATE PROCEDURE p1() +BEGIN +DECLARE c char(100); +DECLARE cur1 CURSOR FOR SHOW TABLES; +OPEN cur1; +FETCH cur1 INTO c; +select c; +CLOSE cur1; +END| +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 'SHOW TABLES; +OPEN cur1; +FETCH cur1 INTO c; +select c; +CLOSE cur1; +END' at line 4 diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 6bcc14d4e49..9ad658645bd 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -953,7 +953,7 @@ BEGIN DECLARE col1, col2, col3, col4, col6 CHAR(255); DECLARE default_val VARCHAR(65532); DECLARE done INT DEFAULT 0; - DECLARE cur1 CURSOR FOR SHOW COLUMNS FROM bug23037; + DECLARE cur1 CURSOR FOR SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT, EXTRA FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='bug23037'; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur1; FETCH cur1 INTO col1, col2, col3, col4, default_val, col6; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index c9145859405..ad516f028e6 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -196,7 +196,7 @@ select f(10)| drop function f| ---error 1322 +--error ER_PARSE_ERROR create procedure p() begin declare c cursor for insert into test.t1 values ("foo", 42); @@ -2178,6 +2178,27 @@ END// delimiter ;// +# +# Bug#29223 declare cursor c for SHOW ..... +# + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +--enable_warnings +--delimiter | +--error ER_PARSE_ERROR +CREATE PROCEDURE p1() +BEGIN + DECLARE c char(100); + DECLARE cur1 CURSOR FOR SHOW TABLES; + + OPEN cur1; + FETCH cur1 INTO c; + select c; + CLOSE cur1; +END| +--delimiter ; + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 39175297753..0989e6e6b24 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2540,25 +2540,13 @@ sp_decl: sp_cursor_stmt: { Lex->sphead->reset_lex(YYTHD); - - /* - We use statement here just be able to get a better - error message. Using 'select' works too, but will then - result in a generic "syntax error" if a non-select - statement is given. - */ } - statement + select { LEX *lex= Lex; - if (lex->sql_command != SQLCOM_SELECT && - !(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)) - { - my_message(ER_SP_BAD_CURSOR_QUERY, ER(ER_SP_BAD_CURSOR_QUERY), - MYF(0)); - MYSQL_YYABORT; - } + DBUG_ASSERT(lex->sql_command == SQLCOM_SELECT); + if (lex->result) { my_message(ER_SP_BAD_CURSOR_SELECT, ER(ER_SP_BAD_CURSOR_SELECT), From 6428dacd44c8207ff7941711ef6219ccc64ba52a Mon Sep 17 00:00:00 2001 From: "malff/marcsql@weblab.(none)" <> Date: Thu, 11 Oct 2007 17:55:18 -0600 Subject: [PATCH 36/55] Bug#27858 (Failing to log to a log table doesn't log anything to error log) Before this patch, failures to write to the log tables (mysql.slow_log and mysql.general_log) were improperly printed (the time was printed twice), or not printed at all. With this patch, failures to write to the log tables is reported in the error log, for all cases of failures. --- mysql-test/r/log_tables.result | 4 +++ mysql-test/t/log_tables.test | 56 ++++++++++++++++++++++++++++++++++ sql/log.cc | 43 +++++++++++++------------- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index 9e67d328849..be0555024fa 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -270,6 +270,10 @@ use mysql; lock tables general_log read local, help_category read local; ERROR HY000: You can't use locks with log tables. unlock tables; +drop table if exists mysql.renamed_general_log; +drop table if exists mysql.renamed_slow_log; +drop table if exists mysql.general_log_new; +drop table if exists mysql.slow_log_new; use mysql; RENAME TABLE general_log TO renamed_general_log; ERROR HY000: Cannot rename 'general_log'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to 'general_log' diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index 89c7c255554..1d65c86295f 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -295,6 +295,13 @@ unlock tables; # Bug #21785 Server crashes after rename of the log table # +--disable_warnings +drop table if exists mysql.renamed_general_log; +drop table if exists mysql.renamed_slow_log; +drop table if exists mysql.general_log_new; +drop table if exists mysql.slow_log_new; +--enable_warnings + use mysql; # Should result in error --error ER_CANT_RENAME_LOG_TABLE @@ -358,6 +365,55 @@ flush logs; drop table renamed_general_log, renamed_slow_log; use test; +# +# Bug#27858 (Failing to log to a log table doesn't log anything to error log) +# +# This test works as expected, it's a negative test. +# The message "[ERROR] Failed to write to mysql.general_log" +# is printed to master.err when writing to the table mysql.general_log +# failed. +# However, this message is picked up by mysql-test-run.pl, +# and reported as a test failure, which is a false negative. +# There is no current way to *selectively* filter out these expected error conditions +# (see mysql-test/lib/mtr_report.pl, mtr_report_stats()). +# Instead of filtering all occurences of "Failed to write to +# mysql.general_log", which could hide bugs when the error is not expected, +# this test case is commented instead. +# TODO: improve filtering of expected errors in master.err in +# mysql-test-run.pl (based on the test name ?), and uncomment this test. + +# --disable_warnings +# drop table if exists mysql.bad_general_log; +# drop table if exists mysql.bad_slow_log; +# drop table if exists mysql.general_log_hide; +# drop table if exists mysql.slow_log_hide; +# --enable_warnings +# +# create table mysql.bad_general_log (a int) engine= CSV; +# create table mysql.bad_slow_log (a int) engine= CSV; +# +# # Rename does not perform checks on the table structure, +# # exploiting this to force a failure to log +# rename table mysql.general_log to mysql.general_log_hide, mysql.bad_general_log TO mysql.general_log; +# rename table mysql.slow_log to mysql.slow_log_hide, mysql.bad_slow_log TO mysql.slow_log; +# +# # The following message should be printed in master.log: +# # [ERROR] Failed to write to mysql.general_log +# # TODO: See how verifying this could be automated +# +# flush tables; +# select "logging this should fail"; +# +# # Restore the log tables +# +# rename table mysql.general_log to mysql.bad_general_log, mysql.general_log_hide TO mysql.general_log; +# rename table mysql.slow_log to mysql.bad_slow_log, mysql.slow_log_hide TO mysql.slow_log; +# +# flush tables; +# +# drop table mysql.bad_general_log; +# drop table mysql.bad_slow_log; + # # Bug #21966 Strange warnings on repair of the log tables # diff --git a/sql/log.cc b/sql/log.cc index 95204e89d0e..9d6f6fa4c9b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -387,10 +387,15 @@ bool Log_to_csv_event_handler:: if (table->field[1]->store(user_host, user_host_len, client_cs) || table->field[2]->store((longlong) thread_id, TRUE) || table->field[3]->store((longlong) server_id, TRUE) || - table->field[4]->store(command_type, command_type_len, client_cs) || - table->field[5]->store(sql_text, sql_text_len, client_cs)) + table->field[4]->store(command_type, command_type_len, client_cs)) goto err; + /* + A positive return value in store() means truncation. + Still logging a message in the log in this case. + */ + if (table->field[5]->store(sql_text, sql_text_len, client_cs) < 0) + goto err; /* mark all fields as not null */ table->field[1]->set_notnull(); @@ -407,19 +412,14 @@ bool Log_to_csv_event_handler:: /* log table entries are not replicated */ if (table->file->ha_write_row(table->record[0])) - { - struct tm start; - localtime_r(&event_time, &start); - - sql_print_error("%02d%02d%02d %2d:%02d:%02d - Failed to write to mysql.general_log", - start.tm_year % 100, start.tm_mon + 1, - start.tm_mday, start.tm_hour, - start.tm_min, start.tm_sec); - } + goto err; result= FALSE; err: + if (result) + sql_print_error("Failed to write to mysql.general_log"); + if (need_rnd_end) { table->file->ha_rnd_end(); @@ -595,25 +595,24 @@ bool Log_to_csv_event_handler:: goto err; table->field[9]->set_notnull(); - /* sql_text */ - if (table->field[10]->store(sql_text,sql_text_len, client_cs)) + /* + Column sql_text. + A positive return value in store() means truncation. + Still logging a message in the log in this case. + */ + if (table->field[10]->store(sql_text, sql_text_len, client_cs) < 0) goto err; /* log table entries are not replicated */ if (table->file->ha_write_row(table->record[0])) - { - struct tm start; - localtime_r(¤t_time, &start); - - sql_print_error("%02d%02d%02d %2d:%02d:%02d - Failed to write to mysql.slow_log", - start.tm_year % 100, start.tm_mon + 1, - start.tm_mday, start.tm_hour, - start.tm_min, start.tm_sec); - } + goto err; result= FALSE; err: + if (result) + sql_print_error("Failed to write to mysql.slow_log"); + if (need_rnd_end) { table->file->ha_rnd_end(); From b92f3309f1c020ab146d0d5e685249535018c1fc Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Fri, 12 Oct 2007 10:55:46 -0300 Subject: [PATCH 37/55] Bug#31409 RENAME TABLE causes server crash or deadlock when used with HANDLER statements If mysql_lock_tables fails because the lock was aborted, we need to reset thd->some_tables_delete, otherwise we might loop indefinitely because handler's tables are not closed in a standard way, meaning that close_thread_tables() (which resets some_tables_deleted) is not used. This patch fixes sporadical failures of handler_myisam/innodb tests which were introduced by previous fix for this bug. --- sql/sql_handler.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e87381dd49c..822f2b2c419 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -466,6 +466,12 @@ retry: { mysql_ha_close_table(thd, tables); hash_tables->table= NULL; + /* + The lock might have been aborted, we need to manually reset + thd->some_tables_deleted because handler's tables are closed + in a non-standard way. Otherwise we might loop indefinitely. + */ + thd->some_tables_deleted= 0; goto retry; } From 227e13c4ca728c20c860ce89dfc8b446d1b89bc2 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 15 Oct 2007 15:45:20 +0400 Subject: [PATCH 38/55] Remove an unused variable that was there since the first implementation of the stored procedure cursors (materialized on disk). --- include/mysql_com.h | 2 +- sql/protocol.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 5850d48fbf5..f76486b9ec2 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -203,7 +203,7 @@ typedef struct st_net { unsigned char reading_or_writing; char save_char; my_bool no_send_ok; /* For SPs and other things that do multiple stmts */ - my_bool no_send_eof; /* For SPs' first version read-only cursors */ + my_bool unused; /* Please remove with the next incompatible ABI change */ my_bool compress; /* Set if OK packet is already sent, and we do not need to send error diff --git a/sql/protocol.cc b/sql/protocol.cc index 2ed241c4c98..9d473912ba3 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -346,7 +346,7 @@ send_eof(THD *thd) { NET *net= &thd->net; DBUG_ENTER("send_eof"); - if (net->vio != 0 && !net->no_send_eof) + if (net->vio != 0) { write_eof_packet(thd, net); VOID(net_flush(net)); From 5cda50307fcbbac7aaeba13e110f9e0b669a9bd1 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 15 Oct 2007 15:49:16 +0400 Subject: [PATCH 39/55] Fix broken compilation. --- sql/net_serv.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 1f75d7ab1d7..18cf1ebae5b 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -123,7 +123,7 @@ my_bool my_net_init(NET *net, Vio* vio) MYF(MY_WME)))) DBUG_RETURN(1); net->buff_end=net->buff+net->max_packet; - net->no_send_ok= net->no_send_eof= net->no_send_error= 0; + net->no_send_ok= net->no_send_error= 0; net->error=0; net->return_errno=0; net->return_status=0; net->pkt_nr=net->compress_pkt_nr=0; net->write_pos=net->read_pos = net->buff; From 1c9e362f759ec6d6d79fee6414e698d89846a463 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 15 Oct 2007 16:42:41 +0400 Subject: [PATCH 40/55] Add comments, tidy up sql_delete.cc to refer to thd->row_count_func explicitly. --- sql/sql_class.cc | 12 ++++++++++++ sql/sql_delete.cc | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 09c8a79c15e..893ecf88a96 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1423,7 +1423,14 @@ bool select_to_file::send_eof() if (my_close(file,MYF(MY_WME))) error= 1; if (!error) + { + /* + In order to remember the value of affected rows for ROW_COUNT() + function, SELECT INTO has to have an own SQLCOM. + TODO: split from SQLCOM_SELECT + */ ::send_ok(thd,row_count); + } file= -1; return error; } @@ -2338,6 +2345,11 @@ bool select_dumpvar::send_eof() if (! row_count) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA)); + /* + In order to remember the value of affected rows for ROW_COUNT() + function, SELECT INTO has to have an own SQLCOM. + TODO: split from SQLCOM_SELECT + */ ::send_ok(thd,row_count); return 0; } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 303918f42a2..4c57fad8d87 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -142,7 +142,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, { free_underlaid_joins(thd, select_lex); thd->row_count_func= 0; - send_ok(thd); // No matching records + send_ok(thd, (ha_rows) thd->row_count_func); // No matching records DBUG_RETURN(0); } #endif @@ -159,7 +159,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, delete select; free_underlaid_joins(thd, select_lex); thd->row_count_func= 0; - send_ok(thd,0L); + send_ok(thd, (ha_rows) thd->row_count_func); /* We don't need to call reset_auto_increment in this case, because mysql_truncate always gives a NULL conds argument, hence we never @@ -386,7 +386,7 @@ cleanup: if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error)) { thd->row_count_func= deleted; - send_ok(thd,deleted); + send_ok(thd, (ha_rows) thd->row_count_func); DBUG_PRINT("info",("%ld records deleted",(long) deleted)); } DBUG_RETURN(error >= 0 || thd->net.report_error); @@ -889,7 +889,7 @@ bool multi_delete::send_eof() if (!local_error) { thd->row_count_func= deleted; - ::send_ok(thd, deleted); + ::send_ok(thd, (ha_rows) thd->row_count_func); } return 0; } From 223536e526f0bfaaa74660212d9f7da078f58f18 Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Mon, 15 Oct 2007 15:53:39 -0400 Subject: [PATCH 41/55] fix problem caused by previous submission for bugs BUG#29589 BUG#29772 --- sql/set_var.cc | 241 +++++++------------------------------------------ 1 file changed, 32 insertions(+), 209 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index cbf07182fc9..697de9cda97 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -620,216 +620,39 @@ static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname); sys_var_thd_bool sys_keep_files_on_create(&vars, "keep_files_on_create", &SV::keep_files_on_create); +/* Read only variables */ -/* - List of all variables for initialisation and storage in hash - This is sorted in alphabetical order to make it easy to add new variables - - If the variable is not in this list, it can't be changed with - SET variable_name= -*/ - -sys_var *sys_variables[]= -{ - &sys_auto_is_null, - &sys_auto_increment_increment, - &sys_auto_increment_offset, - &sys_autocommit, - &sys_automatic_sp_privileges, - &sys_basedir, - &sys_big_tables, - &sys_big_selects, - &sys_binlog_cache_size, - &sys_buffer_results, - &sys_bulk_insert_buff_size, - &sys_character_set_server, - &sys_character_set_database, - &sys_character_set_client, - &sys_character_set_connection, - &sys_character_set_results, - &sys_character_set_filesystem, - &sys_charset_system, - &sys_collation_connection, - &sys_collation_database, - &sys_collation_server, - &sys_completion_type, - &sys_concurrent_insert, - &sys_connect_timeout, - &sys_datadir, - &sys_date_format, - &sys_datetime_format, - &sys_div_precincrement, - &sys_default_week_format, - &sys_delay_key_write, - &sys_delayed_insert_limit, - &sys_delayed_insert_timeout, - &sys_delayed_queue_size, - &sys_keep_files_on_create, - &sys_error_count, - &sys_expire_logs_days, - &sys_flush, - &sys_flush_time, - &sys_ft_boolean_syntax, - &sys_foreign_key_checks, - &sys_group_concat_max_len, - &sys_have_innodb, - &sys_hostname, - &sys_identity, - &sys_init_connect, - &sys_init_slave, - &sys_insert_id, - &sys_interactive_timeout, - &sys_join_buffer_size, - &sys_key_buffer_size, - &sys_key_cache_block_size, - &sys_key_cache_division_limit, - &sys_key_cache_age_threshold, - &sys_last_insert_id, - &sys_lc_time_names, - &sys_license, - &sys_local_infile, - &sys_log_binlog, - &sys_log_off, - &sys_log_queries_not_using_indexes, - &sys_log_update, - &sys_log_warnings, - &sys_long_query_time, - &sys_low_priority_updates, - &sys_max_allowed_packet, - &sys_max_binlog_cache_size, - &sys_max_binlog_size, - &sys_max_connect_errors, - &sys_max_connections, - &sys_max_delayed_threads, - &sys_max_error_count, - &sys_max_insert_delayed_threads, - &sys_max_heap_table_size, - &sys_max_join_size, - &sys_max_length_for_sort_data, - &sys_max_prepared_stmt_count, - &sys_max_relay_log_size, - &sys_max_seeks_for_key, - &sys_max_sort_length, - &sys_max_sp_recursion_depth, - &sys_max_tmp_tables, - &sys_max_user_connections, - &sys_max_write_lock_count, - &sys_multi_range_count, - &sys_myisam_data_pointer_size, - &sys_myisam_max_sort_file_size, - &sys_myisam_repair_threads, - &sys_myisam_sort_buffer_size, - &sys_myisam_stats_method, - &sys_net_buffer_length, - &sys_net_read_timeout, - &sys_net_retry_count, - &sys_net_wait_timeout, - &sys_net_write_timeout, - &sys_new_mode, - &sys_old_passwords, - &sys_optimizer_prune_level, - &sys_optimizer_search_depth, - &sys_preload_buff_size, - &sys_pseudo_thread_id, - &sys_query_alloc_block_size, - &sys_query_cache_size, - &sys_query_prealloc_size, -#ifdef HAVE_QUERY_CACHE - &sys_query_cache_limit, - &sys_query_cache_min_res_unit, - &sys_query_cache_type, - &sys_query_cache_wlock_invalidate, -#endif /* HAVE_QUERY_CACHE */ - &sys_quote_show_create, - &sys_rand_seed1, - &sys_rand_seed2, - &sys_range_alloc_block_size, - &sys_readonly, - &sys_read_buff_size, - &sys_read_rnd_buff_size, -#ifdef HAVE_REPLICATION - &sys_relay_log_purge, -#endif - &sys_rpl_recovery_rank, - &sys_safe_updates, - &sys_secure_auth, - &sys_secure_file_priv, - &sys_select_limit, - &sys_server_id, -#ifdef HAVE_REPLICATION - &sys_slave_compressed_protocol, - &sys_slave_net_timeout, - &sys_slave_trans_retries, - &sys_slave_skip_counter, -#endif - &sys_slow_launch_time, - &sys_sort_buffer, - &sys_sql_big_tables, - &sys_sql_low_priority_updates, - &sys_sql_max_join_size, - &sys_sql_mode, - &sys_sql_warnings, - &sys_sql_notes, - &sys_ssl_ca, - &sys_ssl_capath, - &sys_ssl_cert, - &sys_ssl_cipher, - &sys_ssl_key, - &sys_storage_engine, -#ifdef HAVE_REPLICATION - &sys_sync_binlog_period, -#endif - &sys_sync_frm, - &sys_system_time_zone, - &sys_table_cache_size, - &sys_table_lock_wait_timeout, - &sys_table_type, - &sys_thread_cache_size, - &sys_time_format, - &sys_timed_mutexes, - &sys_timestamp, - &sys_time_zone, - &sys_tmpdir, - &sys_tmp_table_size, - &sys_trans_alloc_block_size, - &sys_trans_prealloc_size, - &sys_tx_isolation, - &sys_version, -#ifdef HAVE_BERKELEY_DB - &sys_version_bdb, -#endif - &sys_version_comment, - &sys_version_compile_machine, - &sys_version_compile_os, -#ifdef HAVE_INNOBASE_DB - &sys_innodb_fast_shutdown, - &sys_innodb_max_dirty_pages_pct, - &sys_innodb_max_purge_lag, - &sys_innodb_table_locks, - &sys_innodb_support_xa, - &sys_innodb_autoextend_increment, - &sys_innodb_sync_spin_loops, - &sys_innodb_concurrency_tickets, - &sys_innodb_thread_sleep_delay, - &sys_innodb_thread_concurrency, - &sys_innodb_commit_concurrency, - &sys_innodb_flush_log_at_trx_commit, -#endif - &sys_trust_routine_creators, - &sys_trust_function_creators, - &sys_engine_condition_pushdown, -#ifdef HAVE_NDBCLUSTER_DB - &sys_ndb_autoincrement_prefetch_sz, - &sys_ndb_cache_check_time, - &sys_ndb_connectstring, - &sys_ndb_force_send, - &sys_ndb_use_exact_count, - &sys_ndb_use_transactions, -#endif - &sys_unique_checks, - &sys_updatable_views_with_limit, - &sys_warning_count -}; +static sys_var_have_variable sys_have_compress(&vars, "have_compress", &have_compress); +static sys_var_have_variable sys_have_crypt(&vars, "have_crypt", &have_crypt); +static sys_var_have_plugin sys_have_csv(&vars, "have_csv", C_STRING_WITH_LEN("csv"), MYSQL_STORAGE_ENGINE_PLUGIN); +static sys_var_have_variable sys_have_dlopen(&vars, "have_dynamic_loading", &have_dlopen); +static sys_var_have_variable sys_have_geometry(&vars, "have_geometry", &have_geometry); +static sys_var_have_plugin sys_have_innodb(&vars, "have_innodb", C_STRING_WITH_LEN("innodb"), MYSQL_STORAGE_ENGINE_PLUGIN); +static sys_var_have_plugin sys_have_ndbcluster(&vars, "have_ndbcluster", C_STRING_WITH_LEN("ndbcluster"), MYSQL_STORAGE_ENGINE_PLUGIN); +static sys_var_have_variable sys_have_openssl(&vars, "have_openssl", &have_ssl); +static sys_var_have_variable sys_have_ssl(&vars, "have_ssl", &have_ssl); +static sys_var_have_plugin sys_have_partition_db(&vars, "have_partitioning", C_STRING_WITH_LEN("partition"), MYSQL_STORAGE_ENGINE_PLUGIN); +static sys_var_have_variable sys_have_query_cache(&vars, "have_query_cache", + &have_query_cache); +static sys_var_have_variable sys_have_rtree_keys(&vars, "have_rtree_keys", &have_rtree_keys); +static sys_var_have_variable sys_have_symlink(&vars, "have_symlink", &have_symlink); +/* Global read-only variable describing server license */ +static sys_var_const_str sys_license(&vars, "license", STRINGIFY_ARG(LICENSE)); +/* Global variables which enable|disable logging */ +static sys_var_log_state sys_var_general_log(&vars, "general_log", &opt_log, + QUERY_LOG_GENERAL); +static sys_var_log_state sys_var_slow_query_log(&vars, "slow_query_log", &opt_slow_log, + QUERY_LOG_SLOW); +sys_var_str sys_var_general_log_path(&vars, "general_log_file", sys_check_log_path, + sys_update_general_log_path, + sys_default_general_log_path, + opt_logname); +sys_var_str sys_var_slow_log_path(&vars, "slow_query_log_file", sys_check_log_path, + sys_update_slow_log_path, + sys_default_slow_log_path, + opt_slow_logname); +static sys_var_log_output sys_var_log_output_state(&vars, "log_output", &log_output_options, + &log_output_typelib, 0); /* From 99a270ba0f86ed5a163b7f570a0808eb6e4eb8cb Mon Sep 17 00:00:00 2001 From: "malff@lambda.hsd1.co.comcast.net." <> Date: Mon, 15 Oct 2007 19:15:38 -0600 Subject: [PATCH 42/55] Bug#28318 (CREATE FUNCTION (UDF) requires a schema) -- part II The root cause of the issue was that the CREATE FUNCTION grammar, for User Defined Functions, was using the sp_name rule. The sp_name rule is intended for fully qualified stored procedure names, like either ident.ident, or just ident but with a default database implicitly selected. A UDF does not have a fully qualified name, only a name (ident), and should not use the sp_name grammar fragment during parsing. The fix is to re-organize the CREATE FUNCTION grammar, to better separate: - creating UDF (no definer, can have AGGREGATE, simple ident) - creating Stored Functions (definer, no AGGREGATE, fully qualified name) With the test case provided, another issue was exposed which is also fixed: the DROP FUNCTION statement was using sp_name and also failing when no database is implicitly selected, when droping UDF functions. The fix is also to change the grammar so that DROP FUNCTION works with both the ident.ident syntax (to drop a stored function), or just the ident syntax (to drop either a UDF or a Stored Function, in the current database) --- mysql-test/r/sp-error.result | 4 +- mysql-test/r/udf.result | 4 +- mysql-test/t/sp-error.test | 7 +- mysql-test/t/udf.test | 4 +- sql/sql_parse.cc | 6 - sql/sql_yacc.yy | 412 +++++++++++++++++++---------------- 6 files changed, 233 insertions(+), 204 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index cc217ecd093..b4bcfbdc7f7 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1211,7 +1211,7 @@ ERROR 42S02: Unknown table 'c' in field list drop procedure bug15091; drop function if exists bug16896; create aggregate function bug16896() returns int return 1; -ERROR 42000: AGGREGATE is not supported for stored functions +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 '() returns int return 1' at line 1 DROP PROCEDURE IF EXISTS bug14702; CREATE IF NOT EXISTS PROCEDURE bug14702() BEGIN @@ -1457,7 +1457,7 @@ CREATE DATABASE mysqltest; USE mysqltest; DROP DATABASE mysqltest; SELECT inexistent(), 1 + ,; -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 '' at line 1 +ERROR 42000: FUNCTION inexistent does not exist SELECT inexistent(); ERROR 42000: FUNCTION inexistent does not exist SELECT .inexistent(); diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 3e29c780ca8..4a12e8e6d81 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -95,10 +95,10 @@ FR DROP TABLE bug19904; CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse RETURNS STRING SONAME "should_not_parse.so"; -ERROR HY000: Incorrect usage of SONAME and DEFINER +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 'RETURNS STRING SONAME "should_not_parse.so"' at line 2 CREATE DEFINER=someone@somewhere FUNCTION should_not_parse RETURNS STRING SONAME "should_not_parse.so"; -ERROR HY000: Incorrect usage of SONAME and DEFINER +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 'RETURNS STRING SONAME "should_not_parse.so"' at line 2 create table t1(f1 int); insert into t1 values(1),(2); explain select myfunc_int(f1) from t1 order by 1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index a1abf4852b0..8133a2271a1 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1744,7 +1744,7 @@ drop procedure bug15091; drop function if exists bug16896; --enable_warnings ---error ER_SP_NO_AGGREGATE +--error ER_PARSE_ERROR create aggregate function bug16896() returns int return 1; @@ -2099,7 +2099,10 @@ DROP DATABASE IF EXISTS mysqltest; CREATE DATABASE mysqltest; USE mysqltest; DROP DATABASE mysqltest; ---error ER_PARSE_ERROR +# Both ER_SP_DOES_NOT_EXIST and ER_PARSE_ERROR are valid here, +# the result is implementation dependent: +# See Bug#29816 for details +--error ER_SP_DOES_NOT_EXIST SELECT inexistent(), 1 + ,; --error ER_SP_DOES_NOT_EXIST SELECT inexistent(); diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 6a516a29534..14aef3361e4 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -113,11 +113,11 @@ DROP TABLE bug19904; # Bug#21269: DEFINER-clause is allowed for UDF-functions # ---error ER_WRONG_USAGE +--error ER_PARSE_ERROR CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse RETURNS STRING SONAME "should_not_parse.so"; ---error ER_WRONG_USAGE +--error ER_PARSE_ERROR CREATE DEFINER=someone@somewhere FUNCTION should_not_parse RETURNS STRING SONAME "should_not_parse.so"; # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8c61243e3c5..a111208cbf9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4016,12 +4016,6 @@ end_with_restore_list: if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0)) break; #ifdef HAVE_DLOPEN - if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, - &thd->sp_func_cache, FALSE)) - { - my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str); - goto error; - } if (!(res = mysql_create_function(thd, &lex->udf))) send_ok(thd); #else diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9c07add98d4..c1012b66bf4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1121,8 +1121,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type cast_type -%type udf_func_type - %type FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword keyword_sp %type user grant_user @@ -1181,11 +1179,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); statement sp_suid sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec - definer view_replace_or_algorithm view_replace view_algorithm_opt - view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail + view_replace_or_algorithm view_replace view_algorithm_opt + view_algorithm view_or_trigger_or_sp definer_tail view_suid view_tail view_list_opt view_list view_select - view_check_option trigger_tail sp_tail + view_check_option trigger_tail sp_tail sf_tail udf_tail case_stmt_specification simple_case_stmt searched_case_stmt + definer_opt no_definer definer END_OF_INPUT %type call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -1570,15 +1569,14 @@ sp_name: | ident { LEX *lex= Lex; - LEX_STRING db= {0,0}; - THD *thd= YYTHD; + LEX_STRING db; if (check_routine_name($1)) { my_error(ER_SP_WRONG_NAME, MYF(0), $1.str); MYSQL_YYABORT; } - if (thd->db && thd->copy_db_to(&db.str, &db.length)) + if (lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; $$= new sp_name(db, $1, false); if ($$) @@ -1586,131 +1584,6 @@ sp_name: } ; -create_function_tail: - RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys - { - LEX *lex=Lex; - if (lex->definer != NULL) - { - /* - DEFINER is a concept meaningful when interpreting SQL code. - UDF functions are compiled. - Using DEFINER with UDF has therefore no semantic, - and is considered a parsing error. - */ - my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER"); - MYSQL_YYABORT; - } - lex->sql_command = SQLCOM_CREATE_FUNCTION; - lex->udf.name = lex->spname->m_name; - lex->udf.returns=(Item_result) $2; - lex->udf.dl=$4.str; - } - | '(' - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - sp_head *sp; - - /* - First check if AGGREGATE was used, in that case it's a - syntax error. - */ - if (lex->udf.type == UDFTYPE_AGGREGATE) - { - my_error(ER_SP_NO_AGGREGATE, MYF(0)); - MYSQL_YYABORT; - } - - if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } - - if (!lex->spname->m_db.length) - { - my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); - MYSQL_YYABORT; - } - - /* Order is important here: new - reset - init */ - sp= new sp_head(); - sp->reset_thd_mem_root(thd); - sp->init(lex); - sp->init_sp_name(thd, lex->spname); - - sp->m_type= TYPE_ENUM_FUNCTION; - lex->sphead= sp; - /* - * We have to turn of CLIENT_MULTI_QUERIES while parsing a - * stored procedure, otherwise yylex will chop it into pieces - * at each ';'. - */ - sp->m_old_cmq= thd->client_capabilities & CLIENT_MULTI_QUERIES; - thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; - lex->sphead->m_param_begin= lip->tok_start+1; - } - sp_fdparam_list ')' - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lex->sphead->m_param_end= lip->tok_start; - } - RETURNS_SYM - { - LEX *lex= Lex; - lex->charset= NULL; - lex->length= lex->dec= NULL; - lex->interval_list.empty(); - lex->type= 0; - } - type - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - - if (sp->fill_field_definition(YYTHD, lex, - (enum enum_field_types) $8, - &sp->m_return_field_def)) - MYSQL_YYABORT; - - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); - } - sp_c_chistics - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->m_body_begin= lip->tok_start; - } - sp_proc_stmt - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - - if (sp->is_not_allowed_in_function("function")) - MYSQL_YYABORT; - - lex->sql_command= SQLCOM_CREATE_SPFUNCTION; - sp->init_strings(YYTHD, lex); - if (!(sp->m_flags & sp_head::HAS_RETURN)) - { - my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); - MYSQL_YYABORT; - } - /* Restore flag if it was cleared above */ - if (sp->m_old_cmq) - YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; - sp->restore_thd_mem_root(YYTHD); - } - ; - sp_a_chistics: /* Empty */ {} | sp_a_chistics sp_chistic {} @@ -3011,10 +2884,6 @@ opt_select_from: opt_limit_clause {} | select_from select_lock_type; -udf_func_type: - /* empty */ { $$ = UDFTYPE_FUNCTION; } - | AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; }; - udf_type: STRING_SYM {$$ = (int) STRING_RESULT; } | REAL {$$ = (int) REAL_RESULT; } @@ -3678,7 +3547,7 @@ alter: lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->spname= $3; } - | ALTER view_algorithm_opt definer view_suid + | ALTER view_algorithm_opt definer_opt view_suid VIEW_SYM table_ident { THD *thd= YYTHD; @@ -5204,9 +5073,31 @@ simple_expr: #endif /* HAVE_DLOPEN */ { THD *thd= lex->thd; - LEX_STRING db= {0,0}; - if (thd->db && thd->copy_db_to(&db.str, &db.length)) + LEX_STRING db; + if (! thd->db && ! lex->sphead) + { + /* + The proper error message should be in the lines of: + Can't resolve () to a function call, + because this function: + - is not a native function, + - is not a user defined function, + - can not match a stored function since no database is selected. + Reusing ER_SP_DOES_NOT_EXIST have a message consistent with + the case when a default database exist, see below. + */ + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), + "FUNCTION", $1); MYSQL_YYABORT; + } + + if (lex->copy_db_to(&db.str, &db.length)) + MYSQL_YYABORT; + + /* + From here, the parser assumes () is a stored function, + as a last choice. This later can lead to ER_SP_DOES_NOT_EXIST. + */ sp_name *name= new sp_name(db, $1, false); if (name) name->init_qname(thd); @@ -6508,9 +6399,11 @@ drop: lex->drop_if_exists=$3; lex->name=$4.str; } - | DROP FUNCTION_SYM if_exists sp_name + | DROP FUNCTION_SYM if_exists ident '.' ident { - LEX *lex=Lex; + THD *thd= YYTHD; + LEX *lex= thd->lex; + sp_name *spname; if (lex->sphead) { my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); @@ -6518,7 +6411,28 @@ drop: } lex->sql_command = SQLCOM_DROP_FUNCTION; lex->drop_if_exists= $3; - lex->spname= $4; + spname= new sp_name($4, $6, true); + spname->init_qname(thd); + lex->spname= spname; + } + | DROP FUNCTION_SYM if_exists ident + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + LEX_STRING db= {0, 0}; + sp_name *spname; + if (lex->sphead) + { + my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); + MYSQL_YYABORT; + } + if (thd->db && lex->copy_db_to(&db.str, &db.length)) + MYSQL_YYABORT; + lex->sql_command = SQLCOM_DROP_FUNCTION; + lex->drop_if_exists= $3; + spname= new sp_name(db, $4, false); + spname->init_qname(thd); + lex->spname= spname; } | DROP PROCEDURE if_exists sp_name { @@ -9567,19 +9481,27 @@ subselect_end: **************************************************************************/ view_or_trigger_or_sp: - definer view_or_trigger_or_sp_tail - {} - | view_replace_or_algorithm definer view_tail - {} + definer definer_tail + {} + | no_definer no_definer_tail + {} + | view_replace_or_algorithm definer_opt view_tail + {} ; -view_or_trigger_or_sp_tail: - view_tail - {} +definer_tail: + view_tail | trigger_tail - {} | sp_tail - {} + | sf_tail + ; + +no_definer_tail: + view_tail + | trigger_tail + | sp_tail + | sf_tail + | udf_tail ; /************************************************************************** @@ -9588,23 +9510,31 @@ view_or_trigger_or_sp_tail: **************************************************************************/ +definer_opt: + no_definer + | definer + ; + +no_definer: + /* empty */ + { + /* + We have to distinguish missing DEFINER-clause from case when + CURRENT_USER specified as definer explicitly in order to properly + handle CREATE TRIGGER statements which come to replication thread + from older master servers (i.e. to create non-suid trigger in this + case). + */ + YYTHD->lex->definer= 0; + } + ; + definer: - /* empty */ - { - /* - We have to distinguish missing DEFINER-clause from case when - CURRENT_USER specified as definer explicitly in order to properly - handle CREATE TRIGGER statements which come to replication thread - from older master servers (i.e. to create non-suid trigger in this - case). - */ - YYTHD->lex->definer= 0; - } - | DEFINER_SYM EQ user - { - YYTHD->lex->definer= get_current_user(YYTHD, $3); - } - ; + DEFINER_SYM EQ user + { + YYTHD->lex->definer= get_current_user(YYTHD, $3); + } +; /************************************************************************** @@ -9755,12 +9685,6 @@ trigger_tail: MYSQL_YYABORT; } - if (!$3->m_db.length) - { - my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); - MYSQL_YYABORT; - } - if (!(sp= new sp_head())) MYSQL_YYABORT; sp->reset_thd_mem_root(thd); @@ -9822,17 +9746,131 @@ trigger_tail: **************************************************************************/ +udf_tail: + AGGREGATE_SYM remember_name FUNCTION_SYM ident + RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_CREATE_FUNCTION; + lex->udf.type= UDFTYPE_AGGREGATE; + lex->stmt_definition_begin= $2; + lex->udf.name = $4; + lex->udf.returns=(Item_result) $6; + lex->udf.dl=$8.str; + } + | remember_name FUNCTION_SYM ident + RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_CREATE_FUNCTION; + lex->udf.type= UDFTYPE_FUNCTION; + lex->stmt_definition_begin= $1; + lex->udf.name = $3; + lex->udf.returns=(Item_result) $5; + lex->udf.dl=$7.str; + } + ; + +sf_tail: + remember_name /* $1 */ + FUNCTION_SYM /* $2 */ + sp_name /* $3 */ + '(' /* 44 */ + { /* $5 */ + THD *thd= YYTHD; + LEX *lex= thd->lex; + Lex_input_stream *lip= thd->m_lip; + sp_head *sp; + + lex->stmt_definition_begin= $1; + lex->spname= $3; + + if (lex->sphead) + { + my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION"); + MYSQL_YYABORT; + } + + /* Order is important here: new - reset - init */ + sp= new sp_head(); + sp->reset_thd_mem_root(thd); + sp->init(lex); + sp->init_sp_name(thd, lex->spname); + + sp->m_type= TYPE_ENUM_FUNCTION; + lex->sphead= sp; + /* + * We have to turn of CLIENT_MULTI_QUERIES while parsing a + * stored procedure, otherwise yylex will chop it into pieces + * at each ';'. + */ + sp->m_old_cmq= thd->client_capabilities & CLIENT_MULTI_QUERIES; + thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; + lex->sphead->m_param_begin= lip->tok_start+1; + } + sp_fdparam_list /* $6 */ + ')' /* $7 */ + { /* $8 */ + THD *thd= YYTHD; + LEX *lex= thd->lex; + Lex_input_stream *lip= thd->m_lip; + + lex->sphead->m_param_end= lip->tok_start; + } + RETURNS_SYM /* $9 */ + { /* $10 */ + LEX *lex= Lex; + lex->charset= NULL; + lex->length= lex->dec= NULL; + lex->interval_list.empty(); + lex->type= 0; + } + type /* $11 */ + { /* $12 */ + LEX *lex= Lex; + sp_head *sp= lex->sphead; + + if (sp->fill_field_definition(YYTHD, lex, + (enum enum_field_types) $11, + &sp->m_return_field_def)) + MYSQL_YYABORT; + + bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); + } + sp_c_chistics /* $13 */ + { /* $14 */ + THD *thd= YYTHD; + LEX *lex= thd->lex; + Lex_input_stream *lip= thd->m_lip; + + lex->sphead->m_chistics= &lex->sp_chistics; + lex->sphead->m_body_begin= lip->tok_start; + } + sp_proc_stmt /* $15 */ + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + + if (sp->is_not_allowed_in_function("function")) + MYSQL_YYABORT; + + lex->sql_command= SQLCOM_CREATE_SPFUNCTION; + sp->init_strings(YYTHD, lex); + if (!(sp->m_flags & sp_head::HAS_RETURN)) + { + my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); + MYSQL_YYABORT; + } + /* Restore flag if it was cleared above */ + if (sp->m_old_cmq) + YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; + sp->restore_thd_mem_root(YYTHD); + } + ; + + sp_tail: - udf_func_type remember_name FUNCTION_SYM sp_name - { - LEX *lex=Lex; - lex->udf.type= $1; - lex->stmt_definition_begin= $2; - lex->spname= $4; - } - create_function_tail - {} - | PROCEDURE remember_name sp_name + PROCEDURE remember_name sp_name { LEX *lex= Lex; sp_head *sp; @@ -9843,12 +9881,6 @@ sp_tail: MYSQL_YYABORT; } - if (!$3->m_db.length) - { - my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); - MYSQL_YYABORT; - } - lex->stmt_definition_begin= $2; /* Order is important here: new - reset - init */ From 8c86e79aa36ce8b41b8ac4b2e1b14f88215674fb Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Tue, 16 Oct 2007 14:42:42 +0200 Subject: [PATCH 43/55] Bug#30710 query_cache.test fails on embedded - per-column privs test The embedded version of the server doesn't use column level grants, and the compile directive NO_EMBEDDED_ACCESS_CHECKS should be checked instead of the redundant HAVE_QUERY_CACHE (which is always the case) to determine if column level grants should be compiled or not. --- mysql-test/r/query_cache.result | 33 ----------------- mysql-test/r/query_cache_notembedded.result | 33 +++++++++++++++++ mysql-test/t/query_cache.test | 39 --------------------- mysql-test/t/query_cache_notembedded.test | 36 +++++++++++++++++++ sql/sql_cache.cc | 2 +- 5 files changed, 70 insertions(+), 73 deletions(-) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 5a15a87bd3c..77bc21b8124 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1650,37 +1650,4 @@ a (select count(*) from t2) 3 0 4 0 drop table t1,t2; -DROP DATABASE IF EXISTS bug30269; -FLUSH STATUS; -CREATE DATABASE bug30269; -USE bug30269; -CREATE TABLE test1 (id int, name varchar(23)); -CREATE VIEW view1 AS SELECT * FROM test1; -INSERT INTO test1 VALUES (5, 'testit'); -GRANT SELECT (id) ON TABLE bug30269.test1 TO 'bug30269'@'localhost'; -GRANT SELECT ON TABLE bug30269.view1 TO 'bug30269'@'localhost'; -set global query_cache_size= 81920; -USE bug30269; -show status like 'Qcache_queries_in_cache'; -Variable_name Value -Qcache_queries_in_cache 0 -# Select statement not stored in query cache because of column privileges. -SELECT id FROM test1 WHERE id>2; -id -5 -show status like 'Qcache_queries_in_cache'; -Variable_name Value -Qcache_queries_in_cache 0 -SELECT id FROM view1 WHERE id>2; -id -5 -show status like 'Qcache_queries_in_cache'; -Variable_name Value -Qcache_queries_in_cache 1 -DROP DATABASE bug30269; -DROP USER 'bug30269'@'localhost'; -set GLOBAL query_cache_type=default; -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 diff --git a/mysql-test/r/query_cache_notembedded.result b/mysql-test/r/query_cache_notembedded.result index 05ef28a3180..ec78c2267d2 100644 --- a/mysql-test/r/query_cache_notembedded.result +++ b/mysql-test/r/query_cache_notembedded.result @@ -347,3 +347,36 @@ drop table t1; drop function f1; set GLOBAL query_cache_size=0; SET GLOBAL log_bin_trust_function_creators = 0; +DROP DATABASE IF EXISTS bug30269; +FLUSH STATUS; +CREATE DATABASE bug30269; +USE bug30269; +CREATE TABLE test1 (id int, name varchar(23)); +CREATE VIEW view1 AS SELECT * FROM test1; +INSERT INTO test1 VALUES (5, 'testit'); +GRANT SELECT (id) ON TABLE bug30269.test1 TO 'bug30269'@'localhost'; +GRANT SELECT ON TABLE bug30269.view1 TO 'bug30269'@'localhost'; +set global query_cache_size= 81920; +USE bug30269; +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 0 +# Select statement not stored in query cache because of column privileges. +SELECT id FROM test1 WHERE id>2; +id +5 +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 0 +SELECT id FROM view1 WHERE id>2; +id +5 +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 1 +DROP DATABASE bug30269; +DROP USER 'bug30269'@'localhost'; +set GLOBAL query_cache_type=default; +set GLOBAL query_cache_limit=default; +set GLOBAL query_cache_min_res_unit=default; +set GLOBAL query_cache_size=default; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 2cfe1ff4ccc..b3b5d08d23d 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1,10 +1,5 @@ -- source include/have_query_cache.inc -# Disabled on embedded due to bug #30710, "query_cache.test fails on -# embedded w/ per-column privs test". Please re-enable when that bug -# is resolved. --- source include/not_embedded.inc - # # Tests with query cache # @@ -1255,40 +1250,6 @@ disconnect user1; disconnect user2; disconnect user3; -# -# Bug #30269 Query cache eats memory -# ---disable_warnings -DROP DATABASE IF EXISTS bug30269; ---enable_warnings -FLUSH STATUS; -CREATE DATABASE bug30269; -USE bug30269; -CREATE TABLE test1 (id int, name varchar(23)); -CREATE VIEW view1 AS SELECT * FROM test1; -INSERT INTO test1 VALUES (5, 'testit'); -GRANT SELECT (id) ON TABLE bug30269.test1 TO 'bug30269'@'localhost'; -GRANT SELECT ON TABLE bug30269.view1 TO 'bug30269'@'localhost'; -set global query_cache_size= 81920; -connect (bug30269, localhost, bug30269,,); -connection bug30269; -USE bug30269; -show status like 'Qcache_queries_in_cache'; ---echo # Select statement not stored in query cache because of column privileges. -SELECT id FROM test1 WHERE id>2; -show status like 'Qcache_queries_in_cache'; -SELECT id FROM view1 WHERE id>2; -show status like 'Qcache_queries_in_cache'; - -connection default; -DROP DATABASE bug30269; -disconnect bug30269; -DROP USER 'bug30269'@'localhost'; - -set GLOBAL query_cache_type=default; -set GLOBAL query_cache_limit=default; -set GLOBAL query_cache_min_res_unit=default; -set GLOBAL query_cache_size=default; --echo End of 5.0 tests # diff --git a/mysql-test/t/query_cache_notembedded.test b/mysql-test/t/query_cache_notembedded.test index a0085c0ba31..929b93e10d5 100644 --- a/mysql-test/t/query_cache_notembedded.test +++ b/mysql-test/t/query_cache_notembedded.test @@ -225,3 +225,39 @@ connection default; set GLOBAL query_cache_size=0; SET GLOBAL log_bin_trust_function_creators = 0; + +# +# Bug #30269 Query cache eats memory +# +--disable_warnings +DROP DATABASE IF EXISTS bug30269; +--enable_warnings +FLUSH STATUS; +CREATE DATABASE bug30269; +USE bug30269; +CREATE TABLE test1 (id int, name varchar(23)); +CREATE VIEW view1 AS SELECT * FROM test1; +INSERT INTO test1 VALUES (5, 'testit'); +GRANT SELECT (id) ON TABLE bug30269.test1 TO 'bug30269'@'localhost'; +GRANT SELECT ON TABLE bug30269.view1 TO 'bug30269'@'localhost'; +set global query_cache_size= 81920; +connect (bug30269, localhost, bug30269,,); +connection bug30269; +USE bug30269; +show status like 'Qcache_queries_in_cache'; +--echo # Select statement not stored in query cache because of column privileges. +SELECT id FROM test1 WHERE id>2; +show status like 'Qcache_queries_in_cache'; +SELECT id FROM view1 WHERE id>2; +show status like 'Qcache_queries_in_cache'; + +connection default; +DROP DATABASE bug30269; +disconnect bug30269; +DROP USER 'bug30269'@'localhost'; + +set GLOBAL query_cache_type=default; +set GLOBAL query_cache_limit=default; +set GLOBAL query_cache_min_res_unit=default; +set GLOBAL query_cache_size=default; + diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index ada927fa467..56b048a4f9d 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -3240,7 +3240,7 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, for (; tables_used; tables_used= tables_used->next_global) { table_count++; -#ifdef HAVE_QUERY_CACHE +#ifndef NO_EMBEDDED_ACCESS_CHECKS /* Disable any attempt to store this statement if there are column level grants on any referenced tables. From c3447cef35286fc1064381497c1ff372b75b4c88 Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Tue, 16 Oct 2007 12:29:22 -0300 Subject: [PATCH 44/55] Bug#31608 missing mysqltest change_user command The problem is that currently there is no way to test the behavior of the mysql_change_user() function using the mysqltest suite because there is no internal command for it. The solution is to introduce a change_user command that can be used to test aspects of the MySQL client function mysql_change_user(). --- client/mysqltest.c | 61 ++++++++++++++++++++++++++++++++- mysql-test/r/change_user.result | 46 +++++++++++++++++++++++++ mysql-test/r/mysqltest.result | 3 ++ mysql-test/t/change_user.test | 35 +++++++++++++++++++ mysql-test/t/mysqltest.test | 18 ++++++++++ 5 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/change_user.result create mode 100644 mysql-test/t/change_user.test diff --git a/client/mysqltest.c b/client/mysqltest.c index 702eab0078f..7a84ec8cf40 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -263,7 +263,7 @@ enum enum_commands { Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST, Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP, Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES, - Q_SEND_QUIT, + Q_SEND_QUIT, Q_CHANGE_USER, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -352,6 +352,7 @@ const char *command_names[]= "cat_file", "diff_files", "send_quit", + "change_user", 0 }; @@ -3028,6 +3029,63 @@ void do_send_quit(struct st_command *command) } +/* + SYNOPSIS + do_change_user + command called command + + DESCRIPTION + change_user [], [], [] + - user to change to + - user password + - default database + + Changes the user and causes the database specified by db to become + the default (current) database for the the current connection. + +*/ + +void do_change_user(struct st_command *command) +{ + MYSQL *mysql = &cur_con->mysql; + /* static keyword to make the NetWare compiler happy. */ + static DYNAMIC_STRING ds_user, ds_passwd, ds_db; + const struct command_arg change_user_args[] = { + { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" }, + { "password", ARG_STRING, FALSE, &ds_passwd, "Password used when connecting" }, + { "database", ARG_STRING, FALSE, &ds_db, "Database to select after connect" }, + }; + + DBUG_ENTER("do_change_user"); + + check_command_args(command, command->first_argument, + change_user_args, + sizeof(change_user_args)/sizeof(struct command_arg), + ','); + + if (!ds_user.length) + dynstr_set(&ds_user, mysql->user); + + if (!ds_passwd.length) + dynstr_set(&ds_passwd, mysql->passwd); + + if (!ds_db.length) + dynstr_set(&ds_db, mysql->db); + + DBUG_PRINT("info",("connection: '%s' user: '%s' password: '%s' database: '%s'", + cur_con->name, ds_user.str, ds_passwd.str, ds_db.str)); + + if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str)) + die("change user failed: %s", mysql_error(mysql)); + + dynstr_free(&ds_user); + dynstr_free(&ds_passwd); + dynstr_free(&ds_db); + + DBUG_VOID_RETURN; +} + + /* SYNOPSIS do_perl @@ -6836,6 +6894,7 @@ int main(int argc, char **argv) case Q_APPEND_FILE: do_append_file(command); break; case Q_DIFF_FILES: do_diff_files(command); break; case Q_SEND_QUIT: do_send_quit(command); break; + case Q_CHANGE_USER: do_change_user(command); break; case Q_CAT_FILE: do_cat_file(command); break; case Q_COPY_FILE: do_copy_file(command); break; case Q_CHMOD_FILE: do_chmod_file(command); break; diff --git a/mysql-test/r/change_user.result b/mysql-test/r/change_user.result new file mode 100644 index 00000000000..d0dfa855add --- /dev/null +++ b/mysql-test/r/change_user.result @@ -0,0 +1,46 @@ +Bug#20023 +SELECT @@session.sql_big_selects; +@@session.sql_big_selects +1 +SELECT @@global.max_join_size; +@@global.max_join_size +-1 +change_user +SELECT @@session.sql_big_selects; +@@session.sql_big_selects +1 +SELECT @@global.max_join_size; +@@global.max_join_size +-1 +SET @@global.max_join_size = 10000; +SET @@session.max_join_size = default; +change_user +SELECT @@session.sql_big_selects; +@@session.sql_big_selects +0 +SET @@global.max_join_size = -1; +SET @@session.max_join_size = default; +change_user +SELECT @@session.sql_big_selects; +@@session.sql_big_selects +1 +Bug#31418 +SELECT IS_FREE_LOCK('bug31418'); +IS_FREE_LOCK('bug31418') +1 +SELECT IS_USED_LOCK('bug31418'); +IS_USED_LOCK('bug31418') +NULL +SELECT GET_LOCK('bug31418', 1); +GET_LOCK('bug31418', 1) +1 +SELECT IS_USED_LOCK('bug31418'); +IS_USED_LOCK('bug31418') +1 +change_user +SELECT IS_FREE_LOCK('bug31418'); +IS_FREE_LOCK('bug31418') +1 +SELECT IS_USED_LOCK('bug31418'); +IS_USED_LOCK('bug31418') +NULL diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index d03e21b1bb0..a7df1a523cf 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -722,4 +722,7 @@ a int(11) YES NULL b varchar(255) YES NULL c datetime YES NULL drop table t1; +mysqltest: At line 1: change user failed: Unknown database 'inexistent' +mysqltest: At line 1: change user failed: Access denied for user 'inexistent'@'localhost' (using password: NO) +mysqltest: At line 1: change user failed: Access denied for user 'root'@'localhost' (using password: YES) End of tests diff --git a/mysql-test/t/change_user.test b/mysql-test/t/change_user.test new file mode 100644 index 00000000000..2900cd434a4 --- /dev/null +++ b/mysql-test/t/change_user.test @@ -0,0 +1,35 @@ +# +# Bug#20023 mysql_change_user() resets the value of SQL_BIG_SELECTS +# + +--echo Bug#20023 +SELECT @@session.sql_big_selects; +SELECT @@global.max_join_size; +--echo change_user +--change_user +SELECT @@session.sql_big_selects; +SELECT @@global.max_join_size; +SET @@global.max_join_size = 10000; +SET @@session.max_join_size = default; +--echo change_user +--change_user +SELECT @@session.sql_big_selects; +SET @@global.max_join_size = -1; +SET @@session.max_join_size = default; +--echo change_user +--change_user +SELECT @@session.sql_big_selects; + +# +# Bug#31418 User locks misfunctioning after mysql_change_user() +# + +--echo Bug#31418 +SELECT IS_FREE_LOCK('bug31418'); +SELECT IS_USED_LOCK('bug31418'); +SELECT GET_LOCK('bug31418', 1); +SELECT IS_USED_LOCK('bug31418'); +--echo change_user +--change_user +SELECT IS_FREE_LOCK('bug31418'); +SELECT IS_USED_LOCK('bug31418'); diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 8a38972c00f..0fcdbb8de46 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -2080,5 +2080,23 @@ eval $show_statement; drop table t1; +# ---------------------------------------------------------------------------- +# Test change_user command +# ---------------------------------------------------------------------------- + +--error 1 +--exec echo "--change_user root,,inexistent" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--change_user inexistent,,test" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--change_user root,inexistent,test" | $MYSQL_TEST 2>&1 + +--change_user +--change_user root +--change_user root,, +--change_user root,,test + --echo End of tests From 4b5914caf52cf4a1d42df9204dce6756085f4145 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Tue, 16 Oct 2007 20:21:40 +0400 Subject: [PATCH 45/55] Update the client ABI to reflect member rename (this is a backward-compatible change). --- include/mysql_h.ic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mysql_h.ic b/include/mysql_h.ic index 8b1c36fdaab..12e16df878a 100644 --- a/include/mysql_h.ic +++ b/include/mysql_h.ic @@ -538,7 +538,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned unsigned char reading_or_writing; char save_char; my_bool no_send_ok; - my_bool no_send_eof; + my_bool unused; my_bool compress; my_bool no_send_error; unsigned char * query_cache_query; From a9c6ed46e2c76fd73744c28564cfc216206bb469 Mon Sep 17 00:00:00 2001 From: "malff@lambda.hsd1.co.comcast.net." <> Date: Tue, 16 Oct 2007 11:16:31 -0600 Subject: [PATCH 46/55] Implementing code review comments --- mysql-test/r/sp.result | 15 +++++++++++++++ mysql-test/t/sp.test | 29 +++++++++++++++++++++++++++++ sql/sql_udf.cc | 4 ++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ef173b9661f..061bbafd9a1 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6563,6 +6563,21 @@ f1() DROP TABLE t1; DROP FUNCTION f1; +DROP PROCEDURE IF EXISTS db28318_a.t1; +DROP PROCEDURE IF EXISTS db28318_b.t2; +DROP DATABASE IF EXISTS db28318_a; +DROP DATABASE IF EXISTS db28318_b; +CREATE DATABASE db28318_a; +CREATE DATABASE db28318_b; +CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1"; +CREATE PROCEDURE db28318_b.t2() CALL t1(); +use db28318_a; +CALL db28318_b.t2(); +ERROR 42000: PROCEDURE db28318_b.t1 does not exist +DROP PROCEDURE db28318_a.t1; +DROP PROCEDURE db28318_b.t2; +DROP DATABASE db28318_a; +DROP DATABASE db28318_b; # ------------------------------------------------------------------ # -- End of 5.0 tests # ------------------------------------------------------------------ diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 501d96c842a..785e7e3793c 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7671,6 +7671,35 @@ DROP FUNCTION f1; ########################################################################### +# +# Bug#28318 (CREATE FUNCTION (UDF) requires a schema) +# + +--disable_warnings +DROP PROCEDURE IF EXISTS db28318_a.t1; +DROP PROCEDURE IF EXISTS db28318_b.t2; +DROP DATABASE IF EXISTS db28318_a; +DROP DATABASE IF EXISTS db28318_b; +--enable_warnings + +CREATE DATABASE db28318_a; +CREATE DATABASE db28318_b; + +CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1"; +CREATE PROCEDURE db28318_b.t2() CALL t1(); + +use db28318_a; + +# In db28318_b.t2, t1 refers to db28318_b.t1 +--error ER_SP_DOES_NOT_EXIST +CALL db28318_b.t2(); + +DROP PROCEDURE db28318_a.t1; +DROP PROCEDURE db28318_b.t2; +DROP DATABASE db28318_a; +DROP DATABASE db28318_b; + + --echo # ------------------------------------------------------------------ --echo # -- End of 5.0 tests --echo # ------------------------------------------------------------------ diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 077660f0bb9..ce6cd43eace 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -426,14 +426,14 @@ int mysql_create_function(THD *thd,udf_func *udf) } if (udf->name.length > NAME_LEN) { - my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name); + my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name.str); DBUG_RETURN(1); } rw_wrlock(&THR_LOCK_udf); if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length))) { - my_error(ER_UDF_EXISTS, MYF(0), udf->name); + my_error(ER_UDF_EXISTS, MYF(0), udf->name.str); goto err; } if (!(dl = find_udf_dl(udf->dl))) From 9388592a2166c0113e79ed4edc3ec3098c80aaa7 Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Tue, 16 Oct 2007 19:32:38 +0200 Subject: [PATCH 47/55] Fixed query_cache_notembedded test program failure because of dependencies between test programs. --- mysql-test/r/query_cache.result | 4 ++++ mysql-test/t/query_cache.test | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 77bc21b8124..73436dc392f 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1651,3 +1651,7 @@ a (select count(*) from t2) 4 0 drop table t1,t2; End of 5.0 tests +set GLOBAL query_cache_type=default; +set GLOBAL query_cache_limit=default; +set GLOBAL query_cache_min_res_unit=default; +set GLOBAL query_cache_size=default; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index b3b5d08d23d..7571e60859f 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1293,3 +1293,9 @@ disconnect user3; # show status like 'Qcache_queries_in_cache'; # drop database db2; # drop database db3; + +set GLOBAL query_cache_type=default; +set GLOBAL query_cache_limit=default; +set GLOBAL query_cache_min_res_unit=default; +set GLOBAL query_cache_size=default; + From f3a6483945ff8af19bacfc25ea613d4968b491ba Mon Sep 17 00:00:00 2001 From: "malff@lambda.hsd1.co.comcast.net." <> Date: Tue, 16 Oct 2007 14:27:20 -0600 Subject: [PATCH 48/55] Fixed broken call to my_error --- sql/sql_yacc.yy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c1012b66bf4..3fd8d339f31 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5087,7 +5087,7 @@ simple_expr: the case when a default database exist, see below. */ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - "FUNCTION", $1); + "FUNCTION", $1.str); MYSQL_YYABORT; } From ee3e6d8171221a9a7b18dcaa2f7e6275b20b4e3f Mon Sep 17 00:00:00 2001 From: "malff@lambda.hsd1.co.comcast.net." <> Date: Tue, 16 Oct 2007 20:47:08 -0600 Subject: [PATCH 49/55] Manual merge of 5.0-runtime to 5.1-runtime --- mysql-test/r/sp-error.result | 15 +- mysql-test/r/sp.result | 16 ++ mysql-test/r/udf.result | 13 +- mysql-test/t/sp.test | 31 +++ mysql-test/t/udf.test | 3 +- sql/item_create.cc | 19 ++ sql/sp_head.cc | 34 ++- sql/sql_yacc.yy | 483 +++++++++++++++++++---------------- 8 files changed, 381 insertions(+), 233 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 46b8adb85b8..1b14d75cd9c 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1226,7 +1226,7 @@ ERROR 42S02: Unknown table 'c' in field list drop procedure bug15091; drop function if exists bug16896; create aggregate function bug16896() returns int return 1; -ERROR 42000: AGGREGATE is not supported for stored functions +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 '() returns int return 1' at line 1 DROP PROCEDURE IF EXISTS bug14702; CREATE IF NOT EXISTS PROCEDURE bug14702() BEGIN @@ -1510,3 +1510,16 @@ FETCH cur1 INTO c; select c; CLOSE cur1; END' at line 4 +DROP DATABASE IF EXISTS mysqltest; +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +SELECT inexistent(), 1 + ,; +ERROR 42000: FUNCTION inexistent does not exist +SELECT inexistent(); +ERROR 42000: FUNCTION inexistent does not exist +SELECT .inexistent(); +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 '()' at line 1 +SELECT ..inexistent(); +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 '.inexistent()' at line 1 +USE test; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 4641866bb43..0c6b4034e91 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6796,6 +6796,22 @@ f1() DROP TABLE t1; DROP FUNCTION f1; +DROP PROCEDURE IF EXISTS db28318_a.t1; +DROP PROCEDURE IF EXISTS db28318_b.t2; +DROP DATABASE IF EXISTS db28318_a; +DROP DATABASE IF EXISTS db28318_b; +CREATE DATABASE db28318_a; +CREATE DATABASE db28318_b; +CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1"; +CREATE PROCEDURE db28318_b.t2() CALL t1(); +use db28318_a; +CALL db28318_b.t2(); +ERROR 42000: PROCEDURE db28318_b.t1 does not exist +DROP PROCEDURE db28318_a.t1; +DROP PROCEDURE db28318_b.t2; +DROP DATABASE db28318_a; +DROP DATABASE db28318_b; +use test; End of 5.0 tests # diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index f1e47905f5d..da27a71c1a1 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -95,10 +95,10 @@ FR DROP TABLE bug19904; CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse RETURNS STRING SONAME "should_not_parse.so"; -ERROR HY000: Incorrect usage of SONAME and DEFINER +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 'RETURNS STRING SONAME "should_not_parse.so"' at line 2 CREATE DEFINER=someone@somewhere FUNCTION should_not_parse RETURNS STRING SONAME "should_not_parse.so"; -ERROR HY000: Incorrect usage of SONAME and DEFINER +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 'RETURNS STRING SONAME "should_not_parse.so"' at line 2 create table t1(f1 int); insert into t1 values(1),(2); explain select myfunc_int(f1) from t1 order by 1; @@ -214,7 +214,7 @@ DROP FUNCTION IF EXISTS metaphon; CREATE FUNCTION metaphon(a int) RETURNS int return 0; CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; -ERROR HY000: Function 'metaphon' already exists +DROP FUNCTION metaphon; DROP FUNCTION metaphon; CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; CREATE FUNCTION metaphon(a int) RETURNS int @@ -334,6 +334,13 @@ Qcache_queries_in_cache 0 drop table t1; drop function metaphon; set GLOBAL query_cache_size=default; +DROP DATABASE IF EXISTS mysqltest; +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +DROP FUNCTION metaphon; +USE test; CREATE TABLE const_len_bug ( str_const varchar(4000), result1 varchar(4000), diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index e6c293cab5f..7d0a6a7b2d8 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7871,6 +7871,37 @@ DROP FUNCTION f1; ########################################################################### +# +# Bug#28318 (CREATE FUNCTION (UDF) requires a schema) +# + +--disable_warnings +DROP PROCEDURE IF EXISTS db28318_a.t1; +DROP PROCEDURE IF EXISTS db28318_b.t2; +DROP DATABASE IF EXISTS db28318_a; +DROP DATABASE IF EXISTS db28318_b; +--enable_warnings + +CREATE DATABASE db28318_a; +CREATE DATABASE db28318_b; + +CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1"; +CREATE PROCEDURE db28318_b.t2() CALL t1(); + +use db28318_a; + +# In db28318_b.t2, t1 refers to db28318_b.t1 +--error ER_SP_DOES_NOT_EXIST +CALL db28318_b.t2(); + +DROP PROCEDURE db28318_a.t1; +DROP PROCEDURE db28318_b.t2; +DROP DATABASE db28318_a; +DROP DATABASE db28318_b; +use test; + +########################################################################### + --echo End of 5.0 tests ########################################################################### diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 23d5111be8e..663dc08d72e 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -206,10 +206,11 @@ DROP FUNCTION IF EXISTS metaphon; CREATE FUNCTION metaphon(a int) RETURNS int return 0; +# this currently passes, and eclipse the stored function --replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB ---error ER_UDF_EXISTS eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; +DROP FUNCTION metaphon; DROP FUNCTION metaphon; --replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB diff --git a/sql/item_create.cc b/sql/item_create.cc index 12b795e79a1..dc9f6e92884 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -2326,6 +2326,25 @@ Item* Create_qfunc::create(THD *thd, LEX_STRING name, List *item_list) { LEX_STRING db; + + if (! thd->db && ! thd->lex->sphead) + { + /* + The proper error message should be in the lines of: + Can't resolve () to a function call, + because this function: + - is not a native function, + - is not a user defined function, + - can not match a qualified (read: stored) function + since no database is selected. + Reusing ER_SP_DOES_NOT_EXIST have a message consistent with + the case when a default database exist, see Create_sp_func::create(). + */ + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), + "FUNCTION", name.str); + return NULL; + } + if (thd->lex->copy_db_to(&db.str, &db.length)) return NULL; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 7de230bba78..66990f8036d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -386,17 +386,43 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) * */ +sp_name::sp_name(THD *thd, char *key, uint key_len) +{ + m_sroutines_key.str= key; + m_sroutines_key.length= key_len; + m_qname.str= ++key; + m_qname.length= key_len - 1; + if ((m_name.str= strchr(m_qname.str, '.'))) + { + m_db.length= m_name.str - key; + m_db.str= strmake_root(thd->mem_root, key, m_db.length); + m_name.str++; + m_name.length= m_qname.length - m_db.length - 1; + } + else + { + m_name.str= m_qname.str; + m_name.length= m_qname.length; + m_db.str= 0; + m_db.length= 0; + } + m_explicit_name= false; +} + void sp_name::init_qname(THD *thd) { - m_sroutines_key.length= m_db.length + m_name.length + 2; + const uint dot= !!m_db.length; + /* m_sroutines format: m_type + [database + dot] + name + nul */ + m_sroutines_key.length= 1 + m_db.length + dot + m_name.length; if (!(m_sroutines_key.str= (char*) thd->alloc(m_sroutines_key.length + 1))) return; m_qname.length= m_sroutines_key.length - 1; m_qname.str= m_sroutines_key.str + 1; - sprintf(m_qname.str, "%.*s.%.*s", - (int) m_db.length, (m_db.length ? m_db.str : ""), - (int) m_name.length, m_name.str); + sprintf(m_qname.str, "%.*s%.*s%.*s", + (int) m_db.length, (m_db.length ? m_db.str : ""), + dot, ".", + (int) m_name.length, m_name.str); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0989e6e6b24..30e62c5d7b5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1211,8 +1211,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type cast_type -%type udf_func_type - %type keyword keyword_sp %type user grant_user @@ -1254,7 +1252,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use opt_delete_options opt_delete_option varchar nchar nvarchar opt_outer table_list table_name table_alias_ref_list table_alias_ref - opt_option opt_place + opt_option opt_place opt_attribute opt_attribute_list attribute column_list column_list_id opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list @@ -1272,14 +1270,15 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); statement sp_suid sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec - definer view_replace_or_algorithm view_replace + view_replace_or_algorithm view_replace view_algorithm view_or_trigger_or_sp_or_event - view_or_trigger_or_sp_or_event_tail + definer_tail no_definer_tail view_suid view_tail view_list_opt view_list view_select - view_check_option trigger_tail sp_tail + view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail install uninstall partition_entry binlog_base64_event init_key_options key_options key_opts key_opt key_using_alg server_def server_options_list server_option + definer_opt no_definer definer END_OF_INPUT %type call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -2002,181 +2001,6 @@ sp_name: } ; -create_function_tail: - RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - if (lex->definer != NULL) - { - /* - DEFINER is a concept meaningful when interpreting SQL code. - UDF functions are compiled. - Using DEFINER with UDF has therefore no semantic, - and is considered a parsing error. - */ - my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER"); - MYSQL_YYABORT; - } - if (is_native_function(thd, & lex->spname->m_name)) - { - my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), - lex->spname->m_name.str); - MYSQL_YYABORT; - } - lex->sql_command = SQLCOM_CREATE_FUNCTION; - lex->udf.name = lex->spname->m_name; - lex->udf.returns=(Item_result) $2; - lex->udf.dl=$4.str; - } - | '(' - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - sp_head *sp; - const char* tmp_param_begin; - - /* - First check if AGGREGATE was used, in that case it's a - syntax error. - */ - if (lex->udf.type == UDFTYPE_AGGREGATE) - { - my_error(ER_SP_NO_AGGREGATE, MYF(0)); - MYSQL_YYABORT; - } - - if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } - /* Order is important here: new - reset - init */ - sp= new sp_head(); - sp->reset_thd_mem_root(thd); - sp->init(lex); - sp->init_sp_name(thd, lex->spname); - - sp->m_type= TYPE_ENUM_FUNCTION; - lex->sphead= sp; - /* - We have to turn off CLIENT_MULTI_QUERIES while parsing a - stored procedure, otherwise yylex will chop it into pieces - at each ';'. - */ - $$= thd->client_capabilities & CLIENT_MULTI_QUERIES; - thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; - - tmp_param_begin= lip->get_cpp_tok_start(); - tmp_param_begin++; - lex->sphead->m_param_begin= tmp_param_begin; - } - sp_fdparam_list ')' - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lex->sphead->m_param_end= lip->get_cpp_tok_start(); - } - RETURNS_SYM - { - LEX *lex= Lex; - lex->charset= NULL; - lex->length= lex->dec= NULL; - lex->interval_list.empty(); - lex->type= 0; - } - type - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - /* - This was disabled in 5.1.12. See bug #20701 - When collation support in SP is implemented, then this test - should be removed. - */ - if (($8 == MYSQL_TYPE_STRING || $8 == MYSQL_TYPE_VARCHAR) - && (lex->type & BINCMP_FLAG)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation"); - MYSQL_YYABORT; - } - - if (sp->fill_field_definition(YYTHD, lex, - (enum enum_field_types) $8, - &sp->m_return_field_def)) - MYSQL_YYABORT; - - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); - } - sp_c_chistics - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); - } - sp_proc_stmt - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - sp_head *sp= lex->sphead; - - if (sp->is_not_allowed_in_function("function")) - MYSQL_YYABORT; - - lex->sql_command= SQLCOM_CREATE_SPFUNCTION; - sp->set_stmt_end(thd); - if (!(sp->m_flags & sp_head::HAS_RETURN)) - { - my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); - MYSQL_YYABORT; - } - if (is_native_function(thd, & sp->m_name)) - { - /* - This warning will be printed when - [1] A client query is parsed, - [2] A stored function is loaded by db_load_routine. - Printing the warning for [2] is intentional, to cover the - following scenario: - - A user define a SF 'foo' using MySQL 5.N - - An application uses select foo(), and works. - - MySQL 5.{N+1} defines a new native function 'foo', as - part of a new feature. - - MySQL 5.{N+1} documentation is updated, and should mention - that there is a potential incompatible change in case of - existing stored function named 'foo'. - - The user deploys 5.{N+1}. At this point, 'select foo()' - means something different, and the user code is most likely - broken (it's only safe if the code is 'select db.foo()'). - With a warning printed when the SF is loaded (which has to occur - before the call), the warning will provide a hint explaining - the root cause of a later failure of 'select foo()'. - With no warning printed, the user code will fail with no - apparent reason. - Printing a warning each time db_load_routine is executed for - an ambiguous function is annoying, since that can happen a lot, - but in practice should not happen unless there *are* name - collisions. - If a collision exists, it should not be silenced but fixed. - */ - push_warning_printf(thd, - MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_NATIVE_FCT_NAME_COLLISION, - ER(ER_NATIVE_FCT_NAME_COLLISION), - sp->m_name.str); - } - /* Restore flag if it was cleared above */ - thd->client_capabilities |= $2; - sp->restore_thd_mem_root(thd); - } - ; - sp_a_chistics: /* Empty */ {} | sp_a_chistics sp_chistic {} @@ -4489,11 +4313,10 @@ create_table_option: } | TRANSACTIONAL_SYM opt_equal ulong_num { - Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; + Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; Lex->create_info.transactional= ($3 != 0 ? HA_CHOICE_YES : - HA_CHOICE_NO); + HA_CHOICE_NO); } - ; default_charset: @@ -4575,7 +4398,7 @@ row_types: | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; } | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; } | COMPACT_SYM { $$= ROW_TYPE_COMPACT; } - | PAGE_SYM { $$= ROW_TYPE_PAGE; } + | PAGE_SYM { $$= ROW_TYPE_PAGE; } ; merge_insert_types: @@ -4589,10 +4412,6 @@ opt_select_from: | select_from select_lock_type ; -udf_func_type: - /* empty */ { $$ = UDFTYPE_FUNCTION; } - | AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; }; - udf_type: STRING_SYM {$$ = (int) STRING_RESULT; } | REAL {$$ = (int) REAL_RESULT; } @@ -5437,7 +5256,7 @@ alter: lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->spname= $3; } - | ALTER view_algorithm definer + | ALTER view_algorithm definer_opt { LEX *lex= Lex; @@ -5450,7 +5269,7 @@ alter: } view_tail {} - | ALTER definer + | ALTER definer_opt /* We have two separate rules for ALTER VIEW rather that optional view_algorithm above, to resolve the ambiguity @@ -5469,7 +5288,7 @@ alter: } view_tail {} - | ALTER definer EVENT_SYM sp_name + | ALTER definer_opt EVENT_SYM sp_name /* BE CAREFUL when you add a new rule to update the block where YYTHD->client_capabilities is set back to original value @@ -5505,7 +5324,7 @@ alter: { /* $1 - ALTER - $2 - definer + $2 - definer_opt $3 - EVENT_SYM $4 - sp_name $5 - the block above @@ -8559,9 +8378,11 @@ drop: lex->drop_if_exists=$3; lex->name= $4; } - | DROP FUNCTION_SYM if_exists sp_name + | DROP FUNCTION_SYM if_exists ident '.' ident { - LEX *lex=Lex; + THD *thd= YYTHD; + LEX *lex= thd->lex; + sp_name *spname; if (lex->sphead) { my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); @@ -8569,7 +8390,28 @@ drop: } lex->sql_command = SQLCOM_DROP_FUNCTION; lex->drop_if_exists= $3; - lex->spname= $4; + spname= new sp_name($4, $6, true); + spname->init_qname(thd); + lex->spname= spname; + } + | DROP FUNCTION_SYM if_exists ident + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + LEX_STRING db= {0, 0}; + sp_name *spname; + if (lex->sphead) + { + my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); + MYSQL_YYABORT; + } + if (thd->db && lex->copy_db_to(&db.str, &db.length)) + MYSQL_YYABORT; + lex->sql_command = SQLCOM_DROP_FUNCTION; + lex->drop_if_exists= $3; + spname= new sp_name(db, $4, false); + spname->init_qname(thd); + lex->spname= spname; } | DROP PROCEDURE if_exists sp_name { @@ -8639,18 +8481,19 @@ table_name: ; table_alias_ref_list: - table_alias_ref - | table_alias_ref_list ',' table_alias_ref; + table_alias_ref + | table_alias_ref_list ',' table_alias_ref + ; table_alias_ref: - table_ident - { - if (!Select->add_table_to_list(YYTHD, $1, NULL, - TL_OPTION_UPDATING | TL_OPTION_ALIAS, - Lex->lock_option )) - MYSQL_YYABORT; - } - ; + table_ident + { + if (!Select->add_table_to_list(YYTHD, $1, NULL, + TL_OPTION_UPDATING | TL_OPTION_ALIAS, + Lex->lock_option )) + MYSQL_YYABORT; + } + ; if_exists: /* empty */ { $$= 0; } @@ -10625,7 +10468,7 @@ keyword_sp: | TEXT_SYM {} | THAN_SYM {} | TRANSACTION_SYM {} - | TRANSACTIONAL_SYM {} + | TRANSACTIONAL_SYM {} | TRIGGERS_SYM {} | TIMESTAMP {} | TIMESTAMP_ADD {} @@ -11855,21 +11698,29 @@ subselect_end: **************************************************************************/ view_or_trigger_or_sp_or_event: - definer view_or_trigger_or_sp_or_event_tail + definer definer_tail {} - | view_replace_or_algorithm definer view_tail + | no_definer no_definer_tail + {} + | view_replace_or_algorithm definer_opt view_tail {} ; -view_or_trigger_or_sp_or_event_tail: +definer_tail: view_tail - {} | trigger_tail - {} | sp_tail - {} + | sf_tail + | event_tail + ; + +no_definer_tail: + view_tail + | trigger_tail + | sp_tail + | sf_tail + | udf_tail | event_tail - {} ; /************************************************************************** @@ -11878,7 +11729,12 @@ view_or_trigger_or_sp_or_event_tail: **************************************************************************/ -definer: +definer_opt: + no_definer + | definer + ; + +no_definer: /* empty */ { /* @@ -11890,7 +11746,10 @@ definer: */ YYTHD->lex->definer= 0; } - | DEFINER_SYM EQ user + ; + +definer: + DEFINER_SYM EQ user { YYTHD->lex->definer= get_current_user(YYTHD, $3); } @@ -12127,17 +11986,193 @@ trigger_tail: **************************************************************************/ -sp_tail: - udf_func_type remember_name FUNCTION_SYM sp_name +udf_tail: + AGGREGATE_SYM remember_name FUNCTION_SYM ident + RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys { - LEX *lex=Lex; - lex->udf.type= $1; + THD *thd= YYTHD; + LEX *lex= thd->lex; + if (is_native_function(thd, & $4)) + { + my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), + $4.str); + MYSQL_YYABORT; + } + lex->sql_command = SQLCOM_CREATE_FUNCTION; + lex->udf.type= UDFTYPE_AGGREGATE; lex->stmt_definition_begin= $2; - lex->spname= $4; + lex->udf.name = $4; + lex->udf.returns=(Item_result) $6; + lex->udf.dl=$8.str; } - create_function_tail - {} - | PROCEDURE remember_name sp_name + | remember_name FUNCTION_SYM ident + RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + if (is_native_function(thd, & $3)) + { + my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), + $3.str); + MYSQL_YYABORT; + } + lex->sql_command = SQLCOM_CREATE_FUNCTION; + lex->udf.type= UDFTYPE_FUNCTION; + lex->stmt_definition_begin= $1; + lex->udf.name = $3; + lex->udf.returns=(Item_result) $5; + lex->udf.dl=$7.str; + } + ; + +sf_tail: + remember_name /* $1 */ + FUNCTION_SYM /* $2 */ + sp_name /* $3 */ + '(' /* $4 */ + { /* $5 */ + THD *thd= YYTHD; + LEX *lex= thd->lex; + Lex_input_stream *lip= thd->m_lip; + sp_head *sp; + const char* tmp_param_begin; + + lex->stmt_definition_begin= $1; + lex->spname= $3; + + if (lex->sphead) + { + my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION"); + MYSQL_YYABORT; + } + /* Order is important here: new - reset - init */ + sp= new sp_head(); + sp->reset_thd_mem_root(thd); + sp->init(lex); + sp->init_sp_name(thd, lex->spname); + + sp->m_type= TYPE_ENUM_FUNCTION; + lex->sphead= sp; + /* + We have to turn off CLIENT_MULTI_QUERIES while parsing a + stored procedure, otherwise yylex will chop it into pieces + at each ';'. + */ + $$= thd->client_capabilities & CLIENT_MULTI_QUERIES; + thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; + + tmp_param_begin= lip->get_cpp_tok_start(); + tmp_param_begin++; + lex->sphead->m_param_begin= tmp_param_begin; + } + sp_fdparam_list /* $6 */ + ')' /* $7 */ + { /* $8 */ + THD *thd= YYTHD; + LEX *lex= thd->lex; + Lex_input_stream *lip= thd->m_lip; + + lex->sphead->m_param_end= lip->get_cpp_tok_start(); + } + RETURNS_SYM /* $9 */ + { /* $10 */ + LEX *lex= Lex; + lex->charset= NULL; + lex->length= lex->dec= NULL; + lex->interval_list.empty(); + lex->type= 0; + } + type /* $11 */ + { /* $12 */ + LEX *lex= Lex; + sp_head *sp= lex->sphead; + /* + This was disabled in 5.1.12. See bug #20701 + When collation support in SP is implemented, then this test + should be removed. + */ + if (($11 == MYSQL_TYPE_STRING || $11 == MYSQL_TYPE_VARCHAR) + && (lex->type & BINCMP_FLAG)) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation"); + MYSQL_YYABORT; + } + + if (sp->fill_field_definition(YYTHD, lex, + (enum enum_field_types) $11, + &sp->m_return_field_def)) + MYSQL_YYABORT; + + bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); + } + sp_c_chistics /* $13 */ + { /* $14 */ + THD *thd= YYTHD; + LEX *lex= thd->lex; + Lex_input_stream *lip= thd->m_lip; + + lex->sphead->m_chistics= &lex->sp_chistics; + lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); + } + sp_proc_stmt /* $15 */ + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + sp_head *sp= lex->sphead; + + if (sp->is_not_allowed_in_function("function")) + MYSQL_YYABORT; + + lex->sql_command= SQLCOM_CREATE_SPFUNCTION; + sp->set_stmt_end(thd); + if (!(sp->m_flags & sp_head::HAS_RETURN)) + { + my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); + MYSQL_YYABORT; + } + if (is_native_function(thd, & sp->m_name)) + { + /* + This warning will be printed when + [1] A client query is parsed, + [2] A stored function is loaded by db_load_routine. + Printing the warning for [2] is intentional, to cover the + following scenario: + - A user define a SF 'foo' using MySQL 5.N + - An application uses select foo(), and works. + - MySQL 5.{N+1} defines a new native function 'foo', as + part of a new feature. + - MySQL 5.{N+1} documentation is updated, and should mention + that there is a potential incompatible change in case of + existing stored function named 'foo'. + - The user deploys 5.{N+1}. At this point, 'select foo()' + means something different, and the user code is most likely + broken (it's only safe if the code is 'select db.foo()'). + With a warning printed when the SF is loaded (which has to occur + before the call), the warning will provide a hint explaining + the root cause of a later failure of 'select foo()'. + With no warning printed, the user code will fail with no + apparent reason. + Printing a warning each time db_load_routine is executed for + an ambiguous function is annoying, since that can happen a lot, + but in practice should not happen unless there *are* name + collisions. + If a collision exists, it should not be silenced but fixed. + */ + push_warning_printf(thd, + MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_NATIVE_FCT_NAME_COLLISION, + ER(ER_NATIVE_FCT_NAME_COLLISION), + sp->m_name.str); + } + /* Restore flag if it was cleared above */ + thd->client_capabilities |= $5; + sp->restore_thd_mem_root(thd); + } + ; + +sp_tail: + PROCEDURE remember_name sp_name { LEX *lex= Lex; sp_head *sp; From 49a0f09bbfa7c29a2919f8f2b56677e8a5436f3c Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Wed, 17 Oct 2007 12:13:56 +0400 Subject: [PATCH 50/55] Fix for BUG#24923: Functions with ENUM issues. The problem was that the RETURNS column in the mysql.proc was of CHAR(64). That was not enough for storing long-named datatypes. The fix is to change CHAR(64) to LONGBLOB, and to throw warnings at the time a stored routine is created if some data is truncated during writing into mysql.proc. --- mysql-test/r/sp.result | 51 +++++++++++ mysql-test/t/sp.test | 70 +++++++++++++++ scripts/mysql_system_tables.sql | 2 +- scripts/mysql_system_tables_fix.sql | 1 + sql/share/errmsg.txt | 3 + sql/sp.cc | 131 +++++++++++++++++++--------- sql/sp.h | 1 + sql/sql_parse.cc | 3 + 8 files changed, 222 insertions(+), 40 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 0c6b4034e91..412f6b94fa2 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6860,4 +6860,55 @@ DROP FUNCTION f2; DROP VIEW v1; DROP VIEW v2; +# +# - Bug#24923: prepare. +# + +DROP FUNCTION IF EXISTS f1; + +# +# - Bug#24923: create required objects. +# + +CREATE FUNCTION f1(p INT) +RETURNS ENUM ('Very_long_enum_element_identifier', +'Another_very_long_enum_element_identifier') +BEGIN +CASE p +WHEN 1 THEN +RETURN 'Very_long_enum_element_identifier'; +ELSE +RETURN 'Another_very_long_enum_element_identifier'; +END CASE; +END| + +# +# - Bug#24923: check. +# + +SELECT f1(1); +f1(1) +Very_long_enum_element_identifier + +SELECT f1(2); +f1(2) +Another_very_long_enum_element_identifier + +SHOW CREATE FUNCTION f1; +Function sql_mode Create Function character_set_client collation_connection Database Collation +f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`(p INT) RETURNS enum('Very_long_enum_element_identifier','Another_very_long_enum_element_identifier') CHARSET latin1 +BEGIN +CASE p +WHEN 1 THEN +RETURN 'Very_long_enum_element_identifier'; +ELSE +RETURN 'Another_very_long_enum_element_identifier'; +END CASE; +END latin1 latin1_swedish_ci latin1_swedish_ci +# +# - Bug#24923: cleanup. +# + +DROP FUNCTION f1; + End of 5.1 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 7d0a6a7b2d8..004e1c4ddd2 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7986,4 +7986,74 @@ DROP VIEW v2; ########################################################################### +# +# Bug#24923: Functions with ENUM issues. +# + +########################################################################### + +--echo # +--echo # - Bug#24923: prepare. +--echo # + +--echo + +--disable_warnings +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +--echo + +--echo # +--echo # - Bug#24923: create required objects. +--echo # + +--echo + +delimiter |; + +CREATE FUNCTION f1(p INT) + RETURNS ENUM ('Very_long_enum_element_identifier', + 'Another_very_long_enum_element_identifier') + BEGIN + CASE p + WHEN 1 THEN + RETURN 'Very_long_enum_element_identifier'; + ELSE + RETURN 'Another_very_long_enum_element_identifier'; + END CASE; + END| + +delimiter ;| + +--echo + +--echo # +--echo # - Bug#24923: check. +--echo # + +--echo + +SELECT f1(1); + +--echo + +SELECT f1(2); + +--echo + +SHOW CREATE FUNCTION f1; + +--echo # +--echo # - Bug#24923: cleanup. +--echo # + +--echo + +DROP FUNCTION f1; + +--echo + +########################################################################### + --echo End of 5.1 tests diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index f7b23e4e7ae..927cbe81ff9 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -60,7 +60,7 @@ CREATE TABLE IF NOT EXISTS time_zone_transition_type ( Time_zone_id int unsign CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint signed NOT NULL, Correction int signed NOT NULL, PRIMARY KEY TranTime (Transition_time) ) engine=MyISAM CHARACTER SET utf8 comment='Leap seconds information for time zones'; -CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type enum('FUNCTION','PROCEDURE') NOT NULL, specific_name char(64) DEFAULT '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', 'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob NOT NULL, returns char(64) DEFAULT '' NOT NULL, body longblob NOT NULL, definer char(77) collate utf8_bin DEFAULT '' NOT NULL, created timestamp, modified timestamp, sql_mode set( 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', 'ANSI_QUOTES', 'IGNORE_SPACE', 'NOT_USED', 'ONLY_FULL_GROUP_BY', 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', 'POSTGRESQL', 'ORACLE', 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', 'NO_TABLE_OPTIONS', 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', 'ANSI', 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE') DEFAULT '' NOT NULL, comment char(64) collate utf8_bin DEFAULT '' NOT NULL, character_set_client char(32) collate utf8_bin, collation_connection char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, PRIMARY KEY (db,name,type)) engine=MyISAM character set utf8 comment='Stored Procedures'; +CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type enum('FUNCTION','PROCEDURE') NOT NULL, specific_name char(64) DEFAULT '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', 'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob NOT NULL, returns longblob DEFAULT '' NOT NULL, body longblob NOT NULL, definer char(77) collate utf8_bin DEFAULT '' NOT NULL, created timestamp, modified timestamp, sql_mode set( 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', 'ANSI_QUOTES', 'IGNORE_SPACE', 'NOT_USED', 'ONLY_FULL_GROUP_BY', 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', 'POSTGRESQL', 'ORACLE', 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', 'NO_TABLE_OPTIONS', 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', 'ANSI', 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE') DEFAULT '' NOT NULL, comment char(64) collate utf8_bin DEFAULT '' NOT NULL, character_set_client char(32) collate utf8_bin, collation_connection char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, PRIMARY KEY (db,name,type)) engine=MyISAM character set utf8 comment='Stored Procedures'; CREATE TABLE IF NOT EXISTS procs_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Routine_name char(64) binary DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp(14), PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges'; diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index 78e6a0ceb57..a43964bf09a 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -344,6 +344,7 @@ ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL, 'MODIFIES_SQL_DATA' ) DEFAULT 'CONTAINS_SQL' NOT NULL, MODIFY body longblob NOT NULL, + MODIFY returns longblob NOT NULL, MODIFY sql_mode set('REAL_AS_FLOAT', 'PIPES_AS_CONCAT', diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 30cf85f3181..8fad09eb221 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6109,3 +6109,6 @@ ER_EVENT_INVALID_CREATION_CTX ER_TRG_CANT_OPEN_TABLE eng "Cannot open table for trigger `%-.64s`.`%-.64s`" + +ER_CANT_CREATE_SROUTINE + eng "Cannot create stored routine `%-.64s`. Check warnings" diff --git a/sql/sp.cc b/sql/sp.cc index 9077862e2f6..1b5d8ca87b8 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -682,6 +682,10 @@ sp_create_routine(THD *thd, int type, sp_head *sp) CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str); + enum_check_fields saved_count_cuted_fields; + + bool store_failed= FALSE; + DBUG_ENTER("sp_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length, sp->m_name.str)); @@ -696,6 +700,9 @@ sp_create_routine(THD *thd, int type, sp_head *sp) */ thd->clear_current_stmt_binlog_row_based(); + saved_count_cuted_fields= thd->count_cuted_fields; + thd->count_cuted_fields= CHECK_FIELD_WARN; + if (!(table= open_proc_table_for_update(thd))) ret= SP_OPEN_TABLE_FAILED; else @@ -725,43 +732,77 @@ sp_create_routine(THD *thd, int type, sp_head *sp) ret= SP_BODY_TOO_LONG; goto done; } - table->field[MYSQL_PROC_FIELD_DB]-> - store(sp->m_db.str, sp->m_db.length, system_charset_info); - table->field[MYSQL_PROC_FIELD_NAME]-> - store(sp->m_name.str, sp->m_name.length, system_charset_info); - table->field[MYSQL_PROC_MYSQL_TYPE]-> - store((longlong)type, TRUE); - table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]-> - store(sp->m_name.str, sp->m_name.length, system_charset_info); + + store_failed= + table->field[MYSQL_PROC_FIELD_DB]-> + store(sp->m_db.str, sp->m_db.length, system_charset_info); + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_NAME]-> + store(sp->m_name.str, sp->m_name.length, system_charset_info); + + store_failed= store_failed || + table->field[MYSQL_PROC_MYSQL_TYPE]-> + store((longlong)type, TRUE); + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]-> + store(sp->m_name.str, sp->m_name.length, system_charset_info); + if (sp->m_chistics->daccess != SP_DEFAULT_ACCESS) - table->field[MYSQL_PROC_FIELD_ACCESS]-> - store((longlong)sp->m_chistics->daccess, TRUE); - table->field[MYSQL_PROC_FIELD_DETERMINISTIC]-> - store((longlong)(sp->m_chistics->detistic ? 1 : 2), TRUE); + { + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_ACCESS]-> + store((longlong)sp->m_chistics->daccess, TRUE); + } + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_DETERMINISTIC]-> + store((longlong)(sp->m_chistics->detistic ? 1 : 2), TRUE); + if (sp->m_chistics->suid != SP_IS_DEFAULT_SUID) - table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]-> - store((longlong)sp->m_chistics->suid, TRUE); - table->field[MYSQL_PROC_FIELD_PARAM_LIST]-> - store(sp->m_params.str, sp->m_params.length, system_charset_info); + { + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]-> + store((longlong)sp->m_chistics->suid, TRUE); + } + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_PARAM_LIST]-> + store(sp->m_params.str, sp->m_params.length, system_charset_info); + if (sp->m_type == TYPE_ENUM_FUNCTION) { String retstr(64); sp_returns_type(thd, retstr, sp); - table->field[MYSQL_PROC_FIELD_RETURNS]-> - store(retstr.ptr(), retstr.length(), system_charset_info); + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_RETURNS]-> + store(retstr.ptr(), retstr.length(), system_charset_info); } - table->field[MYSQL_PROC_FIELD_BODY]-> - store(sp->m_body.str, sp->m_body.length, system_charset_info); - table->field[MYSQL_PROC_FIELD_DEFINER]-> - store(definer, (uint)strlen(definer), system_charset_info); + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_BODY]-> + store(sp->m_body.str, sp->m_body.length, system_charset_info); + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_DEFINER]-> + store(definer, (uint)strlen(definer), system_charset_info); + ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time(); ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time(); - table->field[MYSQL_PROC_FIELD_SQL_MODE]-> - store((longlong)thd->variables.sql_mode, TRUE); + + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_SQL_MODE]-> + store((longlong)thd->variables.sql_mode, TRUE); + if (sp->m_chistics->comment.str) - table->field[MYSQL_PROC_FIELD_COMMENT]-> - store(sp->m_chistics->comment.str, sp->m_chistics->comment.length, - system_charset_info); + { + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_COMMENT]-> + store(sp->m_chistics->comment.str, sp->m_chistics->comment.length, + system_charset_info); + } if ((sp->m_type == TYPE_ENUM_FUNCTION) && !trust_function_creators && mysql_bin_log.is_open()) @@ -794,24 +835,34 @@ sp_create_routine(THD *thd, int type, sp_head *sp) } table->field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]->set_notnull(); - table->field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]->store( - thd->charset()->csname, - strlen(thd->charset()->csname), - system_charset_info); + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]->store( + thd->charset()->csname, + strlen(thd->charset()->csname), + system_charset_info); table->field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]->set_notnull(); - table->field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]->store( - thd->variables.collation_connection->name, - strlen(thd->variables.collation_connection->name), - system_charset_info); + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]->store( + thd->variables.collation_connection->name, + strlen(thd->variables.collation_connection->name), + system_charset_info); table->field[MYSQL_PROC_FIELD_DB_COLLATION]->set_notnull(); - table->field[MYSQL_PROC_FIELD_DB_COLLATION]->store( - db_cs->name, strlen(db_cs->name), system_charset_info); + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_DB_COLLATION]->store( + db_cs->name, strlen(db_cs->name), system_charset_info); table->field[MYSQL_PROC_FIELD_BODY_UTF8]->set_notnull(); - table->field[MYSQL_PROC_FIELD_BODY_UTF8]->store( - sp->m_body_utf8.str, sp->m_body_utf8.length, system_charset_info); + store_failed= store_failed || + table->field[MYSQL_PROC_FIELD_BODY_UTF8]->store( + sp->m_body_utf8.str, sp->m_body_utf8.length, system_charset_info); + + if (store_failed) + { + ret= SP_FLD_STORE_FAILED; + goto done; + } ret= SP_OK; if (table->file->ha_write_row(table->record[0])) @@ -842,6 +893,8 @@ sp_create_routine(THD *thd, int type, sp_head *sp) } done: + thd->count_cuted_fields= saved_count_cuted_fields; + close_thread_tables(thd); DBUG_RETURN(ret); } diff --git a/sql/sp.h b/sql/sp.h index 3797eb289a4..31173e1f90c 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -29,6 +29,7 @@ #define SP_NO_DB_ERROR -8 #define SP_BAD_IDENTIFIER -9 #define SP_BODY_TOO_LONG -10 +#define SP_FLD_STORE_FAILED -11 /* Drop all routines in database 'db' */ int diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b04822c4fc9..4856332631a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3812,6 +3812,9 @@ end_with_restore_list: case SP_BODY_TOO_LONG: my_error(ER_TOO_LONG_BODY, MYF(0), name); break; + case SP_FLD_STORE_FAILED: + my_error(ER_CANT_CREATE_SROUTINE, MYF(0), name); + break; default: my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); break; From f0d70d11844c2360bee2c8268d50a97a11a43f9d Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Wed, 17 Oct 2007 15:44:22 +0400 Subject: [PATCH 51/55] Fix result files (BUG#24923). --- mysql-test/r/information_schema.result | 2 +- mysql-test/r/system_mysql_db.result | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 885acf5c744..d1120d24884 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -578,7 +578,7 @@ proc sql_data_access enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL proc is_deterministic enum('YES','NO') proc security_type enum('INVOKER','DEFINER') proc param_list blob -proc returns char(64) +proc returns longblob proc body longblob proc definer char(77) proc created timestamp diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 7696afdf06d..93694db629d 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -196,7 +196,7 @@ proc CREATE TABLE `proc` ( `is_deterministic` enum('YES','NO') NOT NULL DEFAULT 'NO', `security_type` enum('INVOKER','DEFINER') NOT NULL DEFAULT 'DEFINER', `param_list` blob NOT NULL, - `returns` char(64) NOT NULL DEFAULT '', + `returns` longblob NOT NULL, `body` longblob NOT NULL, `definer` char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, From 253439874a83641a9ab19dfa6398874ce69bb83d Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Wed, 17 Oct 2007 16:43:30 -0300 Subject: [PATCH 52/55] Bug#31608 missing mysqltest change_user command Post merge fixes: close any open statement before the change user command and fix test case output. --- client/mysqltest.c | 6 ++++++ mysql-test/r/change_user.result | 4 ++-- mysql-test/t/change_user.test | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 7a84ec8cf40..90df546babf 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3063,6 +3063,12 @@ void do_change_user(struct st_command *command) sizeof(change_user_args)/sizeof(struct command_arg), ','); + if (cur_con->stmt) + { + mysql_stmt_close(cur_con->stmt); + cur_con->stmt= NULL; + } + if (!ds_user.length) dynstr_set(&ds_user, mysql->user); diff --git a/mysql-test/r/change_user.result b/mysql-test/r/change_user.result index d0dfa855add..cb409621d56 100644 --- a/mysql-test/r/change_user.result +++ b/mysql-test/r/change_user.result @@ -34,8 +34,8 @@ NULL SELECT GET_LOCK('bug31418', 1); GET_LOCK('bug31418', 1) 1 -SELECT IS_USED_LOCK('bug31418'); -IS_USED_LOCK('bug31418') +SELECT IS_USED_LOCK('bug31418') = CONNECTION_ID(); +IS_USED_LOCK('bug31418') = CONNECTION_ID() 1 change_user SELECT IS_FREE_LOCK('bug31418'); diff --git a/mysql-test/t/change_user.test b/mysql-test/t/change_user.test index 2900cd434a4..d0cdfc8a741 100644 --- a/mysql-test/t/change_user.test +++ b/mysql-test/t/change_user.test @@ -28,7 +28,7 @@ SELECT @@session.sql_big_selects; SELECT IS_FREE_LOCK('bug31418'); SELECT IS_USED_LOCK('bug31418'); SELECT GET_LOCK('bug31418', 1); -SELECT IS_USED_LOCK('bug31418'); +SELECT IS_USED_LOCK('bug31418') = CONNECTION_ID(); --echo change_user --change_user SELECT IS_FREE_LOCK('bug31418'); From 86082dfcefb83f8bb81f675bfbf7c234449d1d51 Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Wed, 17 Oct 2007 17:54:11 -0400 Subject: [PATCH 53/55] Bug #29804 UDF parameters don't contain correct string length Previously, UDF *_init functions were passed constant strings with erroneous lengths. The length came from the containing variable's size, not the length of the value itself. Now the *_init functions get the constant as a null terminated string with the correct length supplied too. --- mysql-test/r/udf.result | 24 ++++++++++++++++++++++++ mysql-test/t/udf.test | 36 ++++++++++++++++++++++++++++++++++++ sql/item_func.cc | 3 ++- sql/udf_example.c | 35 +++++++++++++++++++++++++++++++++++ sql/udf_example.def | 2 ++ 5 files changed, 99 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 4a12e8e6d81..e6797796ea0 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -303,4 +303,28 @@ DROP DATABASE mysqltest; CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; DROP FUNCTION metaphon; USE test; +CREATE TABLE const_len_bug ( +str_const varchar(4000), +result1 varchar(4000), +result2 varchar(4000) +); +CREATE TRIGGER check_const_len_trigger BEFORE INSERT ON const_len_bug FOR EACH ROW BEGIN +set NEW.str_const = 'bar'; +set NEW.result2 = check_const_len(NEW.str_const); +END | +CREATE PROCEDURE check_const_len_sp (IN str_const VARCHAR(4000)) +BEGIN +DECLARE result VARCHAR(4000); +SET result = check_const_len(str_const); +insert into const_len_bug values(str_const, result, ""); +END | +CREATE FUNCTION check_const_len RETURNS string SONAME "UDF_EXAMPLE_LIB"; +CALL check_const_len_sp("foo"); +SELECT * from const_len_bug; +str_const result1 result2 +bar Correct length Correct length +DROP FUNCTION check_const_len; +DROP PROCEDURE check_const_len_sp; +DROP TRIGGER check_const_len_trigger; +DROP TABLE const_len_bug; End of 5.0 tests. diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 14aef3361e4..22b8ed10a49 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -326,4 +326,40 @@ eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; DROP FUNCTION metaphon; USE test; +# +# Bug #29804 UDF parameters don't contain correct string length +# + +CREATE TABLE const_len_bug ( + str_const varchar(4000), + result1 varchar(4000), + result2 varchar(4000) +); + +DELIMITER |; +CREATE TRIGGER check_const_len_trigger BEFORE INSERT ON const_len_bug FOR EACH ROW BEGIN + set NEW.str_const = 'bar'; + set NEW.result2 = check_const_len(NEW.str_const); +END | + +CREATE PROCEDURE check_const_len_sp (IN str_const VARCHAR(4000)) +BEGIN +DECLARE result VARCHAR(4000); +SET result = check_const_len(str_const); +insert into const_len_bug values(str_const, result, ""); +END | +DELIMITER ;| + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION check_const_len RETURNS string SONAME "$UDF_EXAMPLE_LIB"; + +CALL check_const_len_sp("foo"); + +SELECT * from const_len_bug; + +DROP FUNCTION check_const_len; +DROP PROCEDURE check_const_len_sp; +DROP TRIGGER check_const_len_trigger; +DROP TABLE const_len_bug; + --echo End of 5.0 tests. diff --git a/sql/item_func.cc b/sql/item_func.cc index f7103c22581..e4d370bbdf2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2924,7 +2924,8 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, String *res= arguments[i]->val_str(&buffers[i]); if (arguments[i]->null_value) continue; - f_args.args[i]= (char*) res->ptr(); + f_args.args[i]= (char*) res->c_ptr(); + f_args.lengths[i]= res->length(); break; } case INT_RESULT: diff --git a/sql/udf_example.c b/sql/udf_example.c index 0f28c2a14b0..df3a69755ad 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -1106,4 +1106,39 @@ char * is_const(UDF_INIT *initid, UDF_ARGS *args __attribute__((unused)), } + +my_bool check_const_len_init(UDF_INIT *initid, UDF_ARGS *args, char *message) +{ + if (args->arg_count != 1) + { + strmov(message, "CHECK_CONST_LEN accepts only one argument"); + return 1; + } + if (args->args[0] == 0) + { + initid->ptr= (char*)"Not constant"; + } + else if(strlen(args->args[0]) == args->lengths[0]) + { + initid->ptr= (char*)"Correct length"; + } + else + { + initid->ptr= (char*)"Wrong length"; + } + initid->max_length = 100; + return 0; +} + +char * check_const_len(UDF_INIT *initid, UDF_ARGS *args __attribute__((unused)), + char *result, unsigned long *length, + char *is_null, char *error __attribute__((unused))) +{ + strmov(result, initid->ptr); + *length= strlen(result); + *is_null= 0; + return result; +} + + #endif /* HAVE_DLOPEN */ diff --git a/sql/udf_example.def b/sql/udf_example.def index 7a87147d7b6..3d569941cc8 100644 --- a/sql/udf_example.def +++ b/sql/udf_example.def @@ -23,3 +23,5 @@ EXPORTS avgcost is_const is_const_init + check_const_len + check_const_len_init From dd135211d8c21c321f304f36bbe374a66c46655f Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Thu, 18 Oct 2007 15:45:07 -0300 Subject: [PATCH 54/55] Bug#21557 entries in the general query log truncated at 1000 characters. The general log write function (general_log_print) uses printf style arguments which need to be pre-processed, meaning that the all arguments are copied to a single buffer and the problem is that the buffer size is constant (1022 characters) but queries can be much larger then this. The solution is to introduce a new log write function that accepts a buffer and it's length as arguments. The function is to be used when a formatted output is not required, which is the case for almost all query write-to-log calls. This is a incompatible change with respect to the log format of prepared statements. --- mysql-test/r/log_tables.result | 214 +++++++++++++++++++++++++++++++++ mysql-test/t/log_tables.test | 116 ++++++++++++++++++ sql/log.cc | 154 +++++++++++++++--------- sql/log.h | 4 + sql/log_event.cc | 2 +- sql/mysql_priv.h | 3 + sql/sp_head.cc | 2 +- sql/sql_parse.cc | 7 +- sql/sql_prepare.cc | 13 +- 9 files changed, 438 insertions(+), 77 deletions(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index c8857c582a9..11c2df2ea2e 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -605,3 +605,217 @@ DROP PROCEDURE IF EXISTS `db_17876.archiveGeneralLog`; DROP DATABASE IF EXISTS `db_17876`; SET GLOBAL general_log = @old_general_log_state; SET GLOBAL slow_query_log = @old_slow_log_state; +truncate table mysql.general_log; +set @old_general_log_state = @@global.general_log; +set global general_log = on; +set @lparam = "000 001 002 003 004 005 006 007 008 009" + "010 011 012 013 014 015 016 017 018 019" + "020 021 022 023 024 025 026 027 028 029" + "030 031 032 033 034 035 036 037 038 039" + "040 041 042 043 044 045 046 047 048 049" + "050 051 052 053 054 055 056 057 058 059" + "060 061 062 063 064 065 066 067 068 069" + "070 071 072 073 074 075 076 077 078 079" + "080 081 082 083 084 085 086 087 088 089" + "090 091 092 093 094 095 096 097 098 099" + "100 101 102 103 104 105 106 107 108 109" + "110 111 112 113 114 115 116 117 118 119" + "120 121 122 123 124 125 126 127 128 129" + "130 131 132 133 134 135 136 137 138 139" + "140 141 142 143 144 145 146 147 148 149" + "150 151 152 153 154 155 156 157 158 159" + "160 161 162 163 164 165 166 167 168 169" + "170 171 172 173 174 175 176 177 178 179" + "180 181 182 183 184 185 186 187 188 189" + "190 191 192 193 194 195 196 197 198 199" + "200 201 202 203 204 205 206 207 208 209" + "210 211 212 213 214 215 216 217 218 219" + "220 221 222 223 224 225 226 227 228 229" + "230 231 232 233 234 235 236 237 238 239" + "240 241 242 243 244 245 246 247 248 249" + "250 251 252 253 254 255 256 257 258 259" + "260 261 262 263 264 265 266 267 268 269" + "270 271 272 273 274 275 276 277 278 279" + "280 281 282 283 284 285 286 287 288 289" + "290 291 292 293 294 295 296 297 298 299" + "300 301 302 303 304 305 306 307 308 309" + "310 311 312 313 314 315 316 317 318 319" + "320 321 322 323 324 325 326 327 328 329" + "330 331 332 333 334 335 336 337 338 339" + "340 341 342 343 344 345 346 347 348 349" + "350 351 352 353 354 355 356 357 358 359" + "360 361 362 363 364 365 366 367 368 369" + "370 371 372 373 374 375 376 377 378 379" + "380 381 382 383 384 385 386 387 388 389" + "390 391 392 393 394 395 396 397 398 399" + "400 401 402 403 404 405 406 407 408 409" + "410 411 412 413 414 415 416 417 418 419" + "420 421 422 423 424 425 426 427 428 429" + "430 431 432 433 434 435 436 437 438 439" + "440 441 442 443 444 445 446 447 448 449" + "450 451 452 453 454 455 456 457 458 459" + "460 461 462 463 464 465 466 467 468 469" + "470 471 472 473 474 475 476 477 478 479" + "480 481 482 483 484 485 486 487 488 489" + "490 491 492 493 494 495 496 497 498 499" + "500 501 502 503 504 505 506 507 508 509" + "510 511 512 513 514 515 516 517 518 519" + "520 521 522 523 524 525 526 527 528 529" + "530 531 532 533 534 535 536 537 538 539" + "540 541 542 543 544 545 546 547 548 549" + "550 551 552 553 554 555 556 557 558 559" + "560 561 562 563 564 565 566 567 568 569" + "570 571 572 573 574 575 576 577 578 579" + "580 581 582 583 584 585 586 587 588 589" + "590 591 592 593 594 595 596 597 598 599" + "600 601 602 603 604 605 606 607 608 609" + "610 611 612 613 614 615 616 617 618 619" + "620 621 622 623 624 625 626 627 628 629" + "630 631 632 633 634 635 636 637 638 639" + "640 641 642 643 644 645 646 647 648 649" + "650 651 652 653 654 655 656 657 658 659" + "660 661 662 663 664 665 666 667 668 669" + "670 671 672 673 674 675 676 677 678 679" + "680 681 682 683 684 685 686 687 688 689" + "690 691 692 693 694 695 696 697 698 699" + "700 701 702 703 704 705 706 707 708 709" + "710 711 712 713 714 715 716 717 718 719" + "720 721 722 723 724 725 726 727 728 729" + "730 731 732 733 734 735 736 737 738 739" + "740 741 742 743 744 745 746 747 748 749" + "750 751 752 753 754 755 756 757 758 759" + "760 761 762 763 764 765 766 767 768 769" + "770 771 772 773 774 775 776 777 778 779" + "780 781 782 783 784 785 786 787 788 789" + "790 791 792 793 794 795 796 797 798 799" + "800 801 802 803 804 805 806 807 808 809" + "810 811 812 813 814 815 816 817 818 819" + "820 821 822 823 824 825 826 827 828 829" + "830 831 832 833 834 835 836 837 838 839" + "840 841 842 843 844 845 846 847 848 849" + "850 851 852 853 854 855 856 857 858 859" + "860 861 862 863 864 865 866 867 868 869" + "870 871 872 873 874 875 876 877 878 879" + "880 881 882 883 884 885 886 887 888 889" + "890 891 892 893 894 895 896 897 898 899" + "900 901 902 903 904 905 906 907 908 909" + "910 911 912 913 914 915 916 917 918 919" + "920 921 922 923 924 925 926 927 928 929" + "930 931 932 933 934 935 936 937 938 939" + "940 941 942 943 944 945 946 947 948 949" + "950 951 952 953 954 955 956 957 958 959" + "960 961 962 963 964 965 966 967 968 969" + "970 971 972 973 974 975 976 977 978 979" + "980 981 982 983 984 985 986 987 988 989" + "990 991 992 993 994 995 996 997 998 999"; +prepare long_query from "select ? as long_query"; +execute long_query using @lparam; +select command_type, argument from mysql.general_log; +command_type argument +Query set @lparam = "000 001 002 003 004 005 006 007 008 009" + "010 011 012 013 014 015 016 017 018 019" + "020 021 022 023 024 025 026 027 028 029" + "030 031 032 033 034 035 036 037 038 039" + "040 041 042 043 044 045 046 047 048 049" + "050 051 052 053 054 055 056 057 058 059" + "060 061 062 063 064 065 066 067 068 069" + "070 071 072 073 074 075 076 077 078 079" + "080 081 082 083 084 085 086 087 088 089" + "090 091 092 093 094 095 096 097 098 099" + "100 101 102 103 104 105 106 107 108 109" + "110 111 112 113 114 115 116 117 118 119" + "120 121 122 123 124 125 126 127 128 129" + "130 131 132 133 134 135 136 137 138 139" + "140 141 142 143 144 145 146 147 148 149" + "150 151 152 153 154 155 156 157 158 159" + "160 161 162 163 164 165 166 167 168 169" + "170 171 172 173 174 175 176 177 178 179" + "180 181 182 183 184 185 186 187 188 189" + "190 191 192 193 194 195 196 197 198 199" + "200 201 202 203 204 205 206 207 208 209" + "210 211 212 213 214 215 216 217 218 219" + "220 221 222 223 224 225 226 227 228 229" + "230 231 232 233 234 235 236 237 238 239" + "240 241 242 243 244 245 246 247 248 249" + "250 251 252 253 254 255 256 257 258 259" + "260 261 262 263 264 265 266 267 268 269" + "270 271 272 273 274 275 276 277 278 279" + "280 281 282 283 284 285 286 287 288 289" + "290 291 292 293 294 295 296 297 298 299" + "300 301 302 303 304 305 306 307 308 309" + "310 311 312 313 314 315 316 317 318 319" + "320 321 322 323 324 325 326 327 328 329" + "330 331 332 333 334 335 336 337 338 339" + "340 341 342 343 344 345 346 347 348 349" + "350 351 352 353 354 355 356 357 358 359" + "360 361 362 363 364 365 366 367 368 369" + "370 371 372 373 374 375 376 377 378 379" + "380 381 382 383 384 385 386 387 388 389" + "390 391 392 393 394 395 396 397 398 399" + "400 401 402 403 404 405 406 407 408 409" + "410 411 412 413 414 415 416 417 418 419" + "420 421 422 423 424 425 426 427 428 429" + "430 431 432 433 434 435 436 437 438 439" + "440 441 442 443 444 445 446 447 448 449" + "450 451 452 453 454 455 456 457 458 459" + "460 461 462 463 464 465 466 467 468 469" + "470 471 472 473 474 475 476 477 478 479" + "480 481 482 483 484 485 486 487 488 489" + "490 491 492 493 494 495 496 497 498 499" + "500 501 502 503 504 505 506 507 508 509" + "510 511 512 513 514 515 516 517 518 519" + "520 521 522 523 524 525 526 527 528 529" + "530 531 532 533 534 535 536 537 538 539" + "540 541 542 543 544 545 546 547 548 549" + "550 551 552 553 554 555 556 557 558 559" + "560 561 562 563 564 565 566 567 568 569" + "570 571 572 573 574 575 576 577 578 579" + "580 581 582 583 584 585 586 587 588 589" + "590 591 592 593 594 595 596 597 598 599" + "600 601 602 603 604 605 606 607 608 609" + "610 611 612 613 614 615 616 617 618 619" + "620 621 622 623 624 625 626 627 628 629" + "630 631 632 633 634 635 636 637 638 639" + "640 641 642 643 644 645 646 647 648 649" + "650 651 652 653 654 655 656 657 658 659" + "660 661 662 663 664 665 666 667 668 669" + "670 671 672 673 674 675 676 677 678 679" + "680 681 682 683 684 685 686 687 688 689" + "690 691 692 693 694 695 696 697 698 699" + "700 701 702 703 704 705 706 707 708 709" + "710 711 712 713 714 715 716 717 718 719" + "720 721 722 723 724 725 726 727 728 729" + "730 731 732 733 734 735 736 737 738 739" + "740 741 742 743 744 745 746 747 748 749" + "750 751 752 753 754 755 756 757 758 759" + "760 761 762 763 764 765 766 767 768 769" + "770 771 772 773 774 775 776 777 778 779" + "780 781 782 783 784 785 786 787 788 789" + "790 791 792 793 794 795 796 797 798 799" + "800 801 802 803 804 805 806 807 808 809" + "810 811 812 813 814 815 816 817 818 819" + "820 821 822 823 824 825 826 827 828 829" + "830 831 832 833 834 835 836 837 838 839" + "840 841 842 843 844 845 846 847 848 849" + "850 851 852 853 854 855 856 857 858 859" + "860 861 862 863 864 865 866 867 868 869" + "870 871 872 873 874 875 876 877 878 879" + "880 881 882 883 884 885 886 887 888 889" + "890 891 892 893 894 895 896 897 898 899" + "900 901 902 903 904 905 906 907 908 909" + "910 911 912 913 914 915 916 917 918 919" + "920 921 922 923 924 925 926 927 928 929" + "930 931 932 933 934 935 936 937 938 939" + "940 941 942 943 944 945 946 947 948 949" + "950 951 952 953 954 955 956 957 958 959" + "960 961 962 963 964 965 966 967 968 969" + "970 971 972 973 974 975 976 977 978 979" + "980 981 982 983 984 985 986 987 988 989" + "990 991 992 993 994 995 996 997 998 999" +Query prepare long_query from "select ? as long_query" +Prepare select ? as long_query +Query execute long_query using @lparam +Execute select '000 001 002 003 004 005 006 007 008 009010 011 012 013 014 015 016 017 018 019020 021 022 023 024 025 026 027 028 029030 031 032 033 034 035 036 037 038 039040 041 042 043 044 045 046 047 048 049050 051 052 053 054 055 056 057 058 059060 061 062 063 064 065 066 067 068 069070 071 072 073 074 075 076 077 078 079080 081 082 083 084 085 086 087 088 089090 091 092 093 094 095 096 097 098 099100 101 102 103 104 105 106 107 108 109110 111 112 113 114 115 116 117 118 119120 121 122 123 124 125 126 127 128 129130 131 132 133 134 135 136 137 138 139140 141 142 143 144 145 146 147 148 149150 151 152 153 154 155 156 157 158 159160 161 162 163 164 165 166 167 168 169170 171 172 173 174 175 176 177 178 179180 181 182 183 184 185 186 187 188 189190 191 192 193 194 195 196 197 198 199200 201 202 203 204 205 206 207 208 209210 211 212 213 214 215 216 217 218 219220 221 222 223 224 225 226 227 228 229230 231 232 233 234 235 236 237 238 239240 241 242 243 244 245 246 247 248 249250 251 252 253 254 255 256 257 258 259260 261 262 263 264 265 266 267 268 269270 271 272 273 274 275 276 277 278 279280 281 282 283 284 285 286 287 288 289290 291 292 293 294 295 296 297 298 299300 301 302 303 304 305 306 307 308 309310 311 312 313 314 315 316 317 318 319320 321 322 323 324 325 326 327 328 329330 331 332 333 334 335 336 337 338 339340 341 342 343 344 345 346 347 348 349350 351 352 353 354 355 356 357 358 359360 361 362 363 364 365 366 367 368 369370 371 372 373 374 375 376 377 378 379380 381 382 383 384 385 386 387 388 389390 391 392 393 394 395 396 397 398 399400 401 402 403 404 405 406 407 408 409410 411 412 413 414 415 416 417 418 419420 421 422 423 424 425 426 427 428 429430 431 432 433 434 435 436 437 438 439440 441 442 443 444 445 446 447 448 449450 451 452 453 454 455 456 457 458 459460 461 462 463 464 465 466 467 468 469470 471 472 473 474 475 476 477 478 479480 481 482 483 484 485 486 487 488 489490 491 492 493 494 495 496 497 498 499500 501 502 503 504 505 506 507 508 509510 511 512 513 514 515 516 517 518 519520 521 522 523 524 525 526 527 528 529530 531 532 533 534 535 536 537 538 539540 541 542 543 544 545 546 547 548 549550 551 552 553 554 555 556 557 558 559560 561 562 563 564 565 566 567 568 569570 571 572 573 574 575 576 577 578 579580 581 582 583 584 585 586 587 588 589590 591 592 593 594 595 596 597 598 599600 601 602 603 604 605 606 607 608 609610 611 612 613 614 615 616 617 618 619620 621 622 623 624 625 626 627 628 629630 631 632 633 634 635 636 637 638 639640 641 642 643 644 645 646 647 648 649650 651 652 653 654 655 656 657 658 659660 661 662 663 664 665 666 667 668 669670 671 672 673 674 675 676 677 678 679680 681 682 683 684 685 686 687 688 689690 691 692 693 694 695 696 697 698 699700 701 702 703 704 705 706 707 708 709710 711 712 713 714 715 716 717 718 719720 721 722 723 724 725 726 727 728 729730 731 732 733 734 735 736 737 738 739740 741 742 743 744 745 746 747 748 749750 751 752 753 754 755 756 757 758 759760 761 762 763 764 765 766 767 768 769770 771 772 773 774 775 776 777 778 779780 781 782 783 784 785 786 787 788 789790 791 792 793 794 795 796 797 798 799800 801 802 803 804 805 806 807 808 809810 811 812 813 814 815 816 817 818 819820 821 822 823 824 825 826 827 828 829830 831 832 833 834 835 836 837 838 839840 841 842 843 844 845 846 847 848 849850 851 852 853 854 855 856 857 858 859860 861 862 863 864 865 866 867 868 869870 871 872 873 874 875 876 877 878 879880 881 882 883 884 885 886 887 888 889890 891 892 893 894 895 896 897 898 899900 901 902 903 904 905 906 907 908 909910 911 912 913 914 915 916 917 918 919920 921 922 923 924 925 926 927 928 929930 931 932 933 934 935 936 937 938 939940 941 942 943 944 945 946 947 948 949950 951 952 953 954 955 956 957 958 959960 961 962 963 964 965 966 967 968 969970 971 972 973 974 975 976 977 978 979980 981 982 983 984 985 986 987 988 989990 991 992 993 994 995 996 997 998 999' as long_query +Query select command_type, argument from mysql.general_log +deallocate prepare long_query; +set global general_log = @old_general_log_state; diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index 1d65c86295f..9fdf77eb575 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -807,3 +807,119 @@ DROP DATABASE IF EXISTS `db_17876`; SET GLOBAL general_log = @old_general_log_state; SET GLOBAL slow_query_log = @old_slow_log_state; +# +# Bug#21557 entries in the general query log truncated at 1000 characters. +# + +truncate table mysql.general_log; +set @old_general_log_state = @@global.general_log; +set global general_log = on; +--disable_result_log +set @lparam = "000 001 002 003 004 005 006 007 008 009" + "010 011 012 013 014 015 016 017 018 019" + "020 021 022 023 024 025 026 027 028 029" + "030 031 032 033 034 035 036 037 038 039" + "040 041 042 043 044 045 046 047 048 049" + "050 051 052 053 054 055 056 057 058 059" + "060 061 062 063 064 065 066 067 068 069" + "070 071 072 073 074 075 076 077 078 079" + "080 081 082 083 084 085 086 087 088 089" + "090 091 092 093 094 095 096 097 098 099" + "100 101 102 103 104 105 106 107 108 109" + "110 111 112 113 114 115 116 117 118 119" + "120 121 122 123 124 125 126 127 128 129" + "130 131 132 133 134 135 136 137 138 139" + "140 141 142 143 144 145 146 147 148 149" + "150 151 152 153 154 155 156 157 158 159" + "160 161 162 163 164 165 166 167 168 169" + "170 171 172 173 174 175 176 177 178 179" + "180 181 182 183 184 185 186 187 188 189" + "190 191 192 193 194 195 196 197 198 199" + "200 201 202 203 204 205 206 207 208 209" + "210 211 212 213 214 215 216 217 218 219" + "220 221 222 223 224 225 226 227 228 229" + "230 231 232 233 234 235 236 237 238 239" + "240 241 242 243 244 245 246 247 248 249" + "250 251 252 253 254 255 256 257 258 259" + "260 261 262 263 264 265 266 267 268 269" + "270 271 272 273 274 275 276 277 278 279" + "280 281 282 283 284 285 286 287 288 289" + "290 291 292 293 294 295 296 297 298 299" + "300 301 302 303 304 305 306 307 308 309" + "310 311 312 313 314 315 316 317 318 319" + "320 321 322 323 324 325 326 327 328 329" + "330 331 332 333 334 335 336 337 338 339" + "340 341 342 343 344 345 346 347 348 349" + "350 351 352 353 354 355 356 357 358 359" + "360 361 362 363 364 365 366 367 368 369" + "370 371 372 373 374 375 376 377 378 379" + "380 381 382 383 384 385 386 387 388 389" + "390 391 392 393 394 395 396 397 398 399" + "400 401 402 403 404 405 406 407 408 409" + "410 411 412 413 414 415 416 417 418 419" + "420 421 422 423 424 425 426 427 428 429" + "430 431 432 433 434 435 436 437 438 439" + "440 441 442 443 444 445 446 447 448 449" + "450 451 452 453 454 455 456 457 458 459" + "460 461 462 463 464 465 466 467 468 469" + "470 471 472 473 474 475 476 477 478 479" + "480 481 482 483 484 485 486 487 488 489" + "490 491 492 493 494 495 496 497 498 499" + "500 501 502 503 504 505 506 507 508 509" + "510 511 512 513 514 515 516 517 518 519" + "520 521 522 523 524 525 526 527 528 529" + "530 531 532 533 534 535 536 537 538 539" + "540 541 542 543 544 545 546 547 548 549" + "550 551 552 553 554 555 556 557 558 559" + "560 561 562 563 564 565 566 567 568 569" + "570 571 572 573 574 575 576 577 578 579" + "580 581 582 583 584 585 586 587 588 589" + "590 591 592 593 594 595 596 597 598 599" + "600 601 602 603 604 605 606 607 608 609" + "610 611 612 613 614 615 616 617 618 619" + "620 621 622 623 624 625 626 627 628 629" + "630 631 632 633 634 635 636 637 638 639" + "640 641 642 643 644 645 646 647 648 649" + "650 651 652 653 654 655 656 657 658 659" + "660 661 662 663 664 665 666 667 668 669" + "670 671 672 673 674 675 676 677 678 679" + "680 681 682 683 684 685 686 687 688 689" + "690 691 692 693 694 695 696 697 698 699" + "700 701 702 703 704 705 706 707 708 709" + "710 711 712 713 714 715 716 717 718 719" + "720 721 722 723 724 725 726 727 728 729" + "730 731 732 733 734 735 736 737 738 739" + "740 741 742 743 744 745 746 747 748 749" + "750 751 752 753 754 755 756 757 758 759" + "760 761 762 763 764 765 766 767 768 769" + "770 771 772 773 774 775 776 777 778 779" + "780 781 782 783 784 785 786 787 788 789" + "790 791 792 793 794 795 796 797 798 799" + "800 801 802 803 804 805 806 807 808 809" + "810 811 812 813 814 815 816 817 818 819" + "820 821 822 823 824 825 826 827 828 829" + "830 831 832 833 834 835 836 837 838 839" + "840 841 842 843 844 845 846 847 848 849" + "850 851 852 853 854 855 856 857 858 859" + "860 861 862 863 864 865 866 867 868 869" + "870 871 872 873 874 875 876 877 878 879" + "880 881 882 883 884 885 886 887 888 889" + "890 891 892 893 894 895 896 897 898 899" + "900 901 902 903 904 905 906 907 908 909" + "910 911 912 913 914 915 916 917 918 919" + "920 921 922 923 924 925 926 927 928 929" + "930 931 932 933 934 935 936 937 938 939" + "940 941 942 943 944 945 946 947 948 949" + "950 951 952 953 954 955 956 957 958 959" + "960 961 962 963 964 965 966 967 968 969" + "970 971 972 973 974 975 976 977 978 979" + "980 981 982 983 984 985 986 987 988 989" + "990 991 992 993 994 995 996 997 998 999"; +--enable_result_log +prepare long_query from "select ? as long_query"; +--disable_result_log +execute long_query using @lparam; +--enable_result_log +select command_type, argument from mysql.general_log; +deallocate prepare long_query; +set global general_log = @old_general_log_state; diff --git a/sql/log.cc b/sql/log.cc index 9d6f6fa4c9b..e923418b23a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -944,73 +944,65 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, return error; } -bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, - const char *format, va_list args) +bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, + const char *query, uint query_length) { bool error= FALSE; Log_event_handler **current_handler= general_log_handler_list; + char user_host_buff[MAX_USER_HOST_SIZE]; + Security_context *sctx= thd->security_ctx; + ulong id; + uint user_host_len= 0; + time_t current_time; - /* - Print the message to the buffer if we have at least one log event handler - enabled and want to log this king of commands - */ - if (*general_log_handler_list && (what_to_log & (1L << (uint) command))) + if (thd) + id= thd->thread_id; /* Normal thread */ + else + id= 0; /* Log from connect handler */ + + lock_shared(); + if (!opt_log) { - char message_buff[MAX_LOG_BUFFER_SIZE]; - char user_host_buff[MAX_USER_HOST_SIZE]; - Security_context *sctx= thd->security_ctx; - ulong id; - uint message_buff_len= 0, user_host_len= 0; - time_t current_time; - if (thd) - { /* Normal thread */ - if ((thd->options & OPTION_LOG_OFF) -#ifndef NO_EMBEDDED_ACCESS_CHECKS - && (sctx->master_access & SUPER_ACL) -#endif - ) - { - return 0; /* No logging */ - } - id= thd->thread_id; - } - else - id=0; /* Log from connect handler */ - - lock_shared(); - if (!opt_log) - { - unlock(); - return 0; - } - user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE, - sctx->priv_user ? sctx->priv_user : "", "[", - sctx->user ? sctx->user : "", "] @ ", - sctx->host ? sctx->host : "", " [", - sctx->ip ? sctx->ip : "", "]", NullS) - - user_host_buff; - - /* prepare message */ - if (format) - message_buff_len= my_vsnprintf(message_buff, - sizeof(message_buff), format, args); - else - message_buff[0]= '\0'; - - current_time= my_time(0); - while (*current_handler) - error+= (*current_handler++)-> - log_general(thd, current_time, user_host_buff, - user_host_len, id, - command_name[(uint) command].str, - command_name[(uint) command].length, - message_buff, message_buff_len, - thd->variables.character_set_client) || error; unlock(); + return 0; } + user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE, + sctx->priv_user ? sctx->priv_user : "", "[", + sctx->user ? sctx->user : "", "] @ ", + sctx->host ? sctx->host : "", " [", + sctx->ip ? sctx->ip : "", "]", NullS) - + user_host_buff; + + current_time= my_time(0); + while (*current_handler) + error+= (*current_handler++)-> + log_general(thd, current_time, user_host_buff, + user_host_len, id, + command_name[(uint) command].str, + command_name[(uint) command].length, + query, query_length, + thd->variables.character_set_client) || error; + unlock(); + return error; } +bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, + const char *format, va_list args) +{ + uint message_buff_len= 0; + char message_buff[MAX_LOG_BUFFER_SIZE]; + + /* prepare message */ + if (format) + message_buff_len= my_vsnprintf(message_buff, sizeof(message_buff), + format, args); + else + message_buff[0]= '\0'; + + return general_log_write(thd, command, message_buff, message_buff_len); +} + void LOGGER::init_error_log(uint error_log_printer) { if (error_log_printer & LOG_NONE) @@ -2075,10 +2067,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, if (my_b_write(&log_file, (uchar*) buff, buff_len)) tmp_errno= errno; } - if (my_b_printf(&log_file, "# User@Host: ", sizeof("# User@Host: ") - 1) - != sizeof("# User@Host: ") - 1) + const uchar uh[]= "# User@Host: "; + if (my_b_write(&log_file, uh, sizeof(uh) - 1)) tmp_errno= errno; - if (my_b_printf(&log_file, user_host, user_host_len) != user_host_len) + if (my_b_write(&log_file, (uchar*) user_host, user_host_len)) tmp_errno= errno; if (my_b_write(&log_file, (uchar*) "\n", 1)) tmp_errno= errno; @@ -3736,12 +3728,44 @@ bool slow_log_print(THD *thd, const char *query, uint query_length, } +bool LOGGER::log_command(THD *thd, enum enum_server_command command) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *sctx= thd->security_ctx; +#endif + /* + Log command if we have at least one log event handler enabled and want + to log this king of commands + */ + if (*general_log_handler_list && (what_to_log & (1L << (uint) command))) + { + if ((thd->options & OPTION_LOG_OFF) +#ifndef NO_EMBEDDED_ACCESS_CHECKS + && (sctx->master_access & SUPER_ACL) +#endif + ) + { + /* No logging */ + return FALSE; + } + + return TRUE; + } + + return FALSE; +} + + bool general_log_print(THD *thd, enum enum_server_command command, const char *format, ...) { va_list args; uint error= 0; + /* Print the message to the buffer if we want to log this king of commands */ + if (! logger.log_command(thd, command)) + return FALSE; + va_start(args, format); error= logger.general_log_print(thd, command, format, args); va_end(args); @@ -3749,6 +3773,16 @@ bool general_log_print(THD *thd, enum enum_server_command command, return error; } +bool general_log_write(THD *thd, enum enum_server_command command, + const char *query, uint query_length) +{ + /* Write the message to the log if we want to log this king of commands */ + if (logger.log_command(thd, command)) + return logger.general_log_write(thd, command, query, query_length); + + return FALSE; +} + void MYSQL_BIN_LOG::rotate_and_purge(uint flags) { if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) diff --git a/sql/log.h b/sql/log.h index e597c986794..bef0101c8b5 100644 --- a/sql/log.h +++ b/sql/log.h @@ -499,6 +499,8 @@ public: void lock_exclusive() { rw_wrlock(&LOCK_logger); } void unlock() { rw_unlock(&LOCK_logger); } bool is_log_table_enabled(uint log_table_type); + bool log_command(THD *thd, enum enum_server_command command); + /* We want to initialize all log mutexes as soon as possible, but we cannot do it in constructor, as safe_mutex relies on @@ -518,6 +520,8 @@ public: ulonglong current_utime); bool general_log_print(THD *thd,enum enum_server_command command, const char *format, va_list args); + bool general_log_write(THD *thd, enum enum_server_command command, + const char *query, uint query_length); /* we use this function to setup all enabled log event handlers */ int set_handlers(uint error_log_printer, diff --git a/sql/log_event.cc b/sql/log_event.cc index d8e22953fc2..a435894382b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2113,7 +2113,7 @@ START SLAVE; . Query: '%s'", expected_error, thd->query); /* If the query was not ignored, it is printed to the general log */ if (thd->net.last_errno != ER_SLAVE_IGNORED_TABLE) - general_log_print(thd, COM_QUERY, "%s", thd->query); + general_log_write(thd, COM_QUERY, thd->query, thd->query_length); compare_errors: diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 79d4c16f9c1..08e535548e0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -740,6 +740,9 @@ bool slow_log_print(THD *thd, const char *query, uint query_length, bool general_log_print(THD *thd, enum enum_server_command command, const char *format,...); +bool general_log_write(THD *thd, enum enum_server_command command, + const char *query, uint query_length); + #include "sql_class.h" #include "sql_acl.h" #include "tztime.h" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 7de230bba78..6e0da982369 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2707,7 +2707,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) queries with SP vars can't be cached) */ if (unlikely((thd->options & OPTION_LOG_OFF)==0)) - general_log_print(thd, COM_QUERY, "%s", thd->query); + general_log_write(thd, COM_QUERY, thd->query, thd->query_length); if (query_cache_send_result_to_client(thd, thd->query, thd->query_length) <= 0) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 695e923e816..83ac2ee44dc 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -782,7 +782,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, packet, packet_length, thd->charset()); if (!mysql_change_db(thd, &tmp, FALSE)) { - general_log_print(thd, command, "%s",thd->db); + general_log_write(thd, command, thd->db, thd->db_length); send_ok(thd); } break; @@ -980,10 +980,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; // fatal error is set char *packet_end= thd->query + thd->query_length; /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */ - const char *format= "%.*b"; const char* found_semicolon= NULL; - general_log_print(thd, command, format, thd->query_length, thd->query); + general_log_write(thd, command, thd->query, thd->query_length); DBUG_PRINT("query",("%-.4096s",thd->query)); if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -1142,7 +1141,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); break; } - general_log_print(thd, command, db.str); + general_log_write(thd, command, db.str, db.length); mysql_rm_db(thd, db.str, 0, 0); break; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 05743b6dfe3..a6cdcf14881 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2947,12 +2947,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) the general log. */ if (thd->spcont == NULL) - { - const char *format= "[%lu] %.*b"; - general_log_print(thd, COM_STMT_PREPARE, format, id, - query_length, query); - - } + general_log_write(thd, COM_STMT_PREPARE, query, query_length); } DBUG_RETURN(error); } @@ -3150,11 +3145,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) the general log. */ if (error == 0 && thd->spcont == NULL) - { - const char *format= "[%lu] %.*b"; - general_log_print(thd, COM_STMT_EXECUTE, format, id, - thd->query_length, thd->query); - } + general_log_write(thd, COM_STMT_EXECUTE, thd->query, thd->query_length); error: flags&= ~ (uint) IS_IN_USE; From a2aafb6034f0c8d52f93acc91ee50c17ad281798 Mon Sep 17 00:00:00 2001 From: "davi@moksha.com.br" <> Date: Thu, 18 Oct 2007 17:24:57 -0300 Subject: [PATCH 55/55] Post merge fix for Bug 21557 --- mysql-test/r/log_tables.result | 3 ++- mysql-test/t/log_tables.test | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index 11c2df2ea2e..337d6b0eca8 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -710,6 +710,7 @@ set @lparam = "000 001 002 003 004 005 006 007 008 009" "990 991 992 993 994 995 996 997 998 999"; prepare long_query from "select ? as long_query"; execute long_query using @lparam; +set global general_log = off; select command_type, argument from mysql.general_log; command_type argument Query set @lparam = "000 001 002 003 004 005 006 007 008 009" @@ -816,6 +817,6 @@ Query prepare long_query from "select ? as long_query" Prepare select ? as long_query Query execute long_query using @lparam Execute select '000 001 002 003 004 005 006 007 008 009010 011 012 013 014 015 016 017 018 019020 021 022 023 024 025 026 027 028 029030 031 032 033 034 035 036 037 038 039040 041 042 043 044 045 046 047 048 049050 051 052 053 054 055 056 057 058 059060 061 062 063 064 065 066 067 068 069070 071 072 073 074 075 076 077 078 079080 081 082 083 084 085 086 087 088 089090 091 092 093 094 095 096 097 098 099100 101 102 103 104 105 106 107 108 109110 111 112 113 114 115 116 117 118 119120 121 122 123 124 125 126 127 128 129130 131 132 133 134 135 136 137 138 139140 141 142 143 144 145 146 147 148 149150 151 152 153 154 155 156 157 158 159160 161 162 163 164 165 166 167 168 169170 171 172 173 174 175 176 177 178 179180 181 182 183 184 185 186 187 188 189190 191 192 193 194 195 196 197 198 199200 201 202 203 204 205 206 207 208 209210 211 212 213 214 215 216 217 218 219220 221 222 223 224 225 226 227 228 229230 231 232 233 234 235 236 237 238 239240 241 242 243 244 245 246 247 248 249250 251 252 253 254 255 256 257 258 259260 261 262 263 264 265 266 267 268 269270 271 272 273 274 275 276 277 278 279280 281 282 283 284 285 286 287 288 289290 291 292 293 294 295 296 297 298 299300 301 302 303 304 305 306 307 308 309310 311 312 313 314 315 316 317 318 319320 321 322 323 324 325 326 327 328 329330 331 332 333 334 335 336 337 338 339340 341 342 343 344 345 346 347 348 349350 351 352 353 354 355 356 357 358 359360 361 362 363 364 365 366 367 368 369370 371 372 373 374 375 376 377 378 379380 381 382 383 384 385 386 387 388 389390 391 392 393 394 395 396 397 398 399400 401 402 403 404 405 406 407 408 409410 411 412 413 414 415 416 417 418 419420 421 422 423 424 425 426 427 428 429430 431 432 433 434 435 436 437 438 439440 441 442 443 444 445 446 447 448 449450 451 452 453 454 455 456 457 458 459460 461 462 463 464 465 466 467 468 469470 471 472 473 474 475 476 477 478 479480 481 482 483 484 485 486 487 488 489490 491 492 493 494 495 496 497 498 499500 501 502 503 504 505 506 507 508 509510 511 512 513 514 515 516 517 518 519520 521 522 523 524 525 526 527 528 529530 531 532 533 534 535 536 537 538 539540 541 542 543 544 545 546 547 548 549550 551 552 553 554 555 556 557 558 559560 561 562 563 564 565 566 567 568 569570 571 572 573 574 575 576 577 578 579580 581 582 583 584 585 586 587 588 589590 591 592 593 594 595 596 597 598 599600 601 602 603 604 605 606 607 608 609610 611 612 613 614 615 616 617 618 619620 621 622 623 624 625 626 627 628 629630 631 632 633 634 635 636 637 638 639640 641 642 643 644 645 646 647 648 649650 651 652 653 654 655 656 657 658 659660 661 662 663 664 665 666 667 668 669670 671 672 673 674 675 676 677 678 679680 681 682 683 684 685 686 687 688 689690 691 692 693 694 695 696 697 698 699700 701 702 703 704 705 706 707 708 709710 711 712 713 714 715 716 717 718 719720 721 722 723 724 725 726 727 728 729730 731 732 733 734 735 736 737 738 739740 741 742 743 744 745 746 747 748 749750 751 752 753 754 755 756 757 758 759760 761 762 763 764 765 766 767 768 769770 771 772 773 774 775 776 777 778 779780 781 782 783 784 785 786 787 788 789790 791 792 793 794 795 796 797 798 799800 801 802 803 804 805 806 807 808 809810 811 812 813 814 815 816 817 818 819820 821 822 823 824 825 826 827 828 829830 831 832 833 834 835 836 837 838 839840 841 842 843 844 845 846 847 848 849850 851 852 853 854 855 856 857 858 859860 861 862 863 864 865 866 867 868 869870 871 872 873 874 875 876 877 878 879880 881 882 883 884 885 886 887 888 889890 891 892 893 894 895 896 897 898 899900 901 902 903 904 905 906 907 908 909910 911 912 913 914 915 916 917 918 919920 921 922 923 924 925 926 927 928 929930 931 932 933 934 935 936 937 938 939940 941 942 943 944 945 946 947 948 949950 951 952 953 954 955 956 957 958 959960 961 962 963 964 965 966 967 968 969970 971 972 973 974 975 976 977 978 979980 981 982 983 984 985 986 987 988 989990 991 992 993 994 995 996 997 998 999' as long_query -Query select command_type, argument from mysql.general_log +Query set global general_log = off deallocate prepare long_query; set global general_log = @old_general_log_state; diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index 9fdf77eb575..c4bce2fbf3d 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -920,6 +920,7 @@ prepare long_query from "select ? as long_query"; --disable_result_log execute long_query using @lparam; --enable_result_log +set global general_log = off; select command_type, argument from mysql.general_log; deallocate prepare long_query; set global general_log = @old_general_log_state;