diff options
32 files changed, 458 insertions, 76 deletions
diff --git a/BUILD/compile-ia64-debug-max b/BUILD/compile-ia64-debug-max index 9cd54de428d..56c36059ea9 100755 --- a/BUILD/compile-ia64-debug-max +++ b/BUILD/compile-ia64-debug-max @@ -9,5 +9,5 @@ then (cd gemini && aclocal && autoheader && aclocal && automake && autoconf) fi -CC=ecc CFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" CXX=ecc CXXFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static --with-debug --with-innodb --with-embedded-server +CC=ecc CFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" CXX=ecc CXXFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static --with-debug --with-innodb --with-embedded-server --with-archive-storage-engine gmake diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 483f324d89c..6ccc886e161 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -33,6 +33,7 @@ bk@mysql.r18.ru brian@avenger.(none) brian@brian-akers-computer.local brian@private-client-ip-101.oz.net +brian@zim.(none) carsten@tsort.bitbybit.dk davida@isil.mysql.com dellis@goetia.(none) diff --git a/Build-tools/Bootstrap b/Build-tools/Bootstrap index 10ebc5c2dd1..827eb4022d7 100755 --- a/Build-tools/Bootstrap +++ b/Build-tools/Bootstrap @@ -210,10 +210,16 @@ if (-d $target_dir) } else { - &logger("Renaming $target_dir to $target_dir.old." . $$); + # Get the time stamp of "configure.in" + @stat= stat("$target_dir/configure.in"); + my $mtime= $stat[9]; + my ($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime); + my $mtime= sprintf("%04d%-02d-%02d-%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min); + + &logger("Renaming $target_dir to $target_dir-$mtime"); $command= "mv "; $command.= "-v " if ($opt_verbose || defined $opt_log); - $command.= "$target_dir $target_dir.old." . $$; + $command.= "$target_dir $target_dir-$mtime"; &run_command($command, "Could not rename $target_dir!"); } } diff --git a/client/mysqldump.c b/client/mysqldump.c index 3a93adf5b36..afaa2dc5a6d 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -489,7 +489,7 @@ static void write_header(FILE *sql_file, char *db_name) "); } fprintf(sql_file, - "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=\"%s%s%s\" */;\n", + "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n", path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",", compatible_mode_normal_str); check_io(sql_file); @@ -863,7 +863,7 @@ static int dbConnect(char *host, char *user,char *passwd) cannot reconnect. */ sock->reconnect= 0; - sprintf(buff, "/*!40100 SET @@SQL_MODE=\"%s\" */", + sprintf(buff, "/*!40100 SET @@SQL_MODE='%s' */", compatible_mode_normal_str); if (mysql_query_with_error_report(sock, 0, buff)) { diff --git a/mysql-test/r/compare.result b/mysql-test/r/compare.result index bf8a5106044..49ec2dd85cc 100644 --- a/mysql-test/r/compare.result +++ b/mysql-test/r/compare.result @@ -36,3 +36,6 @@ hex(a) STRCMP(a,'a') STRCMP(a,'a ') 6109 -1 -1 61 0 0 DROP TABLE t1; +SELECT CHAR(31) = '', '' = CHAR(31); +CHAR(31) = '' '' = CHAR(31) +0 0 diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 7e6b9b44566..61d745d0236 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -330,3 +330,12 @@ SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MA min max avg 10.00 10.00 10 DROP TABLE t1; +create table t1 (a integer, b integer); +insert into t1 values (1,4), (2,2),(2,2), (4,1),(4,1),(4,1),(4,1); +select distinct sum(b) from t1 group by a; +sum(b) +4 +select distinct sum(b) from (select a,b from t1) y group by a; +sum(b) +4 +drop table t1; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 623bd2a0f3c..8f2294caa48 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -60,7 +60,7 @@ INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456) /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, @@ -83,7 +83,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, `b` float default NULL @@ -149,7 +149,7 @@ INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'), (NULL); /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` varchar(255) default NULL @@ -175,7 +175,7 @@ CREATE TABLE t1 (a int) ENGINE=MYISAM; INSERT INTO t1 VALUES (1), (2); /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL40" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL40' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -194,7 +194,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -225,7 +225,7 @@ create table t1(a int); /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -246,7 +246,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,ANSI" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; DROP TABLE IF EXISTS "t1"; CREATE TABLE "t1" ( "a" int(11) default NULL @@ -270,7 +270,7 @@ set global sql_mode='ANSI_QUOTES'; /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -291,7 +291,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,ANSI" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; DROP TABLE IF EXISTS "t1"; CREATE TABLE "t1" ( "a" int(11) default NULL @@ -316,7 +316,7 @@ insert into t1 values (1),(2),(3); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -339,7 +339,7 @@ drop table t1; /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; @@ -360,7 +360,7 @@ create database mysqldump_test_db character set latin2 collate latin2_bin; /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CHARACTER SET latin2 COLLATE latin2_bin */; @@ -383,7 +383,7 @@ INSERT INTO t1 VALUES (_latin1 'ÄÖÜß'); /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -405,7 +405,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -424,7 +424,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -443,7 +443,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -462,7 +462,7 @@ UNLOCK TABLES; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -491,7 +491,7 @@ INSERT INTO t2 VALUES (4),(5),(6); /*!40101 SET NAMES utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t2`; CREATE TABLE `t2` ( `a` int(11) default NULL diff --git a/mysql-test/r/rpl_multi_update2.result b/mysql-test/r/rpl_multi_update2.result new file mode 100644 index 00000000000..99356ebf970 --- /dev/null +++ b/mysql-test/r/rpl_multi_update2.result @@ -0,0 +1,42 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 ( +a int unsigned not null auto_increment primary key, +b int unsigned +) ENGINE=MyISAM; +CREATE TABLE t2 ( +a int unsigned not null auto_increment primary key, +b int unsigned +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 SELECT NULL, 0 FROM t1; +INSERT INTO t2 VALUES (NULL, 0), (NULL,1); +SELECT * FROM t1 ORDER BY a; +a b +1 0 +2 0 +SELECT * FROM t2 ORDER BY a; +a b +1 0 +2 1 +UPDATE t1, t2 SET t1.b = (t2.b+4) WHERE t1.a = t2.a; +SELECT * FROM t1 ORDER BY a; +a b +1 4 +2 5 +SELECT * FROM t2 ORDER BY a; +a b +1 0 +2 1 +SELECT * FROM t1 ORDER BY a; +a b +1 4 +2 5 +SELECT * FROM t2 ORDER BY a; +a b +1 0 +2 1 diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 02662f9900a..437fd624ae1 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2160,3 +2160,51 @@ ERROR 42S22: Unknown column 'a2' in 'scalar IN/ALL/ANY subquery' select * from t1 where a1 > any(select b1 from t2); a1 drop table t1,t2; +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +(select * from t1) = (select 1,2) +NULL +select (select 1,2) = (select * from t1); +(select 1,2) = (select * from t1) +NULL +select row(1,2) = ANY (select * from t1); +row(1,2) = ANY (select * from t1) +0 +select row(1,2) != ALL (select * from t1); +row(1,2) != ALL (select * from t1) +1 +drop table t1; +create table t1 (a integer, b integer); +select row(1,(2,2)) in (select * from t1 ); +ERROR 21000: Operand should contain 2 column(s) +select row(1,(2,2)) = (select * from t1 ); +ERROR 21000: Operand should contain 2 column(s) +select (select * from t1) = row(1,(2,2)); +ERROR 21000: Operand should contain 1 column(s) +drop table t1; +create table t1 (a integer); +insert into t1 values (1); +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +xx 1 = ALL ( select 1 from t1 where 1 = xx ) +1 1 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +drop table t1; +CREATE TABLE `t1` ( `a` char(3) NOT NULL default '', `b` char(3) NOT NULL default '', `c` char(3) NOT NULL default '', PRIMARY KEY (`a`,`b`,`c`)) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (1,1,1); +INSERT INTO t2 VALUES (1,1,1); +PREPARE my_stmt FROM "SELECT t1.b, count(*) FROM t1 group by t1.b having +count(*) > ALL (SELECT COUNT(*) FROM t2 WHERE t2.a=1 GROUP By t2.b)"; +EXECUTE my_stmt; +b count(*) +EXECUTE my_stmt; +b count(*) +deallocate prepare my_stmt; +drop table t1,t2; diff --git a/mysql-test/t/compare.test b/mysql-test/t/compare.test index b0cef48dd3f..e3c042e608a 100644 --- a/mysql-test/t/compare.test +++ b/mysql-test/t/compare.test @@ -30,3 +30,6 @@ CREATE TABLE t1 (a char(10) not null); INSERT INTO t1 VALUES ('a'),('a\0'),('a\t'),('a '); SELECT hex(a),STRCMP(a,'a'), STRCMP(a,'a ') FROM t1; DROP TABLE t1; + +# Bug #8134: Comparison against CHAR(31) at end of string +SELECT CHAR(31) = '', '' = CHAR(31); diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 64e3fe8929b..8b322746ed6 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -214,3 +214,13 @@ CREATE TABLE `t1` ( `itemid` int(11) NOT NULL default '0', `grpid` varchar(15) N insert into t1 values (128, 'rozn', 2, now(), 10),(128, 'rozn', 1, now(), 10); SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MAX(concat(date_,";",price)), 12) price FROM t1 WHERE itemid=128 AND grpid='rozn' GROUP BY itemid, grpid, vendor) lastprices; DROP TABLE t1; + +# +# DISTINCT over grouped select on subquery in the FROM clause +# +create table t1 (a integer, b integer); +insert into t1 values (1,4), (2,2),(2,2), (4,1),(4,1),(4,1),(4,1); +select distinct sum(b) from t1 group by a; +select distinct sum(b) from (select a,b from t1) y group by a; +drop table t1; + diff --git a/mysql-test/t/rpl_multi_update2-slave.opt b/mysql-test/t/rpl_multi_update2-slave.opt new file mode 100644 index 00000000000..17d4171af0e --- /dev/null +++ b/mysql-test/t/rpl_multi_update2-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=nothing.sensible diff --git a/mysql-test/t/rpl_multi_update2.test b/mysql-test/t/rpl_multi_update2.test new file mode 100644 index 00000000000..bba7700a88e --- /dev/null +++ b/mysql-test/t/rpl_multi_update2.test @@ -0,0 +1,33 @@ +# Let's verify that multi-update is not always skipped by slave if +# some replicate-* rules exist. +# (BUG#7011) + +source include/master-slave.inc; + +CREATE TABLE t1 ( + a int unsigned not null auto_increment primary key, + b int unsigned +) ENGINE=MyISAM; + +CREATE TABLE t2 ( + a int unsigned not null auto_increment primary key, + b int unsigned +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 SELECT NULL, 0 FROM t1; + +INSERT INTO t2 VALUES (NULL, 0), (NULL,1); + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +UPDATE t1, t2 SET t1.b = (t2.b+4) WHERE t1.a = t2.a; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +save_master_pos; +connection slave; +sync_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 3ee498ee380..cdec080611d 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1414,8 +1414,11 @@ SELECT f1 FROM t1 WHERE f1 <> ALL ( SELECT SUM(f1) AS sf1 FROM t2 HAVING sf1 > 10000); drop table t1,t2; + +# # Test for BUG#7885: Server crash when 'any' subselect compared to # non-existant field. +# create table t1 (a1 int); create table t2 (b1 int); --error 1054 @@ -1423,3 +1426,56 @@ select * from t1 where a2 > any(select b1 from t2); select * from t1 where a1 > any(select b1 from t2); drop table t1,t2; + +# +# Comparison subquery with * and row +# +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +select (select 1,2) = (select * from t1); +# queries whih can be converted to IN +select row(1,2) = ANY (select * from t1); +select row(1,2) != ALL (select * from t1); +drop table t1; + +# +# Comparison subquery and row with nested rows +# +create table t1 (a integer, b integer); +-- error 1241 +select row(1,(2,2)) in (select * from t1 ); +-- error 1241 +select row(1,(2,2)) = (select * from t1 ); +-- error 1241 +select (select * from t1) = row(1,(2,2)); +drop table t1; + +# +# Forward reference detection +# +create table t1 (a integer); +insert into t1 values (1); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +drop table t1; + +# +# cleaning up of results of subselects (BUG#8125) +# +CREATE TABLE `t1` ( `a` char(3) NOT NULL default '', `b` char(3) NOT NULL default '', `c` char(3) NOT NULL default '', PRIMARY KEY (`a`,`b`,`c`)) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (1,1,1); +INSERT INTO t2 VALUES (1,1,1); +PREPARE my_stmt FROM "SELECT t1.b, count(*) FROM t1 group by t1.b having +count(*) > ALL (SELECT COUNT(*) FROM t2 WHERE t2.a=1 GROUP By t2.b)"; +EXECUTE my_stmt; +EXECUTE my_stmt; +deallocate prepare my_stmt; +drop table t1,t2; diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index e8d07a99048..491056d0e59 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -42,18 +42,20 @@ handle bulk inserts as well (that is if someone was trying to read at the same time since we would want to flush). - A "meta" file is kept. All this file does is contain information on - the number of rows. + A "meta" file is kept alongside the data file. This file serves two purpose. + The first purpose is to track the number of rows in the table. The second + purpose is to determine if the table was closed properly or not. When the + meta file is first opened it is marked as dirty. It is opened when the table + itself is opened for writing. When the table is closed the new count for rows + is written to the meta file and the file is marked as clean. If the meta file + is opened and it is marked as dirty, it is assumed that a crash occured. At + this point an error occurs and the user is told to rebuild the file. + A rebuild scans the rows and rewrites the meta file. If corruption is found + in the data file then the meta file is not repaired. - No attempts at durability are made. You can corrupt your data. A repair - method was added to repair the meta file that stores row information, - but if your data file gets corrupted I haven't solved that. I could - create a repair that would solve this, but do you want to take a - chance of loosing your data? + At some point a recovery method for such a drastic case needs to be divised. - Locks are row level, and you will get a consistant read. Transactions - will be added later (they are not that hard to add at this - stage). + Locks are row level, and you will get a consistant read. For performance as far as table scans go it is quite fast. I don't have good numbers but locally it has out performed both Innodb and MyISAM. For @@ -88,7 +90,6 @@ compression but may speed up ordered searches). Checkpoint the meta file to allow for faster rebuilds. Dirty open (right now the meta file is repaired if a crash occured). - Transactions. Option to allow for dirty reads, this would lower the sync calls, which would make inserts a lot faster, but would mean highly arbitrary reads. @@ -355,6 +356,7 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table) opposite. */ (void)write_meta_file(share->meta_file, share->rows_recorded, TRUE); + /* It is expensive to open and close the data files and since you can't have a gzip file that can be both read and written we keep a writer open @@ -401,7 +403,8 @@ int ha_archive::free_share(ARCHIVE_SHARE *share) (void)write_meta_file(share->meta_file, share->rows_recorded, FALSE); if (gzclose(share->archive_write) == Z_ERRNO) rc= 1; - my_close(share->meta_file,MYF(0)); + if (my_close(share->meta_file, MYF(0))) + rc= 1; my_free((gptr) share, MYF(0)); } pthread_mutex_unlock(&archive_mutex); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 502f8eb92f3..1d75ce99aee 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4672,12 +4672,12 @@ ha_innobase::update_table_comment( dict_print_info_on_foreign_keys(FALSE, file, prebuilt->trx, prebuilt->table); flen = ftell(file); - if(length + flen + 3 > 64000) { + if (flen < 0) { + flen = 0; + } else if (length + flen + 3 > 64000) { flen = 64000 - 3 - length; } - ut_ad(flen > 0); - /* allocate buffer for the full string, and read the contents of the temporary file */ @@ -4741,12 +4741,12 @@ ha_innobase::get_foreign_key_create_info(void) prebuilt->trx->op_info = (char*)""; flen = ftell(file); - if(flen > 64000 - 1) { + if (flen < 0) { + flen = 0; + } else if(flen > 64000 - 1) { flen = 64000 - 1; } - ut_ad(flen >= 0); - /* allocate buffer for the string, and read the contents of the temporary file */ @@ -5142,12 +5142,12 @@ innodb_show_status( srv_printf_innodb_monitor(srv_monitor_file); flen = ftell(srv_monitor_file); os_file_set_eof(srv_monitor_file); - if(flen > 64000 - 1) { + if (flen < 0) { + flen = 0; + } else if (flen > 64000 - 1) { flen = 64000 - 1; } - ut_ad(flen > 0); - /* allocate buffer for the string, and read the contents of the temporary file */ diff --git a/sql/item.cc b/sql/item.cc index 8c45dffce75..ab29c147dfb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1482,12 +1482,13 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } else if (refer != (Item **)not_found_item) { - if (!(*refer)->fixed) + if (!last->ref_pointer_array[counter]) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, "forward reference in item list"); return -1; } + DBUG_ASSERT((*refer)->fixed); /* Here, a subset of actions performed by Item_ref::set_properties is not enough. So we pass ptr to NULL into Item_[direct]_ref @@ -2161,12 +2162,13 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) mark_as_dependent(thd, last, thd->lex->current_select, fld); return 0; } - if (!(*ref)->fixed) + if (!last->ref_pointer_array[counter]) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, "forward reference in item list"); return -1; } + DBUG_ASSERT((*ref)->fixed); mark_as_dependent(thd, last, thd->lex->current_select, this); if (place == IN_HAVING) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 6834799688d..061ed468b78 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -213,7 +213,7 @@ class Item_bool_rowready_func2 :public Item_bool_func2 public: Item_bool_rowready_func2(Item *a, Item *b) :Item_bool_func2(a, b) { - allowed_arg_cols= a->cols(); + allowed_arg_cols= 0; // Fetch this value from first argument } Item *neg_transformer(THD *thd); virtual Item *negated_item(); @@ -390,7 +390,10 @@ class Item_func_interval :public Item_int_func double *intervals; public: Item_func_interval(Item_row *a) - :Item_int_func(a),row(a),intervals(0) { allowed_arg_cols= a->cols(); } + :Item_int_func(a),row(a),intervals(0) + { + allowed_arg_cols= 0; // Fetch this value from first argument + } longlong val_int(); void fix_length_and_dec(); const char *func_name() const { return "interval"; } @@ -743,7 +746,7 @@ class Item_func_in :public Item_int_func Item_func_in(List<Item> &list) :Item_int_func(list), array(0), in_item(0), have_null(0) { - allowed_arg_cols= args[0]->cols(); + allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); void fix_length_and_dec(); diff --git a/sql/item_func.cc b/sql/item_func.cc index 7125f4704b8..bff49541252 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -303,10 +303,24 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) We can't yet set item to *arg as fix_fields may change *arg We shouldn't call fix_fields() twice, so check 'fixed' field first */ - if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) || - (*arg)->check_cols(allowed_arg_cols)) + if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg))) return 1; /* purecov: inspected */ + item= *arg; + + if (allowed_arg_cols) + { + if (item->check_cols(allowed_arg_cols)) + return 1; + } + else + { + /* we have to fetch allowed_arg_cols from first argument */ + DBUG_ASSERT(arg == args); // it is first argument + allowed_arg_cols= item->cols(); + DBUG_ASSERT(allowed_arg_cols); // Can't be 0 any more + } + if (item->maybe_null) maybe_null=1; diff --git a/sql/item_func.h b/sql/item_func.h index ce2b34499d6..8a5347d675e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -32,6 +32,10 @@ class Item_func :public Item_result_field { protected: Item **args, *tmp_arg[2]; + /* + Allowed numbers of columns in result (usually 1, which means scalar value) + 0 means get this number from first argument + */ uint allowed_arg_cols; public: uint arg_count; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8516ea76a7e..16186b1a6d3 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -995,6 +995,10 @@ Item_in_subselect::row_value_transformer(JOIN *join) List_iterator_fast<Item> li(select_lex->item_list); for (uint i= 0; i < n; i++) { + DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); + if (select_lex->ref_pointer_array[i]-> + check_cols(left_expr->el(i)->cols())) + goto err; Item *func= new Item_ref_null_helper(this, select_lex->ref_pointer_array+i, (char *) "<no matter>", @@ -1123,6 +1127,7 @@ void subselect_single_select_engine::cleanup() DBUG_ENTER("subselect_single_select_engine::cleanup"); prepared= optimized= executed= 0; join= 0; + result->cleanup(); DBUG_VOID_RETURN; } @@ -1131,6 +1136,7 @@ void subselect_union_engine::cleanup() { DBUG_ENTER("subselect_union_engine::cleanup"); unit->reinit_exec_mechanism(); + result->cleanup(); DBUG_VOID_RETURN; } @@ -1138,6 +1144,10 @@ void subselect_union_engine::cleanup() void subselect_uniquesubquery_engine::cleanup() { DBUG_ENTER("subselect_uniquesubquery_engine::cleanup"); + /* + subselect_uniquesubquery_engine have not 'result' assigbed, so we do not + cleanup() it + */ DBUG_VOID_RETURN; } @@ -1421,13 +1431,15 @@ int subselect_indexsubquery_engine::exec() uint subselect_single_select_engine::cols() { - return select_lex->item_list.elements; + DBUG_ASSERT(select_lex->join); // should be called after fix_fields() + return select_lex->join->fields_list.elements; } uint subselect_union_engine::cols() { - return unit->first_select()->item_list.elements; + DBUG_ASSERT(unit->is_prepared()); // should be called after fix_fields() + return unit->types.elements; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e71833e6af6..6218bc49f53 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -377,6 +377,7 @@ Item *negate_expression(THD *thd, Item *expr); struct Query_cache_query_flags { unsigned int client_long_flag:1; + unsigned int client_protocol_41:1; uint character_set_client_num; uint character_set_results_num; uint collation_connection_num; @@ -564,6 +565,10 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list, COND *conds, ulong options, enum enum_duplicates handle_duplicates, bool ignore, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); +int mysql_multi_update_lock(THD *thd, + TABLE_LIST *table_list, + List<Item> *fields, + SELECT_LEX *select_lex); int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE_LIST *insert_table_list, TABLE *table, List<Item> &fields, List_item *values, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7d26996856d..7434897ab90 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2405,6 +2405,20 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, thd->allow_sum_func= allow_sum_func; thd->where="field list"; + /* + To prevent fail on forward lookup we fill it with zerows, + then if we got pointer on zero after find_item_in_list we will know + that it is forward lookup. + + There is other way to solve problem: fill array with pointers to list, + but it will be slower. + + TODO: remove it when (if) we made one list for allfields and + ref_pointer_array + */ + if (ref_pointer_array) + bzero(ref_pointer_array, sizeof(Item *) * fields.elements); + Item **ref= ref_pointer_array; while ((item= it++)) { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 55e96ec0c6d..e1367412601 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -776,6 +776,8 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) bzero(&flags, QUERY_CACHE_FLAGS_SIZE); flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? 1 : 0); + flags.client_protocol_41= (thd->client_capabilities & CLIENT_PROTOCOL_41 ? + 1 : 0); flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= @@ -968,6 +970,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) bzero(&flags, QUERY_CACHE_FLAGS_SIZE); flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? 1 : 0); + flags.client_protocol_41= (thd->client_capabilities & CLIENT_PROTOCOL_41 ? + 1 : 0); flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= (thd->variables.character_set_results ? diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 596097d9dc2..e11d8369f57 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1240,6 +1240,14 @@ bool select_singlerow_subselect::send_data(List<Item> &items) } +void select_max_min_finder_subselect::cleanup() +{ + DBUG_ENTER("select_max_min_finder_subselect::cleanup"); + cache= 0; + DBUG_VOID_RETURN; +} + + bool select_max_min_finder_subselect::send_data(List<Item> &items) { DBUG_ENTER("select_max_min_finder_subselect::send_data"); diff --git a/sql/sql_class.h b/sql/sql_class.h index ce60ed06cfd..55099791ae0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1381,6 +1381,7 @@ public: select_max_min_finder_subselect(Item_subselect *item, bool mx) :select_subselect(item), cache(0), fmax(mx) {} + void cleanup(); bool send_data(List<Item> &items); bool cmp_real(); bool cmp_int(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3ac783da9c4..ed974a48ad3 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -164,7 +164,10 @@ void lex_start(THD *thd, uchar *buf,uint length) void lex_end(LEX *lex) { - lex->select_lex.expr_list.delete_elements(); // If error when parsing sql-varargs + for (SELECT_LEX *sl= lex->all_selects_list; + sl; + sl= sl->next_select_in_list()) + sl->expr_list.delete_elements(); // If error when parsing sql-varargs x_free(lex->yacc_yyss); x_free(lex->yacc_yyvs); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e2e0bc61c23..7cb71607edf 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -371,6 +371,7 @@ public: ulong init_prepare_fake_select_lex(THD *thd); int change_result(select_subselect *result, select_subselect *old_result); + inline bool is_prepared() { return prepared; } friend void lex_start(THD *thd, uchar *buf, uint length); friend int subselect_union_engine::exec(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d3a5617d01e..85cd24c4fbb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -52,6 +52,8 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc); #endif static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); +static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, + List<Item> *fields, SELECT_LEX *select_lex); static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(THD *thd, const char **filename_ptr, @@ -1883,6 +1885,8 @@ mysql_execute_command(THD *thd) { int res= 0; LEX *lex= thd->lex; + bool slave_fake_lock= 0; + MYSQL_LOCK *fake_prev_lock= 0; SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first; SELECT_LEX_UNIT *unit= &lex->unit; @@ -1900,6 +1904,23 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION if (thd->slave_thread) { + if (lex->sql_command == SQLCOM_UPDATE_MULTI) + { + DBUG_PRINT("info",("need faked locked tables")); + + if (check_multi_update_lock(thd, tables, &select_lex->item_list, + select_lex)) + goto error; + + /* Fix for replication, the tables are opened and locked, + now we pretend that we have performed a LOCK TABLES action */ + + fake_prev_lock= thd->locked_tables; + if (thd->lock) + thd->locked_tables= thd->lock; + thd->lock= 0; + slave_fake_lock= 1; + } /* Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated @@ -3582,6 +3603,14 @@ purposes internal to the MySQL server", MYF(0)); send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); error: + if (unlikely(slave_fake_lock)) + { + DBUG_PRINT("info",("undoing faked lock")); + thd->lock= thd->locked_tables; + thd->locked_tables= fake_prev_lock; + if (thd->lock == thd->locked_tables) + thd->lock= 0; + } DBUG_VOID_RETURN; } @@ -5012,6 +5041,58 @@ bool check_simple_select() return 0; } +/* + Setup locking for multi-table updates. Used by the replication slave. + Replication slave SQL thread examines (all_tables_not_ok()) the + locking state of referenced tables to determine if the query has to + be executed or ignored. Since in multi-table update, the + 'default' lock is read-only, this lock is corrected early enough by + calling this function, before the slave decides to execute/ignore. + + SYNOPSIS + check_multi_update_lock() + thd Current thread + tables List of user-supplied tables + fields List of fields requiring update + + RETURN VALUES + 0 ok + 1 error +*/ +static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, + List<Item> *fields, SELECT_LEX *select_lex) +{ + bool res= 1; + TABLE_LIST *table; + DBUG_ENTER("check_multi_update_lock"); + + if (check_db_used(thd, tables)) + goto error; + + /* + Ensure that we have UPDATE or SELECT privilege for each table + The exact privilege is checked in mysql_multi_update() + */ + for (table= tables ; table ; table= table->next) + { + TABLE_LIST *save= table->next; + table->next= 0; + if ((check_access(thd, UPDATE_ACL, table->db, &table->grant.privilege,0,1) || + (grant_option && check_grant(thd, UPDATE_ACL, table,0,1,1))) && + check_one_table_access(thd, SELECT_ACL, table)) + goto error; + table->next= save; + } + + if (mysql_multi_update_lock(thd, tables, fields, select_lex)) + goto error; + + res= 0; + +error: + DBUG_RETURN(res); +} + Comp_creator *comp_eq_creator(bool invert) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ccfcb213068..8353ca9333d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1320,7 +1320,7 @@ JOIN::exec() curr_join->select_distinct=0; /* Each row is unique */ curr_join->join_free(0); /* Free quick selects */ - if (select_distinct && ! group_list) + if (curr_join->select_distinct && ! curr_join->group_list) { thd->proc_info="Removing duplicates"; if (curr_join->tmp_having) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c2894a0c86b..6ca794283f1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -464,30 +464,23 @@ static table_map get_table_map(List<Item> *items) } - /* - Setup multi-update handling and call SELECT to do the join + Prepare tables for multi-update + Analyse which tables need specific privileges and perform locking + as required */ -int mysql_multi_update(THD *thd, - TABLE_LIST *table_list, - List<Item> *fields, - List<Item> *values, - COND *conds, - ulong options, - enum enum_duplicates handle_duplicates, bool ignore, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) +int mysql_multi_update_lock(THD *thd, + TABLE_LIST *table_list, + List<Item> *fields, + SELECT_LEX *select_lex) { int res; - multi_update *result; TABLE_LIST *tl; TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first; - List<Item> total_list; const bool using_lock_tables= thd->locked_tables != 0; bool initialized_dervied= 0; - DBUG_ENTER("mysql_multi_update"); - - select_lex->select_limit= HA_POS_ERROR; + DBUG_ENTER("mysql_multi_update_lock"); /* The following loop is here to to ensure that we only lock tables @@ -593,7 +586,7 @@ int mysql_multi_update(THD *thd, (grant_option && check_grant(thd, wants, tl, 0, 0, 0))) { tl->next= save; - DBUG_RETURN(0); + DBUG_RETURN(1); } tl->next= save; } @@ -616,11 +609,7 @@ int mysql_multi_update(THD *thd, /* Relock the tables with the correct modes */ res= lock_tables(thd, table_list, table_count); if (using_lock_tables) - { - if (res) - DBUG_RETURN(res); break; // Don't have to do setup_field() - } /* We must setup fields again as the file may have been reopened @@ -651,6 +640,32 @@ int mysql_multi_update(THD *thd, */ close_thread_tables(thd); } + + DBUG_RETURN(res); +} + +/* + Setup multi-update handling and call SELECT to do the join +*/ + +int mysql_multi_update(THD *thd, + TABLE_LIST *table_list, + List<Item> *fields, + List<Item> *values, + COND *conds, + ulong options, + enum enum_duplicates handle_duplicates, bool ignore, + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) +{ + int res; + TABLE_LIST *tl; + TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first; + List<Item> total_list; + multi_update *result; + DBUG_ENTER("mysql_multi_update"); + + if ((res= mysql_multi_update_lock(thd, table_list, fields, select_lex))) + DBUG_RETURN(res); /* Setup timestamp handling */ for (tl= update_list; tl; tl= tl->next) diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 5bfa9e52595..4dc6a1be27b 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -153,7 +153,7 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length, /* put shorter key in s */ a_length= b_length; a= b; - swap= -1; /* swap sign of result */ + swap= -1^1; /* swap sign of result */ } for (end= a + a_length-length; a < end ; a++) { |