summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqldump.c13
-rw-r--r--extra/my_print_defaults.c23
-rw-r--r--include/my_global.h11
-rw-r--r--mysql-test/include/have_lowercase1.inc4
-rw-r--r--mysql-test/lib/mtr_report.pl4
-rw-r--r--mysql-test/r/alter_table.result24
-rw-r--r--mysql-test/r/func_math.result95
-rw-r--r--mysql-test/r/lowercase1.require2
-rw-r--r--mysql-test/r/lowercase_mixed_tmpdir.result6
-rw-r--r--mysql-test/r/mysqldump.result27
-rw-r--r--mysql-test/r/type_newdecimal.result2
-rw-r--r--mysql-test/r/update.result35
-rw-r--r--mysql-test/t/alter_table.test26
-rw-r--r--mysql-test/t/func_math.test39
-rw-r--r--mysql-test/t/lowercase_mixed_tmpdir-master.opt2
-rw-r--r--mysql-test/t/lowercase_mixed_tmpdir-master.sh6
-rw-r--r--mysql-test/t/lowercase_mixed_tmpdir.test12
-rw-r--r--mysql-test/t/mysqldump.test35
-rw-r--r--mysql-test/t/update.test55
-rw-r--r--mysys/default.c2
-rw-r--r--mysys/my_copy.c7
-rw-r--r--scripts/mysql_install_db.sh6
-rw-r--r--scripts/mysqld_multi.sh312
-rw-r--r--sql/item_func.cc115
-rw-r--r--sql/item_func.h8
-rw-r--r--sql/item_strfunc.cc2
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_table.cc32
-rw-r--r--sql/sql_update.cc19
29 files changed, 650 insertions, 277 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 63db2cc268e..4f908b531b1 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -1489,8 +1489,15 @@ static uint dump_routines_for_db(char *db)
routine body of other routines that are not the creator of!
*/
DBUG_PRINT("info",("length of body for %s row[2] '%s' is %d",
- routine_name, row[2], (int) strlen(row[2])));
- if (strlen(row[2]))
+ routine_name, row[2] ? row[2] : "(null)",
+ row[2] ? (int) strlen(row[2]) : 0));
+ if (row[2] == NULL)
+ {
+ fprintf(sql_file, "\n-- insufficient privileges to %s\n", query_buff);
+ fprintf(sql_file, "-- does %s have permissions on mysql.proc?\n\n", current_user);
+ maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!", current_user, query_buff);
+ }
+ else if (strlen(row[2]))
{
char *query_str= NULL;
char *definer_begin;
@@ -1540,7 +1547,7 @@ static uint dump_routines_for_db(char *db)
/*
we need to change sql_mode only for the CREATE
PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name
- */;
+ */
fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/;;\n",
row[1] /* sql_mode */);
fprintf(sql_file, "/*!50003 %s */;;\n",
diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c
index eb077f91ece..f5f7e68c9e6 100644
--- a/extra/my_print_defaults.c
+++ b/extra/my_print_defaults.c
@@ -33,7 +33,20 @@ const char *default_dbug_option="d:t:o,/tmp/my_print_defaults.trace";
static struct my_option my_long_options[] =
{
- {"config-file", 'c', "The config file to be used.",
+ /*
+ NB: --config-file is troublesome, because get_defaults_options() doesn't
+ know about it, but we pretend --config-file is like --defaults-file. In
+ fact they behave differently: see the comments at the top of
+ mysys/default.c for how --defaults-file should behave.
+
+ This --config-file option behaves as:
+ - If it has a directory name part (absolute or relative), then only this
+ file is read; no error is given if the file doesn't exist
+ - If the file has no directory name part, the standard locations are
+ searched for a file of this name (and standard filename extensions are
+ added if the file has no extension)
+ */
+ {"config-file", 'c', "Deprecated, please use --defaults-file instead. Name of config file to read; if no extension is given, default extension (e.g., .ini or .cnf) will be added",
(gptr*) &config_file, (gptr*) &config_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
#ifdef DBUG_OFF
@@ -43,11 +56,11 @@ static struct my_option my_long_options[] =
{"debug", '#', "Output debug log", (gptr*) &default_dbug_option,
(gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"defaults-file", 'c', "Synonym for --config-file.",
+ {"defaults-file", 'c', "Like --config-file, except: if first option, then read this file only, do not read global or per-user config files; should be the first option",
(gptr*) &config_file, (gptr*) &config_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"defaults-extra-file", 'e',
- "Read this file after the global /etc config file and before the config file in the users home directory.",
+ "Read this file after the global config file and before the config file in the users home directory; should be the first option",
(gptr*) &my_defaults_extra_file, (gptr*) &my_defaults_extra_file, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"defaults-group-suffix", 'g',
@@ -55,7 +68,7 @@ static struct my_option my_long_options[] =
(gptr*) &my_defaults_group_suffix, (gptr*) &my_defaults_group_suffix,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"extra-file", 'e',
- "Synonym for --defaults-extra-file.",
+ "Deprecated. Synonym for --defaults-extra-file.",
(gptr*) &my_defaults_extra_file,
(gptr*) &my_defaults_extra_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -86,7 +99,7 @@ static void usage(my_bool version)
my_print_help(my_long_options);
my_print_default_files(config_file);
my_print_variables(my_long_options);
- printf("\nExample usage:\n%s --config-file=my client mysql\n", my_progname);
+ printf("\nExample usage:\n%s --defaults-file=example.cnf client mysql\n", my_progname);
}
#include <help_end.h>
diff --git a/include/my_global.h b/include/my_global.h
index f446c283d50..e9b371d8d30 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -784,13 +784,20 @@ typedef SOCKET_SIZE_TYPE size_socket;
#define SSIZE_MAX ((~((size_t) 0)) / 2)
#endif
+#ifndef HAVE_FINITE
+#define finite(x) (1.0 / fabs(x) > 0.0)
+#endif
+
+#ifndef HAVE_ISNAN
+#define isnan(x) ((x) != (x))
+#endif
+
#if !defined(HAVE_ISINF)
/* The configure check for "isinf with math.h" has failed */
#ifdef isinf
#undef isinf
#endif
-/* Define isinf to never say that X is infinite */
-#define isinf(X) 0
+#define isinf(X) (!finite(X) && !isnan(X))
#endif
/* Define missing math constants. */
diff --git a/mysql-test/include/have_lowercase1.inc b/mysql-test/include/have_lowercase1.inc
new file mode 100644
index 00000000000..1b33432dbe3
--- /dev/null
+++ b/mysql-test/include/have_lowercase1.inc
@@ -0,0 +1,4 @@
+--require r/lowercase1.require
+--disable_query_log
+show variables like 'lower_case_table_names';
+--enable_query_log
diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl
index a2f22ef8870..d08208d37a6 100644
--- a/mysql-test/lib/mtr_report.pl
+++ b/mysql-test/lib/mtr_report.pl
@@ -238,7 +238,7 @@ sub mtr_report_stats ($) {
}
if (!$::opt_extern)
{
- print "The servers where restarted $tot_restarts times\n";
+ print "The servers were restarted $tot_restarts times\n";
}
if ( $::opt_timer )
@@ -357,7 +357,7 @@ sub mtr_report_stats ($) {
if ( $tot_failed != 0 || $found_problems)
{
- mtr_error("there where failing test cases");
+ mtr_error("there were failing test cases");
}
}
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 82c35ff963a..280cedb8b89 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -860,3 +860,27 @@ ALTER TABLE t1 ADD d INT;
ALTER TABLE t1 ADD KEY (d(20));
ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys
DROP TABLE t1;
+create table t1(id int(8) primary key auto_increment) engine=heap;
+insert into t1 values (null);
+insert into t1 values (null);
+select * from t1;
+id
+1
+2
+alter table t1 auto_increment = 50;
+alter table t1 engine = myisam;
+insert into t1 values (null);
+select * from t1;
+id
+1
+2
+50
+alter table t1 engine = heap;
+insert into t1 values (null);
+select * from t1;
+id
+1
+2
+50
+51
+drop table t1;
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index fc9bfb3b612..ace94217fdc 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -143,9 +143,6 @@ select format(col2,6) from t1 where col1=7;
format(col2,6)
1,234,567,890,123,456.123450
drop table t1;
-select round(150, 2);
-round(150, 2)
-150.00
select ceil(0.09);
ceil(0.09)
1
@@ -156,11 +153,11 @@ create table t1 select round(1, 6);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `round(1, 6)` decimal(7,6) NOT NULL default '0.000000'
+ `round(1, 6)` int(1) NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1;
round(1, 6)
-1.000000
+1
drop table t1;
select abs(-2) * -2;
abs(-2) * -2
@@ -238,3 +235,91 @@ format(t2.f2-t2.f1+1,0)
10,000
drop table t1, t2;
set names default;
+select cast(-2 as unsigned), 18446744073709551614, -2;
+cast(-2 as unsigned) 18446744073709551614 -2
+18446744073709551614 18446744073709551614 -2
+select abs(cast(-2 as unsigned)), abs(18446744073709551614), abs(-2);
+abs(cast(-2 as unsigned)) abs(18446744073709551614) abs(-2)
+18446744073709551614 18446744073709551614 2
+select ceiling(cast(-2 as unsigned)), ceiling(18446744073709551614), ceiling(-2);
+ceiling(cast(-2 as unsigned)) ceiling(18446744073709551614) ceiling(-2)
+18446744073709551614 18446744073709551614 -2
+select floor(cast(-2 as unsigned)), floor(18446744073709551614), floor(-2);
+floor(cast(-2 as unsigned)) floor(18446744073709551614) floor(-2)
+18446744073709551614 18446744073709551614 -2
+select format(cast(-2 as unsigned), 2), format(18446744073709551614, 2), format(-2, 2);
+format(cast(-2 as unsigned), 2) format(18446744073709551614, 2) format(-2, 2)
+18,446,744,073,709,551,614.00 18,446,744,073,709,551,614.00 -2.00
+select sqrt(cast(-2 as unsigned)), sqrt(18446744073709551614), sqrt(-2);
+sqrt(cast(-2 as unsigned)) sqrt(18446744073709551614) sqrt(-2)
+4294967296 4294967296 NULL
+select round(cast(-2 as unsigned), 1), round(18446744073709551614, 1), round(-2, 1);
+round(cast(-2 as unsigned), 1) round(18446744073709551614, 1) round(-2, 1)
+18446744073709551614 18446744073709551614 -2
+select round(4, cast(-2 as unsigned)), round(4, 18446744073709551614), round(4, -2);
+round(4, cast(-2 as unsigned)) round(4, 18446744073709551614) round(4, -2)
+4 4 0
+select truncate(cast(-2 as unsigned), 1), truncate(18446744073709551614, 1), truncate(-2, 1);
+truncate(cast(-2 as unsigned), 1) truncate(18446744073709551614, 1) truncate(-2, 1)
+18446744073709551614 18446744073709551614 -2
+select truncate(4, cast(-2 as unsigned)), truncate(4, 18446744073709551614), truncate(4, -2);
+truncate(4, cast(-2 as unsigned)) truncate(4, 18446744073709551614) truncate(4, -2)
+4 4 0
+select round(10000000000000000000, -19), truncate(10000000000000000000, -19);
+round(10000000000000000000, -19) truncate(10000000000000000000, -19)
+10000000000000000000 10000000000000000000
+select round(1e0, -309), truncate(1e0, -309);
+round(1e0, -309) truncate(1e0, -309)
+0 0
+select round(1e1,308), truncate(1e1, 308);
+round(1e1,308) truncate(1e1, 308)
+10 10
+select round(1e1, 2147483648), truncate(1e1, 2147483648);
+round(1e1, 2147483648) truncate(1e1, 2147483648)
+10 10
+select round(1.1e1, 4294967295), truncate(1.1e1, 4294967295);
+round(1.1e1, 4294967295) truncate(1.1e1, 4294967295)
+11 11
+select round(1.12e1, 4294967296), truncate(1.12e1, 4294967296);
+round(1.12e1, 4294967296) truncate(1.12e1, 4294967296)
+11.2 11.2
+select round(1.5, 2147483640), truncate(1.5, 2147483640);
+round(1.5, 2147483640) truncate(1.5, 2147483640)
+1.500000000000000000000000000000 1.500000000000000000000000000000
+select round(1.5, -2147483649), round(1.5, 2147483648);
+round(1.5, -2147483649) round(1.5, 2147483648)
+0 1.500000000000000000000000000000
+select truncate(1.5, -2147483649), truncate(1.5, 2147483648);
+truncate(1.5, -2147483649) truncate(1.5, 2147483648)
+0 1.500000000000000000000000000000
+select round(1.5, -4294967296), round(1.5, 4294967296);
+round(1.5, -4294967296) round(1.5, 4294967296)
+0 1.500000000000000000000000000000
+select truncate(1.5, -4294967296), truncate(1.5, 4294967296);
+truncate(1.5, -4294967296) truncate(1.5, 4294967296)
+0 1.500000000000000000000000000000
+select round(1.5, -9223372036854775808), round(1.5, 9223372036854775808);
+round(1.5, -9223372036854775808) round(1.5, 9223372036854775808)
+0 1.500000000000000000000000000000
+select truncate(1.5, -9223372036854775808), truncate(1.5, 9223372036854775808);
+truncate(1.5, -9223372036854775808) truncate(1.5, 9223372036854775808)
+0 1.500000000000000000000000000000
+select round(1.5, 18446744073709551615), truncate(1.5, 18446744073709551615);
+round(1.5, 18446744073709551615) truncate(1.5, 18446744073709551615)
+1.500000000000000000000000000000 1.500000000000000000000000000000
+select round(18446744073709551614, -1), truncate(18446744073709551614, -1);
+round(18446744073709551614, -1) truncate(18446744073709551614, -1)
+18446744073709551610 18446744073709551610
+select round(4, -4294967200), truncate(4, -4294967200);
+round(4, -4294967200) truncate(4, -4294967200)
+0 0
+select mod(cast(-2 as unsigned), 3), mod(18446744073709551614, 3), mod(-2, 3);
+mod(cast(-2 as unsigned), 3) mod(18446744073709551614, 3) mod(-2, 3)
+2 2 -2
+select mod(5, cast(-2 as unsigned)), mod(5, 18446744073709551614), mod(5, -2);
+mod(5, cast(-2 as unsigned)) mod(5, 18446744073709551614) mod(5, -2)
+5 5 1
+select pow(cast(-2 as unsigned), 5), pow(18446744073709551614, 5), pow(-2, 5);
+pow(cast(-2 as unsigned), 5) pow(18446744073709551614, 5) pow(-2, 5)
+2.1359870359209e+96 2.1359870359209e+96 -32
+End of 5.0 tests
diff --git a/mysql-test/r/lowercase1.require b/mysql-test/r/lowercase1.require
new file mode 100644
index 00000000000..0341f838f7b
--- /dev/null
+++ b/mysql-test/r/lowercase1.require
@@ -0,0 +1,2 @@
+Variable_name Value
+lower_case_table_names 1
diff --git a/mysql-test/r/lowercase_mixed_tmpdir.result b/mysql-test/r/lowercase_mixed_tmpdir.result
new file mode 100644
index 00000000000..e11b5e4c286
--- /dev/null
+++ b/mysql-test/r/lowercase_mixed_tmpdir.result
@@ -0,0 +1,6 @@
+drop table if exists t1;
+create table t1 (id int) engine=myisam;
+insert into t1 values (1);
+create temporary table t2 select * from t1;
+drop temporary table t2;
+drop table t1;
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index 5caaa9264d0..d9198ffeb48 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -3282,6 +3282,33 @@ v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VI
drop database bug23491_original;
drop database bug23491_restore;
use test;
+#
+# Bug 27293: mysqldump crashes when dumping routines
+# defined by a different user
+#
+# Bug #22761: mysqldump reports no errors when using
+# --routines without mysql.proc privileges
+#
+create database mysqldump_test_db;
+grant all privileges on mysqldump_test_db.* to user1;
+grant all privileges on mysqldump_test_db.* to user2;
+create procedure mysqldump_test_db.sp1() select 'hello';
+DELIMITER ;;
+
+-- insufficient privileges to SHOW CREATE PROCEDURE `sp1`
+-- does user2 have permissions on mysql.proc?
+
+DELIMITER ;
+DELIMITER ;;
+/*!50003 SET SESSION SQL_MODE=""*/;;
+/*!50003 CREATE*/ /*!50020 DEFINER=`user1`@`%`*/ /*!50003 PROCEDURE `sp1`()
+select 'hello' */;;
+/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;;
+DELIMITER ;
+drop procedure sp1;
+drop user user1;
+drop user user2;
+drop database mysqldump_test_db;
#
# End of 5.0 tests
#
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index 359a929d9a3..c103de81bd7 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -763,7 +763,7 @@ truncate(99999999999999999999999999999999999999,31)
99999999999999999999999999999999999999.000000000000000000000000000000
select truncate(99.999999999999999999999999999999999999,31);
truncate(99.999999999999999999999999999999999999,31)
-100.000000000000000000000000000000
+99.999999999999999999999999999999
select truncate(99999999999999999999999999999999999999,-31);
truncate(99999999999999999999999999999999999999,-31)
99999990000000000000000000000000000000
diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result
index 748c2644eb9..dc7c7642a9b 100644
--- a/mysql-test/r/update.result
+++ b/mysql-test/r/update.result
@@ -457,3 +457,38 @@ a quux
2 0.100000000000000000000000000000
3 NULL
DROP TABLE t1;
+set tmp_table_size=1024;
+create table t1 (id int, a int, key idx(a));
+create table t2 (id int unsigned not null auto_increment primary key, a int);
+insert into t2(a) values(1),(2),(3),(4),(5),(6),(7),(8);
+insert into t2(a) select a from t2;
+insert into t2(a) select a from t2;
+insert into t2(a) select a from t2;
+update t2 set a=id;
+insert into t1 select * from t2;
+select count(*) from t1 join t2 on (t1.a=t2.a);
+count(*)
+64
+update t1 join t2 on (t1.a=t2.a) set t1.id=t2.id;
+affected rows: 0
+info: Rows matched: 64 Changed: 0 Warnings: 0
+insert into t2(a) select a from t2;
+update t2 set a=id;
+truncate t1;
+insert into t1 select * from t2;
+select count(*) from t1 join t2 on (t1.a=t2.a);
+count(*)
+128
+update t1 join t2 on (t1.a=t2.a) set t1.id=t2.id;
+affected rows: 0
+info: Rows matched: 128 Changed: 0 Warnings: 0
+update t1 set a=1;
+update t2 set a=1;
+select count(*) from t1 join t2 on (t1.a=t2.a);
+count(*)
+16384
+update t1 join t2 on (t1.a=t2.a) set t1.id=t2.id;
+affected rows: 127
+info: Rows matched: 128 Changed: 127 Warnings: 0
+drop table t1,t2;
+End of 5.0 tests
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index 307138added..83686f31e9e 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -636,3 +636,29 @@ ALTER TABLE t1 ADD d INT;
ALTER TABLE t1 ADD KEY (d(20));
DROP TABLE t1;
+# Bug#25262 Auto Increment lost when changing Engine type
+#
+
+create table t1(id int(8) primary key auto_increment) engine=heap;
+
+insert into t1 values (null);
+insert into t1 values (null);
+
+select * from t1;
+
+# Set auto increment to 50
+alter table t1 auto_increment = 50;
+
+# Alter to myisam
+alter table t1 engine = myisam;
+
+# This insert should get id 50
+insert into t1 values (null);
+select * from t1;
+
+# Alter to heap again
+alter table t1 engine = heap;
+insert into t1 values (null);
+select * from t1;
+
+drop table t1;
diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
index 4041c267134..2ba07dfc581 100644
--- a/mysql-test/t/func_math.test
+++ b/mysql-test/t/func_math.test
@@ -83,11 +83,6 @@ drop table t1;
#
-# Bug #10083 (round doesn't increase decimals)
-#
-select round(150, 2);
-
-#
# Bug @10632 (Ceiling function returns wrong answer)
#
select ceil(0.09);
@@ -177,3 +172,37 @@ select format(t2.f2-t2.f1+1,0) from t1,t2
where t1.f2 = t2.f3 order by t1.f1;
drop table t1, t2;
set names default;
+
+# Bug 24912 -- misc functions have trouble with unsigned
+
+select cast(-2 as unsigned), 18446744073709551614, -2;
+select abs(cast(-2 as unsigned)), abs(18446744073709551614), abs(-2);
+select ceiling(cast(-2 as unsigned)), ceiling(18446744073709551614), ceiling(-2);
+select floor(cast(-2 as unsigned)), floor(18446744073709551614), floor(-2);
+select format(cast(-2 as unsigned), 2), format(18446744073709551614, 2), format(-2, 2);
+select sqrt(cast(-2 as unsigned)), sqrt(18446744073709551614), sqrt(-2);
+select round(cast(-2 as unsigned), 1), round(18446744073709551614, 1), round(-2, 1);
+select round(4, cast(-2 as unsigned)), round(4, 18446744073709551614), round(4, -2);
+select truncate(cast(-2 as unsigned), 1), truncate(18446744073709551614, 1), truncate(-2, 1);
+select truncate(4, cast(-2 as unsigned)), truncate(4, 18446744073709551614), truncate(4, -2);
+select round(10000000000000000000, -19), truncate(10000000000000000000, -19);
+select round(1e0, -309), truncate(1e0, -309);
+select round(1e1,308), truncate(1e1, 308);
+select round(1e1, 2147483648), truncate(1e1, 2147483648);
+select round(1.1e1, 4294967295), truncate(1.1e1, 4294967295);
+select round(1.12e1, 4294967296), truncate(1.12e1, 4294967296);
+select round(1.5, 2147483640), truncate(1.5, 2147483640);
+select round(1.5, -2147483649), round(1.5, 2147483648);
+select truncate(1.5, -2147483649), truncate(1.5, 2147483648);
+select round(1.5, -4294967296), round(1.5, 4294967296);
+select truncate(1.5, -4294967296), truncate(1.5, 4294967296);
+select round(1.5, -9223372036854775808), round(1.5, 9223372036854775808);
+select truncate(1.5, -9223372036854775808), truncate(1.5, 9223372036854775808);
+select round(1.5, 18446744073709551615), truncate(1.5, 18446744073709551615);
+select round(18446744073709551614, -1), truncate(18446744073709551614, -1);
+select round(4, -4294967200), truncate(4, -4294967200);
+select mod(cast(-2 as unsigned), 3), mod(18446744073709551614, 3), mod(-2, 3);
+select mod(5, cast(-2 as unsigned)), mod(5, 18446744073709551614), mod(5, -2);
+select pow(cast(-2 as unsigned), 5), pow(18446744073709551614, 5), pow(-2, 5);
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/lowercase_mixed_tmpdir-master.opt b/mysql-test/t/lowercase_mixed_tmpdir-master.opt
new file mode 100644
index 00000000000..3d21ea72f6b
--- /dev/null
+++ b/mysql-test/t/lowercase_mixed_tmpdir-master.opt
@@ -0,0 +1,2 @@
+--lower-case-table-names=1
+--tmpdir=$MYSQLTEST_VARDIR/tmp/MixedCase
diff --git a/mysql-test/t/lowercase_mixed_tmpdir-master.sh b/mysql-test/t/lowercase_mixed_tmpdir-master.sh
new file mode 100644
index 00000000000..95c26e3aa02
--- /dev/null
+++ b/mysql-test/t/lowercase_mixed_tmpdir-master.sh
@@ -0,0 +1,6 @@
+# This test requires a non-lowercase tmpdir directory on a case-sensitive
+# filesystem.
+
+d="$MYSQLTEST_VARDIR/tmp/MixedCase"
+test -d "$d" || mkdir "$d"
+rm -f "$d"/*
diff --git a/mysql-test/t/lowercase_mixed_tmpdir.test b/mysql-test/t/lowercase_mixed_tmpdir.test
new file mode 100644
index 00000000000..6bd3a6f2acc
--- /dev/null
+++ b/mysql-test/t/lowercase_mixed_tmpdir.test
@@ -0,0 +1,12 @@
+--source include/have_case_sensitive_file_system.inc
+--source include/have_lowercase1.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (id int) engine=myisam;
+insert into t1 values (1);
+create temporary table t2 select * from t1;
+drop temporary table t2;
+drop table t1;
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index 126412057ab..4c4690520c6 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -1495,6 +1495,41 @@ drop database bug23491_original;
drop database bug23491_restore;
use test;
+
+
+--echo #
+--echo # Bug 27293: mysqldump crashes when dumping routines
+--echo # defined by a different user
+--echo #
+--echo # Bug #22761: mysqldump reports no errors when using
+--echo # --routines without mysql.proc privileges
+--echo #
+
+create database mysqldump_test_db;
+
+grant all privileges on mysqldump_test_db.* to user1;
+grant all privileges on mysqldump_test_db.* to user2;
+
+connect (user27293,localhost,user1,,mysqldump_test_db,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection user27293;
+
+create procedure mysqldump_test_db.sp1() select 'hello';
+
+--error 2
+--exec $MYSQL_DUMP -f --compact --user=user2 --password= -h 127.0.0.1 -P $MASTER_MYPORT --routines mysqldump_test_db
+
+--exec $MYSQL_DUMP -f --compact --user=user1 --password= -h 127.0.0.1 -P $MASTER_MYPORT --routines mysqldump_test_db
+
+drop procedure sp1;
+
+connection default;
+drop user user1;
+drop user user2;
+
+drop database mysqldump_test_db;
+
+
+
--echo #
--echo # End of 5.0 tests
--echo #
diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test
index 6cec940d286..f79c9e773aa 100644
--- a/mysql-test/t/update.test
+++ b/mysql-test/t/update.test
@@ -376,3 +376,58 @@ INSERT INTO t1( a )
SELECT * FROM t1;
DROP TABLE t1;
+
+#
+# Bug #22364: Inconsistent "matched rows" when executing UPDATE
+#
+
+connect (con1,localhost,root,,test);
+connection con1;
+
+set tmp_table_size=1024;
+
+# Create the test tables
+create table t1 (id int, a int, key idx(a));
+create table t2 (id int unsigned not null auto_increment primary key, a int);
+insert into t2(a) values(1),(2),(3),(4),(5),(6),(7),(8);
+insert into t2(a) select a from t2;
+insert into t2(a) select a from t2;
+insert into t2(a) select a from t2;
+update t2 set a=id;
+insert into t1 select * from t2;
+
+# Check that the number of matched rows is correct when the temporary
+# table is small enough to not be converted to MyISAM
+select count(*) from t1 join t2 on (t1.a=t2.a);
+--enable_info
+update t1 join t2 on (t1.a=t2.a) set t1.id=t2.id;
+--disable_info
+
+# Increase table sizes
+insert into t2(a) select a from t2;
+update t2 set a=id;
+truncate t1;
+insert into t1 select * from t2;
+
+# Check that the number of matched rows is correct when the temporary
+# table has to be converted to MyISAM
+select count(*) from t1 join t2 on (t1.a=t2.a);
+--enable_info
+update t1 join t2 on (t1.a=t2.a) set t1.id=t2.id;
+--disable_info
+
+# Check that the number of matched rows is correct when there are duplicate
+# key errors
+update t1 set a=1;
+update t2 set a=1;
+select count(*) from t1 join t2 on (t1.a=t2.a);
+--enable_info
+update t1 join t2 on (t1.a=t2.a) set t1.id=t2.id;
+--disable_info
+
+drop table t1,t2;
+
+connection default;
+disconnect con1;
+
+--echo End of 5.0 tests
diff --git a/mysys/default.c b/mysys/default.c
index dc1c5a698b8..aff38b6af0b 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -877,8 +877,8 @@ void my_print_default_files(const char *conf_file)
fputs(name,stdout);
}
}
- puts("");
}
+ puts("");
}
void print_defaults(const char *conf_file, const char **groups)
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
index 6143700befc..ec642b4083c 100644
--- a/mysys/my_copy.c
+++ b/mysys/my_copy.c
@@ -111,6 +111,11 @@ int my_copy(const char *from, const char *to, myf MyFlags)
err:
if (from_file >= 0) VOID(my_close(from_file,MyFlags));
- if (to_file >= 0) VOID(my_close(to_file,MyFlags));
+ if (to_file >= 0)
+ {
+ VOID(my_close(to_file, MyFlags));
+ /* attempt to delete the to-file we've partially written */
+ VOID(my_delete(to, MyFlags));
+ }
DBUG_RETURN(-1);
} /* my_copy */
diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh
index 63995eb1575..934d245db15 100644
--- a/scripts/mysql_install_db.sh
+++ b/scripts/mysql_install_db.sh
@@ -79,7 +79,10 @@ parse_arguments() {
then
# This sed command makes sure that any special chars are quoted,
# so the arg gets passed exactly to the server.
- args="$args "`echo "$arg" | sed -e 's,\([^a-zA-Z0-9_.-]\),\\\\\1,g'`
+ # XXX: This is broken; true fix requires using eval and proper
+ # quoting of every single arg ($basedir, $ldata, etc.)
+ #args="$args "`echo "$arg" | sed -e 's,\([^a-zA-Z0-9_.-]\),\\\\\1,g'`
+ args="$args $arg"
fi
;;
esac
@@ -151,6 +154,7 @@ else
if test -f $i/$fill_help_tables
then
pkgdatadir=$i
+ break
fi
done
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index a664bcfd3ad..92cfbe3ef22 100644
--- a/scripts/mysqld_multi.sh
+++ b/scripts/mysqld_multi.sh
@@ -4,9 +4,10 @@ use Getopt::Long;
use POSIX qw(strftime);
$|=1;
-$VER="2.15";
+$VER="2.16";
+
+my @defaults_options; # Leading --no-defaults, --defaults-file, etc.
-$opt_config_file = undef();
$opt_example = 0;
$opt_help = 0;
$opt_log = undef();
@@ -49,54 +50,52 @@ sub main
print "MySQL distribution.\n";
$my_print_defaults_exists= 0;
}
- if ($my_print_defaults_exists)
+
+ # Remove leading defaults options from @ARGV
+ while (@ARGV > 0)
+ {
+ last unless $ARGV[0] =~
+ /^--(?:no-defaults$|(?:defaults-file|defaults-extra-file)=)/;
+ push @defaults_options, (shift @ARGV);
+ }
+
+ # Handle deprecated --config-file option: convert to --defaults-extra-file
+ foreach my $arg (@ARGV)
{
- foreach my $arg (@ARGV)
+ if ($arg =~ m/^--config-file=(.*)/)
{
- if ($arg =~ m/^--config-file=(.*)/)
- {
- if (!length($1))
- {
- die "Option config-file requires an argument\n";
- }
- elsif (!( -e $1 && -r $1))
- {
- die "Option file '$1' doesn't exists, or is not readable\n";
- }
- else
- {
- $opt_config_file= $1;
- if (!($opt_config_file =~ m/\//))
- {
- # No path. Use current working directory
- $opt_config_file= "./" . $opt_config_file;
- }
- }
- }
+ # Put it at the beginning of the list, so it has lower precedence
+ # than a correct --defaults-extra-file option
+
+ unshift @defaults_options, "--defaults-extra-file=$1";
}
- my $com= "my_print_defaults ";
- $com.= "--config-file=$opt_config_file " if (defined($opt_config_file));
- $com.= "mysqld_multi";
- my @defops = `$com`;
- chop @defops;
- splice @ARGV, 0, 0, @defops;
}
- if (!GetOptions("help","example","version","mysqld=s","mysqladmin=s",
- "config-file=s","user=s","password=s","log=s","no-log",
- "tcp-ip", "silent","verbose"))
+
+ foreach (@defaults_options)
{
- $flag_exit= 1;
+ $_ = quote_shell_word($_);
}
- if (defined($opt_config_file) && !($opt_config_file =~ m/\//))
+
+ # Add [mysqld_multi] options to front of @ARGV, ready for GetOptions()
+ unshift @ARGV, defaults_for_group('mysqld_multi');
+
+ # The --config-file option can be ignored; if passed on the command
+ # line, it's already handled; if specified in the configuration file,
+ # it's redundant and not useful
+ @ARGV= grep { not /^--config-file=/ } @ARGV;
+
+ # We've already handled --no-defaults, --defaults-file, etc.
+ if (!GetOptions("help", "example", "version", "mysqld=s", "mysqladmin=s",
+ "user=s", "password=s", "log=s", "no-log",
+ "tcp-ip", "silent", "verbose"))
{
- # No path. Use current working directory
- $opt_config_file= "./" . $opt_config_file;
+ $flag_exit= 1;
}
usage() if ($opt_help);
if ($opt_verbose && $opt_silent)
{
- print "Both --verbose and --silent has been given. Some of the warnings ";
+ print "Both --verbose and --silent have been given. Some of the warnings ";
print "will be disabled\nand some will be enabled.\n\n";
}
@@ -168,51 +167,42 @@ sub main
}
}
-####
-#### Quote option argument. Add double quotes around the argument
-#### and escape the following: $, \, "
-#### This function is needed, because my_print_defaults drops possible
-#### quotes, single or double, from in front of an argument and from
-#### the end.
-####
+#
+# Quote word for shell
+#
-sub quote_opt_arg
+sub quote_shell_word
{
my ($option)= @_;
- if ($option =~ m/(\-\-[a-zA-Z0-9\_\-]+)=(.*)/)
- {
- $option= $1;
- $arg= $2;
- $arg=~ s/\\/\\\\/g; # Escape escape character first to avoid doubling.
- $arg=~ s/\$/\\\$/g;
- $arg=~ s/\"/\\\"/g;
- $arg= "\"" . $arg . "\"";
- $option= $option . "=" . $arg;
- }
+ $option =~ s!([^\w=./-])!\\$1!g;
return $option;
}
+sub defaults_for_group
+{
+ my ($group) = @_;
+
+ return () unless $my_print_defaults_exists;
+
+ my $com= join ' ', 'my_print_defaults', @defaults_options, $group;
+ my @defaults = `$com`;
+ chomp @defaults;
+ return @defaults;
+}
+
####
#### Init log file. Check for appropriate place for log file, in the following
-#### order my_print_defaults mysqld datadir, @datadir@, /var/log, /tmp
+#### order: my_print_defaults mysqld datadir, @datadir@
####
sub init_log
{
- if ($my_print_defaults_exists)
+ foreach my $opt (defaults_for_group('mysqld'))
{
- @mysqld_opts= `my_print_defaults mysqld`;
- chomp @mysqld_opts;
- foreach my $opt (@mysqld_opts)
+ if ($opt =~ m/^--datadir=(.*)/ && -d "$1" && -w "$1")
{
- if ($opt =~ m/^\-\-datadir[=](.*)/)
- {
- if (-d "$1" && -w "$1")
- {
- $logdir= $1;
- }
- }
+ $logdir= $1;
}
}
if (!defined($logdir))
@@ -303,11 +293,7 @@ sub start_mysqlds()
@groups = &find_groups($groupids);
for ($i = 0; defined($groups[$i]); $i++)
{
- $com = "my_print_defaults";
- $com.= defined($opt_config_file) ? " --config-file=$opt_config_file" : "";
- $com.= " $groups[$i]";
- @options = `$com`;
- chop @options;
+ @options = defaults_for_group($groups[$i]);
$mysqld_found= 1; # The default
$mysqld_found= 0 if (!length($mysqld));
@@ -326,7 +312,7 @@ sub start_mysqlds()
}
else
{
- $options[$j]= quote_opt_arg($options[$j]);
+ $options[$j]= quote_shell_word($options[$j]);
$tmp.= " $options[$j]";
}
}
@@ -401,11 +387,7 @@ sub get_mysqladmin_options
my ($i, @groups)= @_;
my ($mysqladmin_found, $com, $tmp, $j);
- $com = "my_print_defaults";
- $com.= defined($opt_config_file) ? " --config-file=$opt_config_file" : "";
- $com.= " $groups[$i]";
- @options = `$com`;
- chop @options;
+ @options = defaults_for_group($groups[$i]);
$mysqladmin_found= 1; # The default
$mysqladmin_found= 0 if (!length($mysqladmin));
@@ -445,129 +427,81 @@ sub get_mysqladmin_options
return $com;
}
-####
-#### Find groups. Takes the valid group numbers as an argument, parses
-#### them, puts them in the ascending order, removes duplicates and
-#### returns the wanted groups accordingly.
-####
+# Return a list of option files which can be opened. Similar, but not
+# identical, to behavior of my_search_option_files()
+sub list_defaults_files
+{
+ my %opt;
+ foreach (@defaults_options)
+ {
+ return () if /^--no-defaults$/;
+ $opt{$1} = $2 if /^--defaults-(extra-file|file)=(.*)$/;
+ }
+
+ return ($opt{file}) if exists $opt{file};
+
+ my %seen; # Don't list the same file more than once
+ return grep { defined $_ and not $seen{$_}++ and -f $_ and -r $_ }
+ ('/etc/my.cnf',
+ '/etc/mysql/my.cnf',
+ '@sysconfdir@/my.cnf',
+ ($ENV{MYSQL_HOME} ? "$ENV{MYSQL_HOME}/my.cnf" : undef),
+ $opt{'extra-file'},
+ ($ENV{HOME} ? "$ENV{HOME}/.my.cnf" : undef));
+}
+
+# Takes a specification of GNRs (see --help), and returns a list of matching
+# groups which actually are mentioned in a relevant config file
sub find_groups
{
my ($raw_gids) = @_;
- my (@groups, @data, @tmp, $line, $i, $k, @pre_gids, @gids, @tmp2,
- $prev_value);
- # Read the lines from the config file to variable 'data'
- if (defined($opt_config_file))
- {
- open(MY_CNF, "<$opt_config_file") && (@data=<MY_CNF>) && close(MY_CNF);
- }
- else
- {
- if (-f "@sysconfdir@/my.cnf" && -r "@sysconfdir@/my.cnf")
- {
- open(MY_CNF, "<@sysconfdir@/my.cnf") && (@tmp=<MY_CNF>) && close(MY_CNF);
- } elsif (-f "/etc/my.cnf" && -r "/etc/my.cnf")
- {
- open(MY_CNF, "</etc/my.cnf") && (@tmp=<MY_CNF>) && close(MY_CNF);
- }
- for ($i = 0; ($line = shift @tmp); $i++)
- {
- $data[$i] = $line;
- }
- if (-f "/etc/mysql/my.cnf" && -r "/etc/mysql/my.cnf")
- {
- open(MY_CNF, "</etc/mysql/my.cnf") && (@tmp=<MY_CNF>) && close(MY_CNF);
- }
- for (; ($line = shift @tmp); $i++)
- {
- $data[$i] = $line;
- }
- if (defined($ENV{MYSQL_HOME}) && -f "$ENV{MYSQL_HOME}/my.cnf" &&
- -r "$ENV{MYSQL_HOME}/my.cnf")
- {
- open(MY_CNF, "<$ENV{MYSQL_HOME}/my.cnf") && (@tmp=<MY_CNF>) &&
- close(MY_CNF);
- }
- for (; ($line = shift @tmp); $i++)
- {
- $data[$i] = $line;
- }
- if (-f "$homedir/.my.cnf" && -r "$homedir/.my.cnf")
- {
- open(MY_CNF, "<$homedir/.my.cnf") && (@tmp=<MY_CNF>) && close(MY_CNF);
- }
- for (; ($line = shift @tmp); $i++)
- {
- $data[$i] = $line;
- }
- }
- chomp @data;
- # Make a list of the wanted group ids
- if (defined($raw_gids))
- {
- @pre_gids = split(',', $raw_gids);
- }
+ my %gids;
+ my @groups;
+
if (defined($raw_gids))
{
- for ($i = 0, $j = 0; defined($pre_gids[$i]); $i++)
+ # Make a hash of the wanted group ids
+ foreach my $raw_gid (split ',', $raw_gids)
{
- if ($pre_gids[$i] =~ m/^(\d+)$/)
+ # Match 123 or 123-456
+ my ($start, $end) = ($raw_gid =~ /^\s*(\d+)(?:\s*-\s*(\d+))?\s*$/);
+ $end = $start if not defined $end;
+ if (not defined $start or $end < $start or $start < 0)
{
- $gids[$j] = $1;
- $j++;
+ print "ABORT: Bad GNR: $raw_gid; see $my_progname --help\n";
+ exit(1);
}
- elsif ($pre_gids[$i] =~ m/^(\d+)(\-)(\d+)$/)
- {
- for ($k = $1; $k <= $3; $k++)
- {
- $gids[$j] = $k;
- $j++;
- }
- }
- else
+
+ foreach my $i ($start .. $end)
{
- print "ABORT: Bad GNR: $pre_gids[$i] See $my_progname --help\n";
- exit(1);
+ # Use $i + 0 to normalize numbers (002 + 0 -> 2)
+ $gids{$i + 0}= 1;
}
}
}
- # Sort the list of gids numerically in ascending order
- @gids = sort {$a <=> $b} @gids;
- # Remove non-positive integers and duplicates
- for ($i = 0, $j = 0; defined($gids[$i]); $i++)
- {
- next if ($gids[$i] <= 0);
- if (!$i || $prev_value != $gids[$i])
- {
- $tmp2[$j] = $gids[$i];
- $j++;
- }
- $prev_value = $gids[$i];
- }
- @gids = @tmp2;
- # Find and return the wanted groups
- for ($i = 0, $j = 0; defined($data[$i]); $i++)
+
+ my @defaults_files = list_defaults_files();
+ #warn "@{[sort keys %gids]} -> @defaults_files\n";
+ foreach my $file (@defaults_files)
{
- if ($data[$i] =~ m/^(\s*\[\s*)(mysqld)(\d+)(\s*\]\s*)$/)
+ next unless open CONF, "< $file";
+
+ while (<CONF>)
{
- if (defined($raw_gids))
- {
- for ($k = 0; defined($gids[$k]); $k++)
- {
- if ($gids[$k] == $3)
- {
- $groups[$j] = $2 . $3;
- $j++;
- }
- }
- }
- else
+ if (/^\s*\[\s*(mysqld)(\d+)\s*\]\s*$/)
{
- $groups[$j] = $2 . $3;
- $j++;
+ #warn "Found a group: $1$2\n";
+ # Use $2 + 0 to normalize numbers (002 + 0 -> 2)
+ if (not defined($raw_gids) or $gids{$2 + 0})
+ {
+ push @groups, "$1$2";
+ }
}
}
+
+ close CONF;
}
return @groups;
}
@@ -806,8 +740,16 @@ groups found will either be started, stopped, or reported. Note that
syntax for specifying GNRs must appear without spaces.
Options:
---config-file=... Alternative config file.
- Using: $opt_config_file
+
+These options must be given before any others:
+--no-defaults Do not read any defaults file
+--defaults-file=... Read only this configuration file, do not read the
+ standard system-wide and user-specific files
+--defaults-extra-file=... Read this configuration file in addition to the
+ standard system-wide and user-specific files
+Using: @{[join ' ', @defaults_options]}
+
+--config-file=... Deprecated, please use --defaults-extra-file instead
--example Give an example of a config file with extra information.
--help Print this help and exit.
--log=... Log file. Full path to and the name for the log file. NOTE:
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 503b4362e7a..14a4c4dcf4b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -616,6 +616,14 @@ Item *Item_func::get_tmp_table_item(THD *thd)
return copy_or_same(thd);
}
+double Item_int_func::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+
+ return unsigned_flag ? (double) ((ulonglong) val_int()) : (double) val_int();
+}
+
+
String *Item_int_func::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -804,7 +812,10 @@ double Item_func_numhybrid::val_real()
return result;
}
case INT_RESULT:
- return (double)int_op();
+ {
+ longlong result= int_op();
+ return unsigned_flag ? (double) ((ulonglong) result) : (double) result;
+ }
case REAL_RESULT:
return real_op();
case STRING_RESULT:
@@ -1341,6 +1352,8 @@ longlong Item_func_mod::int_op()
DBUG_ASSERT(fixed == 1);
longlong value= args[0]->val_int();
longlong val2= args[1]->val_int();
+ longlong result;
+
if ((null_value= args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
if (val2 == 0)
@@ -1350,9 +1363,13 @@ longlong Item_func_mod::int_op()
}
if (args[0]->unsigned_flag)
- return ((ulonglong) value) % val2;
+ result= args[1]->unsigned_flag ?
+ ((ulonglong) value) % ((ulonglong) val2) : ((ulonglong) value) % val2;
+ else
+ result= args[1]->unsigned_flag ?
+ value % ((ulonglong) val2) : value % val2;
- return value % val2;
+ return result;
}
double Item_func_mod::real_op()
@@ -1407,6 +1424,7 @@ void Item_func_mod::fix_length_and_dec()
{
Item_num_op::fix_length_and_dec();
maybe_null= 1;
+ unsigned_flag= args[0]->unsigned_flag;
}
@@ -1485,8 +1503,9 @@ double Item_func_abs::real_op()
longlong Item_func_abs::int_op()
{
longlong value= args[0]->val_int();
- null_value= args[0]->null_value;
- return value >= 0 ? value : -value;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ return (value >= 0) || unsigned_flag ? value : -value;
}
@@ -1507,6 +1526,7 @@ my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
void Item_func_abs::fix_length_and_dec()
{
Item_func_num1::fix_length_and_dec();
+ unsigned_flag= args[0]->unsigned_flag;
}
@@ -1881,6 +1901,10 @@ my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
void Item_func_round::fix_length_and_dec()
{
+ int decimals_to_set;
+ longlong val1;
+ bool val1_unsigned;
+
unsigned_flag= args[0]->unsigned_flag;
if (!args[1]->const_item())
{
@@ -1889,8 +1913,14 @@ void Item_func_round::fix_length_and_dec()
hybrid_type= REAL_RESULT;
return;
}
-
- int decimals_to_set= max((int)args[1]->val_int(), 0);
+
+ val1= args[1]->val_int();
+ val1_unsigned= args[1]->unsigned_flag;
+ if (val1 < 0)
+ decimals_to_set= val1_unsigned ? INT_MAX : 0;
+ else
+ decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (int) val1;
+
if (args[0]->decimals == NOT_FIXED_DEC)
{
max_length= args[0]->max_length;
@@ -1907,10 +1937,9 @@ void Item_func_round::fix_length_and_dec()
max_length= float_length(decimals);
break;
case INT_RESULT:
- if (!decimals_to_set &&
- (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)))
+ if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
{
- int length_can_increase= test(!truncate && (args[1]->val_int() < 0));
+ int length_can_increase= test(!truncate && (val1 < 0) && !val1_unsigned);
max_length= args[0]->max_length + length_can_increase;
/* Here we can keep INT_RESULT */
hybrid_type= INT_RESULT;
@@ -1936,10 +1965,12 @@ void Item_func_round::fix_length_and_dec()
}
}
-double my_double_round(double value, int dec, bool truncate)
+double my_double_round(double value, longlong dec, bool dec_unsigned,
+ bool truncate)
{
double tmp;
- uint abs_dec= abs(dec);
+ bool dec_negative= (dec < 0) && !dec_unsigned;
+ ulonglong abs_dec= dec_negative ? -dec : dec;
/*
tmp2 is here to avoid return the value with 80 bit precision
This will fix that the test round(0.1,1) = round(0.1,1) is true
@@ -1949,7 +1980,11 @@ double my_double_round(double value, int dec, bool truncate)
tmp=(abs_dec < array_elements(log_10) ?
log_10[abs_dec] : pow(10.0,(double) abs_dec));
- if (truncate)
+ if (dec_negative && isinf(tmp))
+ tmp2= 0;
+ else if (!dec_negative && isinf(value * tmp))
+ tmp2= value;
+ else if (truncate)
{
if (value >= 0)
tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp;
@@ -1965,24 +2000,35 @@ double my_double_round(double value, int dec, bool truncate)
double Item_func_round::real_op()
{
double value= args[0]->val_real();
- int dec= (int) args[1]->val_int();
if (!(null_value= args[0]->null_value || args[1]->null_value))
- return my_double_round(value, dec, truncate);
+ return my_double_round(value, args[1]->val_int(), args[1]->unsigned_flag,
+ truncate);
return 0.0;
}
+/*
+ Rounds a given value to a power of 10 specified as the 'to' argument,
+ avoiding overflows when the value is close to the ulonglong range boundary.
+*/
+
+static inline ulonglong my_unsigned_round(ulonglong value, ulonglong to)
+{
+ ulonglong tmp= value / to * to;
+ return (value - tmp < (to >> 1)) ? tmp : tmp + to;
+}
+
longlong Item_func_round::int_op()
{
longlong value= args[0]->val_int();
- int dec=(int) args[1]->val_int();
+ longlong dec= args[1]->val_int();
decimals= 0;
- uint abs_dec;
+ ulonglong abs_dec;
if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- if (dec >= 0)
+ if ((dec >= 0) || args[1]->unsigned_flag)
return value; // integer have not digits after point
abs_dec= -dec;
@@ -1994,21 +2040,12 @@ longlong Item_func_round::int_op()
tmp= log_10_int[abs_dec];
if (truncate)
- {
- if (unsigned_flag)
- value= (ulonglong(value)/tmp)*tmp;
- else
- value= (value/tmp)*tmp;
- }
+ value= (unsigned_flag) ?
+ ((ulonglong) value / tmp) * tmp : (value / tmp) * tmp;
else
- {
- if (unsigned_flag)
- value= ((ulonglong(value)+(tmp>>1))/tmp)*tmp;
- else if ( value >= 0)
- value= ((value+(tmp>>1))/tmp)*tmp;
- else
- value= ((value-(tmp>>1))/tmp)*tmp;
- }
+ value= (unsigned_flag || value >= 0) ?
+ my_unsigned_round((ulonglong) value, tmp) :
+ -(longlong) my_unsigned_round((ulonglong) -value, tmp);
return value;
}
@@ -2016,14 +2053,18 @@ longlong Item_func_round::int_op()
my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
- int dec=(int) args[1]->val_int();
- if (dec > 0)
+ longlong dec= args[1]->val_int();
+ if (dec > 0 || (dec < 0 && args[1]->unsigned_flag))
{
- decimals= min(dec, DECIMAL_MAX_SCALE); // to get correct output
+ dec= min((ulonglong) dec, DECIMAL_MAX_SCALE);
+ decimals= (uint8) dec; // to get correct output
}
+ else if (dec < INT_MIN)
+ dec= INT_MIN;
+
if (!(null_value= (args[0]->null_value || args[1]->null_value ||
- my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
- decimal_value) > 1)))
+ my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec,
+ truncate, decimal_value) > 1)))
return decimal_value;
return 0;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 635a409e0a2..037a2ee967b 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -278,7 +278,7 @@ public:
{ max_length= 21; }
Item_int_func(List<Item> &list) :Item_func(list) { max_length= 21; }
Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {}
- double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real();
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() {}
@@ -303,12 +303,6 @@ class Item_func_signed :public Item_int_func
public:
Item_func_signed(Item *a) :Item_int_func(a) {}
const char *func_name() const { return "cast_as_signed"; }
- double val_real()
- {
- double tmp= args[0]->val_real();
- null_value= args[0]->null_value;
- return tmp;
- }
longlong val_int();
longlong val_int_from_str(int *error);
void fix_length_and_dec()
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 1991526345c..f9a0f715985 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1995,7 +1995,7 @@ String *Item_func_format::val_str(String *str)
double nr= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
- nr= my_double_round(nr, decimals, FALSE);
+ nr= my_double_round(nr, (longlong) decimals, FALSE, FALSE);
/* Here default_charset() is right as this is not an automatic conversion */
str->set(nr,decimals, default_charset());
if (isnan(nr))
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 7e873dd7cc6..7ab683134e0 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1539,7 +1539,8 @@ ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
ha_rows max_rows, ha_rows *examined_rows);
void filesort_free_buffers(TABLE *table, bool full);
void change_double_for_sort(double nr,byte *to);
-double my_double_round(double value, int dec, bool truncate);
+double my_double_round(double value, longlong dec, bool dec_unsigned,
+ bool truncate);
int get_quick_record(SQL_SELECT *select);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
uint calc_week(TIME *l_time, uint week_behaviour, uint *year);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 6f953349c03..42d59a10712 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -42,6 +42,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
static bool prepare_blob_field(THD *thd, create_field *sql_field);
static bool check_engine(THD *thd, const char *table_name,
enum db_type *new_engine);
+static void set_tmp_file_path(char *buf, size_t bufsize, THD *thd);
/*
@@ -1681,11 +1682,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
- my_snprintf(path, sizeof(path), "%s%s%lx_%lx_%x%s",
- mysql_tmpdir, tmp_file_prefix, current_pid, thd->thread_id,
- thd->tmp_table++, reg_ext);
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, path);
+ set_tmp_file_path(path, sizeof(path), thd);
create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
}
else
@@ -2801,11 +2798,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
{
if (find_temporary_table(thd, db, table_name))
goto table_exists;
- my_snprintf(dst_path, sizeof(dst_path), "%s%s%lx_%lx_%x%s",
- mysql_tmpdir, tmp_file_prefix, current_pid,
- thd->thread_id, thd->tmp_table++, reg_ext);
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, dst_path);
+ set_tmp_file_path(dst_path, sizeof(dst_path), thd);
create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
}
else
@@ -3316,6 +3309,12 @@ view_err:
create_info->avg_row_length= table->s->avg_row_length;
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
create_info->default_table_charset= table->s->table_charset;
+ if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
+ {
+ /* Table has an autoincrement, copy value to new table */
+ table->file->info(HA_STATUS_AUTO);
+ create_info->auto_increment_value= table->file->auto_increment_value;
+ }
restore_record(table, s->default_values); // Empty record for DEFAULT
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
@@ -4313,3 +4312,16 @@ static bool check_engine(THD *thd, const char *table_name,
}
return FALSE;
}
+
+static void set_tmp_file_path(char *buf, size_t bufsize, THD *thd)
+{
+ char *p= strnmov(buf, mysql_tmpdir, bufsize);
+ my_snprintf(p, bufsize - (p - buf), "%s%lx_%lx_%x%s",
+ tmp_file_prefix, current_pid,
+ thd->thread_id, thd->tmp_table++, reg_ext);
+ if (lower_case_table_names)
+ {
+ /* Convert all except tmpdir to lower case */
+ my_casedn_str(files_charset_info, p);
+ }
+}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 6f6c4538040..e17c71ae541 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1354,19 +1354,18 @@ bool multi_update::send_data(List<Item> &not_used_values)
memcpy((char*) tmp_table->field[0]->ptr,
(char*) table->file->ref, table->file->ref_length);
/* Write row, ignoring duplicated updates to a row */
- if ((error= tmp_table->file->write_row(tmp_table->record[0])))
+ error= tmp_table->file->write_row(tmp_table->record[0]);
+ if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)
{
- if (error != HA_ERR_FOUND_DUPP_KEY &&
- error != HA_ERR_FOUND_DUPP_UNIQUE &&
+ if (error &&
create_myisam_from_heap(thd, tmp_table,
- tmp_table_param + offset, error, 1))
- {
- do_update=0;
- DBUG_RETURN(1); // Not a table_is_full error
- }
- }
- else
+ tmp_table_param + offset, error, 1))
+ {
+ do_update= 0;
+ DBUG_RETURN(1); // Not a table_is_full error
+ }
found++;
+ }
}
}
DBUG_RETURN(0);