From dbccc041b6e5137bb8218976e8993e4de3cf45e7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Nov 2002 18:37:00 +0100 Subject: [PATCH 01/46] mysql.server: - fixed some typos and wording (merged from 3.23 tree) - fixed parsing the correct section in /etc/my.cnf ([mysql_server] -> [mysql.server]) as documented in the manual support-files/mysql.server.sh: - fixed some typos and wording (merged from 3.23 tree) - fixed parsing the correct section in /etc/my.cnf ([mysql_server] -> [mysql.server]) as documented in the manual --- support-files/mysql.server.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 139bbb3fd6b..0a9463ac095 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -2,7 +2,7 @@ # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind -# Mysql daemon start/stop script. +# MySQL daemon start/stop script. # Usually this is put in /etc/init.d (at least on machines SYSV R4 based # systems) and linked to /etc/rc3.d/S99mysql and /etc/rc0.d/K01mysql. @@ -20,17 +20,17 @@ # Required-Stop: $local_fs $network $remote_fs # Default-Start: 3 5 # Default-Stop: 3 5 -# Short-Description: start and stop MySLQ +# Short-Description: start and stop MySQL # Description: MySQL is a very fast and reliable SQL database engine. ### END INIT INFO # If you install MySQL on some other places than @prefix@, then you -# have to do one of the following thing for this script to work: +# have to do one of the following things for this script to work: # -# - Run this script from the MySQL installation directory +# - Run this script from within the MySQL installation directory # - Create a /etc/my.cnf file with the following information: # [mysqld] -# basedir=path-to-mysql-installation-directory +# basedir= # - Add the above to any other configuration file (for example ~/.my.ini) # and copy my_print_defaults to /usr/bin # - Add the path to the mysql-installation-directory to the basedir variable @@ -79,7 +79,7 @@ parse_arguments() { done } -# Get arguments from the my.cnf file, groups [mysqld] and [mysql_server] +# Get arguments from the my.cnf file, groups [mysqld] and [mysql.server] if test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" @@ -117,7 +117,7 @@ else test -z "$print_defaults" && print_defaults="my_print_defaults" fi -parse_arguments `$print_defaults $defaults mysqld mysql_server` +parse_arguments `$print_defaults $defaults mysqld mysql.server` # Safeguard (relative paths, core dumps..) cd $basedir From f7eca604785643f203f4f9edee7e7ea024c79570 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 23 Nov 2002 18:41:26 +0200 Subject: [PATCH 02/46] FreeBSD patch by Jeremy Zawodny. His explanation: The socket on which MySQL listens for new connections on a blocking socket most of the time but is set to non-blocking during the accept() of the new connection. Due to a bug in the kernel, the new socket returned by accept() is a blocking socket but returns the O_NONBLOCK flag when queried via fcntl(F_GETFL). That is, the file descriptor and the underlying socket don't agree on the blocking mode. Since MySQL determines via fcntl(F_GETFL) that the socket is non-blocking, it expects the first read() in my_real_read to not block, so it doesn't enable the timeout alarm. However, the read does block, and thus there's no timeout alarm. The thread kill (which relies on rescheduling the timeout alarm) also does not work as a consequence. The bug shows itself if you build MySQL with LinuxThreads support (needed for SMP on FreeBSD). Issuing a KILL command in MySQL won't be "noticed" by the "killed" thread until it runs another query--that makes KILL pretty useless. And the wait_timeout doesn't work either. vio/vio.c: FreeBSD patch by Jeremy Zawodny --- vio/vio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vio/vio.c b/vio/vio.c index bed380c6cd9..d822651cca6 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -98,6 +98,9 @@ Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost) vio->sd); #if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2) #if !defined(NO_FCNTL_NONBLOCK) +#if defined(__FreeBSD__) + fcntl(sd, F_SETFL, vio->fcntl_mode); /* Yahoo! FreeBSD patch */ +#endif vio->fcntl_mode = fcntl(sd, F_GETFL); #elif defined(HAVE_SYS_IOCTL_H) /* hpux */ /* Non blocking sockets doesn't work good on HPUX 11.0 */ From e0baab2eb0f0de4c26bb0568b3afcabb40b36ac9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Nov 2002 13:14:38 +0100 Subject: [PATCH 03/46] mysql.server.sh: - reverted some incompatible/non-portable modifications support-files/mysql.server.sh: - reverted non-portable change ("echo -n" does not work on all platforms) - reverted incompatible change (better fix the docs than break existing installations) --- support-files/mysql.server.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 91821fd09e5..1b050bad627 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -79,7 +79,7 @@ parse_arguments() { done } -# Get arguments from the my.cnf file, groups [mysqld] and [mysql.server] +# Get arguments from the my.cnf file, groups [mysqld] and [mysql_server] if test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" @@ -117,7 +117,7 @@ else test -z "$print_defaults" && print_defaults="my_print_defaults" fi -parse_arguments `$print_defaults $defaults mysqld mysql.server` +parse_arguments `$print_defaults $defaults mysqld mysql_server` # Safeguard (relative paths, core dumps..) cd $basedir @@ -154,7 +154,7 @@ case "$mode" in sleep 1 while [ -s $pid_file -a "$flags" != aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ] do - [ -z "$flags" ] && echo -n "Wait for mysqld to exit" || echo -n "." + [ -z "$flags" ] && echo "Wait for mysqld to exit\c" || echo ".\c" flags=a$flags sleep 1 done From 7d2d7e3fea4c46857af1e930e04c0d012a084e25 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Nov 2002 13:25:18 +0100 Subject: [PATCH 04/46] mysql.server.sh: - reverted some incompatible/non-portable modifications support-files/mysql.server.sh: - reverted some incompatible/non-portable modifications --- support-files/mysql.server.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 0a9463ac095..822e864dd77 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -79,7 +79,7 @@ parse_arguments() { done } -# Get arguments from the my.cnf file, groups [mysqld] and [mysql.server] +# Get arguments from the my.cnf file, groups [mysqld] and [mysql_server] if test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" @@ -117,7 +117,7 @@ else test -z "$print_defaults" && print_defaults="my_print_defaults" fi -parse_arguments `$print_defaults $defaults mysqld mysql.server` +parse_arguments `$print_defaults $defaults mysqld mysql_server` # Safeguard (relative paths, core dumps..) cd $basedir @@ -154,7 +154,7 @@ case "$mode" in sleep 1 while [ -s $pid_file -a "$flags" != aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ] do - [ -z "$flags" ] && echo -n "Wait for mysqld to exit" || echo -n "." + [ -z "$flags" ] && echo "Wait for mysqld to exit\c" || echo ".\c" flags=a$flags sleep 1 done From 562fc5dfccc9bed7dbe952bbc41586500427154a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Nov 2002 13:30:56 +0100 Subject: [PATCH 05/46] - fixed tabbing --- support-files/mysql.server.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 1b050bad627..6c3fa9f1127 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -154,7 +154,7 @@ case "$mode" in sleep 1 while [ -s $pid_file -a "$flags" != aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ] do - [ -z "$flags" ] && echo "Wait for mysqld to exit\c" || echo ".\c" + [ -z "$flags" ] && echo "Wait for mysqld to exit\c" || echo ".\c" flags=a$flags sleep 1 done From 962cedf225399e12700eb2cd30be32174a8570d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Nov 2002 11:21:35 +0100 Subject: [PATCH 06/46] - Updated to Marcs latest version from entropy.ch support-files/make_mysql_pkg.pl: make_mysql_pkg.pl - Updated to Marcs latest version from entropy.ch --- support-files/make_mysql_pkg.pl | 89 +++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/support-files/make_mysql_pkg.pl b/support-files/make_mysql_pkg.pl index 75345c7275b..22283d57098 100644 --- a/support-files/make_mysql_pkg.pl +++ b/support-files/make_mysql_pkg.pl @@ -17,16 +17,30 @@ # History: # # When Who What -# ------------------------------------------------------------- +# ------------------------------------------------------------------ # 2001-09-16 Marc Liyanage First version +# 2001-11-18 Marc Liyanage Improved configure directory options +# use strict; use DirHandle; my $data = {}; -$data->{PREFIX_DIR} = "/usr/local"; -$data->{CONFIG} = "--prefix=$data->{PREFIX_DIR} --with-innodb"; +$data->{PREFIX_DIR} = "/usr/local/mysql"; +$data->{CONFIG} = join(" ", + "--prefix=$data->{PREFIX_DIR}", + "--localstatedir=$data->{PREFIX_DIR}/data", + "--libdir=$data->{PREFIX_DIR}/lib", + "--includedir=$data->{PREFIX_DIR}/include", + "--with-named-z-libs=/usr/local/libz.a", + "--with-innodb", + "--with-server-suffix='-entropy.ch'", + "--with-comment='http://www.entropy.ch/software/macosx/mysql/'", + "--with-mysqld-user=mysql", + "--enable-assembler", + "CFLAGS=\"-DHAVE_BROKEN_REALPATH -lncurses\"", +); @@ -177,8 +191,7 @@ sub make_binary_distribution { # Now we build a fake /usr/local directory hierarchy. -# This will be fed to the pax tool to create -# the archive. +# This will be fed to the pax tool to create the archive. # sub create_pax_root { @@ -190,7 +203,7 @@ sub create_pax_root { chdir($data->{PAXROOT_DIR}); my $tarfile = "$data->{OLDWD}/$data->{BINARY_TARBALL_FILENAME}"; - if(system("tar -xzf $tarfile")) { + if (system("tar -xzf $tarfile")) { abort($data, "Unable to extract $tarfile inside $data->{PAXROOT_DIR}"); } @@ -213,14 +226,35 @@ sub create_pax_root { # First create the symlinks in the bin directory # + # 2001-02-13: we no longer use symlinks for the binaries, we + # use small dummy scripts instead because the + # mysql scripts do a lot of guesswork with their + # own path and that will not work when called via the symlink + # +# symlink("../mysql/bin/$_", "$_") foreach (grep {$_ !~ /^\.+$/} DirHandle->new("../mysql/bin")->read()); + chdir("bin"); - symlink("../mysql/bin/$_", "$_") foreach (grep {$_ !~ /^\.+$/} DirHandle->new("../mysql/bin")->read()); + + foreach my $command (grep {$_ !~ /^\.+$/} DirHandle->new("../mysql/bin")->read()) { + + my $scriptcode = qq+#!/bin/sh\n# Part of the entropy.ch mysql package\ncd /usr/local/mysql/\nexec ./bin/$command "\$\@"\n+; + open(SCRIPTFILE, ">$command") or die "Unable to write open $command\n"; + print SCRIPTFILE $scriptcode; + close(SCRIPTFILE); + chmod(0755, $command); + + } + + + + + # Now include the man pages. Two problems here: # 1.) the make_binary_distribution script does not seem # to include the man pages, so we have to copy them over - # now. + # now. [outdated, was fixed by MySQL!] # 2.) The man pages could be in different sections, so # we have to recursively copy *and* symlink them. # @@ -230,7 +264,7 @@ sub create_pax_root { # arrays which in turn will be stored in a hash, using # the section numbers as hash keys. # - chdir($data->{OLDWD}); + chdir("$data->{PAXROOT_DIR}/mysql"); my %man_sections; foreach my $manpage (grep {$_ =~ /^.+\.(\d+)$/} DirHandle->new("man")->read()) { @@ -249,14 +283,12 @@ sub create_pax_root { foreach my $section (keys(%man_sections)) { - system("mkdir -p $data->{PAXROOT_DIR}/mysql/man/man$section/"); system("mkdir -p man$section"); chdir("man$section"); foreach my $manpage (@{$man_sections{$section}}) { - system("cp $data->{OLDWD}/man/$manpage $data->{PAXROOT_DIR}/mysql/man/man$section/"); - symlink("../../../mysql/man/man$section/$manpage", $manpage) + symlink("../../../mysql/man/$manpage", $manpage) } @@ -265,6 +297,35 @@ sub create_pax_root { } + + # Fix up the library and lib directories. They are packed up wrong in the + # binary distribution tarball. + # + # (no longer needed as of 3.23.47) + # (oops, still needed because 3.23.47 is broken...) + # +# if (-d "$data->{PAXROOT_DIR}/mysql/lib/mysql") { +# abort($data, "$data->{PAXROOT_DIR}/mysql/lib/mysql exists, layout has changed!"); +# } +# chdir("$data->{PAXROOT_DIR}/mysql/lib/"); +# system("mkdir -p mysql"); +# system("mv * mysql"); + +# if (-d "$data->{PAXROOT_DIR}/mysql/include/mysql") { +# abort($data, "$data->{PAXROOT_DIR}/mysql/include/mysql exists, layout has changed!"); +# } +# chdir("$data->{PAXROOT_DIR}/mysql/include/"); +# system("mkdir -p mysql"); +# system("mv * mysql"); + + + + + + + + + } @@ -310,7 +371,7 @@ sub create_package { my $size_compressed = `du -sk $data->{PACKAGE_DIR} | cut -f 1`; chomp($size_compressed); - my $numfiles = `find /tmp/mysql-3.23.42-paxroot/ | wc -l`; + my $numfiles = `find /tmp/mysql-$data->{VERSION}-paxroot | wc -l`; $numfiles--; open(SIZESFILE, ">$data->{PKG_RESOURCES_DIR}/mysql-$data->{VERSION}.sizes") or abort("Unable to write open sizes file $data->{PKG_RESOURCES_DIR}/mysql-$data->{VERSION}.sizes"); @@ -411,4 +472,4 @@ Relocatable NO Required NO InstallOnly NO RequiresReboot NO -InstallFat NO \ No newline at end of file +InstallFat NO From b39752294b6fc55d702432187f3bb6ee0b3d6329 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Nov 2002 03:45:25 +0500 Subject: [PATCH 07/46] add sapdb section into server-cfg, add a lot of new function and tests into crash-me sql-bench/crash-me.sh: - If double double quotes are allowed in identifiers. - Rollback rolls back meta data - NULL sort and NULL sort perserve. - remove one check of "serial". - (Column,Table,Named constraints) new test to crash me if the check syntax is only supported by the parser, but not done for real. - For all ..USER tests, (like current_user), add an extra test if ...USER() is supported. - Add tests for constants TRUE and FALSE - Add test of LIMIT # OFFSET (PostgreSQL syntax) - add test a lot of new functions sql-bench/server-cfg.sh: add sapdb section --- sql-bench/crash-me.sh | 284 +++++++++++++++++++++++++++++++++++++--- sql-bench/server-cfg.sh | 215 +++++++++++++++++++++++++++++- 2 files changed, 475 insertions(+), 24 deletions(-) diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh index d66e8f47d6a..5fa67773566 100644 --- a/sql-bench/crash-me.sh +++ b/sql-bench/crash-me.sh @@ -38,7 +38,7 @@ # as such, and clarify ones such as "mediumint" with comments such as # "3-byte int" or "same as xxx". -$version="1.58"; +$version="1.59"; use DBI; use Getopt::Long; @@ -253,6 +253,9 @@ check_and_report("\` as identifier quote",'quote_ident_with_`',[], 'select `A` from crash_me',[],"1",0); check_and_report("[] as identifier quote",'quote_ident_with_[',[], 'select [A] from crash_me',[],"1",0); +report('Double "" in identifiers as "','quote_ident_with_dbl_"', + 'create table crash_me1 ("abc""d" integer)', + 'drop table crash_me1'); report("Column alias","column_alias","select a as ab from crash_me"); report("Table alias","table_alias","select b.a from crash_me as b"); @@ -301,6 +304,7 @@ try_and_report("LIMIT number of rows","select_limit", ["with TOP", "select TOP 1 * from crash_me"]); report("SELECT with LIMIT #,#","select_limit2", "select * from crash_me limit 1,1"); +report("SELECT with LIMIT # OFFSET #","select_limit3", "select * from crash_me limit 1 offset 1"); # The following alter table commands MUST be kept together! if ($dbh->do("create table crash_q (a integer, b integer,c1 CHAR(10))")) @@ -434,6 +438,9 @@ report("hex strings (x'1ace')","hex_strings","select x'1ace' $end_query"); report_result("Value of logical operation (1=1)","logical_value", "select (1=1) $end_query"); +report_result("Value of TRUE","value_of_true","select TRUE $end_query"); +report_result("Value of FALSE","value_of_false","select FALSE $end_query"); + $logical_value= $limits{'logical_value'}; $false=0; @@ -584,7 +591,7 @@ print "$limits{'query_size'}\n"; "int not null identity,unique(q)", # postgres types "box","bool","circle","polygon","point","line","lseg","path", - "interval", "serial", "inet", "cidr", "macaddr", + "interval", "inet", "cidr", "macaddr", # oracle types "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)", @@ -769,7 +776,6 @@ try_and_report("Automatic row id", "automatic_rowid", ["CURRENT_DATE","current_date","current_date",0,2], ["CURRENT_TIME","current_time","current_time",0,2], ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2], - ["CURRENT_USER","current_user","current_user",0,2], ["EXTRACT","extract_sql","extract(minute from timestamp '2000-02-23 18:43:12.987')",43,0], ["LOCALTIME","localtime","localtime",0,2], ["LOCALTIMESTAMP","localtimestamp","localtimestamp",0,2], @@ -778,11 +784,8 @@ try_and_report("Automatic row id", "automatic_rowid", ["NULLIF with numbers","nullif_num","NULLIF(NULLIF(1,2),1)",undef(),4], ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0], ["POSITION","position","position('ll' in 'hello')",3,0], - ["SESSION_USER","session_user","session_user",0,2], - ["SYSTEM_USER","system_user","system_user",0,2], ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3], ["UPPER","upper","UPPER('abc')","ABC",1], - ["USER","user","user"], ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1], ); @@ -960,8 +963,61 @@ try_and_report("Automatic row id", "automatic_rowid", ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1], ["automatic string->num convert","auto_string2num","'1'+2",3,0], ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1], + ["SUBSTR (2 arg)",'substr2arg',"substr('abcd',2)",'bcd',1], #sapdb func + ["SUBSTR (3 arg)",'substr3arg',"substr('abcd',2,2)",'bc',1], + ["LFILL (3 arg)",'lfill3arg',"lfill('abcd','.',6)",'..abcd',1], + ["RFILL (3 arg)",'rfill3arg',"rfill('abcd','.',6)",'abcd..',1], + ["RPAD (4 arg)",'rpad4arg',"rpad('abcd',2,'+-',8)",'abcd+-+-',1], + ["LPAD (4 arg)",'rpad4arg',"lpad('abcd',2,'+-',8)",'+-+-abcd',1], + ["SAPDB compatible TRIM (1 arg)",'trim1arg',"trim(' abcd ')",'abcd',1], + ["SAPDB compatible TRIM (2 arg)",'trim2arg',"trim('..abcd..','.')",'abcd',1], + ["LTRIM (2 arg)",'ltrim2arg',"ltrim('..abcd..','.')",'abcd..',1], + ["RTRIM (2 arg)",'rtrim2arg',"rtrim('..abcd..','.')",'..abcd',1], + ["EXPAND",'expand2arg',"expand('abcd',6)",'abcd ',0], + ["REPLACE (2 arg) ",'replace2arg',"replace('AbCd','bC')",'Ad',1], + ["MAPCHAR",'mapchar',"mapchar('Aâ')",'Aa',1], + ["ALPHA",'alpha',"alpha('Aâ',2)",'AA',1], + ["ASCII in string cast",'ascii_string',"ascii('a')",'a',1], + ["EBCDIC in string cast",'ebcdic_string',"ebcdic('a')",'a',1], + ["TRUNC (1 arg)",'trunc1arg',"trunc(222.6)",222,0], + ["NOROUND",'noround',"noround(222.6)",222.6,0], + ["FIXED",'fixed',"fixed(222.6666,10,2)",'222.67',0], + ["FLOAT",'float',"float(6666.66,4)",6667,0], + ["LENGTH",'length',"length(1)",2,0], + ["INDEX",'index',"index('abcdefg','cd',1,1)",3,0], + ["ADDDATE",'adddate',"ADDDATE('20021201',3)",'20021204',0], + ["SUBDATE",'subdate',"SUBDATE('20021204',3)",'20021201',0], + ["DATEDIFF (2 arg)",'datediff2arg',"DATEDIFF('20021204','20021201')",'3',0], # sapdb + ["DAYOFWEEK with sapdb internal date as arg",'dayofweek_sapdb',"DAYOFWEEK('19630816')",'5',0], + ["WEEKOFYEAR",'weekofyear',"WEEKOFYEAR('19630816')",'33',0], + ["DAYOFMONTH with sapdb internal date as arg",'dayofmonth_sapdb',"dayofmonth('19630816')",'16',0], + ["DAYOFYEAR with sapdb internal date as arg",'dayofyear_sapdb',"DAYOFYEAR('19630816')",'228',0], + ["MAKEDATE",'makedate',"MAKEDATE(1963,228)",'19630816',0], + ["DAYNAME with sapdb internal date as arg",'dayname_sapdb',"DAYNAME('19630816')",'Friday',0], + ["MONTHNAME with sapdb internal date as arg",'monthname_sapdb',"MONTHNAME('19630816')",'August',0], + ["ADDTIME",'addtime',"ADDTIME('00200212','00000300')",'00200215',0], + ["SUBTIME",'subdate',"SUBDATE('00200215','00000300')",'00200212',0], + ["TIMEDIFF",'timediff',"TIMEDIFF('00200215','00200212')",'00000003',0], + ["MAKETIME",'maketime',"MAKETIME(20,02,12)",'00200212',0], + ["YEAR with sapdb internal date as arg",'year_sapdb',"YEAR('20021201')",'2002',0], + ["MONTH with sapdb internal date as arg",'month_sapdb',"MONTH('20021201')",'12',0], + ["DAY",'day',"DAY('20021201')",1,0], + ["HOUR with sapdb internal time as arg",'hour_sapdb',"HOUR('00200212')",20,0], + ["MINUTE with sapdb internal time as arg",'minute_sapdb',"MINUTE('00200212')",2,0], + ["SECOND with sapdb internal time as arg",'second_sapdb',"SECOND('00200212')",12,0], + ["MICROSECOND",'microsecond',"MICROSECOND('19630816200212111111')",'111111',0], + ["TIMESTAMP",'timestamp',"timestamp('19630816','00200212')",'19630816200212000000',0], + ["TIME",'time',"time('00200212')",'00200212',0], + ["DATE",'date',"date('19630816')",'19630816',0], + ["VALUE",'value',"value(NULL,'WALRUS')",'WALRUS',0], + ["DECODE",'decode',"DECODE('S-103','T72',1,'S-103',2,'Leopard',3)",2,0], + ["NUM",'num',"NUM('2123')",2123,0], + ["CHAR (conversation date)",'char_date',"CHAR(DATE('19630816'),EUR)",'16.08.1963',0], + ["CHR (any type to string)",'chr_str',"CHR(67)",'67',0], + ["HEX",'hex',"HEX('A')",41,0], ); + @sql_group_functions= ( ["AVG","avg","avg(a)",1,0], @@ -1131,6 +1187,20 @@ else } +if ($limits{'func_extra_noround'} eq 'yes') +{ + report("Ignoring NOROUND","ignoring_noround", + "create table crash_q (a int)", + "insert into crash_q values(noround(10.22))", + "drop table crash_q $drop_attr"); +} + +check_parenthesis("func_sql_","CURRENT_USER"); +check_parenthesis("func_sql_","SESSION_USER"); +check_parenthesis("func_sql_","SYSTEM_USER"); +check_parenthesis("func_sql_","USER"); + + report("LIKE on numbers","like_with_number", "create table crash_q (a int,b int)", "insert into crash_q values(10,10)", @@ -1561,19 +1631,29 @@ if (!defined($limits{"transactions"})) { my ($limit,$type); $limit="transactions"; + $limit_r="rollback_metadata"; print "$limit: "; foreach $type (('', 'type=bdb', 'type=innodb', 'type=gemini')) { undef($limits{$limit}); - last if (!report_trans($limit, + if (!report_trans($limit, [create_table("crash_q",["a integer not null"],[], $type), "insert into crash_q values (1)"], "select * from crash_q", "drop table crash_q $drop_attr" - )); + )) + { + report_rollback($limit_r, + [create_table("crash_q",["a integer not null"],[], + $type)], + "insert into crash_q values (1)", + "drop table crash_q $drop_attr" ); + last; + }; } print "$limits{$limit}\n"; + print "$limit_r: $limits{$limit_r}\n"; } report("atomic updates","atomic_updates", @@ -1644,14 +1724,29 @@ report("Column constraints","constraint_check", "create table crash_q (a int check (a>0))", "drop table crash_q $drop_attr"); +report("Ignoring column constraints","ignoring_constraint_check", + "create table crash_q (a int check (a>0))", + "insert into crash_q values(0)", + "drop table crash_q $drop_attr") if ($limits{'constraint_check'} eq 'yes'); + report("Table constraints","constraint_check_table", "create table crash_q (a int ,b int, check (a>b))", "drop table crash_q $drop_attr"); -report("Named constraints","constraint_check", +report("Ignoring table constraints","ignoring_constraint_check_table", + "create table crash_q (a int ,b int, check (a>b))", + "insert into crash_q values(0,0)", + "drop table crash_q $drop_attr") if ($limits{'constraint_check_table'} eq 'yes'); + +report("Named constraints","constraint_check_named", "create table crash_q (a int ,b int, constraint abc check (a>b))", "drop table crash_q $drop_attr"); +report("Ignoring named constraints","ignoring_constraint_check_named", + "create table crash_q (a int ,b int, constraint abc check (a>b))", + "insert into crash_q values(0,0)", + "drop table crash_q $drop_attr") if ($limits{'constraint_check_named'} eq 'yes'); + report("NULL constraint (SyBase style)","constraint_null", "create table crash_q (a int null)", "drop table crash_q $drop_attr"); @@ -2009,6 +2104,90 @@ find_limit("number of columns in group by","columns_in_group_by", ["drop table crash_q $drop_attr"], $max_order_by)); + + +# Safe arithmetic test + +$prompt="safe decimal arithmetic"; +$key="safe_decimal_arithmetic"; +if (!defined($limits{$key})) +{ + print "$prompt="; + save_incomplete($key,$prompt); + if (!safe_query($server->create("crash_me_a",["a decimal(10,2)","b decimal(10,2)"]))) + { + print DBI->errstr(); + die "Can't create table 'crash_me_a' $DBI::errstr\n"; + }; + + if (!safe_query(["insert into crash_me_a (a,b) values (11.4,18.9)"])) + { + die "Can't insert into table 'crash_me_a' a record: $DBI::errstr\n"; + }; + + $arithmetic_safe = 'no'; + $arithmetic_safe = 'yes' + if ( (safe_query_result('select count(*) from crash_me_a where a+b=30.3',1,0) == 0) + and (safe_query_result('select count(*) from crash_me_a where a+b-30.3 = 0',1,0) == 0) + and (safe_query_result('select count(*) from crash_me_a where a+b-30.3 < 0',0,0) == 0) + and (safe_query_result('select count(*) from crash_me_a where a+b-30.3 > 0',0,0) == 0) ); + save_config_data($key,$arithmetic_safe,$prompt); + print "$arithmetic_safe\n"; + assert("drop table crash_me_a $drop_attr"); +} + else +{ + print "$prompt=$limits{$key} (cached)\n"; +} + +# Check where is null values in sorted recordset +if (!safe_query($server->create("crash_me_n",["i integer","r integer"]))) + { + print DBI->errstr(); + die "Can't create table 'crash_me_n' $DBI::errstr\n"; + }; +assert("insert into crash_me_n (i) values(1)"); +assert("insert into crash_me_n values(2,2)"); +assert("insert into crash_me_n values(3,3)"); +assert("insert into crash_me_n values(4,4)"); +assert("insert into crash_me_n (i) values(5)"); + +$key = "position_of_null"; +$prompt ="Where is null values in sorted recordset"; +if (!defined($limits{$key})) +{ + save_incomplete($key,$prompt); + print "$prompt="; + $sth=$dbh->prepare("select r from crash_me_n order by r "); + $sth->execute; + $limit= detect_null_position($sth); + $sth->finish; + print "$limit\n"; + save_config_data($key,$limit,$prompt); +} else { + print "$prompt=$limits{$key} (cache)\n"; +} + +$key = "position_of_null_desc"; +$prompt ="Where is null values in sorted recordset (DESC)"; +if (!defined($limits{$key})) +{ + save_incomplete($key,$prompt); + print "$prompt="; + $sth=$dbh->prepare("select r from crash_me_n order by r desc"); + $sth->execute; + $limit= detect_null_position($sth); + $sth->finish; + print "$limit\n"; + save_config_data($key,$limit,$prompt); +} else { + print "$prompt=$limits{$key} (cache)\n"; +} + + +assert("drop table crash_me_n $drop_attr"); + + # # End of test # @@ -2022,6 +2201,41 @@ $dbh->disconnect || warn $dbh->errstr; save_all_config_data(); exit 0; +# Check where is nulls in the sorted result (for) +# it expects exactly 5 rows in the result + +sub detect_null_position +{ + my $sth = shift; + my ($z,$r1,$r2,$r3,$r4,$r5); + $r1 = $sth->fetchrow_array; + $r2 = $sth->fetchrow_array; + $r3 = $sth->fetchrow_array; + $r4 = $sth->fetchrow_array; + $r5 = $sth->fetchrow_array; + return "first" if ( !defined($r1) && !defined($r2) && defined($r3)); + return "last" if ( !defined($r5) && !defined($r4) && defined($r3)); + return "random"; +} + +sub check_parenthesis { + my $prefix=shift; + my $fn=shift; + my $resultat='no'; + my $param_name=$prefix.lc($fn); + + save_incomplete($param_name,$fn); + if (safe_query("select $fn $end_query") == 1) + { + $resultat="yes"; + } + elsif ( safe_query("select $fn() $end_query") == 1) + { + $resultat="with_parenthesis"; + } + save_config_data($param_name,$resultat,$fn); +} + sub usage { print <rollback; - if ($rc) { - $dbh->{AutoCommit} = 1; + $dbh->rollback; + $dbh->{AutoCommit} = 1; if (safe_query_result($check,"","")) { save_config_data($limit,"yes",$limit); } safe_query($clear); - } else { - $dbh->{AutoCommit} = 1; - save_config_data($limit,"error",$limit); - } } else { save_config_data($limit,"error",$limit); } @@ -2566,6 +2775,39 @@ sub report_trans return $limits{$limit} ne "yes"; } +sub report_rollback +{ + my ($limit,$queries,$check,$clear)=@_; + if (!defined($limits{$limit})) + { + save_incomplete($limit,$prompt); + eval {undef($dbh->{AutoCommit})}; + if (!$@) + { + if (safe_query(\@$queries)) + { + $dbh->rollback; + $dbh->{AutoCommit} = 1; + if (safe_query($check)) { + save_config_data($limit,"no",$limit); + } else { + save_config_data($limit,"yes",$limit); + }; + safe_query($clear); + } else { + save_config_data($limit,"error",$limit); + } + } + else + { + save_config_data($limit,"error",$limit); + } + safe_query($clear); + } + $dbh->{AutoCommit} = 1; + return $limits{$limit} ne "yes"; +} + sub check_and_report { @@ -2892,7 +3134,7 @@ sub read_config_data { if ($key !~ /restart/i) { - $limits{$key}=$limit; + $limits{$key}=$limit eq "null"? undef : $limit; $prompts{$key}=length($prompt) ? substr($prompt,2) : ""; delete $limits{'restart'}; } @@ -2922,7 +3164,8 @@ sub save_config_data return if (defined($limits{$key}) && $limits{$key} eq $limit); if (!defined($limit) || $limit eq "") { - die "Undefined limit for $key\n"; +# die "Undefined limit for $key\n"; + $limit = 'null'; } print CONFIG_FILE "$key=$limit\t# $prompt\n"; $limits{$key}=$limit; @@ -3576,5 +3819,6 @@ sub check_query } + ### TODO: # OID test instead of / in addition to _rowid diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh index e53190a75ec..213ecacea6f 100644 --- a/sql-bench/server-cfg.sh +++ b/sql-bench/server-cfg.sh @@ -69,11 +69,13 @@ sub get_server { $server= new db_db2($host,$database); } elsif ($name =~ /Mimer/i) { $server= new db_Mimer($host,$database); } + elsif ($name =~ /Sapdb/i) + { $server= new db_sapdb($host,$database); } elsif ($name =~ /interBase/i) { $server= new db_interbase($host,$database); } else { - die "Unknown sql server name used: $name\nUse one of: Access, Adabas, AdabasD, Empress, FrontBase, Oracle, Informix, InterBase, DB2, mSQL, Mimer, MS-SQL, MySQL, Pg, Solid or Sybase.\nIf the connection is done trough ODBC the name must end with _ODBC\n"; + die "Unknown sql server name used: $name\nUse one of: Access, Adabas, AdabasD, Empress, FrontBase, Oracle, Informix, InterBase, DB2, mSQL, Mimer, MS-SQL, MySQL, Pg, Solid, SAPDB or Sybase.\nIf the connection is done trough ODBC the name must end with _ODBC\n"; } if ($name =~ /_ODBC$/i || defined($odbc) && $odbc) { @@ -94,7 +96,7 @@ sub get_server sub all_servers { return ["Access", "Adabas", "DB2", "Empress", "FrontBase", "Oracle", - "Informix", "InterBase", "Mimer", "mSQL", "MS-SQL", "MySQL", "Pg", + "Informix", "InterBase", "Mimer", "mSQL", "MS-SQL", "MySQL", "Pg","SAPDB", "Solid", "Sybase"]; } @@ -116,7 +118,6 @@ sub new $self->{'data_source'} .= ";mysql_socket=$socket" if($socket); $self->{'data_source'} .= ";$connect_options" if($connect_options); $self->{'limits'} = \%limits; - $self->{'smds'} = \%smds; $self->{'blob'} = "blob"; $self->{'text'} = "text"; $self->{'double_quotes'} = 1; # Can handle: 'Walker''s' @@ -178,7 +179,6 @@ sub new if (defined($main::opt_create_options) && $main::opt_create_options =~ /type=innodb/i) { - $limits{'max_text_size'} = 8000; # Limit in Innobase $self->{'transactions'} = 1; # Transactions enabled } if (defined($main::opt_create_options) && @@ -3361,4 +3361,211 @@ sub fix_for_insert return $cmd; } +############################################################################# +# Configuration for SAPDB +############################################################################# + +package db_Sapdb; + +sub new +{ + my ($type,$host,$database)= @_; + my $self= {}; + my %limits; + bless $self; + + $self->{'cmp_name'} = "sapdb"; + $self->{'data_source'} = "DBI:SAP_DB:$database"; + $self->{'limits'} = \%limits; + $self->{'blob'} = "LONG"; # * + $self->{'text'} = "LONG"; # * + $self->{'double_quotes'} = 1; # Can handle: 'Walker''s' + $self->{'drop_attr'} = ""; + $self->{'transactions'} = 1; # Transactions enabled * + $self->{'char_null'} = ""; + $self->{'numeric_null'} = ""; + + $limits{'max_conditions'} = 9999; # (Actually not a limit) * + $limits{'max_columns'} = 1023; # Max number of columns in table * + $limits{'max_tables'} = 65000; # Should be big enough * unlimited actually + $limits{'max_text_size'} = 15000; # Max size with default buffers. + $limits{'query_size'} = 64*1024; # Max size with default buffers. *64 kb by default. May be set by system variable + $limits{'max_index'} = 510; # Max number of keys * + $limits{'max_index_parts'} = 16; # Max segments/key * + $limits{'max_column_name'} = 32; # max table and column name * + + $limits{'join_optimizer'} = 1; # Can optimize FROM tables * + $limits{'load_data_infile'} = 0; # Has load data infile * + $limits{'lock_tables'} = 1; # Has lock tables + $limits{'functions'} = 1; # Has simple functions (+/-) * + $limits{'group_functions'} = 1; # Have group functions * + $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings * + $limits{'group_distinct_functions'}= 1; # Have count(distinct) * + $limits{'select_without_from'}= 0; # Cannot do 'select 1'; * + $limits{'multi_drop'} = 0; # Drop table cannot take many tables * + $limits{'subqueries'} = 1; # Supports sub-queries. * + $limits{'left_outer_join'} = 1; # Supports left outer joins * + $limits{'table_wildcard'} = 1; # Has SELECT table_name.* + $limits{'having_with_alias'} = 0; # Can use aliases in HAVING * + $limits{'having_with_group'} = 1; # Can use group functions in HAVING * + $limits{'like_with_column'} = 1; # Can use column1 LIKE column2 * + $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1' * + $limits{'group_by_position'} = 0; # Cannot use 'GROUP BY 1' * + $limits{'alter_table'} = 1; # Have ALTER TABLE * + $limits{'alter_add_multi_col'}= 1; # Have ALTER TABLE t add a int,add b int; * + $limits{'alter_table_dropcol'}= 1; # Have ALTER TABLE DROP column * + $limits{'insert_multi_value'} = 0; # INSERT ... values (1,2),(3,4) * + + $limits{'group_func_extra_std'} = 0; # Does not have group function std(). + + $limits{'func_odbc_mod'} = 0; # Have function mod. * + $limits{'func_extra_%'} = 0; # Does not have % as alias for mod() * + $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function * + $limits{'func_extra_if'} = 0; # Does not have function if. * + $limits{'column_alias'} = 1; # Alias for fields in select statement. * + $limits{'NEG'} = 1; # Supports -id * + $limits{'func_extra_in_num'} = 0; # Has function in * + $limits{'limit'} = 0; # Does not support the limit attribute * + $limits{'working_blobs'} = 1; # If big varchar/blobs works * + $limits{'order_by_unused'} = 1; # + $limits{'working_all_fields'} = 1; # + + + return $self; +} + +# +# Get the version number of the database +# + +sub version +{ + my ($self)=@_; + my ($dbh,$sth,$version,@row); + + $dbh=$self->connect(); + $sth = $dbh->prepare("SELECT KERNEL FROM VERSIONS") or die $DBI::errstr; + $version="SAP DB (unknown)"; + if ($sth->execute && (@row = $sth->fetchrow_array) + && $row[0] =~ /([\d\.]+)/) + { + $version="sap-db $1"; + } + $sth->finish; + $dbh->disconnect; + return $version; +} + +# +# Connection with optional disabling of logging +# + +sub connect +{ + my ($self)=@_; + my ($dbh); + $dbh=DBI->connect($self->{'data_source'}, $main::opt_user, + $main::opt_password,{ PrintError => 0, AutoCommit => 1}) || + die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n"; + + return $dbh; +} + +# +# Returns a list of statements to create a table +# The field types are in ANSI SQL format. +# + +sub create +{ + my($self,$table_name,$fields,$index,$options) = @_; + my($query,@queries,$nr); + my @index; + my @keys; + + $query="create table $table_name ("; + foreach $field (@$fields) + { + $field =~ s/\bmediumint\b/int/i; + $field =~ s/\btinyint\b/int/i; + $field =~ s/ int\(\d\)/ int/i; + $field =~ s/BLOB/LONG/i; + $field =~ s/INTEGER\s*\(\d+\)/INTEGER/i; + $field =~ s/SMALLINT\s*\(\d+\)/SMALLINT/i; + $field =~ s/FLOAT\s*\((\d+),\d+\)/FLOAT\($1\)/i; + $field =~ s/DOUBLE/FLOAT\(38\)/i; + $field =~ s/DOUBLE\s+PRECISION/FLOAT\(38\)/i; + $query.= $field . ','; + } + $nr=0; + foreach $ind (@$index) + { + if ( $ind =~ /\bKEY\b/i ){ + push(@keys,"ALTER TABLE $table_name ADD $ind"); + } elsif ($ind =~ /^unique.*\(([^\(]*)\)$/i) { + $nr++; + my $query="create unique index ${table_name}_$nr on $table_name ($1)"; + push(@index,$query); + }else{ + my @fields = split(' ',$ind); + my $query="CREATE INDEX $fields[1] ON $table_name $fields[2]"; + print "$query \n"; + push(@index,$query); + } + } + substr($query,-1)=")"; # Remove last ','; + $query.=" $options" if (defined($options)); + push(@queries,$query); + push(@queries,@keys); + push(@queries,@index); + return @queries; +} + +sub insert_file { + my($self,$dbname, $file) = @_; + print "insert of an ascii file isn't supported by SAPDB\n"; + return 0; +} + +# +# Do any conversions to the ANSI SQL query so that the database can handle it +# + +sub query { + my($self,$sql) = @_; + return $sql; +} + +sub drop_index { + my ($self,$table,$index) = @_; + return "DROP INDEX $index"; +} + +# +# Abort if the server has crashed +# return: 0 if ok +# 1 question should be retried +# + +sub abort_if_fatal_error +{ + return 0; +} + +sub small_rollback_segment +{ + return 0; +} + +sub reconnect_on_errors +{ + return 0; +} + +sub fix_for_insert +{ + my ($self,$cmd) = @_; + return $cmd; +} + 1; From 6a7f6fefa96ac78c6c94d44c43c637b5deb1330a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Nov 2002 13:01:50 +0100 Subject: [PATCH 08/46] Add the ChangeSet id to Subject: in all emails. BitKeeper/etc/ignore: Added autom4te-2.53.cache/output.0 autom4te-2.53.cache/requests autom4te-2.53.cache/traces.0 bdb/dist/autom4te-2.53.cache/output.0 bdb/dist/autom4te-2.53.cache/requests bdb/dist/autom4te-2.53.cache/traces.0 bkpull.log build.log innobase/autom4te-2.53.cache/output.0 innobase/autom4te-2.53.cache/requests innobase/autom4te-2.53.cache/traces.0 pull.log to the ignore list --- .bzrignore | 12 ++++++++++++ BitKeeper/triggers/post-commit | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.bzrignore b/.bzrignore index 066407445e2..5d8375d2877 100644 --- a/.bzrignore +++ b/.bzrignore @@ -509,3 +509,15 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +autom4te-2.53.cache/output.0 +autom4te-2.53.cache/requests +autom4te-2.53.cache/traces.0 +bdb/dist/autom4te-2.53.cache/output.0 +bdb/dist/autom4te-2.53.cache/requests +bdb/dist/autom4te-2.53.cache/traces.0 +bkpull.log +build.log +innobase/autom4te-2.53.cache/output.0 +innobase/autom4te-2.53.cache/requests +innobase/autom4te-2.53.cache/traces.0 +pull.log diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index 50562ba5cc9..86a612acfcb 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -19,6 +19,8 @@ BK_STATUS=$BK_STATUS$BK_COMMIT if [ "$BK_STATUS" = OK ] then +CHANGESET=`bk changes -r+ | sed -n 's/^ChangeSet@\([^,][^,]*\),.*/\1/p'` + #++ # dev-public@ #-- @@ -28,7 +30,7 @@ then List-ID: From: $FROM To: $TO -Subject: bk commit - 4.0 tree +Subject: bk commit - 4.0 tree ($CHANGESET) EOF bk changes -v -r+ @@ -44,7 +46,7 @@ EOF List-ID: From: $FROM To: $INTERNALS -Subject: bk commit into 4.0 tree +Subject: bk commit into 4.0 tree ($CHANGESET) Below is the list of changes that have just been committed into a local 4.0 repository of $USER. When $USER does a push these changes will @@ -71,7 +73,7 @@ EOF List-ID: From: $FROM To: $DOCS -Subject: bk commit - 4.0 tree (Manual) +Subject: bk commit - 4.0 tree (Manual) ($CHANGESET) EOF bk changes -v -r+ From 09a621897616ecdf0217db082a0b52c26b4c4adc Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Nov 2002 10:05:49 -0400 Subject: [PATCH 09/46] Fix for shutdown on several instances servers started as standalone --- sql/mysqld.cc | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b02d7179ae4..583d9e9debd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -383,7 +383,7 @@ enum db_type default_table_type=DB_TYPE_MYISAM; #undef getpid #include HANDLE hEventShutdown; -static char *event_name; +static char shutdown_event_name[40]; #include "nt_servc.h" static NTService Service; // Service object for WinNT #endif @@ -640,10 +640,6 @@ void kill_mysql(void) { DBUG_PRINT("error",("Got error: %ld from SetEvent",GetLastError())); } - // or: - // HANDLE hEvent=OpenEvent(0, FALSE, "MySqlShutdown"); - // SetEvent(hEventShutdown); - // CloseHandle(hEvent); } #elif defined(OS2) pthread_cond_signal( &eventShutdown); // post semaphore @@ -1993,7 +1989,7 @@ The server will not act as a slave."); (void) thr_setconcurrency(concurrency); // 10 by default #ifdef __WIN__ //IRENA { - hEventShutdown=CreateEvent(0, FALSE, FALSE, "MySqlShutdown"); + hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name); pthread_t hThread; if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0)) sql_print_error("Warning: Can't create thread to handle shutdown requests"); @@ -2182,6 +2178,14 @@ bool default_service_handling(char **argv, int main(int argc, char **argv) { + + /* When several instances are running on the same machine, we + need to have an unique named hEventShudown through the + application PID e.g.: MySQLShutdown1890; MySQLShutdown2342 + */ + int2str((int) GetCurrentProcessId(),strmov(shutdown_event_name, + "MySQLShutdown"), 10); + if (Service.GetOS()) /* true NT family */ { char file_path[FN_REFLEN]; @@ -2196,10 +2200,9 @@ int main(int argc, char **argv) if (Service.IsService(argv[1])) { /* start an optional service */ - event_name= argv[1]; - load_default_groups[0]= argv[1]; + load_default_groups[0]= argv[1]; start_mode= 1; - Service.Init(event_name, mysql_service); + Service.Init(argv[1], mysql_service); return 0; } } @@ -2218,9 +2221,8 @@ int main(int argc, char **argv) use_opt_args=1; opt_argc=argc; opt_argv=argv; - event_name= argv[2]; start_mode= 1; - Service.Init(event_name, mysql_service); + Service.Init(argv[2], mysql_service); return 0; } } @@ -2240,7 +2242,6 @@ int main(int argc, char **argv) { /* start the default service */ start_mode= 1; - event_name= "MySqlShutdown"; Service.Init(MYSQL_SERVICENAME, mysql_service); return 0; } From bbb0f7788457a43821e2ae29bbd1599ea044b9dc Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Nov 2002 18:05:41 +0200 Subject: [PATCH 10/46] fix for SHOW VARS for IA64 and other 64 bit systems --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9829f7f0b78..1d737f0bf62 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1145,7 +1145,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) switch (variables[i].type){ case SHOW_LONG: case SHOW_LONG_CONST: - net_store_data(&packet2,(uint32) *(ulong*) variables[i].value); + net_store_data(&packet2,(long long) *(ulong*) variables[i].value); break; case SHOW_BOOL: net_store_data(&packet2,(ulong) *(bool*) variables[i].value ? From fac5864d88bcc76cc26e2b81c6422e195f89b442 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Nov 2002 12:45:01 +0100 Subject: [PATCH 11/46] A better way to get the ChangeSet revision for the Subject: line. --- BitKeeper/triggers/post-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index 86a612acfcb..636e4262693 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -19,7 +19,7 @@ BK_STATUS=$BK_STATUS$BK_COMMIT if [ "$BK_STATUS" = OK ] then -CHANGESET=`bk changes -r+ | sed -n 's/^ChangeSet@\([^,][^,]*\),.*/\1/p'` +CHANGESET=`bk -R prs -r+ -h -d':I:' ChangeSet` #++ # dev-public@ From 7dc2b70f4960b201e0edfb8b92a565d71053acf4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Nov 2002 16:37:58 +0200 Subject: [PATCH 12/46] Better fix for 64 bit CPU .. --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1d737f0bf62..028d6b055ff 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1145,7 +1145,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) switch (variables[i].type){ case SHOW_LONG: case SHOW_LONG_CONST: - net_store_data(&packet2,(long long) *(ulong*) variables[i].value); + net_store_data(&packet2,(longlong) *(ulong*) variables[i].value); break; case SHOW_BOOL: net_store_data(&packet2,(ulong) *(bool*) variables[i].value ? From 5fe76b206987e5ebee3c13489d439855f290e4bc Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Nov 2002 20:01:17 +0500 Subject: [PATCH 13/46] Merge constraint tests with "ignoring constarint tests" for column,table and named constarints. Now constraint test produces exactly one line in report, with "yes","no" or syntax only". add /odbc to server-version if benchmark/crash-me works over odbc sql-bench/crash-me.sh: merge constraint tests with "ignoring constarint tests" for column,table and named constarints. Now constraint test produces exactly one line in report, with "yes","no" or syntax only". sql-bench/server-cfg.sh: add /odbc to server-version if benchmark/crash-me works over odbc --- sql-bench/crash-me.sh | 50 +++++++++++++++++++++++++---------------- sql-bench/server-cfg.sh | 40 +++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh index 5fa67773566..d9453948d1e 100644 --- a/sql-bench/crash-me.sh +++ b/sql-bench/crash-me.sh @@ -1,4 +1,3 @@ -#!@PERL@ # Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB # # This library is free software; you can redistribute it and/or @@ -1720,32 +1719,22 @@ if ($limits{'foreign_key'} eq 'yes') } } -report("Column constraints","constraint_check", - "create table crash_q (a int check (a>0))", - "drop table crash_q $drop_attr"); +check_constraint("Column constraints","constraint_check", + "create table crash_q (a int check (a>0))", + "insert into crash_q values(0)", + "drop table crash_q $drop_attr"); -report("Ignoring column constraints","ignoring_constraint_check", - "create table crash_q (a int check (a>0))", - "insert into crash_q values(0)", - "drop table crash_q $drop_attr") if ($limits{'constraint_check'} eq 'yes'); -report("Table constraints","constraint_check_table", - "create table crash_q (a int ,b int, check (a>b))", - "drop table crash_q $drop_attr"); - -report("Ignoring table constraints","ignoring_constraint_check_table", +check_constraint("Table constraints","constraint_check_table", "create table crash_q (a int ,b int, check (a>b))", "insert into crash_q values(0,0)", - "drop table crash_q $drop_attr") if ($limits{'constraint_check_table'} eq 'yes'); - -report("Named constraints","constraint_check_named", - "create table crash_q (a int ,b int, constraint abc check (a>b))", "drop table crash_q $drop_attr"); -report("Ignoring named constraints","ignoring_constraint_check_named", +check_constraint("Named constraints","constraint_check_named", "create table crash_q (a int ,b int, constraint abc check (a>b))", "insert into crash_q values(0,0)", - "drop table crash_q $drop_attr") if ($limits{'constraint_check_named'} eq 'yes'); + "drop table crash_q $drop_attr"); + report("NULL constraint (SyBase style)","constraint_null", "create table crash_q (a int null)", @@ -2236,6 +2225,29 @@ sub check_parenthesis { save_config_data($param_name,$resultat,$fn); } +sub check_constraint { + my $prompt = shift; + my $key = shift; + my $create = shift; + my $check = shift; + my $drop = shift; + save_incomplete($key,$prompt); + print "$prompt="; + my $res = 'no'; + + if ( ($t=safe_query($create)) == 1) + { + $res='yes'; + if (safe_query($check) == 1) + { + $res='syntax only'; + } + } + safe_query($drop); + save_config_data($key,$res,$prompt); + print "$res\n"; +} + sub usage { print <finish; $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -431,6 +432,8 @@ sub version { # Strip pre- and endspace $tmp=$1; $tmp =~ s/\s+/ /g; # Remove unnecessary spaces + $tmp .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); + return $tmp; } } @@ -619,6 +622,7 @@ sub new sub version { my ($version,$dir); + $version = "PostgreSQL version ???"; foreach $dir ($ENV{'PGDATA'},"/usr/local/pgsql/data", "/usr/local/pg/data") { if ($dir && -e "$dir/PG_VERSION") @@ -627,11 +631,13 @@ sub version if ($? == 0) { chomp($version); + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return "PostgreSQL $version"; } } } - return "PostgreSQL version ???"; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); + return $version; } @@ -895,6 +901,7 @@ sub new sub version { my ($version,$dir); + $version="Solid version ??"; foreach $dir ($ENV{'SOLIDDIR'},"/usr/local/solid", "/my/local/solid") { if ($dir && -e "$dir/bin/solcon") @@ -903,11 +910,13 @@ sub version if ($? == 0) { chomp($version); + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } } } - return "Solid version ???"; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); + return $version; } sub connect @@ -1136,6 +1145,8 @@ sub version { $version="Empress version ???"; } + + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -1403,6 +1414,7 @@ sub version } $sth->finish; $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -1647,6 +1659,7 @@ sub version } $sth->finish; $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -1846,7 +1859,9 @@ sub new sub version { my ($self)=@_; - return "Access 2000"; #DBI/ODBC can't return the server version + my $version="Access 2000"; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); + return $version; #DBI/ODBC can't return the server version } sub connect @@ -2028,7 +2043,8 @@ sub new sub version { my ($self)=@_; - my($sth,@row); + my($sth,@row, $version); + $version='MS SQL server ?'; $dbh=$self->connect(); $sth = $dbh->prepare("SELECT \@\@VERSION") or die $DBI::errstr; $sth->execute or die $DBI::errstr; @@ -2036,10 +2052,11 @@ sub version if ($row[0]) { @server = split(/\n/,$row[0]); chomp(@server); - return "$server[0]"; - } else { - return "Microsoft SQL server ?"; - } + $version= "$server[0]"; + } + $sth->finish; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); + return $version; } sub connect @@ -2232,8 +2249,8 @@ sub version } $sth->finish; $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; - } sub connect @@ -2466,6 +2483,7 @@ sub version } $sth->finish; $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -2842,6 +2860,7 @@ sub version # $version = $dbh->func(18, GetInfo); $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -3041,6 +3060,7 @@ sub version # $version =~ s/.*version \"(.*)\"$/$1/; $dbh->disconnect; $version = "6.0Beta"; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -3246,6 +3266,7 @@ sub version #$version = $dbh->func(18, GetInfo); $version="FrontBase 3.3"; # $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } @@ -3453,6 +3474,7 @@ sub version } $sth->finish; $dbh->disconnect; + $version .= "/ODBC" if ($self->{'data_source'} =~ /:ODBC:/); return $version; } From 1e68711a02cbaae9c2ae49597b3967ad8f8fea06 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Nov 2002 18:57:56 +0100 Subject: [PATCH 14/46] Added 29 {} at the end of clauses in sql_yacc.yy to make it work with bison 1.75. sql/sql_yacc.yy: Added 29 {} at the end of clauses to make it work with bison 1.75. Otherwise we get errors of the type "sql_yacc.yy:666.7-672.21: type clash (`NONE' `') on default action". --- sql/sql_yacc.yy | 91 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c3c6d8ad66b..6c3152858ed 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -669,7 +669,10 @@ change: LEX *lex = Lex; lex->sql_command = SQLCOM_CHANGE_MASTER; bzero((char*) &lex->mi, sizeof(lex->mi)); - } master_defs; + } + master_defs + {} + ; master_defs: master_def @@ -742,7 +745,7 @@ create: lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type; } create2 - + {} | CREATE opt_unique_or_fulltext INDEX ident ON table_ident { LEX *lex=Lex; @@ -1181,7 +1184,9 @@ alter: lex->alter_keys_onoff=LEAVE_AS_IS; lex->simple_alter=1; } - alter_list; + alter_list + {} + ; alter_list: | alter_list_item @@ -1352,7 +1357,9 @@ repair: lex->sql_command = SQLCOM_REPAIR; lex->check_opt.init(); } - table_list opt_mi_repair_type; + table_list opt_mi_repair_type + {} + ; opt_mi_repair_type: /* empty */ { Lex->check_opt.flags = T_MEDIUM; } @@ -1374,7 +1381,9 @@ analyze: lex->sql_command = SQLCOM_ANALYZE; lex->check_opt.init(); } - table_list opt_mi_check_type; + table_list opt_mi_check_type + {} + ; check: CHECK_SYM table_or_tables @@ -1383,7 +1392,9 @@ check: lex->sql_command = SQLCOM_CHECK; lex->check_opt.init(); } - table_list opt_mi_check_type; + table_list opt_mi_check_type + {} + ; opt_mi_check_type: /* empty */ { Lex->check_opt.flags = T_MEDIUM; } @@ -1407,14 +1418,18 @@ optimize: lex->sql_command = SQLCOM_OPTIMIZE; lex->check_opt.init(); } - table_list opt_mi_check_type; + table_list opt_mi_check_type + {} + ; rename: RENAME table_or_tables { Lex->sql_command=SQLCOM_RENAME_TABLE; } - table_to_table_list; + table_to_table_list + {} + ; table_to_table_list: table_to_table @@ -2297,6 +2312,7 @@ limit_clause: } } limit_options + {} ; limit_options: @@ -2398,7 +2414,10 @@ do: DO_SYM if (!(lex->insert_list = new List_item)) YYABORT; } - values; + values + {} + ; + /* Drop : delete tables or index */ @@ -2464,6 +2483,7 @@ insert: set_lock_for_tables($3); } insert_field_spec + {} ; replace: @@ -2478,6 +2498,7 @@ replace: set_lock_for_tables($3); } insert_field_spec + {} ; insert_lock_option: @@ -2655,13 +2676,15 @@ single_multi: YYABORT; } where_clause opt_order_clause - delete_limit_clause + delete_limit_clause {} | table_wild_list { mysql_init_multi_delete(Lex); } FROM join_table_list where_clause | FROM table_wild_list { mysql_init_multi_delete(Lex); } - USING join_table_list where_clause; + USING join_table_list where_clause + {} + ; table_wild_list: table_wild_one {} @@ -2713,7 +2736,9 @@ opt_table_sym: /* Show things */ -show: SHOW { Lex->wild=0;} show_param; +show: SHOW { Lex->wild=0;} show_param + {} + ; show_param: DATABASES wild @@ -2851,7 +2876,7 @@ describe: if (!add_table_to_list($2, NULL,0)) YYABORT; } - opt_describe_column + opt_describe_column {} | describe_command select { Lex->select_lex.options|= SELECT_DESCRIBE; }; @@ -2875,14 +2900,16 @@ flush: LEX *lex=Lex; lex->sql_command= SQLCOM_FLUSH; lex->type=0; } - flush_options; + flush_options + {} + ; flush_options: flush_options ',' flush_option | flush_option; flush_option: - table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list + table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list {} | TABLES WITH READ_SYM LOCK_SYM { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; } | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE_FREE; } | HOSTS_SYM { Lex->type|= REFRESH_HOSTS; } @@ -2903,7 +2930,10 @@ reset: { LEX *lex=Lex; lex->sql_command= SQLCOM_RESET; lex->type=0; - } reset_options; + } reset_options + {} + ; + reset_options: reset_options ',' reset_option | reset_option; @@ -3309,7 +3339,9 @@ set: lex->option_type=OPT_DEFAULT; lex->var_list.empty(); } - option_value_list; + option_value_list + {} + ; opt_option: /* empty */ {} @@ -3432,7 +3464,9 @@ lock: { Lex->sql_command=SQLCOM_LOCK_TABLES; } - table_lock_list; + table_lock_list + {} + ; table_or_tables: TABLE_SYM @@ -3529,7 +3563,9 @@ revoke: lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero((char*) &lex->mqh, sizeof(lex->mqh)); } - grant_privileges ON opt_table FROM user_list; + grant_privileges ON opt_table FROM user_list + {} + ; grant: GRANT @@ -3545,7 +3581,9 @@ grant: bzero(&(lex->mqh),sizeof(lex->mqh)); } grant_privileges ON opt_table TO_SYM user_list - require_clause grant_options; + require_clause grant_options + {} + ; grant_privileges: grant_privilege_list {} @@ -3557,10 +3595,10 @@ grant_privilege_list: | grant_privilege_list ',' grant_privilege; grant_privilege: - SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list - | INSERT { Lex->which_columns = INSERT_ACL;} opt_column_list - | UPDATE_SYM { Lex->which_columns = UPDATE_ACL; } opt_column_list - | REFERENCES { Lex->which_columns = REFERENCES_ACL;} opt_column_list + SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {} + | INSERT { Lex->which_columns = INSERT_ACL;} opt_column_list {} + | UPDATE_SYM { Lex->which_columns = UPDATE_ACL; } opt_column_list {} + | REFERENCES { Lex->which_columns = REFERENCES_ACL;} opt_column_list {} | DELETE_SYM { Lex->grant |= DELETE_ACL;} | USAGE {} | INDEX { Lex->grant |= INDEX_ACL;} @@ -3781,7 +3819,8 @@ grant_option: }; begin: - BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work; + BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work {} + ; opt_work: /* empty */ {} @@ -3822,7 +3861,7 @@ union_list: YYABORT; lex->select->linkage=UNION_TYPE; } - select_init + select_init {} ; union_opt: From 522d022e1de97eebd97dcfcc0370e6116b9feb15 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Nov 2002 19:38:01 +0100 Subject: [PATCH 15/46] chroot() need chdir("/") afterwards to work --- sql/mysqld.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 71b832f24f4..73c44b49709 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -886,6 +886,7 @@ static void set_root(const char *path) sql_perror("chroot"); unireg_abort(1); } + my_setwd("/", MYF(0)); #endif } From 7989f285aaec4fb4e7ad1ea47bee61b5519ee9e9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Nov 2002 13:05:37 +0200 Subject: [PATCH 16/46] ha_innodb.cc: Make copies of all string-type start/up options in case C-sharp moves them around; remove the need to specify innodb_log_arch_dir in my.cnf, since it has no relevance anyway sql/ha_innodb.cc: Make copies of all string-type start/up options in case C-sharp moves them around; remove the need to specify innodb_log_arch_dir in my.cnf, since it has no relevance anyway --- sql/ha_innodb.cc | 138 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 42 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 95bf8e8eb75..343b8477d38 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -90,10 +90,11 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group, are determined in innobase_init below: */ char* innobase_data_home_dir = NULL; +char* innobase_data_file_path = NULL; char* innobase_log_group_home_dir = NULL; char* innobase_log_arch_dir = NULL; -/* The following has a midleading name: starting from 4.0.5 this also -affects Windows */ +/* The following has a misleading name: starting from 4.0.5, this also +affects Windows: */ char* innobase_unix_file_flush_method = NULL; /* Below we have boolean-valued start-up parameters, and their default @@ -104,14 +105,7 @@ my_bool innobase_log_archive = FALSE; my_bool innobase_use_native_aio = FALSE; my_bool innobase_fast_shutdown = TRUE; -/* - Set default InnoDB data file size to 10 MB and let it be - auto-extending. Thus users can use InnoDB without having to - specify any startup options. -*/ - -char *innobase_data_file_path= (char*) "ibdata1:10M:autoextend"; -static char *internal_innobase_data_file_path=0; +static char *internal_innobase_data_file_path = NULL; /* The following counter is used to convey information to InnoDB about server activity: in selects it is not sensible to call @@ -650,46 +644,89 @@ innobase_init(void) DBUG_ENTER("innobase_init"); - os_innodb_umask = (ulint)my_umask; + os_innodb_umask = (ulint)my_umask; - /* - When using the embedded server, the datadirectory is not - in the current directory. - */ - if (mysql_embedded) - default_path=mysql_real_data_home; - else - { - /* It's better to use current lib, to keep path's short */ - current_dir[0] = FN_CURLIB; - current_dir[1] = FN_LIBCHAR; - current_dir[2] = 0; - default_path=current_dir; + /* First calculate the default path for innodb_data_home_dir etc., + in case the user has not given any value. + + Note that when using the embedded server, the datadirectory is not + necessarily the current directory of this program. */ + + if (mysql_embedded) { + default_path = mysql_real_data_home; + } else { + /* It's better to use current lib, to keep paths short */ + current_dir[0] = FN_CURLIB; + current_dir[1] = FN_LIBCHAR; + current_dir[2] = 0; + default_path = current_dir; } + ut_a(default_path); + if (specialflag & SPECIAL_NO_PRIOR) { srv_set_thread_priorities = FALSE; } else { srv_set_thread_priorities = TRUE; srv_query_thread_priority = QUERY_PRIOR; } + + /* Set InnoDB initialization parameters according to the values + read from MySQL .cnf file */ - /* - Set InnoDB initialization parameters according to the values - read from MySQL .cnf file - */ + /* --------------------------------------------------*/ + /* Make copies of all string-valued parameters, because after + C# calls server_init(), it may move the parameter strings around */ - // Make a copy of innobase_data_file_path to not modify the original - internal_innobase_data_file_path=my_strdup(innobase_data_file_path, - MYF(MY_WME)); + if (innobase_data_home_dir) { + innobase_data_home_dir = my_strdup( + innobase_data_home_dir, + MYF(MY_WME)); + } + if (innobase_data_file_path) { + innobase_data_file_path = my_strdup( + innobase_data_file_path, + MYF(MY_WME)); + } + if (innobase_log_group_home_dir) { + innobase_log_group_home_dir = my_strdup( + innobase_log_group_home_dir, + MYF(MY_WME)); + } + if (innobase_log_arch_dir) { + innobase_log_arch_dir = my_strdup( + innobase_log_arch_dir, + MYF(MY_WME)); + } + if (innobase_unix_file_flush_method) { + innobase_unix_file_flush_method = my_strdup( + innobase_unix_file_flush_method, + MYF(MY_WME)); + } + + /*--------------- Data files -------------------------*/ + + /* The default dir for data files is the datadir of MySQL */ srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir : default_path); - srv_arch_dir = (innobase_log_arch_dir ? innobase_log_arch_dir : - default_path); - ret = (bool) - srv_parse_data_file_paths_and_sizes(internal_innobase_data_file_path, + /* Set default InnoDB data file size to 10 MB and let it be + auto-extending. Thus users can use InnoDB in >= 4.0 without having + to specify any startup options. */ + + if (!innobase_data_file_path) { + innobase_data_file_path = (char*) "ibdata1:10M:autoextend"; + } + + /* Since InnoDB edits the argument in the next call, we make another + copy of it: */ + + internal_innobase_data_file_path = my_strdup(innobase_data_file_path, + MYF(MY_WME)); + + ret = (bool) srv_parse_data_file_paths_and_sizes( + internal_innobase_data_file_path, &srv_data_file_names, &srv_data_file_sizes, &srv_data_file_is_raw_partition, @@ -697,12 +734,26 @@ innobase_init(void) &srv_auto_extend_last_data_file, &srv_last_file_size_max); if (ret == FALSE) { - sql_print_error("InnoDB: syntax error in innodb_data_file_path"); - DBUG_RETURN(TRUE); + sql_print_error( + "InnoDB: syntax error in innodb_data_file_path"); + DBUG_RETURN(TRUE); } - if (!innobase_log_group_home_dir) - innobase_log_group_home_dir= default_path; + /* -------------- Log files ---------------------------*/ + + /* The default dir for log files is the datadir of MySQL */ + + if (!innobase_log_group_home_dir) { + innobase_log_group_home_dir = default_path; + } + + /* Since innodb_log_arch_dir has no relevance under MySQL, + starting from 4.0.6 we always set it the same as + innodb_log_group_home_dir: */ + + innobase_log_arch_dir = innobase_log_group_home_dir; + + srv_arch_dir = innobase_log_arch_dir; ret = (bool) srv_parse_log_group_home_dirs(innobase_log_group_home_dir, @@ -716,9 +767,9 @@ innobase_init(void) DBUG_RETURN(TRUE); } - srv_file_flush_method_str = (innobase_unix_file_flush_method ? - innobase_unix_file_flush_method : - NULL); + /* --------------------------------------------------*/ + + srv_file_flush_method_str = innobase_unix_file_flush_method; srv_n_log_groups = (ulint) innobase_mirrored_log_groups; srv_n_log_files = (ulint) innobase_log_files_in_group; @@ -741,7 +792,9 @@ innobase_init(void) srv_fast_shutdown = (ibool) innobase_fast_shutdown; srv_print_verbose_log = mysql_embedded ? 0 : 1; + if (strcmp(default_charset_info->name, "latin1") == 0) { + /* Store the character ordering table to InnoDB. For non-latin1 charsets we use the MySQL comparison functions, and consequently we do not need to know @@ -4177,3 +4230,4 @@ ha_innobase::get_auto_increment() } #endif /* HAVE_INNOBASE_DB */ + From 469e0b321c15de7290d17de937da2ac04924d347 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Nov 2002 18:07:02 +0500 Subject: [PATCH 17/46] improvement crash-me BitKeeper/etc/ignore: Added core.2430 to the ignore list sql-bench/crash-me.sh: 1) restore #!@PERL@ that I (accidentally) deleted last time 2) comment order_by_remember_desc section 3) rectify WEEK test. Now it returns "EURO" ,"USA", "error" (if it returns wrong week number), or "no" (if this function isn't supported) 4) merge 2 tests for noround() (func_extra_noround and ignoring_noround). Now it returns yes/no/"syntax only" 5) merge 2 tests for foreign key (foreign_key and foreign_key_syntax). Now it returns yes/no/"syntax only" 6) correct misprint in crash-me help ( --db-start-cmd instead of --start-cmd) sql-bench/server-cfg.sh: Misprint correction (db_Sapdb ->db_sapdb) --- .bzrignore | 1 + sql-bench/crash-me.sh | 125 ++++++++++++++++++++++++++++------------ sql-bench/server-cfg.sh | 2 +- 3 files changed, 91 insertions(+), 37 deletions(-) diff --git a/.bzrignore b/.bzrignore index 5d8375d2877..0996f3b057b 100644 --- a/.bzrignore +++ b/.bzrignore @@ -521,3 +521,4 @@ innobase/autom4te-2.53.cache/output.0 innobase/autom4te-2.53.cache/requests innobase/autom4te-2.53.cache/traces.0 pull.log +core.2430 diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh index d9453948d1e..6c3ee9bd0dc 100644 --- a/sql-bench/crash-me.sh +++ b/sql-bench/crash-me.sh @@ -1,3 +1,4 @@ +#!@PERL@ # Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB # # This library is free software; you can redistribute it and/or @@ -279,13 +280,14 @@ report("Order by function","order_by_function", "select a from crash_me order by a+1"); report("Order by on unused column",'order_on_unused', "select b from crash_me order by a"); -check_and_report("Order by DESC is remembered",'order_by_remember_desc', - ["create table crash_q (s int,s1 int)", - "insert into crash_q values(1,1)", - "insert into crash_q values(3,1)", - "insert into crash_q values(2,1)"], - "select s,s1 from crash_q order by s1 DESC,s", - ["drop table crash_q $drop_attr"],[3,2,1],7,undef(),3); +# little bit deprecated +#check_and_report("Order by DESC is remembered",'order_by_remember_desc', +# ["create table crash_q (s int,s1 int)", +# "insert into crash_q values(1,1)", +# "insert into crash_q values(3,1)", +# "insert into crash_q values(2,1)"], +# "select s,s1 from crash_q order by s1 DESC,s", +# ["drop table crash_q $drop_attr"],[3,2,1],7,undef(),3); report("Compute",'compute', "select a from crash_me order by a compute sum(a) by a"); report("INSERT with Value lists",'insert_multi_value', @@ -843,7 +845,6 @@ try_and_report("Automatic row id", "automatic_rowid", ["DAYOFWEEK","dayofweek","dayofweek(DATE '1997-02-01')",7,0], ["DAYOFYEAR","dayofyear","dayofyear(DATE '1997-02-01')",32,0], ["QUARTER","quarter","quarter(DATE '1997-02-01')",1,0], - ["WEEK","week","week(DATE '1997-02-01')",5,0], ["YEAR","year","year(DATE '1997-02-01')",1997,0], ["CURTIME","curtime","curtime()",0,2], ["HOUR","hour","hour('12:13:14')",12,0], @@ -979,7 +980,6 @@ try_and_report("Automatic row id", "automatic_rowid", ["ASCII in string cast",'ascii_string',"ascii('a')",'a',1], ["EBCDIC in string cast",'ebcdic_string',"ebcdic('a')",'a',1], ["TRUNC (1 arg)",'trunc1arg',"trunc(222.6)",222,0], - ["NOROUND",'noround',"noround(222.6)",222.6,0], ["FIXED",'fixed',"fixed(222.6666,10,2)",'222.67',0], ["FLOAT",'float',"float(6666.66,4)",6667,0], ["LENGTH",'length',"length(1)",2,0], @@ -1186,12 +1186,31 @@ else } -if ($limits{'func_extra_noround'} eq 'yes') +# Test: NOROUND { - report("Ignoring NOROUND","ignoring_noround", - "create table crash_q (a int)", - "insert into crash_q values(noround(10.22))", - "drop table crash_q $drop_attr"); + my $resultat = 'undefined'; + my $error; + print "NOROUND: "; + save_incomplete('func_extra_noround','Function NOROUND'); + +# 1) check if noround() function is supported + $error = safe_query("select noround(22.6) $end_query"); + if ($error ne 1) # syntax error -- noround is not supported + { + $resultat = 'no' + } else # Ok, now check if it really works + { + $error=safe_query( "create table crash_me_nr (a int)", + "insert into crash_me_nr values(noround(10.2))", + "drop table crash_me_nr $drop_attr"); + if ($error eq 1) { + $resultat = "syntax only"; + } else { + $resultat = 'yes'; + } + } + print "$resultat\n"; + save_config_data('func_extra_noround',$resultat,"Function NOROUND"); } check_parenthesis("func_sql_","CURRENT_USER"); @@ -1199,6 +1218,32 @@ check_parenthesis("func_sql_","SESSION_USER"); check_parenthesis("func_sql_","SYSTEM_USER"); check_parenthesis("func_sql_","USER"); +# Test: WEEK() +{ + my $explain=""; + my $resultat="no"; + my $error; + print "WEEK:"; + save_incomplete('func_odbc_week','WEEK'); + $error = safe_query_result("select week(DATE '1997-02-01') $end_query",5,0); + # actually this query must return 4 or 5 in the $last_result, + # $error can be 1 (not supported at all) , -1 ( probably USA weeks) + # and 0 - EURO weeks + if ($error == -1) { + if ($last_result == 4) { + $resultat = 'USA'; + $explain = ' started from Sunday'; + } else { + $resultat='error'; + $explain = " must return 4 or 5, but $last_error"; + } + } elsif ($error == 0) { + $resultat = 'EURO'; + $explain = ' started from Monday'; + } + print " $resultat\n"; + save_config_data('func_odbc_week',$resultat,"WEEK $explain"); +} report("LIKE on numbers","like_with_number", "create table crash_q (a int,b int)", @@ -1681,28 +1726,36 @@ report("views","views", "create view crash_q as select a from crash_me", "drop view crash_q $drop_attr"); -report("foreign key syntax","foreign_key_syntax", - create_table("crash_q",["a integer not null"],["primary key (a)"]), - create_table("crash_q2",["a integer not null", - "foreign key (a) references crash_q (a)"], - []), - "insert into crash_q values (1)", - "insert into crash_q2 values (1)", - "drop table crash_q2 $drop_attr", - "drop table crash_q $drop_attr"); - -if ($limits{'foreign_key_syntax'} eq 'yes') +# Test: foreign key { - report_fail("foreign keys","foreign_key", - create_table("crash_q",["a integer not null"], - ["primary key (a)"]), - create_table("crash_q2",["a integer not null", - "foreign key (a) references crash_q (a)"], - []), - "insert into crash_q values (1)", - "insert into crash_q2 values (2)", - "drop table crash_q2 $drop_attr", - "drop table crash_q $drop_attr"); + my $resultat = 'undefined'; + my $error; + print "foreign keys: "; + save_incomplete('foreign_key','foreign keys'); + +# 1) check if foreign keys are supported + safe_query(create_table("crash_me_qf",["a integer not null"], + ["primary key (a)"])); + $error = safe_query( create_table("crash_me_qf2",["a integer not null", + "foreign key (a) references crash_me_qf (a)"], [])); + + if ($error eq 1) # OK -- syntax is supported + { + $resultat = 'error'; + # now check if foreign key really works + safe_query( "insert into crash_me_qf values (1)"); + if (safe_query( "insert into crash_me_qf2 values (2)") eq 1) { + $resultat = 'syntax only'; + } else { + $resultat = 'yes'; + } + + } else { + $resultat = "no"; + } + safe_query( "drop table crash_me_qf2 $drop_attr","drop table crash_me_qf $drop_attr"); + print "$resultat\n"; + save_config_data('foreign_key',$resultat,"foreign keys"); } report("Create SCHEMA","create_schema", @@ -2329,7 +2382,7 @@ $0 takes the following options: --user='user_name' User name to log into the SQL server. ---start-cmd='command to restart server' +--db-start-cmd='command to restart server' Automaticly restarts server with this command if the database server dies. --sleep='time in seconds' (Default $opt_sleep) diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh index 91a40d92772..488bd788056 100644 --- a/sql-bench/server-cfg.sh +++ b/sql-bench/server-cfg.sh @@ -3386,7 +3386,7 @@ sub fix_for_insert # Configuration for SAPDB ############################################################################# -package db_Sapdb; +package db_sapdb; sub new { From 4653621909f900200c1e3238a4f5d2f58f6edf29 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Nov 2002 16:40:18 +0200 Subject: [PATCH 18/46] New multi-table-update code New (simpler) internal timestamp handling. More debuging to heap tables. Small cleanups to multi-table-delete false -> 0 and true -> 1 (We should use TRUE and FALSE) heap/_check.c: Added checking of rows heap/hp_delete.c: Extra debugging heap/hp_scan.c: Extra debugging heap/hp_update.c: Extra debugging heap/hp_write.c: Extra debugging include/my_base.h: Added option to disable row cache when using updates isam/extra.c: Added option to disable row cache when using updates myisam/mi_check.c: Comment cleanup myisam/mi_extra.c: Added option to disable row cache when using updates myisam/sort.c: Indentaion cleanups myisammrg/myrg_extra.c: Added option to disable row cache when using updates mysql-test/r/multi_update.result: Updated results mysql-test/t/multi_update.test: Cleanup up to only use table names t1, t2,... mysys/mf_iocache.c: Safety fix sql/item_cmpfunc.cc: change true-> 1 and false -> 0 sql/mysql_priv.h: Cleaned up SQL_LIST handling sql/sql_base.cc: Fixed grant checking if SELECT tablename.* sql/sql_class.h: Cleaned up multi-table-update sql/sql_delete.cc: Fixed OPTION_SAFE_UPDATE checking in multi-table-delete. Fixed query-cache invalidation in multi-table-delete sql/sql_insert.cc: cleaned up timestamp handling sql/sql_olap.cc: false -> 0 sql/sql_parse.cc: Optimized some list handling. Moved multi-table-update to sql_update.cc sql/sql_select.cc: More comments Fixed create_tmp_table for multi-table-update sql/sql_select.h: New prototypes sql/sql_union.cc: false -> 0 Cleaned up timestamp handling sql/sql_update.cc: New multi-update-table code sql/sql_yacc.yy: false -> 0, true -> 1 Optimized some list handling sql/table.h: Added union for temporary values. Made shared int to be able to store counters. sql/uniques.cc: Indentation cleanup --- heap/_check.c | 57 ++- heap/hp_delete.c | 4 + heap/hp_scan.c | 1 + heap/hp_update.c | 4 + heap/hp_write.c | 5 + include/my_base.h | 3 +- isam/extra.c | 6 + myisam/mi_check.c | 12 +- myisam/mi_extra.c | 4 + myisam/sort.c | 22 +- myisammrg/myrg_extra.c | 3 +- mysql-test/r/multi_update.result | 48 +- mysql-test/t/multi_update.test | 50 +- mysys/mf_iocache.c | 2 + sql/item_cmpfunc.cc | 8 +- sql/mysql_priv.h | 20 +- sql/sql_base.cc | 17 +- sql/sql_class.h | 63 ++- sql/sql_delete.cc | 67 ++- sql/sql_insert.cc | 24 +- sql/sql_olap.cc | 4 +- sql/sql_parse.cc | 79 +--- sql/sql_select.cc | 85 +++- sql/sql_select.h | 1 + sql/sql_union.cc | 19 +- sql/sql_update.cc | 774 ++++++++++++++++--------------- sql/sql_yacc.yy | 11 +- sql/table.h | 16 +- sql/uniques.cc | 3 +- 29 files changed, 776 insertions(+), 636 deletions(-) diff --git a/heap/_check.c b/heap/_check.c index 03fb664cba9..6cc19aba137 100644 --- a/heap/_check.c +++ b/heap/_check.c @@ -21,19 +21,70 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records, ulong blength, my_bool print_status); -/* Returns 0 if the HEAP is ok */ +/* + Check if keys and rows are ok in a heap table + + SYNOPSIS + heap_check_heap() + info Table handler + print_status Prints some extra status + + NOTES + Doesn't change the state of the table handler + + RETURN VALUES + 0 ok + 1 error +*/ int heap_check_heap(HP_INFO *info,my_bool print_status) { int error; uint key; + ulong records=0, deleted=0, pos, next_block; HP_SHARE *share=info->s; - DBUG_ENTER("heap_check_keys"); + HP_INFO save_info= *info; /* Needed because scan_init */ + DBUG_ENTER("heap_check_heap"); - for (error=key=0 ; key < share->keys ; key++) + for (error=key= 0 ; key < share->keys ; key++) error|=check_one_key(share->keydef+key,key, share->records,share->blength, print_status); + /* + This is basicly the same code as in hp_scan, but we repeat it here to + get shorter DBUG log file. + */ + for (pos=next_block= 0 ; ; pos++) + { + if (pos < next_block) + { + info->current_ptr+= share->block.recbuffer; + } + else + { + next_block+= share->block.records_in_block; + if (next_block >= share->records+share->deleted) + { + next_block= share->records+share->deleted; + if (pos >= next_block) + break; /* End of file */ + } + } + _hp_find_record(info,pos); + + if (!info->current_ptr[share->reclength]) + deleted++; + else + records++; + } + + if (records != share->records || deleted != share->deleted) + { + DBUG_PRINT("error",("Found rows: %lu (%lu) deleted %lu (%lu)", + records, share->records, deleted, share->deleted)); + error= 1; + } + *info= save_info; DBUG_RETURN(error); } diff --git a/heap/hp_delete.c b/heap/hp_delete.c index 3ac321d5fa2..6ed6a045543 100644 --- a/heap/hp_delete.c +++ b/heap/hp_delete.c @@ -48,6 +48,10 @@ int heap_delete(HP_INFO *info, const byte *record) pos[share->reclength]=0; /* Record deleted */ share->deleted++; info->current_hash_ptr=0; +#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG) + DBUG_EXECUTE("check_heap",heap_check_heap(info, 0);); +#endif + DBUG_RETURN(0); err: if (++(share->records) == share->blength) diff --git a/heap/hp_scan.c b/heap/hp_scan.c index e74f8b43ba7..0bbe40ba773 100644 --- a/heap/hp_scan.c +++ b/heap/hp_scan.c @@ -62,6 +62,7 @@ int heap_scan(register HP_INFO *info, byte *record) } if (!info->current_ptr[share->reclength]) { + DBUG_PRINT("warning",("Found deleted record")); info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND; DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); } diff --git a/heap/hp_update.c b/heap/hp_update.c index 8cf3e4d4b8d..b0a1926e14a 100644 --- a/heap/hp_update.c +++ b/heap/hp_update.c @@ -46,6 +46,10 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new) memcpy(pos,heap_new,(size_t) share->reclength); if (++(share->records) == share->blength) share->blength+= share->blength; + +#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG) + DBUG_EXECUTE("check_heap",heap_check_heap(info, 0);); +#endif DBUG_RETURN(0); err: diff --git a/heap/hp_write.c b/heap/hp_write.c index 806f40e5be5..18fa95e7760 100644 --- a/heap/hp_write.c +++ b/heap/hp_write.c @@ -60,7 +60,11 @@ int heap_write(HP_INFO *info, const byte *record) info->current_ptr=pos; info->current_hash_ptr=0; info->update|=HA_STATE_AKTIV; +#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG) + DBUG_EXECUTE("check_heap",heap_check_heap(info, 0);); +#endif DBUG_RETURN(0); + err: DBUG_PRINT("info",("Duplicate key: %d",key)); info->errkey= key; @@ -74,6 +78,7 @@ err: *((byte**) pos)=share->del_link; share->del_link=pos; pos[share->reclength]=0; /* Record deleted */ + DBUG_RETURN(my_errno); } /* heap_write */ diff --git a/include/my_base.h b/include/my_base.h index 2450ab33425..8ef8301b84d 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -109,7 +109,8 @@ enum ha_extra_function { HA_EXTRA_BULK_INSERT_BEGIN, HA_EXTRA_BULK_INSERT_FLUSH, /* Flush one index */ HA_EXTRA_BULK_INSERT_END, - HA_EXTRA_PREPARE_FOR_DELETE + HA_EXTRA_PREPARE_FOR_DELETE, + HA_EXTRA_PREPARE_FOR_UPDATE /* Remove read cache if problems */ }; /* The following is parameter to ha_panic() */ diff --git a/isam/extra.c b/isam/extra.c index 570c396955f..e2f13532ddf 100644 --- a/isam/extra.c +++ b/isam/extra.c @@ -123,6 +123,7 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) } #endif if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))) + { if (!(init_io_cache(&info->rec_cache,info->dfile,0, WRITE_CACHE,info->s->state.data_file_length, (pbool) (info->lock_type != F_UNLCK), @@ -131,7 +132,12 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) info->opt_flag|=WRITE_CACHE_USED; info->update&= ~HA_STATE_ROW_CHANGED; } + } break; + case HA_EXTRA_PREPARE_FOR_UPDATE: + if (info->s->data_file_type != DYNAMIC_RECORD) + break; + /* Remove read/write cache if dynamic rows */ case HA_EXTRA_NO_CACHE: if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 9e591325c1c..b984f0e6ee6 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -2329,13 +2329,13 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, for (i=0 ; i < sort_info.total_keys ; i++) { sort_param[i].read_cache=param->read_cache; + /* + two approaches: the same amount of memory for each thread + or the memory for the same number of keys for each thread... + In the second one all the threads will fill their sort_buffers + (and call write_keys) at the same time, putting more stress on i/o. + */ sort_param[i].sortbuff_size= - /* - two approaches: the same amount of memory for each thread - or the memory for the same number of keys for each thread... - In the second one all the threads will fill their sort_buffers - (and call write_keys) at the same time, putting more stress on i/o. - */ #ifndef USING_SECOND_APPROACH param->sort_buffer_length/sort_info.total_keys; #else diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 39eb4b0bd99..d7a3aea516d 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -165,6 +165,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) HA_STATE_EXTEND_BLOCK); } break; + case HA_EXTRA_PREPARE_FOR_UPDATE: + if (info->s->data_file_type != DYNAMIC_RECORD) + break; + /* Remove read/write cache if dynamic rows */ case HA_EXTRA_NO_CACHE: if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { diff --git a/myisam/sort.c b/myisam/sort.c index fd5622e1340..f45ecbaf3a1 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -344,7 +344,6 @@ pthread_handler_decl(thr_find_all_keys,arg) mi_check_print_error(info->sort_info->param,"Sort buffer to small"); /* purecov: tested */ goto err; /* purecov: tested */ } -// (*info->lock_in_memory)(info->sort_info->param);/* Everything is allocated */ if (info->sort_info->param->testflag & T_VERBOSE) printf("Key %d - Allocating buffer for %d keys\n",info->key+1,keys); @@ -424,9 +423,9 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) byte *mergebuf=0; LINT_INIT(length); - for (i=0, sinfo=sort_param ; itotal_keys ; i++, - rec_per_key_part+=sinfo->keyinfo->keysegs, - sinfo++) + for (i= 0, sinfo= sort_param ; + i < sort_info->total_keys ; + i++, rec_per_key_part+=sinfo->keyinfo->keysegs, sinfo++) { if (!sinfo->sort_keys) { @@ -452,15 +451,18 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) } } my_free((gptr) sinfo->sort_keys,MYF(0)); - my_free(mi_get_rec_buff_ptr(info, sinfo->rec_buff), MYF(MY_ALLOW_ZERO_PTR)); + my_free(mi_get_rec_buff_ptr(info, sinfo->rec_buff), + MYF(MY_ALLOW_ZERO_PTR)); sinfo->sort_keys=0; } - for (i=0, sinfo=sort_param ; itotal_keys ; i++, - delete_dynamic(&sinfo->buffpek), - close_cached_file(&sinfo->tempfile), - close_cached_file(&sinfo->tempfile_for_exceptions), - sinfo++) + for (i= 0, sinfo= sort_param ; + i < sort_info->total_keys ; + i++, + delete_dynamic(&sinfo->buffpek), + close_cached_file(&sinfo->tempfile), + close_cached_file(&sinfo->tempfile_for_exceptions), + sinfo++) { if (got_error) continue; diff --git a/myisammrg/myrg_extra.c b/myisammrg/myrg_extra.c index ad17b0f82f2..d375b45df99 100644 --- a/myisammrg/myrg_extra.c +++ b/myisammrg/myrg_extra.c @@ -38,7 +38,8 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function, } else { - if (function == HA_EXTRA_NO_CACHE || function == HA_EXTRA_RESET) + if (function == HA_EXTRA_NO_CACHE || function == HA_EXTRA_RESET || + function == HA_EXTRA_PREPARE_FOR_UPDATE) info->cache_in_use=0; if (function == HA_EXTRA_RESET || function == HA_EXTRA_RESET_STATE) { diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index ce3f7e90f6b..20921816f1e 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -20,7 +20,7 @@ count(*) 10 select count(*) from t2 where t = "bbb"; count(*) -10 +50 select count(*) from t2 where id2 > 90; count(*) 50 @@ -70,71 +70,61 @@ create table t1(id1 int not null primary key, t varchar(100)) pack_keys = 1; create table t2(id2 int not null, t varchar(100), index(id2)) pack_keys = 1; delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500; drop table t1,t2; -DROP TABLE IF EXISTS a,b,c; -CREATE TABLE a ( +CREATE TABLE t1 ( id int(11) NOT NULL default '0', name varchar(10) default NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -INSERT INTO a VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); -CREATE TABLE b ( +INSERT INTO t1 VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); +CREATE TABLE t2 ( id int(11) NOT NULL default '0', name varchar(10) default NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -INSERT INTO b VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); -CREATE TABLE c ( +INSERT INTO t2 VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); +CREATE TABLE t3 ( id int(11) NOT NULL default '0', mydate datetime default NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -INSERT INTO c VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 +INSERT INTO t3 VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 00:00:00'),(7,'2002-07-22 00:00:00'); -delete a,b,c from a,b,c -where to_days(now())-to_days(c.mydate)>=30 -and c.id=a.id and c.id=b.id; -select * from c; +delete t1,t2,t3 from t1,t2,t3 where to_days(now())-to_days(t3.mydate)>=30 and t3.id=t1.id and t3.id=t2.id; +select * from t3; id mydate 1 2002-02-04 00:00:00 5 2002-05-12 00:00:00 6 2002-06-22 00:00:00 7 2002-07-22 00:00:00 -DROP TABLE IF EXISTS a,b,c; -drop table if exists parent, child; -CREATE TABLE IF NOT EXISTS `parent` ( +DROP TABLE IF EXISTS t1,t2,t3; +CREATE TABLE IF NOT EXISTS `t1` ( `id` int(11) NOT NULL auto_increment, `tst` text, `tst1` text, PRIMARY KEY (`id`) ) TYPE=MyISAM; -CREATE TABLE IF NOT EXISTS `child` ( +CREATE TABLE IF NOT EXISTS `t2` ( `ID` int(11) NOT NULL auto_increment, `ParId` int(11) default NULL, `tst` text, `tst1` text, PRIMARY KEY (`ID`), -KEY `IX_ParId_child` (`ParId`), -FOREIGN KEY (`ParId`) REFERENCES `test.parent` (`id`) +KEY `IX_ParId_t2` (`ParId`), +FOREIGN KEY (`ParId`) REFERENCES `t1` (`id`) ) TYPE=MyISAM; -INSERT INTO parent(tst,tst1) -VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE"); -INSERT INTO child(ParId) -VALUES(1), (2), (3); -select * from child; +INSERT INTO t1(tst,tst1) VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE"); +INSERT INTO t2(ParId) VALUES(1), (2), (3); +select * from t2; ID ParId tst tst1 1 1 NULL NULL 2 2 NULL NULL 3 3 NULL NULL -UPDATE child, parent -SET child.tst = parent.tst, -child.tst1 = parent.tst1 -WHERE child.ParId = parent.Id; -select * from child; +UPDATE t2, t1 SET t2.tst = t1.tst, t2.tst1 = t1.tst1 WHERE t2.ParId = t1.Id; +select * from t2; ID ParId tst tst1 1 1 MySQL MySQL AB 2 2 MSSQL Microsoft 3 3 ORACLE ORACLE -drop table parent, child; drop table if exists t1, t2 ; create table t1 (n numeric(10)); create table t2 (n numeric(10)); diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index b3a51ff65bc..ec1ef76753b 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -80,67 +80,59 @@ while ($1) enable_query_log; delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500; drop table t1,t2; -DROP TABLE IF EXISTS a,b,c; -CREATE TABLE a ( + +CREATE TABLE t1 ( id int(11) NOT NULL default '0', name varchar(10) default NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -INSERT INTO a VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); -CREATE TABLE b ( +INSERT INTO t1 VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); +CREATE TABLE t2 ( id int(11) NOT NULL default '0', name varchar(10) default NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -INSERT INTO b VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); -CREATE TABLE c ( +INSERT INTO t2 VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); +CREATE TABLE t3 ( id int(11) NOT NULL default '0', mydate datetime default NULL, PRIMARY KEY (id) ) TYPE=MyISAM; -INSERT INTO c VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 +INSERT INTO t3 VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 00:00:00'),(7,'2002-07-22 00:00:00'); -delete a,b,c from a,b,c -where to_days(now())-to_days(c.mydate)>=30 -and c.id=a.id and c.id=b.id; -select * from c; -DROP TABLE IF EXISTS a,b,c; -drop table if exists parent, child; -CREATE TABLE IF NOT EXISTS `parent` ( +delete t1,t2,t3 from t1,t2,t3 where to_days(now())-to_days(t3.mydate)>=30 and t3.id=t1.id and t3.id=t2.id; +select * from t3; +DROP TABLE IF EXISTS t1,t2,t3; + +CREATE TABLE IF NOT EXISTS `t1` ( `id` int(11) NOT NULL auto_increment, `tst` text, `tst1` text, PRIMARY KEY (`id`) ) TYPE=MyISAM; -CREATE TABLE IF NOT EXISTS `child` ( +CREATE TABLE IF NOT EXISTS `t2` ( `ID` int(11) NOT NULL auto_increment, `ParId` int(11) default NULL, `tst` text, `tst1` text, PRIMARY KEY (`ID`), - KEY `IX_ParId_child` (`ParId`), - FOREIGN KEY (`ParId`) REFERENCES `test.parent` (`id`) + KEY `IX_ParId_t2` (`ParId`), + FOREIGN KEY (`ParId`) REFERENCES `t1` (`id`) ) TYPE=MyISAM; -INSERT INTO parent(tst,tst1) -VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE"); +INSERT INTO t1(tst,tst1) VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE"); -INSERT INTO child(ParId) -VALUES(1), (2), (3); +INSERT INTO t2(ParId) VALUES(1), (2), (3); -select * from child; +select * from t2; -UPDATE child, parent -SET child.tst = parent.tst, -child.tst1 = parent.tst1 -WHERE child.ParId = parent.Id; +UPDATE t2, t1 SET t2.tst = t1.tst, t2.tst1 = t1.tst1 WHERE t2.ParId = t1.Id; -select * from child; +select * from t2; - -drop table parent, child; drop table if exists t1, t2 ; + create table t1 (n numeric(10)); create table t2 (n numeric(10)); insert into t2 values (1),(2),(4),(8),(16),(32); diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index 43b3d30915f..e9c35175bf9 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -445,6 +445,8 @@ void init_io_cache_share(IO_CACHE *info, IO_CACHE_SHARE *s, uint num_threads) s->active=0; /* to catch errors */ info->share=s; info->read_function=_my_b_read_r; + /* Ensure that the code doesn't use pointer to the IO_CACHE object */ + info->current_pos= info->current_end= 0; } /* diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index ee587289168..b5f21c8772e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1658,7 +1658,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const i -= u; } if (i < 0) - return true; + return 1; register const int v = plm1 - i; turboShift = u - v; @@ -1675,7 +1675,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const } j += shift; } - return false; + return 0; } else { @@ -1689,7 +1689,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const i -= u; } if (i < 0) - return true; + return 1; register const int v = plm1 - i; turboShift = u - v; @@ -1706,7 +1706,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const } j += shift; } - return false; + return 0; } } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 43de81cae00..7cfbd84a99d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -242,6 +242,20 @@ typedef struct st_sql_list { uint elements; byte *first; byte **next; + + inline void empty() + { + elements=0; + first=0; + next= &first; + } + inline void link_in_list(byte *element,byte **next_ptr) + { + elements++; + (*next)=element; + next= next_ptr; + *next=0; + } } SQL_LIST; @@ -415,6 +429,10 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List &fields, List &values,COND *conds, ORDER *order, ha_rows limit, enum enum_duplicates handle_duplicates); +int mysql_multi_update(THD *thd, TABLE_LIST *table_list, + List *fields, List *values, + COND *conds, ulong options, + enum enum_duplicates handle_duplicates); int mysql_insert(THD *thd,TABLE_LIST *table,List &fields, List &values, enum_duplicates flag); void kill_delayed_threads(void); @@ -498,7 +516,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table,LEX_STRING *alias, void set_lock_for_tables(thr_lock_type lock_type); void add_join_on(TABLE_LIST *b,Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b); -bool add_proc_to_list(Item *item); +bool add_proc_to_list(THD *thd, Item *item); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); SQL_SELECT *make_select(TABLE *head, table_map const_tables, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 032882080ff..043ce44c140 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1942,8 +1942,8 @@ static key_map get_key_map_from_key_list(TABLE *table, } /**************************************************************************** -** This just drops in all fields instead of current '*' field -** Returns pointer to last inserted field if ok + This just drops in all fields instead of current '*' field + Returns pointer to last inserted field if ok ****************************************************************************/ bool @@ -1957,21 +1957,26 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, for (; tables ; tables=tables->next) { TABLE *table=tables->table; - if (grant_option && !thd->master_access && - check_grant_all_columns(thd,SELECT_ACL,table) ) - DBUG_RETURN(-1); if (!table_name || (!strcmp(table_name,tables->alias) && (!db_name || !strcmp(tables->db,db_name)))) { + /* Ensure that we have access right to all columns */ + if (grant_option && !thd->master_access && + check_grant_all_columns(thd,SELECT_ACL,table) ) + DBUG_RETURN(-1); Field **ptr=table->field,*field; thd->used_tables|=table->map; while ((field = *ptr++)) { Item_field *item= new Item_field(field); if (!found++) - (void) it->replace(item); + (void) it->replace(item); // Replace '*' else it->after(item); + /* + Mark if field used before in this select. + Used by 'insert' to verify if a field name is used twice + */ if (field->query_id == thd->query_id) thd->dupp_field=field; field->query_id=thd->query_id; diff --git a/sql/sql_class.h b/sql/sql_class.h index dba2ad130bf..241b7d0f87a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -592,7 +592,7 @@ public: virtual int prepare(List &list) { return 0; } virtual bool send_fields(List &list,uint flag)=0; virtual bool send_data(List &items)=0; - virtual void initialize_tables (JOIN *join=0) {} + virtual bool initialize_tables (JOIN *join=0) { return 0; } virtual void send_error(uint errcode,const char *err) { ::send_error(&thd->net,errcode,err); @@ -656,10 +656,10 @@ class select_insert :public select_result { List *fields; ulonglong last_insert_id; COPY_INFO info; - uint save_time_stamp; select_insert(TABLE *table_par,List *fields_par,enum_duplicates duplic) - :table(table_par),fields(fields_par), last_insert_id(0), save_time_stamp(0) { + :table(table_par),fields(fields_par), last_insert_id(0) + { bzero((char*) &info,sizeof(info)); info.handle_duplicates=duplic; } @@ -703,8 +703,8 @@ class select_union :public select_result { public: TABLE *table; COPY_INFO info; - uint save_time_stamp; TMP_TABLE_PARAM *tmp_table_param; + bool not_describe; select_union(TABLE *table_par); ~select_union(); @@ -814,37 +814,36 @@ public: bool send_fields(List &list, uint flag) { return 0; } bool send_data(List &items); - void initialize_tables (JOIN *join); + bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); int do_deletes (bool from_send_error); bool send_eof(); }; - class multi_update : public select_result { - TABLE_LIST *update_tables, *table_being_updated; -// Unique **tempfiles; - COPY_INFO *infos; - TABLE **tmp_tables; - THD *thd; - ha_rows updated, found; - List fields; - List **fields_by_tables; - enum enum_duplicates dupl; - uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence; - int error; - bool do_update, not_trans_safe; - public: - multi_update(THD *thd_arg, TABLE_LIST *ut, List &fs, - enum enum_duplicates handle_duplicates, - uint num); - ~multi_update(); - int prepare(List &list); - bool send_fields(List &list, - uint flag) { return 0; } - bool send_data(List &items); - void initialize_tables (JOIN *join); - void send_error(uint errcode,const char *err); - int do_updates (bool from_send_error); - bool send_eof(); - }; +class multi_update : public select_result +{ + TABLE_LIST *all_tables, *update_tables, *table_being_updated; + THD *thd; + TABLE **tmp_tables, *main_table; + TMP_TABLE_PARAM *tmp_table_param; + ha_rows updated, found; + List *fields, *values; + List **fields_for_table, **values_for_table; + uint table_count; + Copy_field *copy_field; + enum enum_duplicates handle_duplicates; + bool do_update, trans_safe, transactional_tables, log_delayed; + +public: + multi_update(THD *thd_arg, TABLE_LIST *ut, List *fields, + List *values, enum_duplicates handle_duplicates); + ~multi_update(); + int prepare(List &list); + bool send_fields(List &list, uint flag) { return 0; } + bool send_data(List &items); + bool initialize_tables (JOIN *join); + void send_error(uint errcode,const char *err); + int do_updates (bool from_send_error); + bool send_eof(); +}; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 1361ff39388..4997305de6b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -213,12 +213,13 @@ cleanup: extern "C" int refposcmp2(void* arg, const void *a,const void *b) { + /* arg is a pointer to file->ref_length */ return memcmp(a,b, *(int*) arg); } multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables_arg) - : delete_tables (dt), thd(thd_arg), deleted(0), + : delete_tables(dt), thd(thd_arg), deleted(0), num_of_tables(num_of_tables_arg), error(0), do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0) { @@ -230,31 +231,22 @@ int multi_delete::prepare(List &values) { DBUG_ENTER("multi_delete::prepare"); - do_delete = true; + do_delete= 1; thd->proc_info="deleting from main table"; - - if (thd->options & OPTION_SAFE_UPDATES) - { - TABLE_LIST *table_ref; - for (table_ref=delete_tables; table_ref; table_ref=table_ref->next) - { - TABLE *table=table_ref->table; - if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys) - { - my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0)); - DBUG_RETURN(1); - } - } - } DBUG_RETURN(0); } -void +bool multi_delete::initialize_tables(JOIN *join) { - int counter=0; TABLE_LIST *walk; + Unique **tempfiles_ptr; + DBUG_ENTER("initialize_tables"); + + if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join)) + DBUG_RETURN(1); + table_map tables_to_delete_from=0; for (walk= delete_tables ; walk ; walk=walk->next) tables_to_delete_from|= walk->table->map; @@ -268,9 +260,10 @@ multi_delete::initialize_tables(JOIN *join) { /* We are going to delete from this table */ TABLE *tbl=walk->table=tab->table; + walk=walk->next; /* Don't use KEYREAD optimization on this table */ tbl->no_keyread=1; - walk=walk->next; + tbl->used_keys= 0; if (tbl->file->has_transactions()) log_delayed= transactional_tables= 1; else if (tbl->tmp_table != NO_TMP_TABLE) @@ -280,19 +273,17 @@ multi_delete::initialize_tables(JOIN *join) } } walk= delete_tables; - walk->table->used_keys=0; - for (walk=walk->next ; walk ; walk=walk->next, counter++) + tempfiles_ptr= tempfiles; + for (walk=walk->next ; walk ; walk=walk->next) { - tables_to_delete_from|= walk->table->map; TABLE *table=walk->table; - /* Don't use key read with MULTI-TABLE-DELETE */ - table->used_keys=0; - tempfiles[counter] = new Unique (refposcmp2, - (void *) &table->file->ref_length, - table->file->ref_length, - MEM_STRIP_BUF_SIZE); + *tempfiles_ptr++= new Unique (refposcmp2, + (void *) &table->file->ref_length, + table->file->ref_length, + MEM_STRIP_BUF_SIZE); } init_ftfuncs(thd,1); + DBUG_RETURN(thd->fatal_error != 0); } @@ -307,7 +298,7 @@ multi_delete::~multi_delete() t->no_keyread=0; } - for (uint counter = 0; counter < num_of_tables-1; counter++) + for (uint counter= 0; counter < num_of_tables-1; counter++) { if (tempfiles[counter]) delete tempfiles[counter]; @@ -414,7 +405,7 @@ int multi_delete::do_deletes(bool from_send_error) else table_being_deleted = delete_tables; - do_delete = false; + do_delete= 0; for (table_being_deleted=table_being_deleted->next; table_being_deleted ; table_being_deleted=table_being_deleted->next, counter++) @@ -468,7 +459,7 @@ bool multi_delete::send_eof() was a non-transaction-safe table involved, since modifications in it cannot be rolled back. */ - if (deleted) + if (deleted && (error <= 0 || normal_tables)) { mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) @@ -478,11 +469,17 @@ bool multi_delete::send_eof() if (mysql_bin_log.write(&qinfo) && !normal_tables) local_error=1; // Log write failed: roll back the SQL statement } - /* Commit or rollback the current SQL statement */ - VOID(ha_autocommit_or_rollback(thd,local_error > 0)); - - query_cache_invalidate3(thd, delete_tables, 1); + if (!log_delayed) + thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; } + /* Commit or rollback the current SQL statement */ + if (transactional_tables) + if (ha_autocommit_or_rollback(thd,local_error > 0)) + local_error=1; + + if (deleted) + query_cache_invalidate3(thd, delete_tables, 1); + if (local_error) ::send_error(&thd->net); else diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 6ce2b50fc36..5ca08aa31b0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -41,7 +41,8 @@ static void unlink_blobs(register TABLE *table); /* Check if insert fields are correct - Resets form->time_stamp if a timestamp value is set + Updates table->time_stamp to point to timestamp field or 0, depending on + if timestamp should be updated or not. */ static int @@ -87,11 +88,12 @@ check_insert_fields(THD *thd,TABLE *table,List &fields, my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name); return -1; } + table->time_stamp=0; if (table->timestamp_field && // Don't set timestamp if used - table->timestamp_field->query_id == thd->query_id) - table->time_stamp=0; // This should be saved + table->timestamp_field->query_id != thd->query_id) + table->time_stamp= table->timestamp_field->offset()+1; } - // For the values we need select_priv + // For the values we need select_priv table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); return 0; } @@ -105,7 +107,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List &fields, !(thd->master_access & SUPER_ACL)); bool transactional_table, log_delayed, bulk_insert=0; uint value_count; - uint save_time_stamp; ulong counter = 1; ulonglong id; COPY_INFO info; @@ -150,14 +151,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List &fields, DBUG_RETURN(-1); thd->proc_info="init"; thd->used_tables=0; - save_time_stamp=table->time_stamp; values= its++; if (check_insert_fields(thd,table,fields,*values,1) || setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0)) - { - table->time_stamp=save_time_stamp; goto abort; - } value_count= values->elements; while ((values = its++)) { @@ -167,14 +164,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List &fields, my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), MYF(0),counter); - table->time_stamp=save_time_stamp; goto abort; } if (setup_fields(thd,table_list,*values,0,0,0)) - { - table->time_stamp=save_time_stamp; goto abort; - } } its.rewind (); /* @@ -333,7 +326,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List &fields, } } thd->proc_info="end"; - table->time_stamp=save_time_stamp; // Restore auto timestamp ptr table->next_number_field=0; thd->count_cuted_fields=0; thd->next_insert_id=0; // Reset this if wrongly used @@ -1287,7 +1279,6 @@ select_insert::prepare(List &values) { DBUG_ENTER("select_insert::prepare"); - save_time_stamp=table->time_stamp; if (check_insert_fields(thd,table,*fields,values,1)) DBUG_RETURN(1); @@ -1308,8 +1299,6 @@ select_insert::~select_insert() { if (table) { - if (save_time_stamp) - table->time_stamp=save_time_stamp; table->next_number_field=0; table->file->extra(HA_EXTRA_RESET); } @@ -1412,7 +1401,6 @@ select_create::prepare(List &values) /* First field to copy */ field=table->field+table->fields - values.elements; - save_time_stamp=table->time_stamp; if (table->timestamp_field) // Don't set timestamp if used { table->timestamp_field->set_time(); diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 930e052ab90..6eb4fbcaaf6 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -75,7 +75,7 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List new !strcmp(((Item_field*)new_item)->table_name,iif->table_name) && !strcmp(((Item_field*)new_item)->field_name,iif->field_name)) { - not_found=false; + not_found= 0; ((Item_field*)new_item)->db_name=iif->db_name; Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name); privlist.push_back(new_one); @@ -151,7 +151,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) if (cursor->do_redirect) { cursor->table= ((TABLE_LIST*) cursor->table)->table; - cursor->do_redirect=false; + cursor->do_redirect= 0; } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0cebde364f7..6b918d3565b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -422,7 +422,7 @@ end: } -static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them=false) +static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0) { (void) pthread_mutex_lock(&LOCK_user_conn); @@ -1826,61 +1826,29 @@ mysql_execute_command(void) select_lex->select_limit, lex->duplicates); } - else + else { - multi_update *result; - uint table_count; - TABLE_LIST *auxi; - const char *msg=0; - - lex->sql_command=SQLCOM_MULTI_UPDATE; - for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next) - table_count++; + const char *msg= 0; + lex->sql_command= SQLCOM_MULTI_UPDATE; if (select_lex->order_list.elements) msg="ORDER BY"; else if (select_lex->select_limit && select_lex->select_limit != HA_POS_ERROR) msg="LIMIT"; - if (msg) { net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg); res= 1; break; } - tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); - if ((res=open_and_lock_tables(thd,tables))) - break; - thd->select_limit=HA_POS_ERROR; - if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) && - !setup_fields(thd,tables,lex->value_list,0,0,0) && - ! thd->fatal_error && - (result=new multi_update(thd,tables,select_lex->item_list, - lex->duplicates, table_count))) - { - List total_list; - List_iterator field_list(select_lex->item_list); - List_iterator value_list(lex->value_list); - Item *item; - while ((item=field_list++)) - total_list.push_back(item); - while ((item=value_list++)) - total_list.push_back(item); - - res=mysql_select(thd,tables,total_list, - select_lex->where, - (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, - (ORDER *)NULL, - select_lex->options | thd->options | - SELECT_NO_JOIN_CACHE, - result); - delete result; - } - else - res= -1; // Error is not sent - close_thread_tables(thd); + res= mysql_multi_update(thd,tables, + &select_lex->item_list, + &lex->value_list, + select_lex->where, + select_lex->options, + lex->duplicates); } - break; + break; case SQLCOM_INSERT: if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege)) goto error; /* purecov: inspected */ @@ -2741,11 +2709,8 @@ mysql_init_select(LEX *lex) select_lex->olap= UNSPECIFIED_OLAP_TYPE; lex->exchange = 0; lex->proc_list.first=0; - select_lex->order_list.elements=select_lex->group_list.elements=0; - select_lex->order_list.first=0; - select_lex->order_list.next= (byte**) &select_lex->order_list.first; - select_lex->group_list.first=0; - select_lex->group_list.next= (byte**) &select_lex->group_list.first; + select_lex->order_list.empty(); + select_lex->group_list.empty(); select_lex->next = (SELECT_LEX *)NULL; } @@ -2818,16 +2783,6 @@ mysql_parse(THD *thd,char *inBuf,uint length) } -inline static void -link_in_list(SQL_LIST *list,byte *element,byte **next) -{ - list->elements++; - (*list->next)=element; - list->next=next; - *next=0; -} - - /***************************************************************************** ** Store field definition for create ** Return 0 if ok @@ -3102,7 +3057,7 @@ void store_position_for_column(const char *name) } bool -add_proc_to_list(Item *item) +add_proc_to_list(THD* thd, Item *item) { ORDER *order; Item **item_ptr; @@ -3113,7 +3068,7 @@ add_proc_to_list(Item *item) *item_ptr= item; order->item=item_ptr; order->free_me=0; - link_in_list(¤t_lex->proc_list,(byte*) order,(byte**) &order->next); + thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next); return 0; } @@ -3167,7 +3122,7 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc) order->asc = asc; order->free_me=0; order->used=0; - link_in_list(&list,(byte*) order,(byte**) &order->next); + list.link_in_list((byte*) order,(byte**) &order->next); DBUG_RETURN(0); } @@ -3248,7 +3203,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, } } } - link_in_list(&thd->lex.select->table_list,(byte*) ptr,(byte**) &ptr->next); + thd->lex.select->table_list.link_in_list((byte*) ptr,(byte**) &ptr->next); DBUG_RETURN(ptr); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7e378420f2..a97bd8bac0a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -437,7 +437,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error) goto err; thd->proc_info="preparing"; - result->initialize_tables(&join); + if (result->initialize_tables(&join)) + goto err; if (join.const_table_map != join.found_const_table_map && !(select_options & SELECT_DESCRIBE)) { @@ -2721,6 +2722,38 @@ make_join_readinfo(JOIN *join,uint options) } +/* + Give error if we some tables are done with a full join + + SYNOPSIS + error_if_full_join() + join Join condition + + USAGE + This is used by multi_table_update and multi_table_delete when running + in safe mode + + RETURN VALUES + 0 ok + 1 Error (full join used) +*/ + +bool error_if_full_join(JOIN *join) +{ + for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables; + tab < end; + tab++) + { + if (tab->type == JT_ALL && !tab->select->quick) + { + my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0)); + return(1); + } + } + return(0); +} + + static void join_free(JOIN *join) { @@ -3401,12 +3434,34 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) /**************************************************************************** - Create a temp table according to a field list. - Set distinct if duplicates could be removed - Given fields field pointers are changed to point at tmp_table - for send_fields + Create internal temporary table ****************************************************************************/ +/* + Create field for temporary table + + SYNOPSIS + create_tmp_field() + thd Thread handler + table Temporary table + item Item to create a field for + type Type of item (normally item->type) + copy_func If set and item is a function, store copy of item + in this array + group 1 if we are going to do a relative group by on result + modify_item 1 if item->result_field should point to new item. + This is relevent for how fill_record() is going to + work: + If modify_item is 1 then fill_record() will update + the record in the original table. + If modify_item is 0 then fill_record() will update + the temporary table + + RETURN + 0 on error + new_created field +*/ + Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item_result_field ***copy_func, Field **from_field, bool group, bool modify_item) @@ -3515,6 +3570,13 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, } +/* + Create a temp table according to a field list. + Set distinct if duplicates could be removed + Given fields field pointers are changed to point at tmp_table + for send_fields +*/ + TABLE * create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, @@ -3675,9 +3737,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, } else { + /* + The last parameter to create_tmp_field() is a bit tricky: + + We need to set it to 0 in union, to get fill_record() to modify the + temporary table. + We need to set it to 1 on multi-table-update and in select to + write rows to the temporary table. + We here distinguish between UNION and multi-table-updates by the fact + that in the later case group is set to the row pointer. + */ Field *new_field=create_tmp_field(thd, table, item,type, ©_func, tmp_from_field, group != 0, - not_all_columns); + not_all_columns || group !=0); if (!new_field) { if (thd->fatal_error) @@ -3991,7 +4063,6 @@ static bool open_tmp_table(TABLE *table) table->db_stat=0; return(1); } - /* VOID(ha_lock(table,F_WRLCK)); */ /* Single thread table */ (void) table->file->extra(HA_EXTRA_QUICK); /* Faster */ return(0); } diff --git a/sql/sql_select.h b/sql/sql_select.h index befa1efde53..a90b2fe3582 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -301,3 +301,4 @@ public: }; bool cp_buffer_from_ref(TABLE_REF *ref); +bool error_if_full_join(JOIN *join); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 9d20a4bd7c9..8cead6596b4 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -33,7 +33,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) TABLE *table; int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0; int res; - bool found_rows_for_union=false; + bool found_rows_for_union= 0; TABLE_LIST result_table_list; TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first; TMP_TABLE_PARAM tmp_table_param; @@ -53,7 +53,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) if (cursor->do_redirect) // False if CUBE/ROLLUP { cursor->table= ((TABLE_LIST*) cursor->table)->table; - cursor->do_redirect=false; + cursor->do_redirect= 0; } } } @@ -138,7 +138,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) res= -1; goto exit; } - union_result->save_time_stamp=!describe; + union_result->not_describe= !describe; union_result->tmp_table_param=&tmp_table_param; for (sl= &lex->select_lex; sl; sl=sl->next) { @@ -150,14 +150,17 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) if (thd->select_limit == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; - res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ? first_table : (TABLE_LIST*) sl->table_list.first, + res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ? + first_table : (TABLE_LIST*) sl->table_list.first, sl->item_list, sl->where, - (sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0, + (sl->braces) ? (ORDER *)sl->order_list.first : + (ORDER *) 0, (ORDER*) sl->group_list.first, sl->having, (ORDER*) NULL, - sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), + sl->options | thd->options | SELECT_NO_UNLOCK | + ((describe) ? SELECT_DESCRIBE : 0), union_result); if (res) goto exit; @@ -226,7 +229,7 @@ exit: ***************************************************************************/ select_union::select_union(TABLE *table_par) - :table(table_par) + :table(table_par), not_describe(0) { bzero((char*) &info,sizeof(info)); /* @@ -243,7 +246,7 @@ select_union::~select_union() int select_union::prepare(List &list) { - if (save_time_stamp && list.elements != table->fields) + if (not_describe && list.elements != table->fields) { my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 97e6ea43bfd..12d0ee8d7a2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -29,10 +29,12 @@ static bool compare_record(TABLE *table, ulong query_id) { if (!table->blob_fields) return cmp_record(table,1); + /* Compare null bits */ if (memcmp(table->null_flags, table->null_flags+table->rec_buff_length, table->null_bytes)) return 1; // Diff in NULL value + /* Compare updated fields */ for (Field **ptr=table->field ; *ptr ; ptr++) { if ((*ptr)->query_id == query_id && @@ -52,10 +54,11 @@ int mysql_update(THD *thd, ha_rows limit, enum enum_duplicates handle_duplicates) { - bool using_limit=limit != HA_POS_ERROR, safe_update= thd->options & OPTION_SAFE_UPDATES; + bool using_limit=limit != HA_POS_ERROR; + bool safe_update= thd->options & OPTION_SAFE_UPDATES; bool used_key_is_modified, transactional_table, log_delayed; int error=0; - uint save_time_stamp, used_index, want_privilege; + uint used_index, want_privilege; ulong query_id=thd->query_id, timestamp_query_id; key_map old_used_keys; TABLE *table; @@ -67,7 +70,6 @@ int mysql_update(THD *thd, if (!(table = open_ltable(thd,table_list,table_list->lock_type))) DBUG_RETURN(-1); /* purecov: inspected */ - save_time_stamp=table->time_stamp; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; @@ -89,6 +91,7 @@ int mysql_update(THD *thd, { timestamp_query_id=table->timestamp_field->query_id; table->timestamp_field->query_id=thd->query_id-1; + table->time_stamp= table->timestamp_field->offset() +1; } /* Check the fields we are going to modify */ @@ -108,7 +111,6 @@ int mysql_update(THD *thd, table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); if (setup_fields(thd,table_list,values,0,0,0)) { - table->time_stamp=save_time_stamp; // Restore timestamp pointer DBUG_RETURN(-1); /* purecov: inspected */ } @@ -119,7 +121,6 @@ int mysql_update(THD *thd, (select && select->check_quick(safe_update, limit)) || !limit) { delete select; - table->time_stamp=save_time_stamp; // Restore timestamp pointer if (error) { DBUG_RETURN(-1); // Error in where @@ -134,7 +135,6 @@ int mysql_update(THD *thd, if (safe_update && !using_limit) { delete select; - table->time_stamp=save_time_stamp; send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } @@ -153,8 +153,8 @@ int mysql_update(THD *thd, if (used_key_is_modified || order) { /* - ** We can't update table directly; We must first search after all - ** matching rows before updating the table! + We can't update table directly; We must first search after all + matching rows before updating the table! */ table->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE); IO_CACHE tempfile; @@ -162,7 +162,6 @@ int mysql_update(THD *thd, DISK_BUFFER_SIZE, MYF(MY_WME))) { delete select; /* purecov: inspected */ - table->time_stamp=save_time_stamp; // Restore timestamp pointer /* purecov: inspected */ DBUG_RETURN(-1); } if (old_used_keys & ((key_map) 1 << used_index)) @@ -193,7 +192,6 @@ int mysql_update(THD *thd, == HA_POS_ERROR) { delete select; - table->time_stamp=save_time_stamp; // Restore timestamp pointer DBUG_RETURN(-1); } } @@ -247,7 +245,6 @@ int mysql_update(THD *thd, if (error >= 0) { delete select; - table->time_stamp=save_time_stamp; // Restore timestamp pointer DBUG_RETURN(-1); } } @@ -297,7 +294,6 @@ int mysql_update(THD *thd, end_read_record(&info); thd->proc_info="end"; VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY)); - table->time_stamp=save_time_stamp; // Restore auto timestamp pointer transactional_table= table->file->has_transactions(); log_delayed= (transactional_table || table->tmp_table); if (updated && (error <= 0 || !transactional_table)) @@ -351,324 +347,338 @@ int mysql_update(THD *thd, DBUG_RETURN(0); } + /*************************************************************************** Update multiple tables from join ***************************************************************************/ -multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List &fs, - enum enum_duplicates handle_duplicates, - uint num) - : update_tables (ut), thd(thd_arg), updated(0), found(0), fields(fs), - dupl(handle_duplicates), num_of_tables(num), num_fields(0), num_updated(0), - error(0), do_update(false) +/* + Setup multi-update handling and call SELECT to do the join +*/ + +int mysql_multi_update(THD *thd, + TABLE_LIST *table_list, + List *fields, + List *values, + COND *conds, + ulong options, + enum enum_duplicates handle_duplicates) { - save_time_stamps = (uint *) sql_calloc (sizeof(uint) * num_of_tables); - tmp_tables = (TABLE **)NULL; - int counter=0; - ulong timestamp_query_id; - not_trans_safe=false; - for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++) + int res; + multi_update *result; + TABLE_LIST *tl; + DBUG_ENTER("mysql_multi_update"); + + table_list->grant.want_privilege=(SELECT_ACL & ~table_list->grant.privilege); + if ((res=open_and_lock_tables(thd,table_list))) + DBUG_RETURN(res); + + thd->select_limit=HA_POS_ERROR; + if (setup_fields(thd, table_list, *fields, 1, 0, 0)) + DBUG_RETURN(-1); + + /* + Count tables and setup timestamp handling + */ + for (tl= (TABLE_LIST*) table_list ; tl ; tl=tl->next) { - TABLE *table=ut->table; - // (void) ut->table->file->extra(HA_EXTRA_NO_KEYREAD); - dt->table->used_keys=0; + TABLE *table= tl->table; if (table->timestamp_field) { - // Don't set timestamp column if this is modified - timestamp_query_id=table->timestamp_field->query_id; - table->timestamp_field->query_id=thd->query_id-1; - if (table->timestamp_field->query_id == thd->query_id) - table->time_stamp=0; - else - table->timestamp_field->query_id=timestamp_query_id; + table->time_stamp=0; + // Only set timestamp column if this is not modified + if (table->timestamp_field->query_id != thd->query_id) + table->time_stamp= table->timestamp_field->offset() +1; } - save_time_stamps[counter]=table->time_stamp; } - error = 1; // In case we do not reach prepare we have to reset timestamps + + if (!(result=new multi_update(thd, table_list, fields, values, + handle_duplicates))) + DBUG_RETURN(-1); + + List total_list; + res= mysql_select(thd,table_list,total_list, + conds, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, + (ORDER *)NULL, + options | SELECT_NO_JOIN_CACHE, + result); + +end: + delete result; + DBUG_RETURN(res); } -int -multi_update::prepare(List &values) + +multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, + List *field_list, List *value_list, + enum enum_duplicates handle_duplicates_arg) + :all_tables(table_list), thd(thd_arg), tmp_tables(0), updated(0), + found(0), fields(field_list), values(value_list), table_count(0), + handle_duplicates(handle_duplicates_arg), do_update(1) +{} + + +/* + Connect fields with tables and create list of tables that are updated +*/ + +int multi_update::prepare(List ¬_used_values) { + TABLE_LIST *table_ref; + SQL_LIST update; + table_map tables_to_update= 0; + Item_field *item; + List_iterator_fast field_it(*fields); + List_iterator_fast value_it(*values); + uint i, max_fields; DBUG_ENTER("multi_update::prepare"); - do_update = true; + thd->count_cuted_fields=1; thd->cuted_fields=0L; - thd->proc_info="updating the main table"; - TABLE_LIST *table_ref; + thd->proc_info="updating main table"; - if (thd->options & OPTION_SAFE_UPDATES) - { - for (table_ref=update_tables; table_ref; table_ref=table_ref->next) - { - TABLE *table=table_ref->table; - if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys) - { - my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0)); - DBUG_RETURN(1); - } - } - } - /* - Here I have to connect fields with tables and only update tables that - need to be updated. - I calculate num_updated and fill-up table_sequence - Set table_list->shared to true or false, depending on whether table is - to be updated or not - */ + while ((item= (Item_field *) field_it++)) + tables_to_update|= item->used_tables(); - Item_field *item; - List_iterator it(fields); - num_fields=fields.elements; - field_sequence = (uint *) sql_alloc(sizeof(uint)*num_fields); - uint *int_ptr=field_sequence; - while ((item= (Item_field *)it++)) + if (!tables_to_update) { - unsigned int counter=0; - for (table_ref=update_tables; table_ref; - table_ref=table_ref->next, counter++) - { - if (table_ref->table == item->field->table) - { - if (!table_ref->shared) - { - TABLE *tbl=table_ref->table; - num_updated++; - table_ref->shared=1; - if (!not_trans_safe && !table_ref->table->file->has_transactions()) - not_trans_safe=true; - // to be moved if initialize_tables has to be used - tbl->no_keyread=1; - tbl->used_keys=0; - } - break; - } - } - if (!table_ref) - { - net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES"); - DBUG_RETURN(1); - } - else - *int_ptr++=counter; - } - if (!num_updated--) - { - net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE"); + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "You didn't specify any tables to UPDATE"); DBUG_RETURN(1); } /* - Here, I have to allocate the array of temporary tables - I have to treat a case of num_updated=1 differently in send_data() method. + We have to check values after setup_tables to get used_keys right in + reference tables */ - if (num_updated) + + if (setup_fields(thd, all_tables, *values, 1,0,0)) + DBUG_RETURN(1); + + /* + Save tables beeing updated in update_tables + update_table->shared is position for table + Don't use key read on tables that are updated + */ + + update.empty(); + for (table_ref= all_tables; table_ref; table_ref=table_ref->next) { - tmp_tables = (TABLE **) sql_calloc(sizeof(TABLE *) * num_updated); - infos = (COPY_INFO *) sql_calloc(sizeof(COPY_INFO) * num_updated); - fields_by_tables = (List_item **)sql_calloc(sizeof(List_item *) * (num_updated + 1)); - unsigned int counter; - List *temp_fields; - for (table_ref=update_tables, counter = 0; table_ref; table_ref=table_ref->next) + TABLE *table=table_ref->table; + if (tables_to_update & table->map) { - if (!table_ref->shared) - continue; - // Here we have to add row offset as an additional field ... - if (!(temp_fields = (List_item *)sql_calloc(sizeof(List_item)))) - { - error = 1; // A proper error message is due here + TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref, + sizeof(*tl)); + if (!tl) DBUG_RETURN(1); - } - temp_fields->empty(); - it.rewind(); int_ptr=field_sequence; - while ((item= (Item_field *)it++)) - { - if (*int_ptr++ == counter) - temp_fields->push_back(item); - } - if (counter) - { - Field_string offset(table_ref->table->file->ref_length,false,"offset",table_ref->table,true); - temp_fields->push_front(new Item_field(((Field *)&offset))); - // Here I make tmp tables - int cnt=counter-1; - TMP_TABLE_PARAM tmp_table_param; - bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); - tmp_table_param.field_count=temp_fields->elements; - if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param, - *temp_fields, - (ORDER*) 0, 1, 0, 0, - TMP_TABLE_ALL_COLUMNS))) - { - error = 1; // A proper error message is due here - DBUG_RETURN(1); - } - tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE); - tmp_tables[cnt]->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - infos[cnt].handle_duplicates=DUP_IGNORE; - temp_fields->pop(); // because we shall use those for values only ... - } - fields_by_tables[counter]=temp_fields; - counter++; + update.link_in_list((byte*) tl, (byte**) &tl->next); + tl->shared= table_count++; + table->no_keyread=1; + table->used_keys=0; + table->pos_in_table_list= tl; } } + table_count= update.elements; + update_tables= (TABLE_LIST*) update.first; + + tmp_tables = (TABLE **) thd->calloc(sizeof(TABLE *) * table_count); + tmp_table_param = (TMP_TABLE_PARAM*) thd->calloc(sizeof(TMP_TABLE_PARAM) * + table_count); + fields_for_table= (List_item **) thd->alloc(sizeof(List_item *) * + table_count); + values_for_table= (List_item **) thd->alloc(sizeof(List_item *) * + table_count); + if (thd->fatal_error) + DBUG_RETURN(1); + for (i=0 ; i < table_count ; i++) + { + fields_for_table[i]= new List_item; + values_for_table[i]= new List_item; + } + if (thd->fatal_error) + DBUG_RETURN(1); + + /* Split fields into fields_for_table[] and values_by_table[] */ + + field_it.rewind(); + while ((item= (Item_field *) field_it++)) + { + Item *value= value_it++; + uint offset= item->field->table->pos_in_table_list->shared; + fields_for_table[offset]->push_back(item); + values_for_table[offset]->push_back(value); + } + if (thd->fatal_error) + DBUG_RETURN(1); + + /* Allocate copy fields */ + max_fields=0; + for (i=0 ; i < table_count ; i++) + set_if_bigger(max_fields, fields_for_table[i]->elements); + copy_field= new Copy_field[max_fields]; init_ftfuncs(thd,1); - error = 0; // Timestamps do not need to be restored, so far ... - DBUG_RETURN(0); + DBUG_RETURN(thd->fatal_error != 0); } -void +/* + Store first used table in main_table as this should be updated first + This is because we know that no row in this table will be read twice. + + Create temporary tables to store changed values for all other tables + that are updated. +*/ + +bool multi_update::initialize_tables(JOIN *join) { -#ifdef NOT_YET - We skip it as it only makes a mess ........... - TABLE_LIST *walk; - table_map tables_to_update_from=0; - for (walk= update_tables ; walk ; walk=walk->next) - tables_to_update_from|= walk->table->map; - - walk= update_tables; - for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables; - tab < end; - tab++) + TABLE_LIST *table_ref; + DBUG_ENTER("initialize_tables"); + + if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join)) + DBUG_RETURN(1); + main_table=join->join_tab->table; + trans_safe= transactional_tables= main_table->file->has_transactions(); + log_delayed= trans_safe || main_table->tmp_table != NO_TMP_TABLE; + + /* Create a temporary table for all tables after except main table */ + for (table_ref= update_tables; table_ref; table_ref=table_ref->next) { - if (tab->table->map & tables_to_update_from) + TABLE *table=table_ref->table; + if (table != main_table) { -// We are going to update from this table - TABLE *tbl=walk->table=tab->table; - /* Don't use KEYREAD optimization on this table */ - tbl->no_keyread=1; - walk=walk->next; + uint cnt= table_ref->shared; + ORDER group; + List temp_fields= *fields_for_table[cnt]; + TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt; + + /* + Create a temporary table to store all fields that are changed for this + table. The first field in the temporary table is a pointer to the + original row so that we can find and update it + */ + + /* ok to be on stack as this is not referenced outside of this func */ + Field_string offset(table->file->ref_length, 0, "offset", + table, 1); + if (temp_fields.push_front(new Item_field(((Field *) &offset)))) + DBUG_RETURN(1); + + /* Make an unique key over the first field to avoid duplicated updates */ + bzero((char*) &group, sizeof(group)); + group.asc= 1; + group.item= (Item**) temp_fields.head_ref(); + + tmp_param->quick_group=1; + tmp_param->field_count=temp_fields.elements; + tmp_param->group_parts=1; + tmp_param->group_length= table->file->ref_length; + if (!(tmp_tables[cnt]=create_tmp_table(thd, + tmp_param, + temp_fields, + (ORDER*) &group, 0, 0, 0, + TMP_TABLE_ALL_COLUMNS))) + DBUG_RETURN(1); + tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE); } } -#endif + DBUG_RETURN(0); } multi_update::~multi_update() { - int counter = 0; - for (table_being_updated=update_tables ; - table_being_updated ; - counter++, table_being_updated=table_being_updated->next) - { - TABLE *table=table_being_updated->table; - table->no_keyread=0; - if (error) - table->time_stamp=save_time_stamps[counter]; - } + TABLE_LIST *table; + for (table= update_tables ; table; table= table->next) + table->table->no_keyread=0; + if (tmp_tables) - for (uint counter = 0; counter < num_updated; counter++) + { + for (uint counter = 0; counter < table_count; counter++) if (tmp_tables[counter]) free_tmp_table(thd,tmp_tables[counter]); + } + if (copy_field) + delete [] copy_field; + thd->count_cuted_fields=0; // Restore this setting + if (!trans_safe) + thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; } -bool multi_update::send_data(List &values) +bool multi_update::send_data(List ¬_used_values) { - List real_values(values); - for (uint counter = 0; counter < fields.elements; counter++) - real_values.pop(); - // We have skipped fields .... - if (!num_updated) + TABLE_LIST *cur_table; + DBUG_ENTER("multi_update::send_data"); + + found++; + for (cur_table= update_tables; cur_table ; cur_table= cur_table->next) { - for (table_being_updated=update_tables ; - table_being_updated ; - table_being_updated=table_being_updated->next) + TABLE *table= cur_table->table; + /* Check if we are using outer join and we didn't find the row */ + if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED)) + continue; + + uint offset= cur_table->shared; + table->file->position(table->record[0]); + if (table == main_table) { - if (!table_being_updated->shared) - continue; - TABLE *table=table_being_updated->table; - /* Check if we are using outer join and we didn't find the row */ - if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED)) - return 0; - table->file->position(table->record[0]); - // Only one table being updated receives a completely different treatment table->status|= STATUS_UPDATED; - store_record(table,1); - if (fill_record(fields,real_values)) - return 1; - found++; - if (/* compare_record(table, query_id) && */ - !(error=table->file->update_row(table->record[1], table->record[0]))) - updated++; - table->file->extra(HA_EXTRA_NO_CACHE); - return error; - } - } - else - { - int secure_counter= -1; - for (table_being_updated=update_tables ; - table_being_updated ; - table_being_updated=table_being_updated->next, secure_counter++) - { - if (!table_being_updated->shared) - continue; - - TABLE *table=table_being_updated->table; - /* Check if we are using outer join and we didn't find the row */ - if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED)) - continue; - table->file->position(table->record[0]); - Item *item; - List_iterator it(real_values); - List values_by_table; - uint *int_ptr=field_sequence; - while ((item= (Item *)it++)) + store_record(table,1); + if (fill_record(*fields_for_table[offset], *values_for_table[offset])) + DBUG_RETURN(1); + if (compare_record(table, thd->query_id)) { - if (*int_ptr++ == (uint) (secure_counter + 1)) - values_by_table.push_back(item); - } - // Here I am breaking values as per each table - if (secure_counter < 0) - { - table->status|= STATUS_UPDATED; - store_record(table,1); - if (fill_record(*fields_by_tables[0],values_by_table)) - return 1; - found++; - if (/*compare_record(table, query_id) && */ - !(error=table->file->update_row(table->record[1], table->record[0]))) + int error; + if (!updated++) { - updated++; - table->file->extra(HA_EXTRA_NO_CACHE); + /* + Inform the main table that we are going to update the table even + while we may be scanning it. This will flush the read cache + if it's used. + */ + main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE); } - else + if ((error=table->file->update_row(table->record[1], + table->record[0]))) { table->file->print_error(error,MYF(0)); - if (!error) error=1; - return 1; + updated--; + DBUG_RETURN(1); } } - else + } + else + { + int error; + TABLE *tmp_table= tmp_tables[offset]; + fill_record(tmp_table->field+1, *values_for_table[offset]); + + /* Store pointer to row */ + 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 != HA_ERR_FOUND_DUPP_KEY && + error != HA_ERR_FOUND_DUPP_UNIQUE)) { - // Here we insert into each temporary table - values_by_table.push_front(new Item_string((char*) table->file->ref, - table->file->ref_length)); - fill_record(tmp_tables[secure_counter]->field,values_by_table); - error= write_record(tmp_tables[secure_counter], - &(infos[secure_counter])); - if (error) + if (create_myisam_from_heap(table, tmp_table_param + offset, error, 1)) { - error=-1; - return 1; + do_update=0; + DBUG_RETURN(1); // Not a table_is_full error } } } } - return 0; + DBUG_RETURN(0); } + void multi_update::send_error(uint errcode,const char *err) { /* First send error what ever it is ... */ ::send_error(&thd->net,errcode,err); - /* reset used flags */ - // update_tables->table->no_keyread=0; - /* If nothing updated return */ if (!updated) return; @@ -676,97 +686,124 @@ void multi_update::send_error(uint errcode,const char *err) /* Something already updated so we have to invalidate cache */ query_cache_invalidate3(thd, update_tables, 1); - /* Below can happen when thread is killed early ... */ - if (!table_being_updated) - table_being_updated=update_tables; - /* - If rows from the first table only has been updated and it is transactional, - just do rollback. - The same if all tables are transactional, regardless of where we are. - In all other cases do attempt updates ... + If all tables that has been updated are trans safe then just do rollback. + If not attempt to do remaining updates. */ - if ((table_being_updated->table->file->has_transactions() && - table_being_updated == update_tables) || !not_trans_safe) + + if (trans_safe) ha_rollback_stmt(thd); - else if (do_update && num_updated) - VOID(do_updates(true)); + else if (do_update && table_count > 1) + { + /* Add warning here */ + VOID(do_updates(0)); + } } -int multi_update::do_updates (bool from_send_error) +int multi_update::do_updates(bool from_send_error) { - int local_error= 0, counter= 0; + TABLE_LIST *cur_table; + int local_error; + ha_rows org_updated; + TABLE *table; + DBUG_ENTER("do_updates"); - if (from_send_error) + do_update= 0; // Don't retry this function + for (cur_table= update_tables; cur_table ; cur_table= cur_table->next) { - /* Found out table number for 'table_being_updated' */ - for (TABLE_LIST *aux=update_tables; - aux != table_being_updated; - aux=aux->next) - counter++; - } - else - table_being_updated = update_tables; + table = cur_table->table; + if (table == main_table) + continue; // Already updated - do_update = false; - for (table_being_updated=table_being_updated->next; - table_being_updated ; - table_being_updated=table_being_updated->next, counter++) - { - if (!table_being_updated->shared) - continue; + org_updated= updated; + byte *ref_pos; + TABLE *tmp_table= tmp_tables[cur_table->shared]; + tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache + table->file->extra(HA_EXTRA_NO_CACHE); - TABLE *table = table_being_updated->table; - TABLE *tmp_table=tmp_tables[counter]; - if (tmp_table->file->extra(HA_EXTRA_NO_CACHE)) + /* + Setup copy functions to copy fields from temporary table + */ + List_iterator_fast field_it(*fields_for_table[cur_table->shared]); + Field **field= tmp_table->field+1; // Skip row pointer + Copy_field *copy_field_ptr= copy_field, *copy_field_end; + for ( ; *field ; field++) { - local_error=1; - break; + Item_field *item= (Item_field* ) field_it++; + (copy_field_ptr++)->set(item->field, *field, 0); } - List list; - Field **ptr=tmp_table->field,*field; - // This is supposed to be something like insert_fields - thd->used_tables|=tmp_table->map; - while ((field = *ptr++)) + copy_field_end=copy_field_ptr; + + if ((local_error = tmp_table->file->rnd_init(1))) + goto err; + + ref_pos= (byte*) tmp_table->field[0]->ptr; + for (;;) { - list.push_back((Item *)new Item_field(field)); - if (field->query_id == thd->query_id) - thd->dupp_field=field; - field->query_id=thd->query_id; - tmp_table->used_keys&=field->part_of_key; - } - tmp_table->used_fields=tmp_table->fields; - local_error=0; - list.pop(); // we get position some other way ... - local_error = tmp_table->file->rnd_init(1); - if (local_error) - return local_error; - while (!(local_error=tmp_table->file->rnd_next(tmp_table->record[0])) && - (!thd->killed || from_send_error || not_trans_safe)) - { - found++; - local_error= table->file->rnd_pos(table->record[0], - (byte*) (*(tmp_table->field))->ptr); - if (local_error) - return local_error; - table->status|= STATUS_UPDATED; - store_record(table,1); - local_error= (fill_record(*fields_by_tables[counter + 1],list) || - /* compare_record(table, query_id) || */ - table->file->update_row(table->record[1],table->record[0])); - if (local_error) + if (thd->killed && trans_safe) + goto err; + if ((local_error=tmp_table->file->rnd_next(tmp_table->record[0]))) { - table->file->print_error(local_error,MYF(0)); - break; + if (local_error == HA_ERR_END_OF_FILE) + break; + if (local_error == HA_ERR_RECORD_DELETED) + continue; // May happen on dup key + goto err; } - else + found++; + if ((local_error= table->file->rnd_pos(table->record[0], ref_pos))) + goto err; + table->status|= STATUS_UPDATED; + store_record(table,1); + + /* Copy data from temporary table to current table */ + for (copy_field_ptr=copy_field; + copy_field_ptr != copy_field_end; + copy_field_ptr++) + (*copy_field_ptr->do_copy)(copy_field_ptr); + + if (compare_record(table, thd->query_id)) + { + if ((local_error=table->file->update_row(table->record[1], + table->record[0]))) + { + if (local_error != HA_ERR_FOUND_DUPP_KEY || + handle_duplicates != DUP_IGNORE) + goto err; + } updated++; + if (table->tmp_table != NO_TMP_TABLE) + log_delayed= 1; + } + } + + if (updated != org_updated) + { + if (table->tmp_table != NO_TMP_TABLE) + log_delayed= 1; // Tmp tables forces delay log + if (table->file->has_transactions()) + log_delayed= transactional_tables= 1; + else + trans_safe= 0; // Can't do safe rollback } - if (local_error == HA_ERR_END_OF_FILE) - local_error = 0; } - return local_error; + DBUG_RETURN(0); + +err: + if (!from_send_error) + table->file->print_error(local_error,MYF(0)); + + if (updated != org_updated) + { + if (table->tmp_table != NO_TMP_TABLE) + log_delayed= 1; + if (table->file->has_transactions()) + log_delayed= transactional_tables= 1; + else + trans_safe= 0; + } + DBUG_RETURN(1); } @@ -774,60 +811,57 @@ int multi_update::do_updates (bool from_send_error) bool multi_update::send_eof() { - thd->proc_info="updating the reference tables"; + char buff[80]; + thd->proc_info="updating reference tables"; /* Does updates for the last n - 1 tables, returns 0 if ok */ - int local_error = (num_updated) ? do_updates(false) : 0; - - /* reset used flags */ -#ifndef NOT_USED - update_tables->table->no_keyread=0; -#endif - if (local_error == -1) - local_error= 0; + int local_error = (table_count) ? do_updates(0) : 0; thd->proc_info= "end"; - if (local_error) - send_error(local_error, "An error occured in multi-table update"); /* Write the SQL statement to the binlog if we updated - rows and we succeeded, or also in an error case when there - was a non-transaction-safe table involved, since - modifications in it cannot be rolled back. + rows and we succeeded or if we updated some non + transacational tables */ - if (updated || not_trans_safe) + if (updated && (local_error <= 0 || !trans_safe)) { mysql_update_log.write(thd,thd->query,thd->query_length); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0); - - /* - mysql_bin_log is not open if binlogging or replication - is not used - */ - - if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) && - !not_trans_safe) - local_error=1; /* Log write failed: roll back the SQL statement */ - - /* Commit or rollback the current SQL statement */ - VOID(ha_autocommit_or_rollback(thd, local_error > 0)); - } - else - local_error= 0; // this can happen only if it is end of file error - if (!local_error) // if the above log write did not fail ... - { - char buff[80]; - sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, - (long) thd->cuted_fields); - if (updated) + if (mysql_bin_log.is_open()) { - query_cache_invalidate3(thd, update_tables, 1); + Query_log_event qinfo(thd, thd->query, thd->query_length, + log_delayed); + if (mysql_bin_log.write(&qinfo) && trans_safe) + local_error=1; // Rollback update } - ::send_ok(&thd->net, - (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, - thd->insert_id_used ? thd->insert_id() : 0L,buff); + if (!log_delayed) + thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; } - thd->count_cuted_fields=0; + + if (transactional_tables) + { + if (ha_autocommit_or_rollback(thd, local_error >= 0)) + local_error=1; + } + + if (local_error > 0) // if the above log write did not fail ... + { + /* Safety: If we haven't got an error before (should not happen) */ + my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update", + MYF(0)); + ::send_error(&thd->net); + return 1; + } + + + sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, + (long) thd->cuted_fields); + if (updated) + { + query_cache_invalidate3(thd, update_tables, 1); + } + ::send_ok(&thd->net, + (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, + thd->insert_id_used ? thd->insert_id() : 0L,buff); return 0; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c3c6d8ad66b..807097f5173 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1436,9 +1436,9 @@ select: select_init { Lex->sql_command=SQLCOM_SELECT; }; select_init: - SELECT_SYM select_part2 { Select->braces=false; } opt_union + SELECT_SYM select_part2 { Select->braces= 0; } opt_union | - '(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt; + '(' SELECT_SYM select_part2 ')' { Select->braces= 1;} union_opt; select_part2: @@ -2350,7 +2350,7 @@ procedure_clause: lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= (byte**) &lex->proc_list.first; - if (add_proc_to_list(new Item_field(NULL,NULL,$2.str))) + if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str))) YYABORT; current_thd->safe_to_cache_query=0; } @@ -2368,10 +2368,11 @@ procedure_list2: procedure_item: remember_name expr { - if (add_proc_to_list($2)) + LEX *lex= Lex; + if (add_proc_to_list(lex->thd, $2)) YYABORT; if (!$2->name) - $2->set_name($1,(uint) ((char*) Lex->tok_end - $1)); + $2->set_name($1,(uint) ((char*) lex->tok_end - $1)); }; opt_into: diff --git a/sql/table.h b/sql/table.h index f998a0fd4e6..3a08cd11a2a 100644 --- a/sql/table.h +++ b/sql/table.h @@ -117,18 +117,22 @@ struct st_table { table_map map; /* ID bit of table (1,2,4,8,16...) */ ulong version,flush_version; uchar *null_flags; - IO_CACHE *io_cache; /* If sorted trough file*/ - byte *record_pointers; /* If sorted in memory */ - ha_rows found_records; /* How many records in sort */ + IO_CACHE *io_cache; /* If sorted trough file*/ + byte *record_pointers; /* If sorted in memory */ + ha_rows found_records; /* How many records in sort */ ORDER *group; ha_rows quick_rows[MAX_KEY]; uint quick_key_parts[MAX_KEY]; key_part_map const_key_parts[MAX_KEY]; ulong query_id; - uint temp_pool_slot; + union /* Temporary variables */ + { + uint temp_pool_slot; /* Used by intern temp tables */ + struct st_table_list *pos_in_table_list; + }; - THD *in_use; /* Which thread uses this */ + THD *in_use; /* Which thread uses this */ struct st_table *next,*prev; }; @@ -148,10 +152,10 @@ typedef struct st_table_list GRANT_INFO grant; thr_lock_type lock_type; uint outer_join; /* Which join type */ + uint shared; /* Used in union or in multi-upd */ uint32 db_length, real_name_length; bool straight; /* optimize with prev table */ bool updating; /* for replicate-do/ignore table */ - bool shared; /* Used twice in union */ bool do_redirect; /* To get the struct in UNION's */ } TABLE_LIST; diff --git a/sql/uniques.cc b/sql/uniques.cc index 60905567ba0..ed256a4b791 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -53,7 +53,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, :max_in_memory_size(max_in_memory_size_arg),elements(0) { my_b_clear(&file); - init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, comp_func_fixed_arg); + init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, + comp_func_fixed_arg); /* If the following fail's the next add will also fail */ my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); From 2f4a98912e1884fbed89c65bba0b1e0cd16f36f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Nov 2002 17:36:36 +0100 Subject: [PATCH 19/46] - removed unused variable $defaults - parse mysql.server section in my.cnf as well --- support-files/mysql.server.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 6c3fa9f1127..f438899b3bf 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -79,7 +79,8 @@ parse_arguments() { done } -# Get arguments from the my.cnf file, groups [mysqld] and [mysql_server] +# Get arguments from the my.cnf file, +# groups [mysqld] [mysql_server] and [mysql.server] if test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" @@ -117,7 +118,7 @@ else test -z "$print_defaults" && print_defaults="my_print_defaults" fi -parse_arguments `$print_defaults $defaults mysqld mysql_server` +parse_arguments `$print_defaults mysqld mysql_server mysql.server` # Safeguard (relative paths, core dumps..) cd $basedir From 50e61c5175846ebcc72e15444b20995234270ee3 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 30 Nov 2002 18:38:44 +0200 Subject: [PATCH 20/46] a fix for a bug with HAVING sum_func IN (...) --- mysql-test/r/group_by.result | 7 +++++++ mysql-test/t/group_by.test | 1 + sql/item_cmpfunc.cc | 8 ++++++++ sql/item_cmpfunc.h | 2 ++ 4 files changed, 18 insertions(+) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 200cbc29b08..b557d90f312 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -30,6 +30,13 @@ Documentation 0 Host communication 0 kkkkkkkkkkk lllllllllll 3 Test Procedures 0 +value description COUNT(bug_id) +BBBBBBBBBBBBB - conversion 2 +BBBBBBBBBBBBB - eeeeeeeee 0 +BBBBBBBBBBBBB - generic 2 +Documentation 0 +Host communication 0 +Test Procedures 0 1+1 a count(*) 2 a 0 1+1 a count(*) diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index dfbb2f325a9..e4b7d659a8e 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -206,6 +206,7 @@ INSERT INTO t2 VALUES ('Web Interface','AAAAAAAA-AAA','id0001','',''); INSERT INTO t2 VALUES ('Host communication','AAAAA','id0001','',''); select value,description,bug_id from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA"; select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value; +select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value having COUNT(bug_id) IN (0,2); drop table t1,t2; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 36ecde337a7..4ef77d0c509 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1029,6 +1029,14 @@ void Item_func_in::update_used_tables() used_tables_cache|=item->used_tables(); const_item_cache&=item->const_item(); } +void Item_func_in::split_sum_func(List &fields) +{ + if (item->used_tables() || item->type() == SUM_FUNC_ITEM) + { + fields.push_front(item); + item=new Item_ref((Item**) fields.head_ref(),0,item->name); + } +} longlong Item_func_bit_or::val_int() diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index e7c598808e8..72d4e06e39c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -410,6 +410,7 @@ class Item_func_in :public Item_int_func longlong val_int(); bool fix_fields(THD *thd,struct st_table_list *tlist) { + with_sum_func= with_sum_func || item->with_sum_func; return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); } void fix_length_and_dec(); @@ -421,6 +422,7 @@ class Item_func_in :public Item_int_func enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return " IN "; } void update_used_tables(); + void split_sum_func(List &fields); }; From d5be7db312283260d3ca11de946ceb53c1ac4d84 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 1 Dec 2002 00:02:58 +0200 Subject: [PATCH 21/46] Fixed --datadir for embedded server --- sql/mysqld.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2404b35b00f..01923509042 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3966,6 +3966,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'h': strmake(mysql_real_data_home,argument, sizeof(mysql_real_data_home)-1); + /* Correct pointer set by my_getopt (for embedded library) */ + mysql_data_home= mysql_real_data_home; break; case 'L': strmake(language, argument, sizeof(language)-1); From b22dc24cbb160d0bbe7e43fc67d22d6147740f6b Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 1 Dec 2002 00:48:35 +0200 Subject: [PATCH 22/46] Fixed some bugs from last multi-table-update push. More tests for multi-table-update & timestamp handling mysql-test/r/innodb.result: New multi-table-update tests mysql-test/r/multi_update.result: New multi-table-update tests mysql-test/r/type_timestamp.result: New timestamp tests mysql-test/t/innodb.test: New multi-table-update tests mysql-test/t/multi_update.test: New multi-table-update tests mysql-test/t/type_timestamp.test: New timestamp tests sql/sql_select.cc: Fixed bug in safe mode checking sql/sql_update.cc: Fixed bug in autocommit in multi-table-update --- mysql-test/r/innodb.result | 15 +++++++ mysql-test/r/multi_update.result | 70 ++++++++++++++++++++++++++++++ mysql-test/r/type_timestamp.result | 32 +++++++++++--- mysql-test/t/innodb.test | 13 ++++++ mysql-test/t/multi_update.test | 56 ++++++++++++++++++++++-- mysql-test/t/type_timestamp.test | 21 ++++++--- sql/sql_select.cc | 2 +- sql/sql_update.cc | 4 +- 8 files changed, 195 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 67c78f34392..1e136acb21d 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1021,3 +1021,18 @@ id code name 7 4 Matt COMMIT; DROP TABLE t1; +drop table if exists t1,t2; +create table t1 (n int(10), d int(10)) type=innodb; +create table t2 (n int(10), d int(10)) type=innodb; +insert into t1 values(1,1),(1,2); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1; +n d +1 10 +1 10 +select * from t2; +n d +1 30 +2 20 +drop table t1,t2; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 20921816f1e..7d1f5bd53f6 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -166,3 +166,73 @@ n d 2 20 unlock tables; drop table t1,t2; +set sql_safe_updates=1; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +set sql_safe_updates=0; +drop table t1,t2; +set timestamp=1038401397; +create table t1 (n int(10) not null primary key, d int(10), t timestamp); +create table t2 (n int(10) not null primary key, d int(10), t timestamp); +insert into t1 values(1,1,NULL); +insert into t2 values(1,10,NULL),(2,20,NULL); +set timestamp=1038000000; +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +select * from t1; +n d t +1 10 20021123002000 +select * from t2; +n d t +1 10 20021127154957 +2 20 20021127154957 +UPDATE t1,t2 SET 1=2 WHERE t1.n=t2.n; +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 '1=2 WHERE t1.n=t2.n' at line 1 +drop table t1,t2; +set timestamp=0; +set sql_safe_updates=0; +create table t1 (n int(10) not null primary key, d int(10)); +create table t2 (n int(10) not null primary key, d int(10)); +insert into t1 values(1,1), (3,3); +insert into t2 values(1,10),(2,20); +UPDATE t2 left outer join t1 on t1.n=t2.n SET t1.d=t2.d; +select * from t1; +n d +1 10 +3 3 +select * from t2; +n d +1 10 +2 20 +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(1,2); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1; +n d +1 10 +1 10 +select * from t2; +n d +1 30 +2 20 +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(3,2); +insert into t2 values(1,10),(1,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1; +n d +1 10 +3 2 +select * from t2; +n d +1 30 +1 30 +drop table t1,t2; diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index bd5e9f04992..088f3b205b9 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -1,11 +1,31 @@ -drop table if exists t1; -CREATE TABLE t1 ( t timestamp); +drop table if exists t1,t2; +CREATE TABLE t1 (a int, t timestamp); +CREATE TABLE t2 (a int, t datetime); SET TIMESTAMP=1234; -insert into t1 values(NULL); +insert into t1 values(1,NULL); +insert into t1 values(2,"2002-03-03"); +SET TIMESTAMP=1235; +insert into t1 values(3,NULL); +SET TIMESTAMP=1236; +insert into t1 (a) values(4); +insert into t2 values(5,"2002-03-04"),(6,NULL),(7,"2002-03-05"),(8,"00-00-00"); +SET TIMESTAMP=1237; +insert into t1 select * from t2; +SET TIMESTAMP=1238; +insert into t1 (a) select a+1 from t2 where a=8; select * from t1; -t -19700101032034 -drop table t1; +a t +1 19700101032034 +2 20020303000000 +3 19700101032035 +4 19700101032036 +5 20020304000000 +6 19700101032037 +7 20020305000000 +8 00000000000000 +9 19700101032038 +drop table t1,t2; +SET TIMESTAMP=1234; CREATE TABLE t1 (value TEXT NOT NULL, id VARCHAR(32) NOT NULL, stamp timestamp, PRIMARY KEY (id)); INSERT INTO t1 VALUES ("my value", "myKey","1999-04-02 00:00:00"); SELECT stamp FROM t1 WHERE id="myKey"; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index e6d57899082..8edde83507a 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -660,3 +660,16 @@ insert into t1 (code, name) values (3, 'Jeremy'), (4, 'Matt'); select id, code, name from t1 order by id; COMMIT; DROP TABLE t1; + +# +# Test of multi-table-update +# +drop table if exists t1,t2; +create table t1 (n int(10), d int(10)) type=innodb; +create table t2 (n int(10), d int(10)) type=innodb; +insert into t1 values(1,1),(1,2); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1; +select * from t2; +drop table t1,t2; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index ec1ef76753b..b79b0749c82 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -1,9 +1,6 @@ # -# Only run the test if we are using --big-test, because this test takes a -# long time +# Test of update statement that uses many tables. # -#-- require r/big_test.require -#eval select $BIG_TEST as using_big_test; drop table if exists t1,t2,t3; create table t1(id1 int not null auto_increment primary key, t char(12)); @@ -166,3 +163,54 @@ select * from t1; select * from t2; unlock tables; drop table t1,t2; + +# +# Test safe updates and timestamps +# +set sql_safe_updates=1; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1); +insert into t2 values(1,10),(2,20); +--error 1175 +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +set sql_safe_updates=0; +drop table t1,t2; +set timestamp=1038401397; +create table t1 (n int(10) not null primary key, d int(10), t timestamp); +create table t2 (n int(10) not null primary key, d int(10), t timestamp); +insert into t1 values(1,1,NULL); +insert into t2 values(1,10,NULL),(2,20,NULL); +set timestamp=1038000000; +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +select * from t1; +select * from t2; +--error 1064 +UPDATE t1,t2 SET 1=2 WHERE t1.n=t2.n; +drop table t1,t2; +set timestamp=0; +set sql_safe_updates=0; +create table t1 (n int(10) not null primary key, d int(10)); +create table t2 (n int(10) not null primary key, d int(10)); +insert into t1 values(1,1), (3,3); +insert into t2 values(1,10),(2,20); +UPDATE t2 left outer join t1 on t1.n=t2.n SET t1.d=t2.d; +select * from t1; +select * from t2; +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(1,2); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1; +select * from t2; +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(3,2); +insert into t2 values(1,10),(1,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1; +select * from t2; +drop table t1,t2; diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 19af6b0c49c..2929184df93 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -2,14 +2,25 @@ # Test timestamp # -drop table if exists t1; -CREATE TABLE t1 ( t timestamp); +drop table if exists t1,t2; +CREATE TABLE t1 (a int, t timestamp); +CREATE TABLE t2 (a int, t datetime); SET TIMESTAMP=1234; -insert into t1 values(NULL); +insert into t1 values(1,NULL); +insert into t1 values(2,"2002-03-03"); +SET TIMESTAMP=1235; +insert into t1 values(3,NULL); +SET TIMESTAMP=1236; +insert into t1 (a) values(4); +insert into t2 values(5,"2002-03-04"),(6,NULL),(7,"2002-03-05"),(8,"00-00-00"); +SET TIMESTAMP=1237; +insert into t1 select * from t2; +SET TIMESTAMP=1238; +insert into t1 (a) select a+1 from t2 where a=8; select * from t1; -drop table t1; - +drop table t1,t2; +SET TIMESTAMP=1234; CREATE TABLE t1 (value TEXT NOT NULL, id VARCHAR(32) NOT NULL, stamp timestamp, PRIMARY KEY (id)); INSERT INTO t1 VALUES ("my value", "myKey","1999-04-02 00:00:00"); SELECT stamp FROM t1 WHERE id="myKey"; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a97bd8bac0a..89f0ac1885a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2744,7 +2744,7 @@ bool error_if_full_join(JOIN *join) tab < end; tab++) { - if (tab->type == JT_ALL && !tab->select->quick) + if (tab->type == JT_ALL && (!tab->select || !tab->select->quick)) { my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0)); return(1); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 12d0ee8d7a2..887d4e0acc0 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -832,7 +832,7 @@ bool multi_update::send_eof() Query_log_event qinfo(thd, thd->query, thd->query_length, log_delayed); if (mysql_bin_log.write(&qinfo) && trans_safe) - local_error=1; // Rollback update + local_error= 1; // Rollback update } if (!log_delayed) thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; @@ -840,7 +840,7 @@ bool multi_update::send_eof() if (transactional_tables) { - if (ha_autocommit_or_rollback(thd, local_error >= 0)) + if (ha_autocommit_or_rollback(thd, local_error != 0)) local_error=1; } From a3f9f721bca6d7d2dcd414fa295812995219ca86 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Dec 2002 10:47:15 +0200 Subject: [PATCH 23/46] Fixed bug in <=> NULL handling --- sql/opt_range.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0645fe15df3..b2128c3eb4a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1030,7 +1030,7 @@ get_mm_leaf(Field *field,KEY_PART *key_part, { /* convert column_name <=> NULL -> column_name IS NULL */ char *str= (char*) sql_alloc(1); // Get local copy of key - if (!*str) + if (!str) DBUG_RETURN(0); *str = 1; DBUG_RETURN(new SEL_ARG(field,str,str)); From e3cecfd10c8006c6a9dabbb149225adbf5ce4deb Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Dec 2002 13:41:08 +0200 Subject: [PATCH 24/46] Fixed bug in MAX() optimization when used with JOIN and ON expressions (Patch from 4.0.5) mysql-test/r/group_by.result: Updated results mysql-test/t/group_by.test: Test for bug sql/item_cmpfunc.cc: Fixed bug in MAX() optimization when used with JOIN and ON expressions sql/item_cmpfunc.h: Fixed bug in MAX() optimization when used with JOIN and ON expressions sql/opt_sum.cc: Fixed bug in MAX() optimization when used with JOIN and ON expressions --- mysql-test/r/group_by.result | 6 ++++++ mysql-test/t/group_by.test | 41 +++++++++++++++++++++++++++++++++++- sql/item_cmpfunc.cc | 39 ++++++++++++++++++++++++++++++++++ sql/item_cmpfunc.h | 2 ++ sql/opt_sum.cc | 13 ++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 200cbc29b08..df67f19d957 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -84,3 +84,9 @@ xID xID1 Level 2 2 ** 3 134 *** 4 185 **** +pid c1id c2id value id active id active +1 1 NULL 1 1 Yes NULL NULL +1 NULL 3 3 NULL NULL 3 Yes +1 4 NULL 4 4 Yes NULL NULL +max(value) +4 diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index dfbb2f325a9..fa32f2a6fa0 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -2,7 +2,7 @@ # Test of group (Failed for Lars Hoss ) # -drop table if exists t1,t2; +drop table if exists t1,t2,t3; CREATE TABLE t1 ( spID int(10) unsigned, userID int(10) unsigned, @@ -270,3 +270,42 @@ insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1; drop table t1; + +# +# Problem with MAX and LEFT JOIN +# + +CREATE TABLE t1 ( + pid int(11) unsigned NOT NULL default '0', + c1id int(11) unsigned default NULL, + c2id int(11) unsigned default NULL, + value int(11) unsigned NOT NULL default '0', + UNIQUE KEY pid2 (pid,c1id,c2id), + UNIQUE KEY pid (pid,value) +) TYPE=MyISAM; + +INSERT INTO t1 VALUES (1, 1, NULL, 1),(1, 2, NULL, 2),(1, NULL, 3, 3),(1, 4, NULL, 4),(1, 5, NULL, 5); + +CREATE TABLE t2 ( + id int(11) unsigned NOT NULL default '0', + active enum('Yes','No') NOT NULL default 'Yes', + PRIMARY KEY (id) +) TYPE=MyISAM; + +INSERT INTO t2 VALUES (1, 'Yes'),(2, 'No'),(4, 'Yes'),(5, 'No'); + +CREATE TABLE t3 ( + id int(11) unsigned NOT NULL default '0', + active enum('Yes','No') NOT NULL default 'Yes', + PRIMARY KEY (id) +); +INSERT INTO t3 VALUES (3, 'Yes'); + +select * from t1 AS m LEFT JOIN t2 AS c1 ON m.c1id = +c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id = c2.id AND +c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS NOT NULL); +select max(value) from t1 AS m LEFT JOIN t2 AS c1 ON +m.c1id = c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id = +c2.id AND c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS +NOT NULL); +drop table t1,t2,t3; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 36ecde337a7..c50a1bc088f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1207,6 +1207,45 @@ longlong Item_cond_or::val_int() return 0; } +/* + Create an AND expression from two expressions + + SYNOPSIS + and_expressions() + a expression or NULL + b expression. + org_item Don't modify a if a == *org_item + If a == NULL, org_item is set to point at b, + to ensure that future calls will not modify b. + + NOTES + This will not modify item pointed to by org_item or b + The idea is that one can call this in a loop and create and + 'and' over all items without modifying any of the original items. + + RETURN + NULL Error + Item +*/ + +Item *and_expressions(Item *a, Item *b, Item **org_item) +{ + if (!a) + return (*org_item= (Item*) b); + if (a == *org_item) + { + Item_cond *res; + if ((res= new Item_cond_and(a, (Item*) b))) + res->used_tables_cache= a->used_tables() | b->used_tables(); + return res; + } + if (((Item_cond_and*) a)->add((Item*) b)) + return 0; + ((Item_cond_and*) a)->used_tables_cache|= b->used_tables(); + return a; +} + + longlong Item_func_isnull::val_int() { /* diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index e7c598808e8..061376a7e2d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -573,3 +573,5 @@ inline Item *and_conds(Item *a,Item *b) cond->update_used_tables(); return cond; } + +Item *and_expressions(Item *a, Item *b, Item **org_item); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index df49d52d54a..b88cfb4e073 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -37,6 +37,19 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) bool recalc_const_item=0; table_map removed_tables=0; Item *item; + COND *org_conds= conds; + + /* Add all ON conditions to WHERE condition */ + for (TABLE_LIST *tl=tables; tl ; tl= tl->next) + { + if (tl->on_expr) + conds= and_expressions(conds, tl->on_expr, &org_conds); + } + + /* + Iterate through item is select part and replace COUNT(), MIN() and MAX() + with constants (if possible) + */ while ((item= it++)) { From 3e5d156223e50f003928f01d96e2f6c75b1240f4 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Dec 2002 14:16:02 +0200 Subject: [PATCH 25/46] Fix for sum_func IN (..) --- mysql-test/r/group_by.result | 5 +++++ mysql-test/t/group_by.test | 2 ++ sql/item_cmpfunc.cc | 6 +++++- sql/item_cmpfunc.h | 3 ++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index b557d90f312..7b104996769 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -47,6 +47,11 @@ userid count(*) 3 3 2 1 1 2 +userid count(*) +3 3 +1 2 +userid count(*) +3 3 table type possible_keys key key_len ref rows Extra t1 range spID spID 5 NULL 2 where used; Using index; Using temporary table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index e4b7d659a8e..c3e4f34b0fa 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -235,6 +235,8 @@ CREATE TABLE t1 ( INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3); explain select userid,count(*) from t1 group by userid desc; select userid,count(*) from t1 group by userid desc; +select userid,count(*) from t1 group by userid desc having (count(*)+1) IN (4,3); +select userid,count(*) from t1 group by userid desc having 3 IN (1,COUNT(*)); explain select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; explain select spid,count(*) from t1 where spid between 1 and 2 group by spid; select spid,count(*) from t1 where spid between 1 and 2 group by spid; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 4ef77d0c509..b53d596da08 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1029,13 +1029,17 @@ void Item_func_in::update_used_tables() used_tables_cache|=item->used_tables(); const_item_cache&=item->const_item(); } + void Item_func_in::split_sum_func(List &fields) { - if (item->used_tables() || item->type() == SUM_FUNC_ITEM) + if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) + item->split_sum_func(fields); + else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) { fields.push_front(item); item=new Item_ref((Item**) fields.head_ref(),0,item->name); } + Item_func::split_sum_func(fields); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 72d4e06e39c..7827cf9a78b 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -410,8 +410,9 @@ class Item_func_in :public Item_int_func longlong val_int(); bool fix_fields(THD *thd,struct st_table_list *tlist) { + bool res= (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); with_sum_func= with_sum_func || item->with_sum_func; - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return res; } void fix_length_and_dec(); ~Item_func_in() { delete item; delete array; delete in_item; } From 0df9ecc32b7c8bfadc4f923ddef4f298b94429ce Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Dec 2002 15:12:56 +0200 Subject: [PATCH 26/46] moving fix elsewhere ... sql/sql_show.cc: moving a fix to 4.1. --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 028d6b055ff..a8567112fe9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1145,7 +1145,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) switch (variables[i].type){ case SHOW_LONG: case SHOW_LONG_CONST: - net_store_data(&packet2,(longlong) *(ulong*) variables[i].value); + net_store_data(&packet2,(int32) *(ulong*) variables[i].value); break; case SHOW_BOOL: net_store_data(&packet2,(ulong) *(bool*) variables[i].value ? From 007b739f3fcd81543b37d06a9b9b1831c5a98512 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Dec 2002 15:33:16 +0200 Subject: [PATCH 27/46] Proper fix for SHOW VARS on 64-bit systems --- sql/mysqld.cc | 2 +- sql/sql_show.cc | 5 ++++- sql/structs.h | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f67fa8afd8c..6aa41f9f800 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3110,7 +3110,7 @@ struct show_var_st init_vars[]= { #endif {"interactive_timeout", (char*) &net_interactive_timeout, SHOW_LONG}, {"join_buffer_size", (char*) &join_buff_size, SHOW_LONG}, - {"key_buffer_size", (char*) &keybuff_size, SHOW_LONG}, + {"key_buffer_size", (char*) &keybuff_size, SHOW_LONG_AS_LONGLONG}, {"language", language, SHOW_CHAR}, {"large_files_support", (char*) &opt_large_files, SHOW_BOOL}, #ifdef HAVE_MLOCKALL diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a8567112fe9..12979f77e56 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1145,7 +1145,10 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) switch (variables[i].type){ case SHOW_LONG: case SHOW_LONG_CONST: - net_store_data(&packet2,(int32) *(ulong*) variables[i].value); + net_store_data(&packet2,(uint32) *(ulong*) variables[i].value); + break; + case SHOW_LONG_AS_LONGLONG: + net_store_data(&packet2,(longlong) *(ulong*) variables[i].value); break; case SHOW_BOOL: net_store_data(&packet2,(ulong) *(bool*) variables[i].value ? diff --git a/sql/structs.h b/sql/structs.h index 36f503312c0..90924b842d6 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -125,7 +125,7 @@ typedef struct { enum SHOW_TYPE { SHOW_LONG,SHOW_CHAR,SHOW_INT,SHOW_CHAR_PTR,SHOW_BOOL, SHOW_MY_BOOL,SHOW_OPENTABLES,SHOW_STARTTIME,SHOW_QUESTION, - SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE}; + SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_LONG_AS_LONGLONG}; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; From 80b143c111fc3df20e3fe2dcfe4880c30b001498 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Dec 2002 13:08:25 +0200 Subject: [PATCH 28/46] Change of internal key_field=NULL handling to avoid error messages. Optimized SELECT DISTINCT ... ORDER BY ... LIMIT Fixed reference to uninitalized variable mysql-test/r/distinct.result: Updated results for new tests mysql-test/r/func_math.result: Fixed test of RND() mysql-test/r/innodb.result: Updated results for new tests mysql-test/r/null.result: Updated results for new tests mysql-test/t/distinct.test: New distinct test mysql-test/t/func_math.test: Fixed test of RND() mysql-test/t/innodb.test: Test for bugs mysql-test/t/null.test: TEst for bugs sql/field.h: Change of NULL handling to avoid error messages sql/field_conv.cc: Change of NULL handling to avoid error messages sql/item.cc: Change of NULL handling to avoid error messages sql/item.h: Change of NULL handling to avoid error messages sql/item_cmpfunc.cc: Change of NULL handling to avoid error messages sql/item_func.cc: Change of NULL handling to avoid error messages sql/item_func.h: Cleaned up RND() handling sql/item_timefunc.cc: Change of NULL handling to avoid error messages sql/item_timefunc.h: Change of NULL handling to avoid error messages sql/opt_range.cc: Fixed bug in <=> NULL sql/password.c: Indentation cleanup sql/sql_base.cc: Change of NULL handling to avoid error messages sql/sql_class.cc: Fixed reference to uninitalized variable sql/sql_handler.cc: Change of NULL handling to avoid error messages sql/sql_select.cc: Change of NULL handling to avoid error messages Optimized SELECT DISTINCT ... ORDER BY ... LIMIT sql/sql_select.h: Change of NULL handling to avoid error messages sql/unireg.cc: Change of NULL handling to avoid error messages --- mysql-test/r/distinct.result | 24 +++++++ mysql-test/r/func_math.result | 3 +- mysql-test/r/innodb.result | 22 ++++++ mysql-test/r/null.result | 19 ++++- mysql-test/t/distinct.test | 10 +++ mysql-test/t/func_math.test | 1 + mysql-test/t/innodb.test | 23 ++++++ mysql-test/t/null.test | 14 ++++ sql/field.h | 2 +- sql/field_conv.cc | 24 ++++++- sql/item.cc | 29 ++++---- sql/item.h | 27 +++---- sql/item_cmpfunc.cc | 18 ++++- sql/item_func.cc | 25 ++++--- sql/item_func.h | 4 +- sql/item_timefunc.cc | 4 +- sql/item_timefunc.h | 4 +- sql/opt_range.cc | 6 +- sql/password.c | 2 +- sql/sql_base.cc | 4 +- sql/sql_class.cc | 17 +++-- sql/sql_handler.cc | 4 +- sql/sql_select.cc | 128 +++++++++++++++++++++++----------- sql/sql_select.h | 18 ++--- sql/unireg.cc | 2 +- 25 files changed, 315 insertions(+), 119 deletions(-) diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 10a00995c9e..020d6c6534f 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -198,6 +198,30 @@ a select distinct 1 from t1,t3 where t1.a=t3.a; 1 1 +explain SELECT distinct t1.a from t1; +table type possible_keys key key_len ref rows Extra +t1 index NULL PRIMARY 4 NULL 2 Using index +explain SELECT distinct t1.a from t1 order by a desc; +table type possible_keys key key_len ref rows Extra +t1 index NULL PRIMARY 4 NULL 2 Using index +explain SELECT t1.a from t1 group by a order by a desc; +table type possible_keys key key_len ref rows Extra +t1 index NULL PRIMARY 4 NULL 2 Using index +explain SELECT distinct t1.a from t1 order by a desc limit 1; +table type possible_keys key key_len ref rows Extra +t1 index NULL PRIMARY 4 NULL 2 Using index +explain SELECT distinct a from t3 order by a desc limit 2; +table type possible_keys key key_len ref rows Extra +t3 index NULL a 5 NULL 204 Using index +explain SELECT distinct a,b from t3 order by a+1; +table type possible_keys key key_len ref rows Extra +t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort +explain SELECT distinct a,b from t3 order by a limit 10; +table type possible_keys key key_len ref rows Extra +t3 index NULL a 5 NULL 204 Using temporary +explain SELECT a,b from t3 group by a,b order by a+1; +table type possible_keys key key_len ref rows Extra +t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort drop table t1,t2,t3,t4; CREATE TABLE t1 (name varchar(255)); INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae'); diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index f1c0de2f88a..811a16fff6c 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -31,9 +31,10 @@ log10(100) log10(18) log10(-4) log10(0) log10(NULL) select pow(10,log10(10)),power(2,4); pow(10,log10(10)) power(2,4) 10.000000 16.000000 +set @@rand_seed1=10000000,@@rand_seed2=1000000; select rand(999999),rand(); rand(999999) rand() -0.014231365187309 0.8078568166195 +0.014231365187309 0.028870999839968 select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1); PI() sin(pi()/2) cos(pi()/2) abs(tan(pi())) cot(1) asin(1) acos(0) atan(1) 3.141593 1.000000 0.000000 0.000000 0.64209262 1.570796 1.570796 0.785398 diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 1e136acb21d..9d50a6a86e9 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1036,3 +1036,25 @@ n d 1 30 2 20 drop table t1,t2; +create table t1 (a int, b int) type=innodb; +insert into t1 values(20,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a; +b ifnull(t2.b,"this is null") +NULL this is null +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +b ifnull(t2.b,"this is null") +NULL this is null +insert into t1 values(10,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +b ifnull(t2.b,"this is null") +NULL this is null +NULL this is null +drop table t1; +create table t1 (a varchar(10) not null) type=myisam; +create table t2 (b varchar(10) not null unique) type=innodb; +select t1.a from t1,t2 where t1.a=t2.b; +a +drop table t1,t2; diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 07724a56025..cdea66cbf58 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -6,7 +6,7 @@ select 1 | NULL,1 & NULL,1+NULL,1-NULL; NULL NULL NULL NULL select NULL=NULL,NULL<>NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0; NULL=NULL NULL<>NULL IFNULL(NULL,1.1)+0 IFNULL(NULL,1) | 0 -NULL NULL 1.1 1 +NULL NULL 1 1 select strcmp("a",NULL),(1NULL; DROP TABLE t1; + +# +# Testing of IFNULL +# +create table t1 (a int, b int) type=myisam; +insert into t1 values(20,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a; +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +insert into t1 values(10,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +drop table t1; diff --git a/sql/field.h b/sql/field.h index ba28a6a872e..f064724f6a2 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1058,7 +1058,7 @@ Field *make_field(char *ptr, uint32 field_length, uint pack_length_to_packflag(uint type); uint32 calc_pack_length(enum_field_types type,uint32 length); bool set_field_to_null(Field *field); -bool set_field_to_null_with_conversions(Field *field); +bool set_field_to_null_with_conversions(Field *field, bool no_conversions); uint find_enum(TYPELIB *typelib,const char *x, uint length); ulonglong find_set(TYPELIB *typelib,const char *x, uint length); bool test_if_int(const char *str,int length); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 53b26920c14..ffc93f3e871 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -122,8 +122,26 @@ set_field_to_null(Field *field) } +/* + Set field to NULL or TIMESTAMP or to next auto_increment number + + SYNOPSIS + set_field_to_null_with_conversions() + field Field to update + no_conversion Set to 1 if we should return 1 if field can't + take null values. + If set to 0 we will do store the 'default value' + if the field is a special field. If not we will + give an error. + + RETURN VALUES + 0 Field could take 0 or an automatic conversion was used + 1 Field could not take NULL and no conversion was used. + If no_conversion was not set, an error message is printed +*/ + bool -set_field_to_null_with_conversions(Field *field) +set_field_to_null_with_conversions(Field *field, bool no_conversions) { if (field->real_maybe_null()) { @@ -131,6 +149,8 @@ set_field_to_null_with_conversions(Field *field) field->reset(); return 0; } + if (no_conversions) + return 1; /* Check if this is a special type, which will get a special walue @@ -156,8 +176,6 @@ set_field_to_null_with_conversions(Field *field) } - - static void do_skip(Copy_field *copy __attribute__((unused))) { } diff --git a/sql/item.cc b/sql/item.cc index b3b4e99e28a..ec9b07c443c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -419,7 +419,7 @@ void Item_field::save_org_in_field(Field *to) if (field->is_null()) { null_value=1; - set_field_to_null_with_conversions(to); + set_field_to_null_with_conversions(to, 1); } else { @@ -429,12 +429,12 @@ void Item_field::save_org_in_field(Field *to) } } -bool Item_field::save_in_field(Field *to) +bool Item_field::save_in_field(Field *to, bool no_conversions) { if (result_field->is_null()) { null_value=1; - return set_field_to_null_with_conversions(to); + return set_field_to_null_with_conversions(to, no_conversions); } else { @@ -461,9 +461,9 @@ bool Item_field::save_in_field(Field *to) 1 Field doesn't support NULL values and can't handle 'field = NULL' */ -bool Item_null::save_in_field(Field *field) +bool Item_null::save_in_field(Field *field, bool no_conversions) { - return set_field_to_null_with_conversions(field); + return set_field_to_null_with_conversions(field, no_conversions); } @@ -485,7 +485,7 @@ bool Item_null::save_safe_in_field(Field *field) } -bool Item::save_in_field(Field *field) +bool Item::save_in_field(Field *field, bool no_conversions) { if (result_type() == STRING_RESULT || result_type() == REAL_RESULT && @@ -496,7 +496,7 @@ bool Item::save_in_field(Field *field) str_value.set_quick(buff,sizeof(buff)); result=val_str(&str_value); if (null_value) - return set_field_to_null_with_conversions(field); + return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); field->store(result->ptr(),result->length()); str_value.set_quick(0, 0); @@ -513,7 +513,7 @@ bool Item::save_in_field(Field *field) { longlong nr=val_int(); if (null_value) - return set_field_to_null_with_conversions(field); + return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); field->store(nr); } @@ -521,7 +521,7 @@ bool Item::save_in_field(Field *field) } -bool Item_string::save_in_field(Field *field) +bool Item_string::save_in_field(Field *field, bool no_conversions) { String *result; result=val_str(&str_value); @@ -532,7 +532,7 @@ bool Item_string::save_in_field(Field *field) return 0; } -bool Item_int::save_in_field(Field *field) +bool Item_int::save_in_field(Field *field, bool no_conversions) { longlong nr=val_int(); if (null_value) @@ -542,7 +542,7 @@ bool Item_int::save_in_field(Field *field) return 0; } -bool Item_real::save_in_field(Field *field) +bool Item_real::save_in_field(Field *field, bool no_conversions) { double nr=val(); if (null_value) @@ -597,7 +597,7 @@ longlong Item_varbinary::val_int() } -bool Item_varbinary::save_in_field(Field *field) +bool Item_varbinary::save_in_field(Field *field, bool no_conversions) { field->set_notnull(); if (field->result_type() == STRING_RESULT) @@ -658,9 +658,10 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables) return 0; } + /* -** If item is a const function, calculate it and return a const item -** The original item is freed if not returned + If item is a const function, calculate it and return a const item + The original item is freed if not returned */ Item_result item_cmp_type(Item_result a,Item_result b) diff --git a/sql/item.h b/sql/item.h index 563db2291fb..ad68287a92c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -53,11 +53,11 @@ public: void set_name(char* str,uint length=0); void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual bool fix_fields(THD *,struct st_table_list *); - virtual bool save_in_field(Field *field); + virtual bool save_in_field(Field *field, bool no_conversions); virtual void save_org_in_field(Field *field) - { (void) save_in_field(field); } + { (void) save_in_field(field, 1); } virtual bool save_safe_in_field(Field *field) - { return save_in_field(field); } + { return save_in_field(field, 1); } virtual bool send(THD *thd, String *str); virtual bool eq(const Item *, bool binary_cmp) const; virtual Item_result result_type () const { return REAL_RESULT; } @@ -130,7 +130,7 @@ public: } void make_field(Send_field *field); bool fix_fields(THD *,struct st_table_list *); - bool save_in_field(Field *field); + bool save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field); table_map used_tables() const; enum Item_result result_type () const @@ -156,7 +156,7 @@ public: longlong val_int(); String *val_str(String *str); void make_field(Send_field *field); - bool save_in_field(Field *field); + bool save_in_field(Field *field, bool no_conversions); bool save_safe_in_field(Field *field); enum Item_result result_type () const { return STRING_RESULT; } @@ -190,7 +190,7 @@ public: double val() { return (double) value; } String *val_str(String*); void make_field(Send_field *field); - bool save_in_field(Field *field); + bool save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_int(name,value,max_length); } void print(String *str); @@ -232,7 +232,7 @@ public: max_length=length; } Item_real(double value_par) :value(value_par) {} - bool save_in_field(Field *field); + bool save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));} @@ -277,7 +277,7 @@ public: double val() { return atof(str_value.ptr()); } longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); } String *val_str(String*) { return (String*) &str_value; } - bool save_in_field(Field *field); + bool save_in_field(Field *field, bool no_conversions); void make_field(Send_field *field); enum Item_result result_type () const { return STRING_RESULT; } bool basic_const_item() const { return 1; } @@ -298,7 +298,7 @@ public: Item_default() { name= (char*) "DEFAULT"; } enum Type type() const { return DEFAULT_ITEM; } void make_field(Send_field *field) {} - bool save_in_field(Field *field) + bool save_in_field(Field *field, bool no_conversions) { field->set_default(); return 0; @@ -339,7 +339,7 @@ public: double val() { return (double) Item_varbinary::val_int(); } longlong val_int(); String *val_str(String*) { return &str_value; } - bool save_in_field(Field *field); + bool save_in_field(Field *field, bool no_conversions); void make_field(Send_field *field); enum Item_result result_type () const { return INT_RESULT; } unsigned int size_of() { return sizeof(*this);} @@ -401,7 +401,8 @@ public: bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); } void make_field(Send_field *field) { (*ref)->make_field(field); } bool fix_fields(THD *,struct st_table_list *); - bool save_in_field(Field *field) { return (*ref)->save_in_field(field); } + bool save_in_field(Field *field, bool no_conversions) + { return (*ref)->save_in_field(field, no_conversions); } void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } table_map used_tables() const { return (*ref)->used_tables(); } @@ -421,9 +422,9 @@ class Item_int_with_ref :public Item_int public: Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg) {} - bool save_in_field(Field *field) + bool save_in_field(Field *field, bool no_conversions) { - return ref->save_in_field(field); + return ref->save_in_field(field, no_conversions); } unsigned int size_of() { return sizeof(*this);} }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index b5f21c8772e..0dc1e91d372 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -48,7 +48,7 @@ static bool convert_constant_item(Field *field, Item **item) { if ((*item)->const_item() && (*item)->type() != Item::INT_ITEM) { - if (!(*item)->save_in_field(field) && + if (!(*item)->save_in_field(field, 1) && !((*item)->null_value)) { Item *tmp=new Item_int_with_ref(field->val_int(), *item); @@ -444,15 +444,29 @@ longlong Item_func_between::val_int() return 0; } +static Item_result item_store_type(Item_result a,Item_result b) +{ + if (a == STRING_RESULT || b == STRING_RESULT) + return STRING_RESULT; + else if (a == REAL_RESULT || b == REAL_RESULT) + return REAL_RESULT; + else + return INT_RESULT; +} + void Item_func_ifnull::fix_length_and_dec() { maybe_null=args[1]->maybe_null; max_length=max(args[0]->max_length,args[1]->max_length); decimals=max(args[0]->decimals,args[1]->decimals); - cached_result_type=args[0]->result_type(); + if ((cached_result_type=item_store_type(args[0]->result_type(), + args[1]->result_type())) != + REAL_RESULT) + decimals= 0; } + double Item_func_ifnull::val() { diff --git a/sql/item_func.cc b/sql/item_func.cc index 5721a2f5e8c..c3b1190a4b6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -696,21 +696,20 @@ double Item_func_round::val() } -double Item_func_rand::val() +void Item_func_rand::fix_length_and_dec() { - THD* thd = current_thd; + decimals=NOT_FIXED_DEC; + max_length=float_length(decimals); if (arg_count) { // Only use argument once in query uint32 tmp= (uint32) (args[0]->val_int()); - randominit(&thd->rand,(uint32) (tmp*0x10001L+55555555L), - (uint32) (tmp*0x10000001L)); -#ifdef DELETE_ITEMS - delete args[0]; -#endif - arg_count=0; + if ((rand= (struct rand_struct*) sql_alloc(sizeof(*rand)))) + randominit(rand,(uint32) (tmp*0x10001L+55555555L), + (uint32) (tmp*0x10000001L)); } - else if (!thd->rand_used) + else { + THD *thd= current_thd; /* No need to send a Rand log event if seed was given eg: RAND(seed), as it will be replicated in the query as such. @@ -722,8 +721,14 @@ double Item_func_rand::val() thd->rand_used=1; thd->rand_saved_seed1=thd->rand.seed1; thd->rand_saved_seed2=thd->rand.seed2; + rand= &thd->rand; } - return rnd(&thd->rand); +} + + +double Item_func_rand::val() +{ + return rnd(rand); } longlong Item_func_sign::val_int() diff --git a/sql/item_func.h b/sql/item_func.h index b7e0cee540a..501dcdadc3f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -459,20 +459,20 @@ public: const char *func_name() const { return truncate ? "truncate" : "round"; } double val(); void fix_length_and_dec(); - unsigned int size_of() { return sizeof(*this);} }; class Item_func_rand :public Item_real_func { + struct rand_struct *rand; public: Item_func_rand(Item *a) :Item_real_func(a) {} Item_func_rand() :Item_real_func() {} double val(); const char *func_name() const { return "rand"; } - void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); } bool const_item() const { return 0; } table_map used_tables() const { return RAND_TABLE_BIT; } + void fix_length_and_dec(); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ccbba3777c4..6a95c15a226 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -403,7 +403,7 @@ String *Item_date::val_str(String *str) } -bool Item_date::save_in_field(Field *field) +bool Item_date::save_in_field(Field *field, bool no_conversions) { TIME ltime; timestamp_type t_type=TIMESTAMP_FULL; @@ -518,7 +518,7 @@ bool Item_func_now::get_date(TIME *res, } -bool Item_func_now::save_in_field(Field *to) +bool Item_func_now::save_in_field(Field *to, bool no_conversions) { to->set_notnull(); to->store_time(<ime,TIMESTAMP_FULL); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index c0255e71d27..0ca2a36609d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -231,7 +231,7 @@ public: double val() { return (double) val_int(); } const char *func_name() const { return "date"; } void fix_length_and_dec() { decimals=0; max_length=10; } - bool save_in_field(Field *to); + bool save_in_field(Field *to, bool no_conversions); void make_field(Send_field *tmp_field) { init_make_field(tmp_field,FIELD_TYPE_DATE); @@ -316,7 +316,7 @@ public: enum Item_result result_type () const { return STRING_RESULT; } double val() { return (double) value; } longlong val_int() { return value; } - bool save_in_field(Field *to); + bool save_in_field(Field *to, bool no_conversions); String *val_str(String *str) { str_value.set(buff,buff_length); return &str_value; } const char *func_name() const { return "now"; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d1f99604959..a18c0178b5d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1029,7 +1029,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, field->cmp_type() != value->result_type()) DBUG_RETURN(0); - if (value->save_in_field(field)) + if (value->save_in_field(field, 1)) { /* This happens when we try to insert a NULL field in a not null column */ // TODO; Check if we can we remove the following block. @@ -1038,9 +1038,9 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, /* convert column_name <=> NULL -> column_name IS NULL */ // Get local copy of key char *str= (char*) alloc_root(param->mem_root,1); - if (!*str) + if (!str) DBUG_RETURN(0); - *str = 1; + *str= 1; DBUG_RETURN(new SEL_ARG(field,str,str)); } DBUG_RETURN(&null_element); // cmp with NULL is never true diff --git a/sql/password.c b/sql/password.c index 48181ea18e6..318c8e84db3 100644 --- a/sql/password.c +++ b/sql/password.c @@ -43,7 +43,7 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2) { /* For mysql 3.21.# */ #ifdef HAVE_purify - bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ + bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ #endif rand_st->max_value= 0x3FFFFFFFL; rand_st->max_value_dbl=(double) rand_st->max_value; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 043ce44c140..7b7c8c01aab 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2098,7 +2098,7 @@ fill_record(List &fields,List &values) while ((field=(Item_field*) f++)) { value=v++; - if (value->save_in_field(field->field)) + if (value->save_in_field(field->field, 0)) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -2116,7 +2116,7 @@ fill_record(Field **ptr,List &values) while ((field = *ptr++)) { value=v++; - if (value->save_in_field(field)) + if (value->save_in_field(field, 0)) DBUG_RETURN(1); } DBUG_RETURN(0); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a5f14a507f7..8b276cf0d9b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -158,9 +158,8 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), { pthread_mutex_lock(&LOCK_thread_count); ulong tmp=(ulong) (rnd(&sql_rand) * 3000000); - randominit(&rand, tmp + (ulong) start_time, - tmp + (ulong) thread_id); pthread_mutex_unlock(&LOCK_thread_count); + randominit(&rand, tmp + (ulong) start_time, tmp + (ulong) thread_id); } } @@ -171,16 +170,16 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), void THD::init(void) { - server_status= SERVER_STATUS_AUTOCOMMIT; - update_lock_default= (variables.low_priority_updates ? - TL_WRITE_LOW_PRIORITY : - TL_WRITE); - options= thd_startup_options; - sql_mode=(uint) opt_sql_mode; - open_options=ha_open_options; pthread_mutex_lock(&LOCK_global_system_variables); variables= global_system_variables; pthread_mutex_unlock(&LOCK_global_system_variables); + server_status= SERVER_STATUS_AUTOCOMMIT; + options= thd_startup_options; + sql_mode=(uint) opt_sql_mode; + open_options=ha_open_options; + update_lock_default= (variables.low_priority_updates ? + TL_WRITE_LOW_PRIORITY : + TL_WRITE); session_tx_isolation= (enum_tx_isolation) variables.tx_isolation; } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index ea02c46c0f4..289d2434225 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -180,10 +180,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, Item *item; for (key_len=0 ; (item=it_ke++) ; key_part++) { - item->save_in_field(key_part->field); + item->save_in_field(key_part->field, 1); key_len+=key_part->store_length; } - if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len)))) + if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len)))) { send_error(&thd->net,ER_OUTOFMEMORY); goto err; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 89f0ac1885a..eaa291f4d90 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -130,7 +130,9 @@ static int setup_group(THD *thd,TABLE_LIST *tables,List &fields, List &all_fields, ORDER *order, bool *hidden); static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List &fields, List &all_fields,ORDER *new_order); -static ORDER *create_distinct_group(ORDER *order, List &fields); +static ORDER *create_distinct_group(THD *thd, ORDER *order, + List &fields, + bool *all_order_by_fields_used); static bool test_if_subpart(ORDER *a,ORDER *b); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); static void calc_group_buffer(JOIN *join,ORDER *group); @@ -228,6 +230,10 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, bzero((char*) &keyuse,sizeof(keyuse)); thd->proc_info="init"; thd->used_tables=0; // Updated by setup_fields + /* select_limit is used to decide if we are likely to scan the whole table */ + select_limit= thd->select_limit; + if (having || (select_options & OPTION_FOUND_ROWS)) + select_limit= HA_POS_ERROR; if (setup_tables(tables) || setup_fields(thd,tables,fields,1,&all_fields,1) || @@ -436,6 +442,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, thd->proc_info="statistics"; if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error) goto err; + thd->proc_info="preparing"; if (result->initialize_tables(&join)) goto err; @@ -444,7 +451,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, { error=return_zero_rows(&join,result,tables,fields, join.tmp_table_param.sum_func_count != 0 && - !group,0,"",having,procedure); + !group,0,"no matching row in const table",having, + procedure); goto err; } if (!(thd->options & OPTION_BIG_SELECTS) && @@ -504,21 +512,47 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, if (! hidden_group_fields) select_distinct=0; } - else if (select_distinct && join.tables - join.const_tables == 1 && - (thd->select_limit == HA_POS_ERROR || - (join.select_options & OPTION_FOUND_ROWS) || - order && - !(skip_sort_order= - test_if_skip_sort_order(&join.join_tab[join.const_tables], - order, thd->select_limit,1)))) + else if (select_distinct && join.tables - join.const_tables == 1) { - if ((group=create_distinct_group(order,fields))) + /* + We are only using one table. In this case we change DISTINCT to a + GROUP BY query if: + - The GROUP BY can be done through indexes (no sort) and the ORDER + BY only uses selected fields. + (In this case we can later optimize away GROUP BY and ORDER BY) + - We are scanning the whole table without LIMIT + This can happen if: + - We are using CALC_FOUND_ROWS + - We are using an ORDER BY that can't be optimized away. + + We don't want to use this optimization when we are using LIMIT + because in this case we can just create a temporary table that + holds LIMIT rows and stop when this table is full. + */ + JOIN_TAB *tab= &join.join_tab[join.const_tables]; + bool all_order_fields_used; + if (order) + skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); + if ((group=create_distinct_group(thd, order, fields, + &all_order_fields_used))) { - select_distinct=0; - no_order= !order; - join.group=1; // For end_write_group - } - else if (thd->fatal_error) // End of memory + bool skip_group= (skip_sort_order && + test_if_skip_sort_order(tab, group, select_limit, + 1) != 0); + if ((skip_group && all_order_fields_used) || + select_limit == HA_POS_ERROR || + (order && !skip_sort_order)) + { + /* Change DISTINCT to GROUP BY */ + select_distinct= 0; + no_order= !order; + if (all_order_fields_used) + order=0; + join.group=1; // For end_write_group + } + else + group= 0; + } else if (thd->fatal_error) // End of memory goto err; } group=remove_const(&join,group,conds,&simple_group); @@ -622,10 +656,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, order=group; if (order && (join.const_tables == join.tables || - (simple_order && + ((simple_order || skip_sort_order) && test_if_skip_sort_order(&join.join_tab[join.const_tables], order, - (join.select_options & OPTION_FOUND_ROWS) ? - HA_POS_ERROR : thd->select_limit,0)))) + select_limit, 0)))) order=0; select_describe(&join,need_tmp, order != 0 && !skip_sort_order, @@ -653,7 +686,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, group ? 0 : select_distinct, group && simple_group, (order == 0 || skip_sort_order) && - !(join.select_options & OPTION_FOUND_ROWS), + select_limit != HA_POS_ERROR, join.select_options))) goto err; /* purecov: inspected */ @@ -706,9 +739,10 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ if (order && skip_sort_order) { - (void) test_if_skip_sort_order(&join.join_tab[join.const_tables], - order, thd->select_limit,0); - order=0; + /* Should always succeed */ + if (test_if_skip_sort_order(&join.join_tab[join.const_tables], + order, thd->select_limit,0)) + order=0; } } @@ -877,8 +911,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, DBUG_EXECUTE("where",print_where(conds,"having after sort");); } } - select_limit= thd->select_limit; - if (having || group || (join.select_options & OPTION_FOUND_ROWS)) + if (group) select_limit= HA_POS_ERROR; else { @@ -953,13 +986,21 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table, } +/* + Calculate the best possible join and initialize the join structure + + RETURN VALUES + 0 ok + 1 Fatal error +*/ + static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, DYNAMIC_ARRAY *keyuse_array) { int error; uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part; - table_map const_table_map,found_const_table_map,all_table_map; + table_map found_const_table_map,all_table_map; TABLE **table_vector; JOIN_TAB *stat,*stat_end,*s,**stat_ref; SQL_SELECT *select; @@ -979,7 +1020,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, join->best_ref=stat_vector; stat_end=stat+table_count; - const_table_map=found_const_table_map=all_table_map=0; + found_const_table_map=all_table_map=0; const_count=0; for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++) @@ -1070,7 +1111,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, DBUG_RETURN(1); /* Read tables with 0 or 1 rows (system tables) */ - join->const_table_map=const_table_map; + join->const_table_map= 0; for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count; p_pos < p_end ; @@ -1107,16 +1148,16 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, if (s->dependent) // If dependent on some table { // All dep. must be constants - if (s->dependent & ~(join->const_table_map)) + if (s->dependent & ~(found_const_table_map)) continue; if (table->file->records <= 1L && !(table->file->table_flags() & HA_NOT_EXACT_COUNT)) { // system table - int tmp; + int tmp= 0; s->type=JT_SYSTEM; join->const_table_map|=table->map; set_position(join,const_count++,s,(KEYUSE*) 0); - if ((tmp=join_read_const_table(s,join->positions+const_count-1))) + if ((tmp= join_read_const_table(s,join->positions+const_count-1))) { if (tmp > 0) DBUG_RETURN(1); // Fatal error @@ -1141,7 +1182,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, { if (keyuse->val->type() != Item::NULL_ITEM) { - if (!((~join->const_table_map) & keyuse->used_tables)) + if (!((~found_const_table_map) & keyuse->used_tables)) const_ref|= (key_map) 1 << keyuse->keypart; else refs|=keyuse->used_tables; @@ -1162,7 +1203,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, join->const_table_map|=table->map; set_position(join,const_count++,s,start_keyuse); if (create_ref_for_key(join, s, start_keyuse, - join->const_table_map)) + found_const_table_map)) DBUG_RETURN(1); if ((tmp=join_read_const_table(s, join->positions+const_count-1))) @@ -1210,8 +1251,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, { ha_rows records; if (!select) - select=make_select(s->table, join->const_table_map, - join->const_table_map, + select=make_select(s->table, found_const_table_map, + found_const_table_map, and_conds(conds,s->on_expr),&error); records=get_quick_record_count(select,s->table, s->const_keys, join->row_limit); @@ -2373,12 +2414,13 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, bool store_val_in_field(Field *field,Item *item) { + bool error; THD *thd=current_thd; ha_rows cuted_fields=thd->cuted_fields; thd->count_cuted_fields=1; - item->save_in_field(field); + error= item->save_in_field(field, 1); thd->count_cuted_fields=0; - return cuted_fields != thd->cuted_fields; + return error || cuted_fields != thd->cuted_fields; } @@ -6577,12 +6619,14 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List &fields, */ static ORDER * -create_distinct_group(ORDER *order_list,List &fields) +create_distinct_group(THD *thd, ORDER *order_list, List &fields, + bool *all_order_by_fields_used) { List_iterator li(fields); Item *item; ORDER *order,*group,**prev; + *all_order_by_fields_used= 1; while ((item=li++)) item->marker=0; /* Marker that field is not used */ @@ -6591,13 +6635,15 @@ create_distinct_group(ORDER *order_list,List &fields) { if (order->in_field_list) { - ORDER *ord=(ORDER*) sql_memdup(order,sizeof(ORDER)); + ORDER *ord=(ORDER*) thd->memdup((char*) order,sizeof(ORDER)); if (!ord) return 0; *prev=ord; prev= &ord->next; (*ord->item)->marker=1; } + else + *all_order_by_fields_used= 0; } li.rewind(); @@ -6607,7 +6653,7 @@ create_distinct_group(ORDER *order_list,List &fields) continue; if (!item->marker) { - ORDER *ord=(ORDER*) sql_calloc(sizeof(ORDER)); + ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); if (!ord) return 0; ord->item=li.ref(); @@ -7059,7 +7105,7 @@ copy_sum_funcs(Item_sum **func_ptr) { Item_sum *func; for (; (func = *func_ptr) ; func_ptr++) - (void) func->save_in_field(func->result_field); + (void) func->save_in_field(func->result_field, 1); return; } @@ -7090,7 +7136,7 @@ copy_funcs(Item_result_field **func_ptr) { Item_result_field *func; for (; (func = *func_ptr) ; func_ptr++) - (void) func->save_in_field(func->result_field); + (void) func->save_in_field(func->result_field, 1); return; } diff --git a/sql/sql_select.h b/sql/sql_select.h index a90b2fe3582..d0e10f75727 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -247,12 +247,12 @@ class store_key_field: public store_key copy_field.set(to_field,from_field,0); } } - bool copy() - { - copy_field.do_copy(©_field); - return err != 0; - } - const char *name() const { return field_name; } + bool copy() + { + copy_field.do_copy(©_field); + return err != 0; + } + const char *name() const { return field_name; } }; @@ -269,8 +269,7 @@ public: {} bool copy() { - item->save_in_field(to_field); - return err != 0; + return item->save_in_field(to_field, 1) || err != 0; } const char *name() const { return "func"; } }; @@ -293,7 +292,8 @@ public: if (!inited) { inited=1; - item->save_in_field(to_field); + if (item->save_in_field(to_field, 1)) + err= 1; } return err != 0; } diff --git a/sql/unireg.cc b/sql/unireg.cc index cc8440da1e4..5183f471fa2 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -574,7 +574,7 @@ static bool make_empty_rec(File file,enum db_type table_type, if (field->def && (regfield->real_type() != FIELD_TYPE_YEAR || field->def->val_int() != 0)) - field->def->save_in_field(regfield); + field->def->save_in_field(regfield, 1); else if (regfield->real_type() == FIELD_TYPE_ENUM && (field->flags & NOT_NULL_FLAG)) { From 9b515ad043bd06015ab626e04c56fdf52ffcade2 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Dec 2002 18:16:48 +0200 Subject: [PATCH 29/46] row0sel.c: Fix a hang introduced in 4.0.5 in INSERT INTO ... SELECT ... when binlogging is not on innobase/row/row0sel.c: Fix a hang introduced in 4.0.5 in INSERT INTO ... SELECT ... when binlogging is not on --- innobase/row/row0sel.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index ce6ed091a48..a3744089258 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2702,14 +2702,22 @@ row_search_for_mysql( unique_search_from_clust_index = TRUE; - if (prebuilt->select_lock_type == LOCK_NONE + if (trx->mysql_n_tables_locked == 0 + && prebuilt->select_lock_type == LOCK_NONE && trx->isolation_level > TRX_ISO_READ_UNCOMMITTED && trx->read_view) { /* This is a SELECT query done as a consistent read, and the read view has already been allocated: let us try a search shortcut through the hash - index */ + index. + NOTE that we must also test that + mysql_n_tables_locked == 0, because this might + also be INSERT INTO ... SELECT ... or + CREATE TABLE ... SELECT ... . Our algorithm is + NOT prepared to inserts interleaved with the SELECT, + and if we try that, we can deadlock on the adaptive + hash index semaphore! */ if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED) { /* There is an x-latch request: release From e753fa4d8d30976b0c4a7ca68bd81b3a11bba06b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 00:27:09 +0100 Subject: [PATCH 30/46] Security bug: password length check should be in check_user, not check_connections(), otherwise COM_CHANGE_USER is unprotected and can be used for both privilege escalation and buffer overrun --- sql/sql_parse.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1803568f880..fe7e98c7028 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -109,6 +109,8 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, NET *net= &thd->net; thd->db=0; + if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH) + return 1; if (!(thd->user = my_strdup(user, MYF(0)))) { send_error(net,ER_OUT_OF_RESOURCES); @@ -458,8 +460,6 @@ check_connections(THD *thd) char *user= (char*) net->read_pos+5; char *passwd= strend(user)+1; char *db=0; - if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH) - return ER_HANDSHAKE_ERROR; if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) db=strend(passwd)+1; if (thd->client_capabilities & CLIENT_INTERACTIVE) From a31d258ba7c36c0ed27a5bed576dc430bc7219a6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 01:26:32 +0100 Subject: [PATCH 31/46] protect from [heap] buffer overrrun by malicious server --- libmysql/libmysql.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index bab6d304094..3c1353e0088 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -307,7 +307,7 @@ net_safe_read(MYSQL *mysql) DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", vio_description(net->vio),len)); end_server(mysql); - net->last_errno=(net->last_errno == ER_NET_PACKET_TOO_LARGE ? + net->last_errno=(net->last_errno == ER_NET_PACKET_TOO_LARGE ? CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST); strmov(net->last_error,ER(net->last_errno)); @@ -891,7 +891,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, uint field,pkt_len; ulong len; uchar *cp; - char *to; + char *to, *end_to; MYSQL_DATA *result; MYSQL_ROWS **prev_ptr,*cur; NET *net = &mysql->net; @@ -929,6 +929,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, *prev_ptr=cur; prev_ptr= &cur->next; to= (char*) (cur->data+fields+1); + end_to=to+pkt_len-1; for (field=0 ; field < fields ; field++) { if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH) @@ -938,6 +939,13 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, else { cur->data[field] = to; + if (to+len > end_to) + { + free_rows(result); + net->last_errno=CR_UNKNOWN_ERROR; + strmov(net->last_error,ER(net->last_errno)); + DBUG_RETURN(0); + } memcpy(to,(char*) cp,len); to[len]=0; to+=len+1; cp+=len; From faefac308f722b9669bec622c34c269c9341e675 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 09:54:58 +0100 Subject: [PATCH 32/46] proper casting in COM_TABLE_DUMP (backported from 4.0) --- sql/sql_parse.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fe7e98c7028..ddbc34b2c7e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -768,8 +768,8 @@ bool do_command(THD *thd) thread_safe_increment(com_other,&LOCK_thread_count); slow_command = TRUE; char* data = packet + 1; - uint db_len = *data; - uint tbl_len = *(data + db_len + 1); + uint db_len = *(uchar *)data; + uint tbl_len = *(uchar *)(data + db_len + 1); char* db = sql_alloc(db_len + tbl_len + 2); memcpy(db, data + 1, db_len); char* tbl_name = db + db_len; From 2d2e834ce1be474b3b09dd60a1c4a9f2f67fc6e0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 10:47:51 +0100 Subject: [PATCH 33/46] post-merge fix myisam/mi_rnext_same.c: cleanup --- myisam/mi_rnext_same.c | 5 ++--- mysql-test/r/group_by.result | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/myisam/mi_rnext_same.c b/myisam/mi_rnext_same.c index 662bdb154b3..a9d1953323c 100644 --- a/myisam/mi_rnext_same.c +++ b/myisam/mi_rnext_same.c @@ -27,14 +27,13 @@ int mi_rnext_same(MI_INFO *info, byte *buf) { int error; - uint inx,flag,not_used; + uint inx,not_used; MI_KEYDEF *keyinfo; DBUG_ENTER("mi_rnext_same"); if ((int) (inx=info->lastinx) < 0 || info->lastpos == HA_OFFSET_ERROR) DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX); keyinfo=info->s->keyinfo+inx; - flag=SEARCH_BIGGER; /* Read next */ if (fast_mi_readinfo(info)) DBUG_RETURN(my_errno); @@ -44,7 +43,7 @@ int mi_rnext_same(MI_INFO *info, byte *buf) for (;;) { if ((error=_mi_search_next(info,keyinfo,info->lastkey, - info->lastkey_length,flag, + info->lastkey_length,SEARCH_BIGGER, info->s->state.key_root[inx]))) break; if (_mi_key_cmp(keyinfo->seg,info->lastkey2,info->lastkey, diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 0e8c6520d5c..ddddb3fa07d 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -205,6 +205,14 @@ Documentation 0 Host communication 0 kkkkkkkkkkk lllllllllll 3 Test Procedures 0 +select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value having COUNT(bug_id) IN (0,2); +value description COUNT(bug_id) +BBBBBBBBBBBBB - conversion 2 +BBBBBBBBBBBBB - eeeeeeeee 0 +BBBBBBBBBBBBB - generic 2 +Documentation 0 +Host communication 0 +Test Procedures 0 drop table t1,t2; create table t1 (foo int); insert into t1 values (1); @@ -232,6 +240,13 @@ userid count(*) 3 3 2 1 1 2 +select userid,count(*) from t1 group by userid desc having (count(*)+1) IN (4,3); +userid count(*) +3 3 +1 2 +select userid,count(*) from t1 group by userid desc having 3 IN (1,COUNT(*)); +userid count(*) +3 3 explain select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; table type possible_keys key key_len ref rows Extra t1 range spID spID 5 NULL 2 Using where; Using index From 93bed6061b6d5637f7f381580b92dbe1aa494970 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 15:27:08 +0200 Subject: [PATCH 34/46] A fix for the bug in a SELECT with joined tables with ORDER BY and LIMIT clause when filesort had to be used. In that case LIMIT was applied to filesort of one of the tables, although it could not be. This fix solved problems with LEFT JOIN too... --- mysql-test/r/select.result | 13 +++++++++++++ mysql-test/t/select.test | 8 +++++++- sql/sql_select.cc | 8 +++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index fdcc7f9cdea..a921d75f20a 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3468,3 +3468,16 @@ a a a 2 2 2 3 3 3 drop table t1; +drop table if exists t1,t2; +CREATE TABLE t1 ( aa char(2), id int(11) NOT NULL auto_increment, t2_id int(11) NOT NULL default '0', PRIMARY KEY (id), KEY replace_id (t2_id)) TYPE=MyISAM; +INSERT INTO t1 VALUES ("1",8264,2506),("2",8299,2517),("3",8301,2518),("4",8302,2519),("5",8303,2520),("6",8304,2521),("7",8305,2522); +CREATE TABLE t2 ( id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) TYPE=MyISAM; +INSERT INTO t2 VALUES (2517), (2518), (2519), (2520), (2521), (2522); +select * from t1, t2 WHERE t1.t2_id = t2.id and t1.t2_id > 0 order by t1.id LIMIT 0, 5; +aa id t2_id id +2 8299 2517 2517 +3 8301 2518 2518 +4 8302 2519 2519 +5 8303 2520 2520 +6 8304 2521 2521 +drop table if exists t1,t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 15d44bcd672..d9b75fca362 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1795,5 +1795,11 @@ select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a)); # natural join select * from t1 natural join (t1 as t2 left join t1 as t3 using (a)); select * from (t1 as t2 left join t1 as t3 using (a)) natural join t1; - drop table t1; +drop table if exists t1,t2; +CREATE TABLE t1 ( aa char(2), id int(11) NOT NULL auto_increment, t2_id int(11) NOT NULL default '0', PRIMARY KEY (id), KEY replace_id (t2_id)) TYPE=MyISAM; +INSERT INTO t1 VALUES ("1",8264,2506),("2",8299,2517),("3",8301,2518),("4",8302,2519),("5",8303,2520),("6",8304,2521),("7",8305,2522); +CREATE TABLE t2 ( id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) TYPE=MyISAM; +INSERT INTO t2 VALUES (2517), (2518), (2519), (2520), (2521), (2522); +select * from t1, t2 WHERE t1.t2_id = t2.id and t1.t2_id > 0 order by t1.id LIMIT 0, 5; +drop table if exists t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index eaa291f4d90..80b1ceb0538 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -923,7 +923,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, JOIN_TAB *end_table= &join.join_tab[join.tables]; for (; table < end_table ; table++) { - if (table->select_cond) + /* + table->keyuse is set in the case there was an original WHERE clause + on the table that was optimized away. + table->on_expr tells us that it was a LEFT JOIN and there will be + at least one row generated from the table. + */ + if (table->select_cond || (table->keyuse && !table->on_expr)) { /* We have to sort all rows */ select_limit= HA_POS_ERROR; From 6456d593c775ec19eb5695d1a86299027c4f54aa Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 16:52:46 +0200 Subject: [PATCH 35/46] Fixed 'stack direction' check in autoconf Workaround for problem with autconf 2.53 on Solaris (Fixes problem with SOCKET_SIZE_TYPE) BUILD/compile-solaris-sparc: Removed non standard compiler options BUILD/compile-solaris-sparc-purify: Removed non standard compiler options acinclude.m4: Fixed 'stack direction' check. Workaround for problem with autconf 2.53 on Solaris (Fixes problem with SOCKET_SIZE_TYPE) --- BUILD/compile-solaris-sparc | 2 +- BUILD/compile-solaris-sparc-purify | 2 +- acinclude.m4 | 35 ++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/BUILD/compile-solaris-sparc b/BUILD/compile-solaris-sparc index f8f7c8755df..af7c4bc5bc5 100755 --- a/BUILD/compile-solaris-sparc +++ b/BUILD/compile-solaris-sparc @@ -11,6 +11,6 @@ then (cd gemini && aclocal && autoheader && aclocal && automake && autoconf) fi -CFLAGS="-g -Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa" CXX=gcc CXXFLAGS="-Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa -g" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client +CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa" CXX=gcc CXXFLAGS="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa -g" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client gmake -j 4 diff --git a/BUILD/compile-solaris-sparc-purify b/BUILD/compile-solaris-sparc-purify index 8bb53bba876..d73d817dd6c 100755 --- a/BUILD/compile-solaris-sparc-purify +++ b/BUILD/compile-solaris-sparc-purify @@ -6,7 +6,7 @@ aclocal && autoheader && aclocal && automake && autoconf (cd bdb/dist && sh s_all) (cd innobase && aclocal && autoheader && aclocal && automake && autoconf) -CFLAGS="-g -Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db --with-innodb +CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db --with-innodb gmake -j 4 diff --git a/acinclude.m4 b/acinclude.m4 index 246fb40eb83..83cc01cc127 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -520,7 +520,8 @@ fi AC_DEFUN(MYSQL_STACK_DIRECTION, [AC_CACHE_CHECK(stack direction for C alloca, ac_cv_c_stack_direction, - [AC_TRY_RUN([find_stack_direction () + [AC_TRY_RUN([#include + int find_stack_direction () { static char *addr = 0; auto char dummy; @@ -532,7 +533,7 @@ AC_DEFUN(MYSQL_STACK_DIRECTION, else return (&dummy > addr) ? 1 : -1; } - main () + int main () { exit (find_stack_direction() < 0); }], ac_cv_c_stack_direction=1, ac_cv_c_stack_direction=-1, @@ -1152,3 +1153,33 @@ AC_DEFUN(MYSQL_SYS_LARGEFILE, esac]) fi ]) + +# Local version of _AC_PROG_CXX_EXIT_DECLARATION that does not +# include #stdlib.h as this breaks things on Solaris +# (Conflicts with pthreads and big file handling) + +m4_define([_AC_PROG_CXX_EXIT_DECLARATION], +[for ac_declaration in \ + ''\ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include +$ac_declaration], + [exit (42);])], + [], + [continue]) + _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration], + [exit (42);])], + [break]) +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi +])# _AC_PROG_CXX_EXIT_DECLARATION From e955255cf67b483234ffdf4a61028bf046be47b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 16:16:06 +0100 Subject: [PATCH 36/46] - Portability fixes for HP compiler on HPUX11 (backport from 4.0 tree) - sql_analyse.cc: Fixed bug in decimal handling configure.in: - Portability fix for HP compiler on HPUX11 libmysql/password.c: - Portability fix for HP compiler on HPUX11 mysys/hash.c: - Portability fix for HP compiler on HPUX11 mysys/my_static.c: - Portability fix for HP compiler on HPUX11 mysys/my_static.h: - Portability fix for HP compiler on HPUX11 mysys/my_tempnam.c: - Portability fix for HP compiler on HPUX11 sql/sql_analyse.cc: - Fixed bug in decimal handling --- configure.in | 6 ++++++ libmysql/password.c | 2 +- mysys/hash.c | 15 ++++++++++----- mysys/my_static.c | 2 +- mysys/my_static.h | 2 +- mysys/my_tempnam.c | 6 ++++++ sql/sql_analyse.cc | 2 +- 7 files changed, 26 insertions(+), 9 deletions(-) diff --git a/configure.in b/configure.in index 3fb495281a0..3a5c1a56408 100644 --- a/configure.in +++ b/configure.in @@ -893,6 +893,12 @@ case $SYSTEM_TYPE in echo "Using --with-named-thread=-lpthread" with_named_thread="-lpthread" fi + # Fixes for HPUX 11.0 compiler + if test "$ac_cv_prog_gcc" = "no" + then + CFLAGS="$CFLAGS +DD64 -DHAVE_BROKEN_INLINE" + CXXFLAGS="$CXXFLAGS +DD64 +O2" + fi ;; *rhapsody*) if test "$ac_cv_prog_gcc" = "yes" diff --git a/libmysql/password.c b/libmysql/password.c index 0fd5861873a..71ed68c6b2c 100644 --- a/libmysql/password.c +++ b/libmysql/password.c @@ -92,7 +92,7 @@ void make_scrambled_password(char *to,const char *password) sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); } -static inline uint char_val(char X) +static inline unsigned int char_val(char X) { return (uint) (X >= '0' && X <= '9' ? X-'0' : X >= 'A' && X <= 'Z' ? X-'A'+10 : diff --git a/mysys/hash.c b/mysys/hash.c index eb74b1f30dd..602823e6d43 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -83,7 +83,12 @@ void hash_free(HASH *hash) /* some helper functions */ -inline byte* +/* + This function is char* instead of byte* as HPUX11 compiler can't + handle inline functions that are not defined as native types +*/ + +inline char* hash_key(HASH *hash,const byte *record,uint *length,my_bool first) { if (hash->get_key) @@ -104,7 +109,7 @@ static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax, uint maxlength) { uint length; - byte *key=hash_key(hash,pos->data,&length,0); + byte *key= (byte*) hash_key(hash,pos->data,&length,0); return hash_mask((*hash->calc_hashnr)(key,length),buffmax,maxlength); } @@ -183,10 +188,10 @@ uint calc_hashnr_caseup(const byte *key, uint len) #ifndef __SUNPRO_C /* SUNPRO can't handle this */ inline #endif -uint rec_hashnr(HASH *hash,const byte *record) +unsigned int rec_hashnr(HASH *hash,const byte *record) { uint length; - byte *key=hash_key(hash,record,&length,0); + byte *key= (byte*) hash_key(hash,record,&length,0); return (*hash->calc_hashnr)(key,length); } @@ -273,7 +278,7 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink) static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length) { uint rec_keylength; - byte *rec_key=hash_key(hash,pos->data,&rec_keylength,1); + byte *rec_key= (byte*) hash_key(hash,pos->data,&rec_keylength,1); return (length && length != rec_keylength) || (hash->flags & HASH_CASE_INSENSITIVE ? my_casecmp(rec_key,key,rec_keylength) : diff --git a/mysys/my_static.c b/mysys/my_static.c index 00061893cdc..72bf7207efa 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -61,7 +61,7 @@ USED_MEM* my_once_root_block=0; /* pointer to first block */ uint my_once_extra=ONCE_ALLOC_INIT; /* Memory to alloc / block */ /* from my_tempnam */ -#ifndef HAVE_TEMPNAM +#if !defined(HAVE_TEMPNAM) || defined(HPUX11) int _my_tempnam_used=0; #endif diff --git a/mysys/my_static.h b/mysys/my_static.h index e9d1a30b786..e139b0ec127 100644 --- a/mysys/my_static.h +++ b/mysys/my_static.h @@ -57,7 +57,7 @@ extern const char *soundex_map; extern USED_MEM* my_once_root_block; extern uint my_once_extra; -#ifndef HAVE_TEMPNAM +#if !defined(HAVE_TEMPNAM) || defined(HPUX11) extern int _my_tempnam_used; #endif diff --git a/mysys/my_tempnam.c b/mysys/my_tempnam.c index fdaf018af0d..d4979fcaa6e 100644 --- a/mysys/my_tempnam.c +++ b/mysys/my_tempnam.c @@ -24,6 +24,12 @@ #include "mysys_priv.h" #include + +/* HPUX 11.0 doesn't allow us to change the environ pointer */ +#ifdef HPUX11 +#undef HAVE_TEMPNAM +#endif + #include "my_static.h" #include "mysys_err.h" diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index de367e8c052..457356d4253 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -641,7 +641,7 @@ bool analyse::end_of_records() case FIELD_TYPE_DECIMAL: ans.append("DECIMAL", 7); // if item is FIELD_ITEM, it _must_be_ Field_num in this case - if (((Field_num*) (*f)->item)->zerofill) + if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill) ans.append(" ZEROFILL"); break; default: From 8cf927658d7720519380a3a88dc6c6f3e0b4c898 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 17:37:51 +0100 Subject: [PATCH 37/46] new client error added: CR_MALFORMED_PACKET --- include/errmsg.h | 8 +++++--- libmysql/errmsg.c | 11 +++++++---- libmysql/libmysql.c | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/errmsg.h b/include/errmsg.h index 842d53c9303..5136af5b87a 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -28,7 +28,7 @@ extern const char *client_errors[]; /* Error messages */ #define CR_MIN_ERROR 2000 /* For easier client code */ #define CR_MAX_ERROR 2999 -#if defined(OS2) && defined( MYSQL_SERVER) +#if defined(OS2) && defined(MYSQL_SERVER) #define CER(X) client_errors[(X)-CR_MIN_ERROR] #else #define ER(X) client_errors[(X)-CR_MIN_ERROR] @@ -51,8 +51,8 @@ extern const char *client_errors[]; /* Error messages */ #define CR_SERVER_LOST 2013 #define CR_COMMANDS_OUT_OF_SYNC 2014 #define CR_NAMEDPIPE_CONNECTION 2015 -#define CR_NAMEDPIPEWAIT_ERROR 2016 -#define CR_NAMEDPIPEOPEN_ERROR 2017 +#define CR_NAMEDPIPEWAIT_ERROR 2016 +#define CR_NAMEDPIPEOPEN_ERROR 2017 #define CR_NAMEDPIPESETSTATE_ERROR 2018 #define CR_CANT_READ_CHARSET 2019 #define CR_NET_PACKET_TOO_LARGE 2020 @@ -62,3 +62,5 @@ extern const char *client_errors[]; /* Error messages */ #define CR_PROBE_SLAVE_CONNECT 2024 #define CR_PROBE_MASTER_CONNECT 2025 #define CR_SSL_CONNECTION_ERROR 2026 +#define CR_MALFORMED_PACKET 2027 + diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index 47d19281a04..375ca7329c0 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -50,7 +50,8 @@ const char *client_errors[]= "Error on SHOW SLAVE HOSTS:", "Error connecting to slave:", "Error connecting to master:", - "SSL connection error" + "SSL connection error", + "Malformed packet" }; /* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */ @@ -63,7 +64,7 @@ const char *client_errors[]= "Não pode se conectar ao servidor MySQL local através do 'socket' '%-.64s' (%d)", "Não pode se conectar ao servidor MySQL em '%-.64s' (%d)", "Não pode criar 'socket TCP/IP' (%d)", - "'Host' servidor MySQL '%-.64s' (%d) desconhecido", + "'Host' servidor MySQL '%-.64s' (%d) desconhecido", "Servidor MySQL desapareceu", "Incompatibilidade de protocolos. Versão do Servidor: %d - Versão do Cliente: %d", "Cliente do MySQL com falta de memória", @@ -84,7 +85,8 @@ const char *client_errors[]= "Error on SHOW SLAVE HOSTS:", "Error connecting to slave:", "Error connecting to master:", - "SSL connection error" + "SSL connection error", + "Malformed packet" }; #else /* ENGLISH */ @@ -116,7 +118,8 @@ const char *client_errors[]= "Error on SHOW SLAVE HOSTS:", "Error connecting to slave:", "Error connecting to master:", - "SSL connection error" + "SSL connection error", + "Malformed packet" }; #endif diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index da6c445d161..6965c1d79d8 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -985,7 +985,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, if (to+len > end_to) { free_rows(result); - net->last_errno=CR_UNKNOWN_ERROR; + net->last_errno=CR_MALFORMED_PACKET; strmov(net->last_error,ER(net->last_errno)); DBUG_RETURN(0); } From ad6e0804017b2a54a33aa643efe2bb374c0a95b6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 19:16:45 +0100 Subject: [PATCH 38/46] - portability patch to work around bugs in the HP compiler's "inline" handling (backport from 4.0 tree) --- include/global.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/global.h b/include/global.h index 4ab7cbbeee6..988797b330c 100644 --- a/include/global.h +++ b/include/global.h @@ -122,6 +122,10 @@ double my_ulonglong2double(unsigned long long A); #undef HAVE_PREAD #undef HAVE_PWRITE #endif +#if defined(HAVE_BROKEN_INLINE) && !defined(__cplusplus) +#undef inline +#define inline +#endif #ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */ #undef HAVE_GETHOSTBYNAME_R From 76c982ea9288bdc55746b63d03ff82d6a89f02ec Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 20:51:18 +0200 Subject: [PATCH 39/46] A fix for double free'd pointer bug ... BitKeeper/etc/ignore: Added innobase/stamp-h1 stamp-h1 to the ignore list --- .bzrignore | 2 ++ sql/sql_table.cc | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.bzrignore b/.bzrignore index 4a707ae05df..5b35d1f6611 100644 --- a/.bzrignore +++ b/.bzrignore @@ -331,3 +331,5 @@ bdb/dist/autom4te.cache/traces.0 innobase/autom4te.cache/output.0 innobase/autom4te.cache/requests innobase/autom4te.cache/traces.0 +innobase/stamp-h1 +stamp-h1 diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0a09b6232e8..ec866b927e6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1528,8 +1528,14 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, /* We changed a temporary table */ if (error) { + /* + * The following function call will also free a + * new_table pointer. + * Therefore, here new_table pointer is not free'd as it is + * free'd in close_temporary() which is called by by the + * close_temporary_table() function. + */ close_temporary_table(thd,new_db,tmp_name); - my_free((gptr) new_table,MYF(0)); goto err; } /* Close lock if this is a transactional table */ From 28b22803212aa093064cf6ae5830b2fb49e6aaf8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Dec 2002 00:13:45 +0500 Subject: [PATCH 40/46] Remove useless field conversation --- sql-bench/server-cfg.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh index 488bd788056..7f96c06ef99 100644 --- a/sql-bench/server-cfg.sh +++ b/sql-bench/server-cfg.sh @@ -252,7 +252,7 @@ sub create $query="create table $table_name ("; foreach $field (@$fields) { - $field =~ s/ decimal/ double(10,2)/i; +# $field =~ s/ decimal/ double(10,2)/i; $field =~ s/ big_decimal/ double(10,2)/i; $query.= $field . ','; } From ada3e325457bd2796c355c59cfdc179e3feeb16b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 21:39:15 +0200 Subject: [PATCH 41/46] some code cleanup sql/sql_table.cc: code cleanup --- sql/sql_table.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ec866b927e6..e2fa8bc00d5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1848,7 +1848,6 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (to->file->external_lock(thd,F_UNLCK)) error=1; err: - tmp_error = ha_recovery_logging(thd,TRUE); free_io_cache(from); *copied= found_count; *deleted=delete_count; From 491415cd0365f544d9199e96db34f30e58bed6ba Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Dec 2002 21:50:59 +0200 Subject: [PATCH 42/46] a test case for double free'ing of pointer in alter table ... --- mysql-test/t/temp_table.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test index 3cf18bae9fe..0eba893fe60 100644 --- a/mysql-test/t/temp_table.test +++ b/mysql-test/t/temp_table.test @@ -60,3 +60,8 @@ insert into t2 values (1,1),(2,1),(3,1),(4,2); # do a query using ELT, a join and an ORDER BY. select one.id, two.val, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id; drop table t1,t2; +create temporary table t1 (a int not null); +insert into t1 values (1),(1); +-- error 1062 +alter table t1 add primary key (a); +drop table t1; From d3237f34ef7ad284555d29dd42c1adb5e6592ca0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Dec 2002 00:33:18 +0100 Subject: [PATCH 43/46] .del-errmsg.c~444b5d4031149217: Delete: client/errmsg.c BitKeeper/deleted/.del-errmsg.c~444b5d4031149217: Delete: client/errmsg.c --- client/errmsg.c | 125 ------------------------------------------------ 1 file changed, 125 deletions(-) delete mode 100644 client/errmsg.c diff --git a/client/errmsg.c b/client/errmsg.c deleted file mode 100644 index 6cb28f3f53e..00000000000 --- a/client/errmsg.c +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Error messages for MySQL clients */ -/* error messages for the demon is in share/language/errmsg.sys */ - -#include -#include -#include "errmsg.h" - -#ifdef GERMAN -const char *client_errors[]= -{ - "Unbekannter MySQL Fehler", - "Kann UNIX-Socket nicht anlegen (%d)", - "Keine Verbindung zu lokalem MySQL Server, socket: '%-.64s' (%d)", - "Keine Verbindung zu MySQL Server auf %-.64s (%d)", - "Kann TCP/IP-Socket nicht anlegen (%d)", - "Unbekannter MySQL Server Host (%-.64s) (%d)", - "MySQL Server nicht vorhanden", - "Protokolle ungleich. Server Version = % d Client Version = %d", - "MySQL client got out of memory", - "Wrong host info", - "Localhost via UNIX socket", - "%-.64s via TCP/IP", - "Error in server handshake", - "Lost connection to MySQL server during query", - "Commands out of sync; You can't run this command now", - "Verbindung ueber Named Pipe; Host: %-.64s", - "Kann nicht auf Named Pipe warten. Host: %-.64s pipe: %-.32s (%lu)", - "Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)", - "Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)", - "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'", - "Embedded server", - "Error on SHOW SLAVE STATUS:", - "Error on SHOW SLAVE HOSTS:", - "Error connecting to slave:", - "Error connecting to master:" - -}; - -/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */ - -#elif defined PORTUGUESE -const char *client_errors[]= -{ - "Erro desconhecido do MySQL", - "Não pode criar 'UNIX socket' (%d)", - "Não pode se conectar ao servidor MySQL local através do 'socket' '%-.64s' (%d)", - "Não pode se conectar ao servidor MySQL em '%-.64s' (%d)", - "Não pode criar 'socket TCP/IP' (%d)", - "'Host' servidor MySQL '%-.64s' (%d) desconhecido", - "Servidor MySQL desapareceu", - "Incompatibilidade de protocolos. Versão do Servidor: %d - Versão do Cliente: %d", - "Cliente do MySQL com falta de memória", - "Informação inválida de 'host'", - "Localhost via 'UNIX socket'", - "%-.64s via 'TCP/IP'", - "Erro na negociação de acesso ao servidor", - "Conexão perdida com servidor MySQL durante 'query'", - "Comandos fora de sincronismo. Você não pode executar este comando agora", - "%-.64s via 'named pipe'", - "Não pode esperar pelo 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)", - "Não pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)", - "Não pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)", - "Não pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)", - "Obteve pacote maior do que 'max_allowed_packet'", - "Embedded server", - "Error on SHOW SLAVE STATUS:", - "Error on SHOW SLAVE HOSTS:", - "Error connecting to slave:", - "Error connecting to master:" -}; - -#else /* ENGLISH */ -const char *client_errors[]= -{ - "Unknown MySQL error", - "Can't create UNIX socket (%d)", - "Can't connect to local MySQL server through socket '%-.64s' (%d)", - "Can't connect to MySQL server on '%-.64s' (%d)", - "Can't create TCP/IP socket (%d)", - "Unknown MySQL Server Host '%-.64s' (%d)", - "MySQL server has gone away", - "Protocol mismatch. Server Version = %d Client Version = %d", - "MySQL client run out of memory", - "Wrong host info", - "Localhost via UNIX socket", - "%-.64s via TCP/IP", - "Error in server handshake", - "Lost connection to MySQL server during query", - "Commands out of sync; You can't run this command now", - "%-.64s via named pipe", - "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'", - "Embedded server", - "Error on SHOW SLAVE STATUS:", - "Error on SHOW SLAVE HOSTS:", - "Error connecting to slave:", - "Error connecting to master:" -}; -#endif - - -void init_client_errs(void) -{ - my_errmsg[CLIENT_ERRMAP] = &client_errors[0]; -} From 591b058518dcbc736398d64e8bfd1ac43099323e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Dec 2002 03:40:33 +0200 Subject: [PATCH 44/46] Removed copying of parameters as this leads to memory leaks in embedded server. Fixed 'not initialized' memory error. mysql-test/mysql-test-run.sh: Updates to be able to more easily use --valgrind mysql-test/r/alter_table.result: Added missing drop table mysql-test/t/alter_table.test: Added missing drop table sql/field.cc: Simple optimizations sql/ha_innodb.cc: Remove copying of parameters as this leads to memory leaks in MySQL. Should be instead fixed by, in embedded server, make a temporary copy of all parameters and free them on server-end sql/log.cc: Simple optimization sql/mysql_priv.h: Move external reference to struct to include file sql/mysqld.cc: Added safety asserts sql/sql_class.cc: Fixed non fatal 'not initialized memory reference error' in thread init sql/sql_udf.cc: Clear current_thd for global thread strings/strto.c: Simple optimization --- mysql-test/mysql-test-run.sh | 73 +++++++++++++++++++++++---------- mysql-test/r/alter_table.result | 2 +- mysql-test/t/alter_table.test | 2 +- sql/field.cc | 22 ++++++---- sql/ha_innodb.cc | 30 -------------- sql/log.cc | 70 ++++++++++++++++--------------- sql/mysql_priv.h | 1 + sql/mysqld.cc | 3 ++ sql/sql_class.cc | 3 +- sql/sql_udf.cc | 2 + strings/strto.c | 5 +-- 11 files changed, 114 insertions(+), 99 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 4317ba0e749..928beaf0aa4 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -19,7 +19,7 @@ TZ=GMT-3; export TZ # for UNIX_TIMESTAMP tests to work # Program Definitions #-- -PATH=/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11 +PATH=/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11:$PATH MASTER_40_ARGS="--rpl-recovery-rank=1 --init-rpl-role=master" # Standard functions @@ -47,13 +47,17 @@ which () sleep_until_file_deleted () { - file=$1 + pid=$1; + file=$2 loop=$SLEEP_TIME_FOR_DELETE while (test $loop -gt 0) do if [ ! -r $file ] then - sleep $SLEEP_TIME_AFTER_RESTART + if test $pid != "0" + then + wait_for_pid $pid + fi return fi sleep 1 @@ -79,6 +83,13 @@ sleep_until_file_created () exit 1; } +# For the future + +wait_for_pid() +{ + pid=$1 +} + # No paths below as we can't be sure where the program is! SED=sed @@ -152,6 +163,7 @@ TOT_TEST=0 USERT=0 SYST=0 REALT=0 +FAST_START="" MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp SLAVE_LOAD_TMPDIR=../../var/tmp #needs to be same length to test logging RES_SPACE=" " @@ -314,7 +326,7 @@ while test $# -gt 0; do VALGRIND="valgrind --alignment=8 --leak-check=yes" EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc" - SLEEP_TIME_AFTER_RESTART=120 + #SLEEP_TIME_AFTER_RESTART=120 SLEEP_TIME_FOR_DELETE=120 ;; --valgrind-options=*) @@ -335,6 +347,9 @@ while test $# -gt 0; do --debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/slave.trace" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT --debug" ;; + --fast) + FAST_START=1 + ;; -- ) shift; break ;; --* ) $ECHO "Unrecognized option: $1"; exit 1 ;; * ) break ;; @@ -731,12 +746,19 @@ EOF manager_term() { - ident=$1 + pid=$1 + ident=$2 shift if [ $USE_MANAGER = 0 ] ; then - $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock -O \ - connect_timeout=5 -O shutdown_timeout=20 shutdown >> $MYSQL_MANAGER_LOG 2>&1 - return + $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=5 --shutdown_timeout=20 shutdown >> $MYSQL_MANAGER_LOG 2>&1 + res=$? + # Some systems require an extra connect + $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=1 ping >> $MYSQL_MANAGER_LOG 2>&1 + if test $res = 0 + then + wait_for_pid $pid + fi + return $res fi $MYSQL_MANAGER_CLIENT $MANAGER_QUIET_OPT --user=$MYSQL_MANAGER_USER \ --password=$MYSQL_MANAGER_PW --port=$MYSQL_MANAGER_PORT < /dev/null 2>&1 - $MYSQLADMIN --no-defaults --socket=$SLAVE_MYSOCK -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 - $MYSQLADMIN --no-defaults --host=$hostname --port=$MASTER_MYPORT -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 - $MYSQLADMIN --no-defaults --host=$hostname --port=$SLAVE_MYPORT -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 - $MYSQLADMIN --no-defaults --host=$hostname --port=`expr $SLAVE_MYPORT + 1` -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 - sleep_until_file_deleted $MASTER_MYPID - sleep_until_file_deleted $SLAVE_MYPID + if [ -z "$FAST_START" ] + then + # Ensure that no old mysqld test servers are running + $MYSQLADMIN --no-defaults --socket=$MASTER_MYSOCK -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 + $MYSQLADMIN --no-defaults --socket=$SLAVE_MYSOCK -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 + $MYSQLADMIN --no-defaults --host=$hostname --port=$MASTER_MYPORT -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 + $MYSQLADMIN --no-defaults --host=$hostname --port=$SLAVE_MYPORT -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 + $MYSQLADMIN --no-defaults --host=$hostname --port=`expr $SLAVE_MYPORT + 1` -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1 + sleep_until_file_deleted 0 $MASTER_MYPID + sleep_until_file_deleted 0 $SLAVE_MYPID + else + rm $MASTER_MYPID $SLAVE_MYPID + fi # Kill any running managers if [ -f "$MANAGER_PID_FILE" ] diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 1d6d69465da..096ef2fd79e 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1,t2; create table t1 ( col1 int not null auto_increment primary key, col2 varchar(30) not null, diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 2b329f3ec6e..1c3987e2a31 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -2,7 +2,7 @@ # Test of alter table # -drop table if exists t1; +drop table if exists t1,t2; create table t1 ( col1 int not null auto_increment primary key, col2 varchar(30) not null, diff --git a/sql/field.cc b/sql/field.cc index e631ade16b1..afd594b7045 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1491,12 +1491,14 @@ void Field_medium::sql_type(String &res) const void Field_long::store(const char *from,uint len) { + char *end; while (len && isspace(*from)) { len--; from++; } long tmp; String tmp_str(from,len); + from= tmp_str.c_ptr(); // Add end null if needed errno=0; if (unsigned_flag) { @@ -1506,11 +1508,13 @@ void Field_long::store(const char *from,uint len) errno=ERANGE; } else - tmp=(long) strtoul(tmp_str.c_ptr(),NULL,10); + tmp=(long) strtoul(from, &end, 10); } else - tmp=strtol(tmp_str.c_ptr(),NULL,10); - if (errno || current_thd->count_cuted_fields && !test_if_int(from,len)) + tmp=strtol(from, &end, 10); + if (errno || + (from+len != end && current_thd->count_cuted_fields && + !test_if_int(from,len))) current_thd->cuted_fields++; #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -1719,12 +1723,14 @@ void Field_long::sql_type(String &res) const void Field_longlong::store(const char *from,uint len) { + char *end; while (len && isspace(*from)) { // For easy error check len--; from++; } longlong tmp; String tmp_str(from,len); + from= tmp_str.c_ptr(); // Add end null if needed errno=0; if (unsigned_flag) { @@ -1734,12 +1740,14 @@ void Field_longlong::store(const char *from,uint len) errno=ERANGE; } else - tmp=(longlong) strtoull(tmp_str.c_ptr(),NULL,10); + tmp=(longlong) strtoull(from, &end, 10); } else - tmp=strtoll(tmp_str.c_ptr(),NULL,10); - if (errno || current_thd->count_cuted_fields && !test_if_int(from,len)) - current_thd->cuted_fields++; + tmp=strtoll(from, &end, 10); + if (errno || + (from+len != end && current_thd->count_cuted_fields && + !test_if_int(from,len))) + current_thd->cuted_fields++; #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 343b8477d38..2868011c443 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -674,36 +674,6 @@ innobase_init(void) /* Set InnoDB initialization parameters according to the values read from MySQL .cnf file */ - /* --------------------------------------------------*/ - /* Make copies of all string-valued parameters, because after - C# calls server_init(), it may move the parameter strings around */ - - if (innobase_data_home_dir) { - innobase_data_home_dir = my_strdup( - innobase_data_home_dir, - MYF(MY_WME)); - } - if (innobase_data_file_path) { - innobase_data_file_path = my_strdup( - innobase_data_file_path, - MYF(MY_WME)); - } - if (innobase_log_group_home_dir) { - innobase_log_group_home_dir = my_strdup( - innobase_log_group_home_dir, - MYF(MY_WME)); - } - if (innobase_log_arch_dir) { - innobase_log_arch_dir = my_strdup( - innobase_log_arch_dir, - MYF(MY_WME)); - } - if (innobase_unix_file_flush_method) { - innobase_unix_file_flush_method = my_strdup( - innobase_unix_file_flush_method, - MYF(MY_WME)); - } - /*--------------- Data files -------------------------*/ /* The default dir for data files is the datadir of MySQL */ diff --git a/sql/log.cc b/sql/log.cc index 597985e8796..32dbdac1074 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1053,40 +1053,44 @@ bool MYSQL_LOG::write(Log_event* event_info) No check for auto events flag here - this write method should never be called if auto-events are enabled */ - if (thd && thd->last_insert_id_used) + if (thd) { - Intvar_log_event e(thd,(uchar)LAST_INSERT_ID_EVENT,thd->last_insert_id); - e.set_log_pos(this); - if (thd->server_id) - e.server_id = thd->server_id; - if (e.write(file)) - goto err; - } - if (thd && thd->insert_id_used) - { - Intvar_log_event e(thd,(uchar)INSERT_ID_EVENT,thd->last_insert_id); - e.set_log_pos(this); - if (thd->server_id) - e.server_id = thd->server_id; - if (e.write(file)) - goto err; - } - if (thd && thd->rand_used) - { - Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2); - e.set_log_pos(this); - if (e.write(file)) - goto err; - } - if (thd && thd->variables.convert_set) - { - char buf[1024] = "SET CHARACTER SET "; - char* p = strend(buf); - p = strmov(p, thd->variables.convert_set->name); - Query_log_event e(thd, buf, (ulong)(p - buf), 0); - e.set_log_pos(this); - if (e.write(file)) - goto err; + if (thd->last_insert_id_used) + { + Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT, + thd->last_insert_id); + e.set_log_pos(this); + if (thd->server_id) + e.server_id = thd->server_id; + if (e.write(file)) + goto err; + } + if (thd->insert_id_used) + { + Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id); + e.set_log_pos(this); + if (thd->server_id) + e.server_id = thd->server_id; + if (e.write(file)) + goto err; + } + if (thd->rand_used) + { + Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2); + e.set_log_pos(this); + if (e.write(file)) + goto err; + } + if (thd->variables.convert_set) + { + char buf[256], *p; + p= strmov(strmov(buf, "SET CHARACTER SET "), + thd->variables.convert_set->name); + Query_log_event e(thd, buf, (ulong) (p - buf), 0); + e.set_log_pos(this); + if (e.write(file)) + goto err; + } } event_info->set_log_pos(this); if (event_info->write(file) || diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7cfbd84a99d..ffdf74b412f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -689,6 +689,7 @@ extern String empty_string; extern SHOW_VAR init_vars[],status_vars[], internal_vars[]; extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; +extern struct rand_struct sql_rand; /* optional things, have_* variables */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a65cbd1139d..ecde4bc8645 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -32,6 +32,7 @@ #include #include #include +#include #ifndef DBUG_OFF #define ONE_THREAD @@ -2091,6 +2092,7 @@ int main(int argc, char **argv) (void) grant_init((THD*) 0); init_max_user_conn(); init_update_queries(); + DBUG_ASSERT(current_thd == 0); #ifdef HAVE_DLOPEN if (!opt_noacl) @@ -2099,6 +2101,7 @@ int main(int argc, char **argv) /* init_slave() must be called after the thread keys are created */ init_slave(); + DBUG_ASSERT(current_thd == 0); if (opt_bin_log && !server_id) { server_id= !master_host ? 1 : 2; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8b276cf0d9b..5f73c6fa64e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -37,7 +37,6 @@ #include #include -extern struct rand_struct sql_rand; /***************************************************************************** ** Instansiate templates @@ -159,7 +158,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), pthread_mutex_lock(&LOCK_thread_count); ulong tmp=(ulong) (rnd(&sql_rand) * 3000000); pthread_mutex_unlock(&LOCK_thread_count); - randominit(&rand, tmp + (ulong) start_time, tmp + (ulong) thread_id); + randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); } } diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 420ec67f0c5..937d1e52656 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -202,6 +202,8 @@ void udf_init() new_thd->version--; // Force close to free memory close_thread_tables(new_thd); delete new_thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); DBUG_VOID_RETURN; } diff --git a/strings/strto.c b/strings/strto.c index 84dccbcbeb8..c98b19a7e67 100644 --- a/strings/strto.c +++ b/strings/strto.c @@ -103,6 +103,7 @@ function (const char *nptr,char **endptr,int base) } /* Check for a sign. */ + negative= 0; if (*s == '-') { negative = 1; @@ -110,11 +111,9 @@ function (const char *nptr,char **endptr,int base) } else if (*s == '+') { - negative = 0; ++s; } - else - negative = 0; + if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X') s += 2; From fdb093fc476af146feaa6d4403db0c25bb6484d8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Dec 2002 16:38:49 +0200 Subject: [PATCH 45/46] Copy arguments given to mysql_server_init() Made keybuff_size longlong (To make show variables work similar on 32 and 64 bit systems) Fixed some 'not initalized variable errors' in multi-table-update. Fixed memory leak in multi-table-update. Now all tests works under valgrind without any errors. libmysqld/lib_sql.cc: Copy arguments given to mysql_server_init() mysql-test/r/temp_table.result: Update test results (after merge form 3.23) sql/handler.cc: Made keybuff_size longlong sql/mysql_priv.h: Made keybuff_size longlong sql/mysqld.cc: Made keybuff_size longlong sql/set_var.cc: Made keybuff_size longlong sql/set_var.h: Made keybuff_size longlong sql/sql_select.cc: Simple cleanup sql/sql_select.h: Make TMP_TABLE_PARAM to be allocated through Sql_alloc sql/sql_update.cc: Fixed some 'not initalized variable errors' in multi-table-update. Fixed memory leak in multi-table-update --- libmysqld/lib_sql.cc | 40 +++++++++++++++++++++++++++++++++- mysql-test/r/temp_table.result | 5 +++++ sql/handler.cc | 4 ++-- sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 15 ++++++++----- sql/set_var.cc | 19 +++++++++++++++- sql/set_var.h | 16 ++++++++++++++ sql/sql_select.cc | 10 ++++----- sql/sql_select.h | 3 ++- sql/sql_update.cc | 18 ++++++++++----- 10 files changed, 109 insertions(+), 25 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 94f30e5061b..14d293d91e3 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -275,11 +275,39 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, } +/* + Make a copy of array and the strings array points to +*/ + +char **copy_arguments(int argc, char **argv) +{ + uint length= 0; + char **from, **res, **end= argv+argc; + + for (from=argv ; from != end ; from++) + length+= strlen(*from); + + if ((res= (char**) my_malloc(sizeof(argv)*(argc+1)+length+argc, + MYF(MY_WME)))) + { + char **to= res, *to_str= (char*) (res+argc+1); + for (from=argv ; from != end ;) + { + *to++= to_str; + to_str= strmov(to_str, *from++)+1; + } + *to= 0; // Last ptr should be null + } + return res; +} + + extern "C" { static my_bool inited, org_my_init_done; ulong max_allowed_packet, net_buffer_length; +char ** copy_arguments_ptr= 0; int STDCALL mysql_server_init(int argc, char **argv, char **groups) { @@ -303,7 +331,7 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) argvp = (char ***) &fake_argv; } if (!groups) - groups = (char**) fake_groups; + groups = (char**) fake_groups; my_umask=0660; // Default umask for new files my_umask_dir=0700; // Default umask for new directories @@ -319,6 +347,14 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) MY_INIT((char *)"mysql_embedded"); // init my_sys library & pthreads } + /* + Make a copy of the arguments to guard against applications that + may change or move the initial arguments. + */ + if (argvp == &argv) + if (!(copy_arguments_ptr= argv= copy_arguments(argc, argv))) + return 1; + tzset(); // Set tzname start_time=time((time_t*) 0); @@ -566,6 +602,8 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) void STDCALL mysql_server_end() { + my_free((char*) copy_arguments_ptr, MYF(MY_ALLOW_ZERO_PTR)); + copy_arguments_ptr=0; clean_up(0); #ifdef THREAD /* Don't call my_thread_end() if the application is using MY_INIT() */ diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index 45f879e182b..7c8d10cf0a6 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -72,6 +72,11 @@ id val elt(two.val,'one','two') 2 1 one 4 2 two drop table t1,t2; +create temporary table t1 (a int not null); +insert into t1 values (1),(1); +alter table t1 add primary key (a); +Duplicate entry '1' for key 1 +drop table t1; drop table if exists t1; CREATE TABLE t1 ( d datetime default NULL diff --git a/sql/handler.cc b/sql/handler.cc index c4e742ef519..d4fd45613d4 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -883,13 +883,13 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, void ha_key_cache(void) { if (keybuff_size) - (void) init_key_cache(keybuff_size); + (void) init_key_cache((ulong) keybuff_size); } void ha_resize_key_cache(void) { - (void) resize_key_cache(keybuff_size); + (void) resize_key_cache((ulong) keybuff_size); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ffdf74b412f..3cf6bb2c1a5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -625,6 +625,7 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], time_zone[30], *opt_init_file; extern char blob_newline; extern double log_10[32]; +extern ulonglong keybuff_size; extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables; extern ulong created_tmp_tables, created_tmp_disk_tables; extern ulong aborted_threads,aborted_connects; @@ -643,8 +644,7 @@ extern ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count; extern ulong ha_read_key_count, ha_read_next_count, ha_read_prev_count; extern ulong ha_read_first_count, ha_read_last_count; extern ulong ha_read_rnd_count, ha_read_rnd_next_count; -extern ulong ha_commit_count, ha_rollback_count; -extern ulong keybuff_size,table_cache_size; +extern ulong ha_commit_count, ha_rollback_count,table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong max_insert_delayed_threads, max_user_connections; extern ulong long_query_count, what_to_log,flush_time,opt_sql_mode; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ecde4bc8645..2c15b21ac7d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -318,7 +318,8 @@ ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL | uint protocol_version=PROTOCOL_VERSION; struct system_variables global_system_variables; struct system_variables max_system_variables; -ulong keybuff_size,table_cache_size, +ulonglong keybuff_size; +ulong table_cache_size, thread_stack, thread_stack_min,what_to_log= ~ (1L << (uint) COM_TIME), query_buff_size, @@ -1372,7 +1373,7 @@ or misconfigured. This error can also be caused by malfunctioning hardware.\n", We will try our best to scrape up some info that will hopefully help diagnose\n\ the problem, but since we have already crashed, something is definitely wrong\n\ and this may fail.\n\n"); - fprintf(stderr, "key_buffer_size=%ld\n", keybuff_size); + fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size); fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size); fprintf(stderr, "sort_buffer_size=%ld\n", thd->variables.sortbuff_size); fprintf(stderr, "max_used_connections=%ld\n", max_used_connections); @@ -1380,8 +1381,9 @@ and this may fail.\n\n"); fprintf(stderr, "threads_connected=%d\n", thread_count); fprintf(stderr, "It is possible that mysqld could use up to \n\ key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\ -bytes of memory\n", (keybuff_size + (global_system_variables.read_buff_size + - thd->variables.sortbuff_size) * +bytes of memory\n", ((ulong) keybuff_size + + (global_system_variables.read_buff_size + + thd->variables.sortbuff_size) * max_connections)/ 1024); fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); @@ -3509,8 +3511,9 @@ struct my_option my_long_options[] = IO_SIZE, 0}, {"key_buffer_size", OPT_KEY_BUFFER_SIZE, "The size of the buffer used for index blocks. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", - (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, GET_ULONG, REQUIRED_ARG, - KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE, 0}, + (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, GET_ULL, + REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, + IO_SIZE, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to execute to file.", (gptr*) &global_system_variables.long_query_time, diff --git a/sql/set_var.cc b/sql/set_var.cc index 0675f7b4286..28222740c14 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -119,7 +119,7 @@ sys_var_thd_ulong sys_interactive_timeout("interactive_timeout", &SV::net_interactive_timeout); sys_var_thd_ulong sys_join_buffer_size("join_buffer_size", &SV::join_buff_size); -sys_var_long_ptr sys_key_buffer_size("key_buffer_size", +sys_var_ulonglong_ptr sys_key_buffer_size("key_buffer_size", &keybuff_size, fix_key_buffer_size); sys_var_bool_ptr sys_local_infile("local_infile", @@ -669,6 +669,23 @@ void sys_var_long_ptr::set_default(THD *thd, enum_var_type type) } +bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var) +{ + ulonglong tmp= var->value->val_int(); + if (option_limits) + *value= (ulonglong) getopt_ull_limit_value(tmp, option_limits); + else + *value= (ulonglong) tmp; + return 0; +} + + +void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type) +{ + *value= (ulonglong) option_limits->def_value; +} + + bool sys_var_bool_ptr::update(THD *thd, set_var *var) { *value= (my_bool) var->save_result.ulong_value; diff --git a/sql/set_var.h b/sql/set_var.h index a171c4f5e76..3edd0373db9 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -85,6 +85,22 @@ public: }; +class sys_var_ulonglong_ptr :public sys_var +{ +public: + ulonglong *value; + sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr) + :sys_var(name_arg),value(value_ptr) {} + sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr, + sys_after_update_func func) + :sys_var(name_arg,func), value(value_ptr) {} + bool update(THD *thd, set_var *var); + void set_default(THD *thd, enum_var_type type); + SHOW_TYPE type() { return SHOW_LONGLONG; } + byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; } +}; + + class sys_var_bool_ptr :public sys_var { public: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 80b1ceb0538..c4bc10a8b2a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2848,9 +2848,7 @@ join_free(JOIN *join) } join->group_fields.delete_elements(); join->tmp_table_param.copy_funcs.delete_elements(); - if (join->tmp_table_param.copy_field) // Because of bug in ecc - delete [] join->tmp_table_param.copy_field; - join->tmp_table_param.copy_field=0; + join->tmp_table_param.cleanup(); DBUG_VOID_RETURN; } @@ -3699,13 +3697,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, NullS)) { bitmap_clear_bit(&temp_pool, temp_pool_slot); - DBUG_RETURN(NULL); /* purecov: inspected */ + DBUG_RETURN(NULL); /* purecov: inspected */ } if (!(param->copy_field=copy=new Copy_field[field_count])) { bitmap_clear_bit(&temp_pool, temp_pool_slot); - my_free((gptr) table,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(NULL); /* purecov: inspected */ + my_free((gptr) table,MYF(0)); /* purecov: inspected */ + DBUG_RETURN(NULL); /* purecov: inspected */ } param->funcs=copy_func; strmov(tmpname,path); diff --git a/sql/sql_select.h b/sql/sql_select.h index d0e10f75727..40eb4d8ef51 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -115,7 +115,8 @@ typedef struct st_position { /* Used in find_best */ /* Param to create temporary tables when doing SELECT:s */ -class TMP_TABLE_PARAM { +class TMP_TABLE_PARAM :public Sql_alloc +{ public: List copy_funcs; List_iterator_fast copy_funcs_it; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 887d4e0acc0..4eab38bebad 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -412,9 +412,10 @@ end: multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, List *field_list, List *value_list, enum enum_duplicates handle_duplicates_arg) - :all_tables(table_list), thd(thd_arg), tmp_tables(0), updated(0), - found(0), fields(field_list), values(value_list), table_count(0), - handle_duplicates(handle_duplicates_arg), do_update(1) + :all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0), + updated(0), found(0), fields(field_list), values(value_list), + table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), + do_update(1), trans_safe(0) {} @@ -594,9 +595,14 @@ multi_update::~multi_update() if (tmp_tables) { - for (uint counter = 0; counter < table_count; counter++) - if (tmp_tables[counter]) - free_tmp_table(thd,tmp_tables[counter]); + for (uint cnt = 0; cnt < table_count; cnt++) + { + if (tmp_tables[cnt]) + { + free_tmp_table(thd, tmp_tables[cnt]); + tmp_table_param[cnt].cleanup(); + } + } } if (copy_field) delete [] copy_field; From ae4323e0d9fcbbca12b65f811cadb993b816d636 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 6 Dec 2002 21:11:27 +0200 Subject: [PATCH 46/46] After merge fixes Added THD to add_to_xxx_list() functions for faster parsing. heap/_check.c: After merge fix mysql-test/r/distinct.result: After merge fix mysql-test/r/multi_update.result: Make timestamp test portable mysql-test/t/multi_update.test: Make timestamp test portable sql/field.cc: After merge fix sql/item_sum.cc: After merge fix sql/log_event.cc: Remove compiler warning sql/mysql_priv.h: Added THD to add_to_list (Faster parsing) sql/sql_derived.cc: Fixed parameters to create_tmp_table() sql/sql_lex.cc: Added THD to add_to_list (Faster parsing) sql/sql_lex.h: Added THD to add_to_list (Faster parsing) sql/sql_parse.cc: Added THD to add_to_list (Faster parsing) sql/sql_select.cc: After merge fixes Fixed return values from JOIN::optimize() Replaced test_function_query with '!tables_list' Optimized arguments to create_tmp_table() sql/sql_select.h: Removed test_function_query variable Updated prototypes sql/sql_union.cc: Updated argument lists. sql/sql_update.cc: After merge fixes sql/sql_yacc.yy: Added THD to all add_xxx_to_list() functions sql/table.h: After merge fix --- heap/_check.c | 2 +- mysql-test/r/distinct.result | 32 ++++---- mysql-test/r/multi_update.result | 14 ++-- mysql-test/t/multi_update.test | 4 +- sql/field.cc | 9 ++- sql/item_sum.cc | 16 ++-- sql/log_event.cc | 12 ++- sql/mysql_priv.h | 27 ++++--- sql/sql_derived.cc | 4 +- sql/sql_lex.cc | 16 ++-- sql/sql_lex.h | 14 ++-- sql/sql_parse.cc | 17 ++-- sql/sql_select.cc | 132 +++++++++++++++++-------------- sql/sql_select.h | 11 +-- sql/sql_union.cc | 10 +-- sql/sql_update.cc | 19 ++--- sql/sql_yacc.yy | 84 ++++++++++---------- sql/table.h | 3 +- 18 files changed, 227 insertions(+), 199 deletions(-) diff --git a/heap/_check.c b/heap/_check.c index 5ee511bf92a..bc1cd24113c 100644 --- a/heap/_check.c +++ b/heap/_check.c @@ -75,7 +75,7 @@ int heap_check_heap(HP_INFO *info, my_bool print_status) break; /* End of file */ } } - _hp_find_record(info,pos); + hp_find_record(info,pos); if (!info->current_ptr[share->reclength]) deleted++; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 809eb22f987..aefcba9ed9d 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -199,29 +199,29 @@ select distinct 1 from t1,t3 where t1.a=t3.a; 1 1 explain SELECT distinct t1.a from t1; -table type possible_keys key key_len ref rows Extra -t1 index NULL PRIMARY 4 NULL 2 Using index +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index explain SELECT distinct t1.a from t1 order by a desc; -table type possible_keys key key_len ref rows Extra -t1 index NULL PRIMARY 4 NULL 2 Using index +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index explain SELECT t1.a from t1 group by a order by a desc; -table type possible_keys key key_len ref rows Extra -t1 index NULL PRIMARY 4 NULL 2 Using index +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index explain SELECT distinct t1.a from t1 order by a desc limit 1; -table type possible_keys key key_len ref rows Extra -t1 index NULL PRIMARY 4 NULL 2 Using index +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index explain SELECT distinct a from t3 order by a desc limit 2; -table type possible_keys key key_len ref rows Extra -t3 index NULL a 5 NULL 204 Using index +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 index NULL a 5 NULL 204 Using index explain SELECT distinct a,b from t3 order by a+1; -table type possible_keys key key_len ref rows Extra -t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort explain SELECT distinct a,b from t3 order by a limit 10; -table type possible_keys key key_len ref rows Extra -t3 index NULL a 5 NULL 204 Using temporary +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 index NULL a 5 NULL 204 Using temporary explain SELECT a,b from t3 group by a,b order by a+1; -table type possible_keys key key_len ref rows Extra -t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort drop table t1,t2,t3,t4; CREATE TABLE t1 (name varchar(255)); INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae'); diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 7d1f5bd53f6..8cf035343b1 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -182,13 +182,13 @@ insert into t1 values(1,1,NULL); insert into t2 values(1,10,NULL),(2,20,NULL); set timestamp=1038000000; UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; -select * from t1; -n d t -1 10 20021123002000 -select * from t2; -n d t -1 10 20021127154957 -2 20 20021127154957 +select n,d,unix_timestamp(t) from t1; +n d unix_timestamp(t) +1 10 1038000000 +select n,d,unix_timestamp(t) from t2; +n d unix_timestamp(t) +1 10 1038401397 +2 20 1038401397 UPDATE t1,t2 SET 1=2 WHERE t1.n=t2.n; 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 '1=2 WHERE t1.n=t2.n' at line 1 drop table t1,t2; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index b79b0749c82..ff456b710c1 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -183,8 +183,8 @@ insert into t1 values(1,1,NULL); insert into t2 values(1,10,NULL),(2,20,NULL); set timestamp=1038000000; UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; -select * from t1; -select * from t2; +select n,d,unix_timestamp(t) from t1; +select n,d,unix_timestamp(t) from t2; --error 1064 UPDATE t1,t2 SET 1=2 WHERE t1.n=t2.n; drop table t1,t2; diff --git a/sql/field.cc b/sql/field.cc index 7b3b88a69f1..77bd7392dd2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1577,12 +1577,12 @@ void Field_medium::sql_type(String &res) const int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) { char *end; - while (len && my_isspace(system_charset_info,*from)) + while (len && my_isspace(cs,*from)) { len--; from++; } long tmp; - String tmp_str(from,len); + String tmp_str(from, len, cs); from= tmp_str.c_ptr(); // Add end null if needed int error= 0; errno=0; @@ -1602,6 +1602,7 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) if (errno || (from+len != end && current_thd->count_cuted_fields && !test_if_int(from,len))) + { current_thd->cuted_fields++; error= 1; } @@ -1826,12 +1827,12 @@ void Field_long::sql_type(String &res) const int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) { char *end; - while (len && my_isspace(system_charset_info,*from)) + while (len && my_isspace(cs,*from)) { // For easy error check len--; from++; } longlong tmp; - String tmp_str(from,len); + String tmp_str(from, len, cs); from= tmp_str.c_ptr(); // Add end null if needed int error= 0; errno=0; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index fe7523a5fc5..a1f772f4d46 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -43,7 +43,8 @@ Item_sum::Item_sum(List &list) void Item_sum::mark_as_sum_func() { - current_thd->lex.current_select->with_sum_func= with_sum_func= 1; + current_thd->lex.current_select->with_sum_func=1; + with_sum_func= 1; } void Item_sum::make_field(Send_field *tmp_field) @@ -991,9 +992,9 @@ bool Item_sum_count_distinct::setup(THD *thd) tmp_table_param->cleanup(); } if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, - 0, 0, + 0, select_lex->options | thd->options, - select_lex->master_unit()))) + HA_POS_ERROR))) return 1; table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows table->no_rows=1; @@ -1091,7 +1092,7 @@ bool Item_sum_count_distinct::setup(THD *thd) int Item_sum_count_distinct::tree_to_myisam() { - if (create_myisam_from_heap(table, tmp_table_param, + if (create_myisam_from_heap(current_thd, table, tmp_table_param, HA_ERR_RECORD_FILE_FULL, 1) || tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this, left_root_right)) @@ -1137,7 +1138,8 @@ bool Item_sum_count_distinct::add() if (tree_to_myisam()) return 1; } - else if (!tree_insert(&tree, table->record[0] + rec_offset, 0, tree.custom_arg)) + else if (!tree_insert(&tree, table->record[0] + rec_offset, 0, + tree.custom_arg)) return 1; } else if ((error=table->file->write_row(table->record[0]))) @@ -1145,13 +1147,15 @@ bool Item_sum_count_distinct::add() if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE) { - if (create_myisam_from_heap(table, tmp_table_param, error,1)) + if (create_myisam_from_heap(current_thd, table, tmp_table_param, error, + 1)) return 1; // Not a table_is_full error } } return 0; } + longlong Item_sum_count_distinct::val_int() { if (!table) // Empty query diff --git a/sql/log_event.cc b/sql/log_event.cc index d9ee832f7d3..5050bba9965 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1194,9 +1194,15 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, sql_ex.empty_flags = 0; switch (handle_dup) { - case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break; - case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break; - case DUP_ERROR: break; + case DUP_IGNORE: + sql_ex.opt_flags |= IGNORE_FLAG; + break; + case DUP_REPLACE: + sql_ex.opt_flags |= REPLACE_FLAG; + break; + case DUP_UPDATE: // Impossible here + case DUP_ERROR: + break; } if (!ex->field_term->length()) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index cb9e3a362b4..9714c2bcdd7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -460,7 +460,8 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List &fields, int mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, List *values, COND *conds, ulong options, - enum enum_duplicates handle_duplicates); + enum enum_duplicates handle_duplicates, + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); int mysql_insert(THD *thd,TABLE_LIST *table,List &fields, List &values, List &update_fields, List &update_values, enum_duplicates flag); @@ -554,13 +555,13 @@ int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, /* sql_base.cc */ void set_item_name(Item *item,char *pos,uint length); -bool add_field_to_list(char *field_name, enum enum_field_types type, +bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type, char *length, char *decimal, uint type_modifier, Item *default_value, Item *comment, char *change, TYPELIB *interval,CHARSET_INFO *cs); void store_position_for_column(const char *name); -bool add_to_list(SQL_LIST &list,Item *group,bool asc=0); +bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0); void add_join_on(TABLE_LIST *b,Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b); bool add_proc_to_list(THD *thd, Item *item); @@ -871,22 +872,26 @@ Item *get_system_var(enum_var_type var_type, const char *var_name, uint length, /* Some inline functions for more speed */ -inline bool add_item_to_list(Item *item) +inline bool add_item_to_list(THD *thd, Item *item) { - return current_lex->current_select->add_item_to_list(item); + return thd->lex.current_select->add_item_to_list(thd, item); } -inline bool add_value_to_list(Item *value) + +inline bool add_value_to_list(THD *thd, Item *value) { - return current_lex->value_list.push_back(value); + return thd->lex.value_list.push_back(value); } -inline bool add_order_to_list(Item *item, bool asc) + +inline bool add_order_to_list(THD *thd, Item *item, bool asc) { - return current_lex->current_select->add_order_to_list(item, asc); + return thd->lex.current_select->add_order_to_list(thd, item, asc); } -inline bool add_group_to_list(Item *item, bool asc) + +inline bool add_group_to_list(THD *thd, Item *item, bool asc) { - return current_lex->current_select->add_group_to_list(item, asc); + return thd->lex.current_select->add_group_to_list(thd, item, asc); } + inline void mark_as_null_row(TABLE *table) { table->null_row=1; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 76a97a2e4b8..f0df6811133 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -66,10 +66,10 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count=item_list.elements; if (!(table=create_tmp_table(thd, &tmp_table_param, item_list, - (ORDER*) 0, 0, 1, 0, + (ORDER*) 0, 0, 1, (sl->options | thd->options | TMP_TABLE_ALL_COLUMNS), - unit))) + HA_POS_ERROR))) { res=-1; goto exit; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 54f28668644..833f36dbe9f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1098,19 +1098,19 @@ st_select_lex* st_select_lex_node::select_lex() DBUG_RETURN(0); } -bool st_select_lex_node::add_item_to_list(Item *item) +bool st_select_lex_node::add_item_to_list(THD *thd, Item *item) { return 1; } -bool st_select_lex_node::add_group_to_list(Item *item, bool asc) +bool st_select_lex_node::add_group_to_list(THD *thd, Item *item, bool asc) { return 1; } -bool st_select_lex_node::add_order_to_list(Item *item, bool asc) +bool st_select_lex_node::add_order_to_list(THD *thd, Item *item, bool asc) { - return add_to_list(order_list,item,asc); + return add_to_list(thd, order_list,item,asc); } bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func) @@ -1166,7 +1166,7 @@ TABLE_LIST* st_select_lex_node::get_table_list() { return 0; } List* st_select_lex_node::get_item_list() { return 0; } List* st_select_lex_node::get_use_index() { return 0; } List* st_select_lex_node::get_ignore_index() { return 0; } -TABLE_LIST *st_select_lex_node::add_table_to_list(Table_ident *table, +TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, bool updating, thr_lock_type flags, @@ -1269,14 +1269,14 @@ st_select_lex* st_select_lex::select_lex() return this; } -bool st_select_lex::add_item_to_list(Item *item) +bool st_select_lex::add_item_to_list(THD *thd, Item *item) { return item_list.push_back(item); } -bool st_select_lex::add_group_to_list(Item *item, bool asc) +bool st_select_lex::add_group_to_list(THD *thd, Item *item, bool asc) { - return add_to_list(group_list, item, asc); + return add_to_list(thd, group_list, item, asc); } bool st_select_lex::add_ftfunc_to_list(Item_func_match *func) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 453728bfc0e..0c761baffa3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -227,9 +227,9 @@ public: void exclude(); virtual st_select_lex* select_lex(); - virtual bool add_item_to_list(Item *item); - bool add_order_to_list(Item *item, bool asc); - virtual bool add_group_to_list(Item *item, bool asc); + virtual bool add_item_to_list(THD *thd, Item *item); + bool add_order_to_list(THD *thd, Item *item, bool asc); + virtual bool add_group_to_list(THD *thd, Item *item, bool asc); virtual bool add_ftfunc_to_list(Item_func_match *func); virtual st_select_lex_unit* master_unit()= 0; @@ -242,7 +242,7 @@ public: virtual List* get_item_list(); virtual List* get_use_index(); virtual List* get_ignore_index(); - virtual TABLE_LIST *add_table_to_list(Table_ident *table, + virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, bool updating, thr_lock_type flags= TL_UNLOCK, @@ -363,15 +363,15 @@ public: uint get_in_sum_expr(); st_select_lex* select_lex(); - bool add_item_to_list(Item *item); - bool add_group_to_list(Item *item, bool asc); + bool add_item_to_list(THD *thd, Item *item); + bool add_group_to_list(THD *thd, Item *item, bool asc); bool add_ftfunc_to_list(Item_func_match *func); TABLE_LIST* get_table_list(); List* get_item_list(); List* get_use_index(); List* get_ignore_index(); - TABLE_LIST* add_table_to_list(Table_ident *table, + TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, bool updating, thr_lock_type flags= TL_UNLOCK, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8e8e2c44e01..af0a46e6919 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2070,7 +2070,7 @@ mysql_execute_command(THD *thd) walk->lock_type= auxi->lock_type; auxi->table_list= walk; // Remember corresponding table } - if (add_item_to_list(new Item_null())) + if (add_item_to_list(thd, new Item_null())) { res= -1; break; @@ -2927,7 +2927,7 @@ void create_select_for_variable(const char *var_name) lex->sql_command= SQLCOM_SELECT; tmp.str= (char*) var_name; tmp.length=strlen(var_name); - add_item_to_list(get_system_var(OPT_SESSION, tmp)); + add_item_to_list(lex->thd, get_system_var(OPT_SESSION, tmp)); DBUG_VOID_RETURN; } @@ -2992,14 +2992,13 @@ mysql_parse(THD *thd, char *inBuf, uint length) ** Return 0 if ok ******************************************************************************/ -bool add_field_to_list(char *field_name, enum_field_types type, +bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, char *length, char *decimals, uint type_modifier, Item *default_value, Item *comment, char *change, TYPELIB *interval, CHARSET_INFO *cs) { register create_field *new_field; - THD *thd=current_thd; LEX *lex= &thd->lex; uint allowed_type_modifier=0; char warn_buff[MYSQL_ERRMSG_SIZE]; @@ -3304,7 +3303,7 @@ add_proc_to_list(THD* thd, Item *item) ORDER *order; Item **item_ptr; - if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*)))) + if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*)))) return 1; item_ptr = (Item**) (order+1); *item_ptr= item; @@ -3351,12 +3350,12 @@ static void remove_escape(char *name) ****************************************************************************/ -bool add_to_list(SQL_LIST &list,Item *item,bool asc) +bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) { ORDER *order; Item **item_ptr; DBUG_ENTER("add_to_list"); - if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*)))) + if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*)))) DBUG_RETURN(1); item_ptr = (Item**) (order+1); *item_ptr=item; @@ -3369,7 +3368,8 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc) } -TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table, +TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, + Table_ident *table, LEX_STRING *alias, bool updating, thr_lock_type flags, @@ -3377,7 +3377,6 @@ TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table, List *ignore_index) { register TABLE_LIST *ptr; - THD *thd=current_thd; char *alias_str; DBUG_ENTER("add_table_to_list"); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a5c69763863..3437ae875b9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -377,7 +377,6 @@ JOIN::prepare(TABLE_LIST *tables_init, int JOIN::optimize() { - ha_rows select_limit; DBUG_ENTER("JOIN::optimize"); #ifdef HAVE_REF_TO_FIELDS // Not done yet @@ -400,19 +399,17 @@ JOIN::optimize() #endif conds= optimize_cond(conds,&cond_value); - if (thd->fatal_error) + if (thd->fatal_error || thd->net.report_error) { // quick abort delete procedure; - error= 0; - DBUG_RETURN(1); - } else if (thd->net.report_error) - // normal error processing & cleanup - DBUG_RETURN(-1); + error= thd->net.report_error ? -1 : 1; + DBUG_RETURN(-1); // Return without cleanup + } if (cond_value == Item::COND_FALSE || (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS))) - { /* Impossible cond */ + { /* Impossible cond */ zero_result_cause= "Impossible WHERE"; DBUG_RETURN(0); } @@ -429,24 +426,21 @@ JOIN::optimize() DBUG_RETURN(0); } zero_result_cause= "Select tables optimized away"; - tables_list= 0; // All tables resolved + tables_list= 0; // All tables resolved } } if (!tables_list) - { - test_function_query= 1; DBUG_RETURN(0); - } - error= -1; + error= -1; // Error is sent to client sort_by_table= get_sort_by_table(order, group_list, tables_list); /* Calculate how to do the join */ thd->proc_info= "statistics"; if (make_join_statistics(this, tables_list, conds, &keyuse) || thd->fatal_error) - DBUG_RETURN(-1); + DBUG_RETURN(1); if (select_lex->dependent) { @@ -460,7 +454,9 @@ JOIN::optimize() } thd->proc_info= "preparing"; if (result->initialize_tables(this)) - DBUG_RETURN(-1); + { + DBUG_RETURN(1); // error = -1 + } if (const_table_map != found_const_table_map && !(select_options & SELECT_DESCRIBE)) { @@ -474,7 +470,7 @@ JOIN::optimize() { /* purecov: inspected */ my_message(ER_TOO_BIG_SELECT, ER(ER_TOO_BIG_SELECT), MYF(0)); error= 1; /* purecov: inspected */ - DBUG_RETURN(-1); + DBUG_RETURN(1); } if (const_tables && !thd->locked_tables && !(select_options & SELECT_NO_UNLOCK)) @@ -502,9 +498,9 @@ JOIN::optimize() select=make_select(*table, const_table_map, const_table_map, conds, &error); if (error) - { /* purecov: inspected */ - error= -1; /* purecov: inspected */ - DBUG_RETURN(-1); + { /* purecov: inspected */ + error= -1; /* purecov: inspected */ + DBUG_RETURN(1); } if (make_join_select(this, select, conds)) { @@ -543,11 +539,11 @@ JOIN::optimize() bool all_order_fields_used; if (order) skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); - if ((group=create_distinct_group(thd, order, fields_list, - &all_order_fields_used))) + if ((group_list=create_distinct_group(thd, order, fields_list, + &all_order_fields_used))) { bool skip_group= (skip_sort_order && - test_if_skip_sort_order(tab, group, select_limit, + test_if_skip_sort_order(tab, group_list, select_limit, 1) != 0); if ((skip_group && all_order_fields_used) || select_limit == HA_POS_ERROR || @@ -561,10 +557,10 @@ JOIN::optimize() group=1; // For end_write_group } else - group= 0; + group_list= 0; } else if (thd->fatal_error) // End of memory - DBUG_RETURN(-1); + DBUG_RETURN(1); } group_list= remove_const(this, group_list, conds, &simple_group); if (!group_list && group) @@ -648,7 +644,7 @@ JOIN::optimize() (order && simple_order || group_list && simple_group)) { if (add_ref_to_table_cond(thd,&join_tab[const_tables])) - DBUG_RETURN(-1); + DBUG_RETURN(1); } if (!(select_options & SELECT_BIG_RESULT) && @@ -712,7 +708,7 @@ JOIN::exec() DBUG_ENTER("JOIN::exec"); - if (test_function_query) + if (!tables_list) { // Only test of functions error=0; if (select_options & SELECT_DESCRIBE) @@ -790,9 +786,9 @@ JOIN::exec() group_list : (ORDER*) 0), group_list ? 0 : select_distinct, group_list && simple_group, - (order == 0 || skip_sort_order) && - select_limit != HA_POS_ERROR, - select_options, unit))) + select_options, + (order == 0 || skip_sort_order) ? select_limit : + HA_POS_ERROR))) DBUG_VOID_RETURN; if (having_list && @@ -917,9 +913,8 @@ JOIN::exec() if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields, (ORDER*) 0, select_distinct && !group_list, - 1, 0, - select_options, unit))) - DBUG_VOID_RETURN; + 1, select_options, HA_POS_ERROR))) + DBUG_VOID_RETURN; if (group_list) { thd->proc_info="Creating sort index"; @@ -1122,9 +1117,10 @@ mysql_select(THD *thd, TABLE_LIST *tables, List &fields, COND *conds, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, bool fake_select_lex) { + int err; + bool free_join= 1; DBUG_ENTER("mysql_select"); - bool free_join= 1; JOIN *join; if (!fake_select_lex && select_lex->join != 0) { @@ -1168,13 +1164,13 @@ mysql_select(THD *thd, TABLE_LIST *tables, List &fields, COND *conds, } } - switch (join->optimize()) + if ((err= join->optimize())) { - case 1: - DBUG_RETURN(join->error); - case -1: - goto err; - } + if (err == -1) + DBUG_RETURN(join->error); + DBUG_ASSERT(err == 1); + goto err; // 1 + } if (thd->net.report_error || (free_join && join->global_optimize())) goto err; @@ -1187,13 +1183,13 @@ err: thd->limit_found_rows = join->send_records; thd->examined_row_count = join->examined_rows; thd->proc_info="end"; - int error= (fake_select_lex?join->error:join->cleanup(thd)) || - thd->net.report_error; + err= (fake_select_lex ? join->error : join->cleanup(thd)); + if (thd->net.report_error) + err= -1; delete join; - DBUG_RETURN(error); + DBUG_RETURN(err); } - else - DBUG_RETURN(join->error); + DBUG_RETURN(join->error); } /***************************************************************************** @@ -3887,8 +3883,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, TABLE * create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, ulong select_options, - SELECT_LEX_UNIT *unit) + ulong select_options, ha_rows rows_limit) { TABLE *table; uint i,field_count,reclength,null_count,null_pack_length, @@ -3908,9 +3903,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, uint temp_pool_slot=MY_BIT_NONE; DBUG_ENTER("create_tmp_table"); - DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d allow_distinct_limit: %d group: %d", + DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d", (int) distinct, (int) save_sum_fields, - (int) allow_distinct_limit,test(group))); + (ulong) rows_limit,test(group))); statistic_increment(created_tmp_tables, &LOCK_status); @@ -4286,13 +4281,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, null_pack_length-=hidden_null_pack_length; keyinfo->key_parts= ((field_count-param->hidden_field_count)+ test(null_pack_length)); - if (allow_distinct_limit) - { - set_if_smaller(table->max_rows, unit->select_limit_cnt); - param->end_write_records= unit->select_limit_cnt; - } - else - param->end_write_records= HA_POS_ERROR; + set_if_smaller(table->max_rows, rows_limit); + param->end_write_records= rows_limit; table->distinct=1; table->keys=1; if (blob_count) @@ -5679,7 +5669,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if ((error=table->file->write_row(table->record[0]))) { - if (create_myisam_from_heap(join.thd, table, + if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) DBUG_RETURN(-1); // Not a table_is_full error @@ -6060,12 +6050,32 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } -/***************************************************************************** +/* If not selecting by given key, create an index how records should be read - return: 0 ok - -1 some fatal error - 1 no records -*****************************************************************************/ + + SYNOPSIS + create_sort_index() + thd Thread handler + tab Table to sort (in join structure) + order How table should be sorted + filesort_limit Max number of rows that needs to be sorted + select_limit Max number of rows in final output + Used to decide if we should use index or not + + + IMPLEMENTATION + - If there is an index that can be used, 'tab' is modified to use + this index. + - If no index, create with filesort() an index file that can be used to + retrieve rows in order (should be done with 'read_record'). + The sorted data is stored in tab->table and will be freed when calling + free_io_cache(tab->table). + + RETURN VALUES + 0 ok + -1 Some fatal error + 1 No records +*/ static int create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order, diff --git a/sql/sql_select.h b/sql/sql_select.h index 31693628be5..1fbe2052831 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -160,7 +160,7 @@ class JOIN :public Sql_alloc bool sort_and_group,first_record,full_join,group, no_field_update; bool do_send_rows; table_map const_table_map,found_const_table_map,outer_join; - ha_rows send_records,found_records,examined_rows,row_limit; + ha_rows send_records,found_records,examined_rows,row_limit, select_limit; POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1]; double best_read; List *fields; @@ -196,7 +196,6 @@ class JOIN :public Sql_alloc SQL_SELECT *select; //created in optimisation phase TABLE *exec_tmp_table; //used in 'exec' to hold temporary - my_bool test_function_query; // need to return select items 1 row const char *zero_result_cause; // not 0 if exec must return zero result my_bool union_part; // this subselect is part of union @@ -228,7 +227,6 @@ class JOIN :public Sql_alloc error(0), select(0), exec_tmp_table(0), - test_function_query(0), zero_result_cause(0) { fields_list = fields; @@ -261,16 +259,15 @@ void TEST_join(JOIN *join); bool store_val_in_field(Field *field,Item *val); TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, ulong select_options, - SELECT_LEX_UNIT *unit); + ulong select_options, ha_rows rows_limit); void free_tmp_table(THD *thd, TABLE *entry); void count_field_types(TMP_TABLE_PARAM *param, List &fields, bool reset_with_sum_func); bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,List &fields); void copy_fields(TMP_TABLE_PARAM *param); void copy_funcs(Item_result_field **func_ptr); -bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error, - bool ignore_last_dupp_error); +bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, + int error, bool ignore_last_dupp_error); /* functions from opt_sum.cc */ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 705152ee9f2..6e8c2ebdb5c 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -81,7 +81,8 @@ bool select_union::send_data(List &values) if (thd->net.last_errno == ER_RECORD_FILE_FULL) { thd->clear_error(); // do not report user about table overflow - if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0)) + if (create_myisam_from_heap(thd, table, tmp_table_param, + info.last_errno, 0)) return 1; } else @@ -150,10 +151,9 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result) tmp_table_param.field_count=item_list.elements; if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, (ORDER*) 0, !union_option, - 1, 0, - (first_select()->options | thd->options | - TMP_TABLE_ALL_COLUMNS), - this))) + 1, (first_select()->options | thd->options | + TMP_TABLE_ALL_COLUMNS), + HA_POS_ERROR))) goto err; table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3aab5cd30a9..614d3d5803b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -437,7 +437,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, Connect fields with tables and create list of tables that are updated */ -int multi_update::prepare(List ¬_used_values) +int multi_update::prepare(List ¬_used_values, SELECT_LEX_UNIT *unit) { TABLE_LIST *table_ref; SQL_LIST update; @@ -531,7 +531,6 @@ int multi_update::prepare(List ¬_used_values) for (i=0 ; i < table_count ; i++) set_if_bigger(max_fields, fields_for_table[i]->elements); copy_field= new Copy_field[max_fields]; - init_ftfuncs(thd,1); DBUG_RETURN(thd->fatal_error != 0); } @@ -575,7 +574,7 @@ multi_update::initialize_tables(JOIN *join) /* ok to be on stack as this is not referenced outside of this func */ Field_string offset(table->file->ref_length, 0, "offset", - table, 1); + table, my_charset_bin); if (temp_fields.push_front(new Item_field(((Field *) &offset)))) DBUG_RETURN(1); @@ -591,8 +590,9 @@ multi_update::initialize_tables(JOIN *join) if (!(tmp_tables[cnt]=create_tmp_table(thd, tmp_param, temp_fields, - (ORDER*) &group, 0, 0, 0, - TMP_TABLE_ALL_COLUMNS))) + (ORDER*) &group, 0, 0, + TMP_TABLE_ALL_COLUMNS, + HA_POS_ERROR))) DBUG_RETURN(1); tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE); } @@ -682,7 +682,8 @@ bool multi_update::send_data(List ¬_used_values) (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)) { - if (create_myisam_from_heap(table, tmp_table_param + offset, error, 1)) + if (create_myisam_from_heap(thd, table, tmp_table_param + offset, + error, 1)) { do_update=0; DBUG_RETURN(1); // Not a table_is_full error @@ -697,7 +698,7 @@ bool multi_update::send_data(List ¬_used_values) void multi_update::send_error(uint errcode,const char *err) { /* First send error what ever it is ... */ - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); /* If nothing updated return */ if (!updated) @@ -869,7 +870,7 @@ bool multi_update::send_eof() /* Safety: If we haven't got an error before (should not happen) */ my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update", MYF(0)); - ::send_error(&thd->net); + ::send_error(thd); return 1; } @@ -880,7 +881,7 @@ bool multi_update::send_eof() { query_cache_invalidate3(thd, update_tables, 1); } - ::send_ok(&thd->net, + ::send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); return 0; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3109aadca38..d23efaa2a6d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -814,7 +814,7 @@ create: THD *thd= YYTHD; LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_TABLE; - if (!lex->select_lex.add_table_to_list($5, + if (!lex->select_lex.add_table_to_list(thd,$5, ($2 & HA_LEX_CREATE_TMP_TABLE ? &tmp_table_alias : @@ -838,7 +838,7 @@ create: { LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_INDEX; - if (!lex->current_select->add_table_to_list($7,NULL,1)) + if (!lex->current_select->add_table_to_list(lex->thd, $7,NULL,1)) YYABORT; lex->create_list.empty(); lex->key_list.empty(); @@ -1058,7 +1058,7 @@ field_spec: type opt_attribute { LEX *lex=Lex; - if (add_field_to_list($1.str, + if (add_field_to_list(lex->thd, $1.str, (enum enum_field_types) $3, lex->length,lex->dec,lex->type, lex->default_value, lex->comment, @@ -1368,7 +1368,7 @@ alter: LEX *lex=&thd->lex; lex->sql_command = SQLCOM_ALTER_TABLE; lex->name=0; - if (!lex->select_lex.add_table_to_list($4, NULL,1)) + if (!lex->select_lex.add_table_to_list(thd, $4, NULL,1)) YYABORT; lex->drop_primary=0; lex->create_list.empty(); @@ -1423,7 +1423,7 @@ alter_list_item: type opt_attribute { LEX *lex=Lex; - if (add_field_to_list($3.str, + if (add_field_to_list(lex->thd,$3.str, (enum enum_field_types) $5, lex->length,lex->dec,lex->type, lex->default_value, lex->comment, @@ -1634,9 +1634,10 @@ table_to_table_list: table_to_table: table_ident TO_SYM table_ident { - SELECT_LEX_NODE *sl= Lex->current_select; - if (!sl->add_table_to_list($1,NULL,1,TL_IGNORE) || - !sl->add_table_to_list($3,NULL,1,TL_IGNORE)) + LEX *lex=Lex; + SELECT_LEX_NODE *sl= lex->current_select; + if (!sl->add_table_to_list(lex->thd, $1,NULL,1,TL_IGNORE) || + !sl->add_table_to_list(lex->thd, $3,NULL,1,TL_IGNORE)) YYABORT; }; @@ -1760,7 +1761,7 @@ select_item_list: | select_item | '*' { - if (add_item_to_list(new Item_field(NULL,NULL,"*"))) + if (add_item_to_list(YYTHD, new Item_field(NULL,NULL,"*"))) YYABORT; }; @@ -1768,7 +1769,7 @@ select_item_list: select_item: remember_name select_item2 remember_end select_alias { - if (add_item_to_list($2)) + if (add_item_to_list(YYTHD, $2)) YYABORT; if ($4.str) $2->set_name($4.str); @@ -2475,7 +2476,8 @@ join_table: { LEX *lex= Lex; SELECT_LEX_NODE *sel= lex->current_select; - if (!($$= sel->add_table_to_list($2, $3, 0, lex->lock_option, + if (!($$= sel->add_table_to_list(lex->thd, $2, $3, 0, + lex->lock_option, sel->get_use_index(), sel->get_ignore_index()))) YYABORT; @@ -2488,7 +2490,7 @@ join_table: SELECT_LEX_UNIT *unit= lex->current_select->master_unit(); lex->current_select= unit->outer_select(); if (!($$= lex->current_select-> - add_table_to_list(new Table_ident(unit), $5, 0, + add_table_to_list(lex->thd, new Table_ident(unit), $5, 0, lex->lock_option))) YYABORT; }; @@ -2623,9 +2625,9 @@ group_clause: group_list: group_list ',' order_ident order_dir - { if (add_group_to_list($3,(bool) $4)) YYABORT; } + { if (add_group_to_list(YYTHD, $3,(bool) $4)) YYABORT; } | order_ident order_dir - { if (add_group_to_list($1,(bool) $2)) YYABORT; }; + { if (add_group_to_list(YYTHD, $1,(bool) $2)) YYABORT; }; olap_opt: /* empty */ {} @@ -2684,9 +2686,9 @@ order_clause: order_list: order_list ',' order_ident order_dir - { if (add_order_to_list($3,(bool) $4)) YYABORT; } + { if (add_order_to_list(YYTHD, $3,(bool) $4)) YYABORT; } | order_ident order_dir - { if (add_order_to_list($1,(bool) $2)) YYABORT; }; + { if (add_order_to_list(YYTHD, $1,(bool) $2)) YYABORT; }; order_dir: /* empty */ { $$ = 1; } @@ -2881,7 +2883,7 @@ drop: lex->drop_list.empty(); lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, $3.str)); - if (!lex->current_select->add_table_to_list($5,NULL, 1)) + if (!lex->current_select->add_table_to_list(lex->thd, $5,NULL, 1)) YYABORT; } | DROP DATABASE if_exists ident @@ -2905,7 +2907,7 @@ table_list: table_name: table_ident - { if (!Select->add_table_to_list($1, NULL, 1)) YYABORT; }; + { if (!Select->add_table_to_list(YYTHD, $1, NULL, 1)) YYABORT; }; if_exists: /* empty */ { $$= 0; } @@ -3109,12 +3111,12 @@ update: update_list: update_list ',' simple_ident equal expr { - if (add_item_to_list($3) || add_value_to_list($5)) + if (add_item_to_list(YYTHD, $3) || add_value_to_list(YYTHD, $5)) YYABORT; } | simple_ident equal expr { - if (add_item_to_list($1) || add_value_to_list($3)) + if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3)) YYABORT; }; @@ -3139,7 +3141,7 @@ delete: single_multi: FROM table_ident { - if (!Select->add_table_to_list($2, NULL, 1, Lex->lock_option)) + if (!Select->add_table_to_list(YYTHD, $2, NULL, 1, Lex->lock_option)) YYABORT; } where_clause opt_order_clause @@ -3160,14 +3162,14 @@ table_wild_list: table_wild_one: ident opt_wild { - if (!Select->add_table_to_list(new Table_ident($1), NULL, 1, + if (!Select->add_table_to_list(YYTHD, new Table_ident($1), NULL, 1, Lex->lock_option)) YYABORT; } | ident '.' ident opt_wild { - if (!Select->add_table_to_list(new Table_ident($1, $3, 0), NULL, 1, - Lex->lock_option)) + if (!Select->add_table_to_list(YYTHD, new Table_ident($1, $3, 0), + NULL, 1, Lex->lock_option)) YYABORT; } ; @@ -3240,7 +3242,7 @@ show_param: Lex->sql_command= SQLCOM_SHOW_FIELDS; if ($5) $4->change_db($5); - if (!Select->add_table_to_list($4, NULL, 0)) + if (!Select->add_table_to_list(YYTHD, $4, NULL, 0)) YYABORT; } | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ @@ -3273,7 +3275,7 @@ show_param: Lex->sql_command= SQLCOM_SHOW_KEYS; if ($4) $3->change_db($4); - if (!Select->add_table_to_list($3, NULL, 0)) + if (!Select->add_table_to_list(YYTHD, $3, NULL, 0)) YYABORT; } | COLUMN_SYM TYPES_SYM @@ -3331,7 +3333,7 @@ show_param: | CREATE TABLE_SYM table_ident { Lex->sql_command = SQLCOM_SHOW_CREATE; - if(!Select->add_table_to_list($3, NULL,0)) + if(!Select->add_table_to_list(YYTHD, $3, NULL,0)) YYABORT; } | MASTER_SYM STATUS_SYM @@ -3376,7 +3378,7 @@ describe: lex->wild=0; lex->verbose=0; lex->sql_command=SQLCOM_SHOW_FIELDS; - if (!Select->add_table_to_list($2, NULL,0)) + if (!Select->add_table_to_list(lex->thd, $2, NULL,0)) YYABORT; } opt_describe_column {} @@ -3500,14 +3502,14 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term opt_ignore_lines opt_field_spec { - if (!Select->add_table_to_list($11, NULL, 1)) + if (!Select->add_table_to_list(YYTHD, $11, NULL, 1)) YYABORT; } | LOAD TABLE_SYM table_ident FROM MASTER_SYM { Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE; - if (!Select->add_table_to_list($3, NULL, 1)) + if (!Select->add_table_to_list(YYTHD, $3, NULL, 1)) YYABORT; } @@ -3683,13 +3685,15 @@ ident_or_text: user: ident_or_text { - if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user)))) + THD *thd= YYTHD; + if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; $$->user = $1; $$->host.str=NullS; } | ident_or_text '@' ident_or_text { - if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user)))) + THD *thd= YYTHD; + if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; $$->user = $1; $$->host=$3; }; @@ -3936,7 +3940,7 @@ option_value: { THD *thd=YYTHD; LEX_USER *user; - if (!(user=(LEX_USER*) sql_alloc(sizeof(LEX_USER)))) + if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))) YYABORT; user->host.str=0; user->user.str=thd->priv_user; @@ -3973,7 +3977,7 @@ text_or_password: $$=$3.str; else { - char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1); + char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1); make_scrambled_password(buff,$3.str); $$=buff; } @@ -4011,7 +4015,7 @@ table_lock_list: table_lock: table_ident opt_table_alias lock_option { - if (!Select->add_table_to_list($1, $2, 0, (thr_lock_type) $3)) + if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3)) YYABORT; } ; @@ -4037,14 +4041,14 @@ handler: { LEX *lex= Lex; lex->sql_command = SQLCOM_HA_OPEN; - if (!lex->current_select->add_table_to_list($2, $4, 0)) + if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0)) YYABORT; } | HANDLER_SYM table_ident CLOSE_SYM { LEX *lex= Lex; lex->sql_command = SQLCOM_HA_CLOSE; - if (!lex->current_select->add_table_to_list($2, 0, 0)) + if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) YYABORT; } | HANDLER_SYM table_ident READ_SYM @@ -4054,7 +4058,7 @@ handler: lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ lex->current_select->select_limit= 1; lex->current_select->offset_limit= 0L; - if (!lex->current_select->add_table_to_list($2, 0, 0)) + if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) YYABORT; } handler_read_or_scan where_clause opt_limit_clause { } @@ -4249,7 +4253,7 @@ opt_table: | table_ident { LEX *lex=Lex; - if (!lex->current_select->add_table_to_list($1,NULL,0)) + if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL,0)) YYABORT; if (lex->grant == GLOBAL_ACLS) lex->grant = TABLE_ACLS & ~GRANT_ACL; @@ -4273,7 +4277,7 @@ grant_user: $$=$1; $1->password=$4; if ($4.length) { - char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1); + char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1); if (buff) { make_scrambled_password(buff,$4.str); diff --git a/sql/table.h b/sql/table.h index 149cc6bca13..d24e4e1e422 100644 --- a/sql/table.h +++ b/sql/table.h @@ -118,7 +118,8 @@ struct st_table { table_map map; /* ID bit of table (1,2,4,8,16...) */ ulong version,flush_version; uchar *null_flags; - IO_CACHE *io_cache; /* If sorted trough filebyte *record_pointers; /* If sorted in memory */ + IO_CACHE *io_cache; /* If sorted trough filebyte */ + byte *record_pointers; /* If sorted in memory */ ha_rows found_records; /* How many records in sort */ ORDER *group; ha_rows quick_rows[MAX_KEY];