diff options
author | timour@mysql.com <> | 2004-11-25 11:37:28 +0200 |
---|---|---|
committer | timour@mysql.com <> | 2004-11-25 11:37:28 +0200 |
commit | 38ab93c6befaca29e2fc36f0f24ce2d1e464550b (patch) | |
tree | 29ad0385fdb639f58ab052e5bb498f9429a374d9 | |
parent | 5eae363c329978a8d87cadc76a1a4967f38a7d70 (diff) | |
parent | cf722bc3f5040d447f657477485e362b967d1f3e (diff) | |
download | mariadb-git-38ab93c6befaca29e2fc36f0f24ce2d1e464550b.tar.gz |
Merge for BUG#3759 which was missing from the main tree for some reason.
210 files changed, 4184 insertions, 1403 deletions
diff --git a/.bzrignore b/.bzrignore index 8583b7ef437..1d14c09a602 100644 --- a/.bzrignore +++ b/.bzrignore @@ -545,3 +545,4 @@ vio/test-sslserver vio/viotest-ssl scripts/make_win_binary_distribution EXCEPTIONS-CLIENT +support-files/my-innodb-heavy-4G.cnf diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index ce1b4d16eb9..241b050d8f9 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -9,6 +9,7 @@ acurtis@pcgem.rdg.cyberkinetica.com ahlentz@co3064164-a.rochd1.qld.optusnet.com.au akishkin@work.mysql.com antony@ltantony.dsl-verizon.net +antony@ltantony.rdg.cyberkinetica.homeunix.net arjen@bitbike.com arjen@co3064164-a.bitbike.com arjen@fred.bitbike.com @@ -20,8 +21,10 @@ bar@mysql.com bell@laptop.sanja.is.com.ua bell@sanja.is.com.ua bk@admin.bk +brian@brian-akers-computer.local carsten@tsort.bitbybit.dk davida@isil.mysql.com +dellis@goetia.(none) dlenev@brandersnatch.localdomain dlenev@build.mysql.com dlenev@mysql.com @@ -33,6 +36,7 @@ greg@mysql.com guilhem@mysql.com gweir@build.mysql.com gweir@work.mysql.com +hartmut@mysql.com heikki@donna.mysql.fi heikki@hundin.mysql.fi heikki@rescue. @@ -43,7 +47,9 @@ hf@genie.(none) igor@hundin.mysql.fi igor@rurik.mysql.com ingo@mysql.com +jani@a193-229-222-105.elisa-laajakaista.fi jani@a80-186-24-72.elisa-laajakaista.fi +jani@a80-186-41-201.elisa-laajakaista.fi jani@dsl-jkl1657.dial.inet.fi jani@hynda.(none) jani@hynda.mysql.fi @@ -66,6 +72,7 @@ kostja@oak.local lenz@kallisto.mysql.com lenz@mysql.com marko@hundin.mysql.fi +matt@mysql.com miguel@hegel.(none) miguel@hegel.br miguel@hegel.local @@ -133,6 +140,7 @@ tim@bitch.mysql.fi tim@black.box tim@hundin.mysql.fi tim@sand.box +tim@siva.hindu.god tim@threads.polyesthetic.msg tim@white.box tim@work.mysql.com diff --git a/Build-tools/Bootstrap b/Build-tools/Bootstrap index 8cad093bc5f..a7d347ba32f 100755 --- a/Build-tools/Bootstrap +++ b/Build-tools/Bootstrap @@ -288,6 +288,10 @@ unless ($opt_skip_manual) system ("bk cat $opt_docdir/Docs/$file.texi > $target_dir/Docs/$file.texi") == 0 or &abort("Could not update $file.texi in $target_dir/Docs/!"); } + system ("rm -f $target_dir/Docs/Images/Makefile*") == 0 + or &abort("Could not remove Makefiles in $target_dir/Docs/Images/!"); + system ("cp $opt_docdir/Docs/Images/*.* $target_dir/Docs/Images") == 0 + or &abort("Could not copy image files in $target_dir/Docs/Images/!"); } # diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index 1650e3d4a09..af03f3209aa 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -10,7 +10,7 @@ use Sys::Hostname; $opt_distribution=$opt_user=$opt_config_env=$opt_config_extra_env=""; $opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_suffix=""; $opt_tmp=$opt_version_suffix=""; -$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=0; +$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_one_error=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=0; $opt_innodb=$opt_bdb=$opt_raid=$opt_libwrap=$opt_clearlogs=$opt_without_ndbcluster=0; GetOptions( @@ -36,6 +36,7 @@ GetOptions( "no-test", "no-mysqltest", "no-benchmark", + "one-error", "perl-files=s", "perl-options=s", "raid", @@ -298,6 +299,7 @@ if ($opt_stage <= 2) $command=$make; $command.= " $opt_make_options" if (defined($opt_make_options) && $opt_make_options ne ""); safe_system($command); + print LOG "Do-compile: Build successful\n"; } # @@ -358,10 +360,16 @@ $ENV{"LD_LIBRARY_PATH"}= ("$test_dir/lib" . # if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest) { + my $force= ""; + if (!$opt_one_error) + { + $force= "--force"; # default + } log_timestamp(); system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir); safe_cd("${test_dir}/mysql-test"); - check_system("./mysql-test-run --warnings --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful"); + check_system("./mysql-test-run $force --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful"); + # 'mysql-test-run' writes its own final message for log evaluation. } # @@ -535,7 +543,10 @@ Do not run any tests. Do not run the benchmark test (written in perl) --no-mysqltest -Do not run the the mysql-test-run test (Same as 'make test') +Do not run the mysql-test-run test (Same as 'make test') + +--one-error +Terminate the mysql-test-run test after the first difference (default: use '--force') --perl-files=list of files Compile and install the given perl modules. diff --git a/Build-tools/mysql-copyright b/Build-tools/mysql-copyright index ad4547b493c..81d6d761498 100755 --- a/Build-tools/mysql-copyright +++ b/Build-tools/mysql-copyright @@ -1,9 +1,9 @@ -#!/usr/bin/perl -i +#!/usr/bin/perl -wi # Untar a MySQL distribution, change the copyright texts, # pack it up again to a given directory -$VER="1.3"; +$VER="1.5"; use Cwd; use File::Basename; @@ -79,7 +79,7 @@ sub main $newdistname .= $suffix if $win_flag; } # find out the extract path (should be same as distname!) - chomp($destdir = `tar ztf ../$distfile | head -1`); + chomp($destdir= `tar ztf ../$distfile | head -1`); # remove slash from the end $destdir= substr($destdir, 0, -1); @@ -103,34 +103,25 @@ sub main unlink("$destdir/PUBLIC", "$destdir/README"); unlink("$destdir/COPYING", "$destdir/EXCEPTIONS-CLIENT"); copy("$WD/Docs/MySQLEULA.txt", "$destdir"); - - # remove readline subdir and update configure accordingly - system("rm -rf $destdir/cmd-line-utils/readline"); - if ($win_flag) { - chdir("$destdir") or (print "$! Unable to change directory to $destdir!\n" && exit(0)); - } else { - chdir("$destdir"); - unlink ("configure") or die "Can't delete $destdir/configure: $!\n"; - open(CONFIGURE,"<configure.in") or die "$! Unable to open configure.in to read from!\n"; - local $/; - undef $/; - my $configure = <CONFIGURE>; - close(CONFIGURE); - $configure =~ s|cmd\-line\-utils/readline/Makefile dnl\n?||g; - open(CONFIGURE,">configure.in") or die "$! Unable to open configure.in to write to!\n"; - print CONFIGURE $configure; - close(CONFIGURE); - `aclocal && autoheader && aclocal && automake && autoconf`; - if (! -f "configure") { - print "\"./configure\" was not produced, exiting!\n"; - exit(0); - } + + # remove subdirectories 'bdb', 'cmd-line-utils/readline' + my @extra_fat= ('bdb', 'cmd-line-utils/readline'); + + foreach my $fat (@extra_fat) + { + &trim_the_fat($fat); } # fix file copyrights &fix_usage_copyright(); &add_copyright(); - + + # fix LICENSE tag in include/mysql_version.h + &fix_mysql_version(); + + # apply "autotools" - must be last to ensure proper timestamps + &run_autotools(); + # rename the directory with new distribution name chdir("$WD/$dir"); print "renaming $destdir $newdistname\n" if $opt_verbose; @@ -143,7 +134,6 @@ sub main # remove temporary directory chdir($WD) or print "$! Unable to move up one dir\n"; - `cd $WD`; my $cwd = getcwd(); print "current dir is $cwd\n" if $opt_verbose ; if (-e $dir) { @@ -154,7 +144,111 @@ sub main } } exit(0); -} +} + +#### +#### This function will s/GPL/Commercial/ in include/mysql_version.h for the +#### LICENSE tag. +#### +sub fix_mysql_version +{ + my $cwd= getcwd(); + chdir("$destdir"); + my $header_file= (-f 'include/mysql_version.h.in')? 'include/mysql_version.h.in' : 'include/mysql_version.h'; + + open(MYSQL_VERSION,"<$header_file") or die "Unable to open $header_file for read: $!\n"; + undef $/; + my $mysql_version= <MYSQL_VERSION>; + close(MYSQL_VERSION); + + $mysql_version=~ s/\#define LICENSE[\s\t]+GPL/#define LICENSE Commercial/; + + open(MYSQL_VERSION,">$header_file") or die "Unable to open $header_file for write: $!\n"; + print MYSQL_VERSION $mysql_version; + close(MYSQL_VERSION); + chdir("$cwd"); +} + +#### +#### This function will remove unwanted parts of a src tree for the mysqlcom +#### distributions. +#### + +sub trim_the_fat +{ + my $the_fat= shift; + my $cwd= getcwd(); + + chdir("$destdir"); + if ( -d "${the_fat}" ) + { + system("rm -rf ${the_fat}"); + if (!$win_flag) + { + open(CONFIG_IN,"<configure.in") or die "Unable to open configure.in for read: $!\n"; + undef $/; + my $config_in= <CONFIG_IN>; + close(CONFIG_IN); + + # + # If $the_fat Makefile line closes the parenthesis, then + # replace that line with just the closing parenthesis. + # + if ($config_in=~ m|${the_fat}/Makefile\)\n?|) + { + $config_in=~ s|${the_fat}/Makefile(\)\n?)|$1|; + } + # + # Else just delete the line + # + else + { + $config_in=~ s|${the_fat}/Makefile dnl\n?||; + } + + open(CONFIG_IN,">configure.in") or die "Unable to open configure.in for write: $!\n"; + print CONFIG_IN $config_in; + close(CONFIG_IN); + } + } + chdir("$cwd"); +} + + +#### +#### This function will run the autotools on the reduced source tree. +#### + +sub run_autotools +{ + my $cwd= getcwd(); + + if (!$win_flag) + { + chdir("$destdir"); + unlink ("configure") or die "Can't delete $destdir/configure: $!\n"; + + # File "configure.in" has already been modified by "trim_the_fat()" + + # It must be ensured that the timestamps of the relevant files are really + # ascending, for otherwise the Makefile may cause a re-run of these + # autotools. Experience shows that deletion is the only safe way. + unlink ("config.h.in") or die "Can't delete $destdir/config.h.in: $!\n"; + unlink ("aclocal.m4") or die "Can't delete $destdir/aclocal.m4: $!\n"; + + # These sleep commands also ensure the ascending order. + `aclocal && sleep 2 && autoheader && sleep 2 && automake && sleep 2 && autoconf`; + die "'./configure' was not produced!" unless (-f "configure"); + + if (-d "autom4te.cache") { + print "Trying to delete autom4te.cache dir\n" if $opt_verbose; + system("rm -rf autom4te.cache") or print "Unable to delete autom4te.cache dir: $!\n"; + } + + chdir("$cwd"); + } +} + #### #### mysqld and MySQL client programs have a usage printed with --help. @@ -187,6 +281,7 @@ sub add_copyright foreach my $file (@files) { next if ! -f $file; + next if -B $file; print "processing file $file in cwd $cwd\n" if $opt_verbose; `$WD/Build-tools/mysql-copyright-2 "$file"`; } diff --git a/Build-tools/mysql-copyright-2 b/Build-tools/mysql-copyright-2 index a1a870526da..2ea2e8ef441 100755 --- a/Build-tools/mysql-copyright-2 +++ b/Build-tools/mysql-copyright-2 @@ -90,6 +90,7 @@ sub add_copyright $ARGV =~ /\.cc$/ || $ARGV =~ /\.h$/ || $ARGV =~ /\.cpp$/ || + $ARGV =~ /\.txt$/ || $ARGV =~ /\.yy$/) { $start_copyright="/* "; diff --git a/Docs/Images/Makefile.am b/Docs/Images/Makefile.am new file mode 100644 index 00000000000..b57d701d8a0 --- /dev/null +++ b/Docs/Images/Makefile.am @@ -0,0 +1,35 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA + +## Process this file with automake to create Makefile.in + +# This is a dummy file to satisfy the hierarchy of Makefiles. +# When a release is built, the true Makefile will be copied +# together with the "real" files in this directory. + +EXTRA_DIST = + +# Nothing to create in this dummy directory. +all: + : + +# Nothing to cleanup in this dummy directory. +clean: + : + +# Don't update the files from bitkeeper +%::SCCS/s.% diff --git a/Docs/Makefile.am b/Docs/Makefile.am index a4e8e14a38d..2f32dfca1b4 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -9,7 +9,7 @@ # If you know how to fix any of this more elegantly please mail # docs@mysql.com -TEXI2HTML_FLAGS = -iso -number +TEXI2HTML_FLAGS = -iso -number -acc DVIPS = dvips MAKEINFO = @MAKEINFO@ TEXINFO_TEX = Support/texinfo.tex @@ -24,6 +24,8 @@ BUILT_SOURCES = $(targets) manual_toc.html include.texi EXTRA_DIST = $(noinst_SCRIPTS) $(BUILT_SOURCES) mysqld_error.txt \ INSTALL-BINARY reservedwords.texi +SUBDIRS = Images + all: $(targets) txt_files txt_files: ../INSTALL-SOURCE ../COPYING ../EXCEPTIONS-CLIENT \ diff --git a/Docs/Support/texi2html b/Docs/Support/texi2html index 5dda7c8bbd5..f13c006c7dc 100755 --- a/Docs/Support/texi2html +++ b/Docs/Support/texi2html @@ -1,4 +1,4 @@ -#!PATH_TO_PERL -*- perl -*- +#!/usr/bin/perl # Add path to perl on the previous line and make this executable # if you want to use this as a normal script. 'di '; @@ -12,7 +12,7 @@ #-############################################################################## # @(#)texi2html 1.52 971230 Written (mainly) by Lionel Cons, Lionel.Cons@cern.ch -# Enhanced by David Axmark, david@detron.se +# Enhanced by David Axmark # The man page for this program is included at the end of this file and can be # viewed using the command 'nroff -man texi2html'. @@ -40,8 +40,7 @@ $NODESRE = '[^@{}:\'`"]+'; # RE for a list of node names $XREFRE = '[^@{}]+'; # RE for a xref (should use NODERE) $ERROR = "***"; # prefix for errors and warnings -$THISPROG = "texi2html 1.52 (hacked by david\@detron.se)"; # program name and version -$HOMEPAGE = "http://www.mathematik.uni-kl.de/~obachman/Texi2html/"; # program home page +$THISPROG = "texi2html 1.52 (with additions by MySQL AB)"; # program name and version $TODAY = &pretty_date; # like "20 September 1993" $SPLITTAG = "<!-- SPLIT HERE -->\n"; # tag to know where to split $PROTECTTAG = "_ThisIsProtected_"; # tag to recognize protected sections @@ -114,10 +113,12 @@ $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//E # %accent_map = ( '"', 'uml', + '\'', 'acute', + ',{', 'cedil', '~', 'tilde', '^', 'circ', '`', 'grave', - '\'', 'acute', + 'ringaccent{', 'ring', ); # @@ -125,7 +126,7 @@ $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//E # %simple_map = ( # cf. makeinfo.c - "*", "<BR>", # HTML+ + "*", "<br />", # HTML+ " ", " ", "\n", "\n", "|", "", @@ -134,6 +135,8 @@ $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//E "!", "!", "?", "?", ".", ".", + # @- means "allow word break", not — + "-", "", ); # @@ -141,9 +144,10 @@ $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//E # %things_map = ( 'TeX', 'TeX', - 'br', '<P>', # paragraph break + 'br', '<p>', # paragraph break 'bullet', '*', 'copyright', '(C)', + 'registeredsymbol', '(R)', 'dots', '...', 'equiv', '==', 'error', 'error-->', @@ -161,27 +165,28 @@ $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//E %style_map = ( 'asis', '', 'b', 'B', - 'cite', 'CITE', - 'code', 'CODE', + 'cite', 'cite', + 'code', 'code', + 'command', 'code', 'ctrl', '&do_ctrl', # special case - 'dfn', 'STRONG', # DFN tag is illegal in the standard + 'dfn', 'strong', # DFN tag is illegal in the standard 'dmn', '', # useless 'email', '&fix_email', # special - 'emph', 'EM', - 'file', '"TT', # will put quotes, cf. &apply_style - 'i', 'I', - 'kbd', 'KBD', - 'key', 'KBD', + 'emph', 'em', + 'file', '"tt', # will put quotes, cf. &apply_style + 'i', 'i', + 'kbd', 'kbd', + 'key', 'kbd', 'r', '', # unsupported - 'samp', '"SAMP', # will put quotes, cf. &apply_style + 'samp', '"samp', # will put quotes, cf. &apply_style 'sc', '&do_sc', # special case - 'strong', 'STRONG', - 't', 'TT', + 'strong', 'strong', + 't', 'tt', 'titlefont', '', # useless 'image', '&fix_image', # Image 'url', '&fix_url', # URL 'uref', '&fix_uref', # URL Reference - 'var', 'VAR', + 'var', 'var', 'w', '', # unsupported ); @@ -317,6 +322,7 @@ $usage = <<EOT; This is $THISPROG To convert a Texinfo file to HMTL: $0 [options] file where options can be: +-acc : convert @"-like accents to &entities; -expandinfo : use \@ifinfo sections, not \@iftex -glossary : handle a glossary -invisible name: use 'name' as an invisible anchor @@ -445,11 +451,15 @@ $html_num = 0; if ($use_iso) { $things_map{'bullet'} = "•"; $things_map{'copyright'} = "©"; + $things_map{'registeredsymbol'} = "®"; $things_map{'dots'} = "…"; $things_map{'equiv'} = "≡"; $things_map{'expansion'} = "→"; $things_map{'point'} = "∗"; $things_map{'result'} = "⇒"; + $things_map{'ss'} = "ß"; + $things_map{'o'} = "ø"; + $things_map{'O'} = "Ø"; } # @@ -505,23 +515,27 @@ $html_element = ''; # current HTML element # watch out for regexps, / and escaped characters! $subst_code = ''; foreach (keys(%simple_map)) { - ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars - $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n"; + $re = quotemeta $_; # protect regexp chars + $sub = quotemeta $simple_map{$_}; + $subst_code .= "s/\\\@$re/$sub/g;\n"; } foreach (keys(%things_map)) { - $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n"; + $re = quotemeta $_; # protect regexp chars + $sub = quotemeta $things_map{$_}; + $subst_code .= "s/\\\@$re\\{\\}/$sub/g;\n"; } if ($use_acc) { # accentuated characters foreach (keys(%accent_map)) { + my $brace = /{$/ ? '}' : ''; if ($_ eq "`") { $subst_code .= "s/$;3"; } elsif ($_ eq "'") { $subst_code .= "s/$;4"; } else { - $subst_code .= "s/\\\@\\$_"; + $subst_code .= "s/\\\@\\Q$_\\E"; } - $subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n"; + $subst_code .= "(\\w)$brace/&\${1}$accent_map{$_};/gi;\n"; } } eval("sub simple_substitutions { $subst_code }"); @@ -703,7 +717,7 @@ READ_LINE: while ($_ = &next_line) s/{[^{}]+}//g); print "# Multitable with $multitable_cols columns\n" if $debug and $DEBUG_USER; - push(@lines, &debug("<TABLE BORDER WIDTH=\"100%\">\n", __LINE__)); + push(@lines, &debug("<TABLE BORDER>\n", __LINE__)); } else { warn "$ERROR Bad table line: $_"; } @@ -873,7 +887,7 @@ READ_LINE: while ($_ = &next_line) &simple_substitutions; s/\@value{($VARRE)}/$value{$1}/eg; s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4 - s|\s+\@tab\s*| </TD><TD> |g if ($in_multitable); + s/(^|\s+)\@tab\s*/ <\/TD><TD> /g if ($in_multitable); # # analyze the tag again @@ -885,7 +899,7 @@ READ_LINE: while ($_ = &next_line) $name =~ s/\s+$//; $level = $sec2level{$tag}; $name = &update_sec_num($tag, $level) . " $name" - if $number_sections && $tag !~ /^unnumbered/; + if $number_sections && $tag !~ /^unnumbered/ && $tag ne 'subsubheading'; if ($tag =~ /heading$/) { push(@lines, &html_debug("\n", __LINE__)); if ($html_element ne 'body') { @@ -1079,7 +1093,7 @@ EOC push(@lines, &debug("</TD></TR>\n", __LINE__)) unless $html_element eq 'TABLE'; &html_pop_if('TR'); - $what =~ s|\s+\@tab\s*| </TD><TD> |g; + $what =~ s/(^|\s+)\@tab\s*/ <\/TD><TD> /g; push(@lines, &debug("<TR><TD>$what\n", __LINE__)); &html_push('TR'); if ($deferred_ref) @@ -1463,11 +1477,7 @@ print "# end of pass 4\n" if $verbose; # # #---############################################################################ -$header = <<EOT; -<!-- This HTML file has been created by $THISPROG - from $docu on $TODAY --> -EOT - + $header = ''; $full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document"; $title = $value{'_settitle'} || $full_title; $_ = &substitute_style($full_title); @@ -1811,12 +1821,14 @@ sub fix_image { my($text) = @_; my($arg1, $ext); - $text =~ /^([^,]*)$/; + $text =~ /^([^,]*)/; die "error in image: '$text'" unless defined($1); $arg1 = $1; $arg1 =~ s/@@/@/g; - $ext = "jpg" if -f "$arg1.jpg"; - $ext = "gif" if -f "$arg1.gif"; + foreach (@include_dirs) { + $ext = "jpg" if -f "$_/$arg1.jpg"; + $ext = "gif" if -f "$_/$arg1.gif"; + } if (defined($ext)) { "<IMG SRC=\"$arg1.$ext\">"; @@ -2010,7 +2022,7 @@ sub print_toplevel_header { local($_); - &print_header; # pass given arg... + &print_header unless $opt_empty_headers; # pass given arg... print FILE $full_title; if ($value{'_subtitle'}) { $value{'_subtitle'} =~ s/\n+$//; @@ -2042,13 +2054,7 @@ EOT sub print_toplevel_footer { - &print_ruler; - print FILE <<EOT; -This document was generated on $TODAY using the -<A HREF=\"$HOMEPAGE\">texi2html</A> -translator version 1.52 (extended by davida\@detron.se).</P> -EOT - &print_footer; + &print_footer unless $opt_empty_headers; } sub protect_texi @@ -2065,8 +2071,10 @@ sub protect_html { local($what) = @_; # protect & < > - # Avoid loop in & replacement. This instead bugs out for &# in text.. - $what =~ s/\&([^#]|$)/\&\#38;$1/g; + # hack for the two entity-like variable reference in existing examples + $what =~ s/\&(length|ts);/\&\#38;$1;/g; + # this leaves alone entities, but encodes standalone ampersands + $what =~ s/\&(?!([a-z0-9]+|#\d+);)/\&\#38;/ig; $what =~ s/\</\&\#60;/g; $what =~ s/\>/\&\#62;/g; # but recognize some HTML things diff --git a/Makefile.am b/Makefile.am index fb0735b562c..1609b5a1da1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,7 @@ AUTOMAKE_OPTIONS = foreign EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT SUBDIRS = . include @docs_dirs@ @readline_dir@ \ @thread_dirs@ pstack @sql_client_dirs@ \ - @sql_server_dirs@ scripts man tests \ + @sql_server_dirs@ scripts @man_dirs@ tests \ BUILD netware os2 @libmysqld_dirs@ \ @bench_dirs@ support-files @fs_dirs@ @tools_dirs@ diff --git a/acinclude.m4 b/acinclude.m4 index a88957ea3df..6c567f00765 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -788,7 +788,7 @@ AC_DEFUN(MYSQL_FIND_OPENSSL, [ AC_DEFUN(MYSQL_CHECK_OPENSSL, [ AC_MSG_CHECKING(for OpenSSL) AC_ARG_WITH([openssl], - [ --with-openssl Include the OpenSSL support], + [ --with-openssl[=DIR] Include the OpenSSL support], [openssl="$withval"], [openssl=no]) @@ -806,8 +806,19 @@ AC_MSG_CHECKING(for OpenSSL) [openssl_libs="$withval"], [openssl_libs=""]) - if test "$openssl" = "yes" + if test "$openssl" != "no" then + if test "$openssl" != "yes" + then + if test -z "$openssl_includes" + then + openssl_includes="$openssl/include" + fi + if test -z "$openssl_libs" + then + openssl_libs="$openssl/lib" + fi + fi MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs]) #force VIO use vio_dir="vio" @@ -843,6 +854,14 @@ AC_MSG_CHECKING(for OpenSSL) NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS $openssl_libs" else AC_MSG_RESULT(no) + if test ! -z "$openssl_includes" + then + AC_MSG_ERROR(Can't have --with-openssl-includes without --with-openssl); + fi + if test ! -z "$openssl_libs" + then + AC_MSG_ERROR(Can't have --with-openssl-libs without --with-openssl); + fi fi AC_SUBST(openssl_libs) AC_SUBST(openssl_includes) diff --git a/client/client_priv.h b/client/client_priv.h index 5029f219494..016c9e5ee80 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -38,4 +38,5 @@ enum options_client { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_SHUTDOWN_TIMEOUT, OPT_LOCAL_INFILE, OPT_DELETE_MASTER_LOGS, - OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION, OPT_FRM }; + OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION, OPT_FRM, + OPT_HEXBLOB }; diff --git a/client/mysql.cc b/client/mysql.cc index 73067700656..4aac548a065 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -689,6 +689,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), while (*argument) *argument++= 'x'; // Destroy argument if (*start) start[1]=0 ; + tty_password= 0; } else tty_password= 1; @@ -759,7 +760,7 @@ static int get_options(int argc, char **argv) opt_max_allowed_packet= *mysql_params->p_max_allowed_packet; opt_net_buffer_length= *mysql_params->p_net_buffer_length; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, 0))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); *mysql_params->p_max_allowed_packet= opt_max_allowed_packet; @@ -2200,20 +2201,77 @@ static int com_source(String *buffer, char *line) static int com_use(String *buffer __attribute__((unused)), char *line) { - char *tmp; - char buff[256]; + char tmp[FN_REFLEN], buff[FN_REFLEN + 1]; + MYSQL_RES *res; + MYSQL_ROW row; + char *c_buff, *c_tmp; while (isspace(*line)) line++; strnmov(buff,line,sizeof(buff)-1); // Don't destroy history if (buff[0] == '\\') // Short command buff[1]=' '; - tmp=(char *) strtok(buff," \t;"); // Skip connect command - if (!tmp || !(tmp=(char *) strtok(NullS," \t;"))) + c_buff= buff; + while ((*c_buff != ' ') && (*c_buff != '\t')) // Skip connect command + c_buff++; + c_buff++; + + while ((*c_buff == ' ') || (*c_buff == '\t')) + c_buff++; + c_tmp= tmp; + if (*c_buff == '`') // Handling backticks + { + c_buff++; + for (; *c_buff; c_tmp++) + { + if (*c_buff == '`') + { + if (c_buff[1] == '`') + { + *c_tmp= '`'; + c_buff+= 2; + } + else + break; + } + else + *c_tmp= *(c_buff++); + } + } + else + for (; !strchr(" \t;", *c_buff); c_buff++, c_tmp++) + *c_tmp= *c_buff; + *c_tmp= '\0'; + + if (!*tmp) { put_info("USE must be followed by a database name",INFO_ERROR); return 0; } + /* + We need to recheck the current database, because it may change + under our feet, for example if DROP DATABASE or RENAME DATABASE + (latter one not yet available by the time the comment was written) + */ + /* Let's reset current_db, assume it's gone */ + my_free(current_db, MYF(MY_ALLOW_ZERO_PTR)); + current_db= 0; + /* + We don't care about in case of an error below because current_db + was just set to 0. + */ + if (!mysql_query(&mysql, "SELECT DATABASE()") && + (res= mysql_use_result(&mysql))) + { + row= mysql_fetch_row(res); + if (row[0]) + { + current_db= my_strdup(row[0], MYF(MY_WME)); + } + (void) mysql_fetch_row(res); // Read eof + mysql_free_result(res); + } + if (!current_db || cmp_database(current_db,tmp)) { if (one_database) diff --git a/client/mysqladmin.c b/client/mysqladmin.c index e2843685d50..978e0c7e88b 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.c @@ -246,7 +246,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc,char *argv[]) { - int error, ho_error; + int error= 0, ho_error; MYSQL mysql; char **commands, **save_argv; @@ -254,7 +254,7 @@ int main(int argc,char *argv[]) mysql_init(&mysql); load_defaults("my",load_default_groups,&argc,&argv); save_argv = argv; /* Save for free_defaults */ - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, 0))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) { free_defaults(save_argv); exit(ho_error); @@ -285,10 +285,25 @@ int main(int argc,char *argv[]) opt_ssl_capath, opt_ssl_cipher); #endif if (sql_connect(&mysql, option_wait)) - error = 1; + { + unsigned int err= mysql_errno(&mysql); + if (err >= CR_MIN_ERROR && err <= CR_MAX_ERROR) + error= 1; + else + { + /* Return 0 if all commands are PING */ + for (; argc > 0; argv++, argc--) + { + if (find_type(argv[0], &command_typelib, 2) != ADMIN_PING) + { + error= 1; + break; + } + } + } + } else { - error = 0; while (!interrupted && (!opt_count_iterations || nr_iterations)) { new_line = 0; @@ -539,7 +554,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { char *pos,buff[40]; ulong sec; - pos=strchr(status,' '); + pos= (char*) strchr(status,' '); *pos++=0; printf("%s\t\t\t",status); /* print label */ if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec))) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 93e0b98b1e5..7c3d22c4900 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -559,7 +559,7 @@ static int parse_args(int *argc, char*** argv) result_file = stdout; load_defaults("my",load_default_groups,argc,argv); - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); return 0; diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 718b92da466..8764611adf4 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -273,7 +273,7 @@ static int get_options(int *argc, char ***argv) load_defaults("my", load_default_groups, argc, argv); - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, 0))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (!what_to_do) @@ -413,18 +413,18 @@ static int process_all_tables_in_db(char *database) LINT_INIT(res); if (use_db(database)) return 1; - if (!(mysql_query(sock, "SHOW TABLES") || - (res = mysql_store_result(sock)))) + if (mysql_query(sock, "SHOW TABLES") || + !((res= mysql_store_result(sock)))) return 1; if (opt_all_in_1) { - /* + /* We need table list in form `a`, `b`, `c` that's why we need 4 more chars added to to each table name space is for more readable output in logs and in case of error */ - + char *tables, *end; uint tot_length = 0; diff --git a/client/mysqldump.c b/client/mysqldump.c index c0ef07a7670..58d601654a4 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -78,7 +78,8 @@ static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick=0, extended_insert = 0, opt_alldbs=0,opt_create_db=0,opt_first_slave=0, opt_autocommit=0,opt_master_data,opt_disable_keys=0,opt_xml=0, opt_delete_master_logs=0, tty_password=0, - opt_single_transaction=0, opt_comments= 0; + opt_single_transaction=0, opt_comments= 0, + opt_hex_blob; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*sock=0; static char insert_pat[12 * 1024],*opt_password=0,*current_user=0, @@ -113,6 +114,9 @@ static struct my_option my_long_options[] = {"character-sets-dir", OPT_CHARSETS_DIR, "Directory where character sets are", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"comments", 'i', "Write additional information.", + (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {"complete-insert", 'c', "Use complete insert statements.", (gptr*) &cFlag, (gptr*) &cFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use compression in server/client protocol.", @@ -150,7 +154,7 @@ static struct my_option my_long_options[] = "Fields in the i.file are opt. enclosed by ...", (gptr*) &opt_enclosed, (gptr*) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...", - (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, NO_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"first-slave", 'x', "Locks all tables across all databases.", (gptr*) &opt_first_slave, (gptr*) &opt_first_slave, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -165,6 +169,9 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"hex-blob", OPT_HEXBLOB, "Dump binary strings (CHAR BINARY, " + "VARCHAR BINARY, BLOB) in hexadecimal format.", + (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", (gptr*) ¤t_host, (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", @@ -179,10 +186,6 @@ static struct my_option my_long_options[] = "Wrap tables with autocommit/commit statements.", (gptr*) &opt_autocommit, (gptr*) &opt_autocommit, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"single-transaction", OPT_TRANSACTION, - "Dump all tables in single transaction to get consistent snapshot. Mutually exclusive with --lock-tables.", - (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, GET_BOOL, NO_ARG, - 0, 0, 0, 0, 0, 0}, {"no-create-db", 'n', "'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;' will not be put in the output. The above line will be added otherwise, if --databases or --all-databases option was given.}", (gptr*) &opt_create_db, (gptr*) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0, @@ -191,9 +194,6 @@ static struct my_option my_long_options[] = (gptr*) &tFlag, (gptr*) &tFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-data", 'd', "No row information.", (gptr*) &dFlag, (gptr*) &dFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"set-variable", 'O', - "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"opt", OPT_OPTIMIZE, "Same as --add-drop-table --add-locks --all --quick --extended-insert --lock-tables --disable-keys", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -215,6 +215,13 @@ static struct my_option my_long_options[] = {"result-file", 'r', "Direct output to a given file. This option should be used in MSDOS, because it prevents new line '\\n' from being converted to '\\r\\n' (carriage return + line feed).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"set-variable", 'O', + "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"single-transaction", OPT_TRANSACTION, + "Dump all tables in single transaction to get consistent snapshot. Mutually exclusive with --lock-tables.", + (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -245,9 +252,6 @@ static struct my_option my_long_options[] = (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L, MALLOC_OVERHEAD-1024, 1024, 0}, - {"comments", 'i', "Write additional information.", - (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG, - 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -413,7 +417,7 @@ static int get_options(int *argc, char ***argv) md_result_file= stdout; load_defaults("my",load_default_groups,argc,argv); - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, 0))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); *mysql_params->p_max_allowed_packet= opt_max_allowed_packet; @@ -1104,6 +1108,7 @@ static void dumpTable(uint numFields, char *table) for (i = 0; i < mysql_num_fields(res); i++) { + int is_blob; if (!(field = mysql_fetch_field(res))) { sprintf(query,"%s: Not enough fields from table %s! Aborting.\n", @@ -1112,6 +1117,14 @@ static void dumpTable(uint numFields, char *table) error= EX_CONSCHECK; goto err; } + + is_blob= (opt_hex_blob && (field->flags & BINARY_FLAG) && + (field->type == FIELD_TYPE_STRING || + field->type == FIELD_TYPE_VAR_STRING || + field->type == FIELD_TYPE_BLOB || + field->type == FIELD_TYPE_LONG_BLOB || + field->type == FIELD_TYPE_MEDIUM_BLOB || + field->type == FIELD_TYPE_TINY_BLOB)) ? 1 : 0; if (extended_insert) { ulong length = lengths[i]; @@ -1126,18 +1139,37 @@ static void dumpTable(uint numFields, char *table) { if (!IS_NUM_FIELD(field)) { + /* + "length * 2 + 2" is OK for both HEX and non-HEX modes: + - In HEX mode we need exactly 2 bytes per character + plus 2 bytes for '0x' prefix. + - In non-HEX mode we need up to 2 bytes per character, + plus 2 bytes for leading and trailing '\'' characters. + */ if (dynstr_realloc(&extended_row,length * 2+2)) { fputs("Aborting dump (out of memory)",stderr); error= EX_EOM; goto err; } - dynstr_append(&extended_row,"\'"); - extended_row.length += + if (opt_hex_blob && is_blob) + { + dynstr_append(&extended_row, "0x"); + extended_row.length+= mysql_hex_string(extended_row.str + + extended_row.length, + row[i], length); + extended_row.str[extended_row.length]= '\0'; + } + else + { + dynstr_append(&extended_row,"\'"); + extended_row.length += mysql_real_escape_string(&mysql_connection, - &extended_row.str[extended_row.length],row[i],length); - extended_row.str[extended_row.length]='\0'; - dynstr_append(&extended_row,"\'"); + &extended_row.str[extended_row.length], + row[i],length); + extended_row.str[extended_row.length]='\0'; + dynstr_append(&extended_row,"\'"); + } } else { @@ -1180,7 +1212,19 @@ static void dumpTable(uint numFields, char *table) if (opt_xml) print_quoted_xml(md_result_file, field->name, row[i], lengths[i]); - else + else if (opt_hex_blob && is_blob) + { /* sakaik got this idea. */ + ulong counter; + char xx[4]; + unsigned char *ptr= row[i]; + fputs("0x", md_result_file); + for (counter = 0; counter < lengths[i]; counter++) + { + sprintf(xx, "%02X", ptr[counter]); + fputs(xx, md_result_file); + } + } + else unescape(md_result_file, row[i], lengths[i]); } else diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 751379591ff..50c3a26a882 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -206,7 +206,7 @@ static int get_options(int *argc, char ***argv) { int ho_error; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, 0))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (enclosed && opt_enclosed) @@ -246,10 +246,8 @@ static int write_to_table(char *filename, MYSQL *sock) DBUG_ENTER("write_to_table"); DBUG_PRINT("enter",("filename: %s",filename)); - local_file= sock->unix_socket == 0 || opt_local_file; - fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */ - if (local_file) + if (! opt_local_file) strmov(hard_path,filename); else my_load_path(hard_path, filename, NULL); /* filename includes the path */ @@ -268,7 +266,7 @@ static int write_to_table(char *filename, MYSQL *sock) to_unix_path(hard_path); if (verbose) { - if (local_file) + if (opt_local_file) fprintf(stdout, "Loading data from LOCAL file: %s into %s\n", hard_path, tablename); else @@ -277,7 +275,7 @@ static int write_to_table(char *filename, MYSQL *sock) } sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'", opt_low_priority ? "LOW_PRIORITY" : "", - local_file ? "LOCAL" : "", hard_path); + opt_local_file ? "LOCAL" : "", hard_path); end= strend(sql_statement); if (replace) end= strmov(end, " REPLACE"); diff --git a/client/mysqlmanager-pwgen.c b/client/mysqlmanager-pwgen.c index dc845008ce0..57d91b52f49 100644 --- a/client/mysqlmanager-pwgen.c +++ b/client/mysqlmanager-pwgen.c @@ -95,7 +95,7 @@ int parse_args(int argc, char** argv) { int ho_error; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); return 0; diff --git a/client/mysqlmanagerc.c b/client/mysqlmanagerc.c index 78485427473..0001a0266e6 100644 --- a/client/mysqlmanagerc.c +++ b/client/mysqlmanagerc.c @@ -133,7 +133,7 @@ int parse_args(int argc, char **argv) load_defaults("my",load_default_groups,&argc,&argv); default_argv= argv; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); return 0; diff --git a/client/mysqlshow.c b/client/mysqlshow.c index cabe55cd95e..1a9aec02955 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -261,7 +261,7 @@ get_options(int *argc,char ***argv) { int ho_error; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, 0))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (tty_password) diff --git a/client/mysqltest.c b/client/mysqltest.c index df54b60dc97..2ec07692a4d 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2062,7 +2062,7 @@ int parse_args(int argc, char **argv) load_defaults("my",load_default_groups,&argc,&argv); default_argv= argv; - if ((handle_options(&argc, &argv, my_long_options, get_one_option, 0))) + if ((handle_options(&argc, &argv, my_long_options, get_one_option))) exit(1); if (argc > 1) diff --git a/configure.in b/configure.in index 7853b615ae0..06a0c1bd52f 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.21) +AM_INIT_AUTOMAKE(mysql, 4.0.23) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -40,12 +40,12 @@ do case $host_os in netware* | modesto*) echo "$i/errmsg.sys: $i/errmsg.txt - \$(top_builddir)/extra/comp_err.linux \$^ $i/errmsg.sys" \ + \$(top_builddir)/extra/comp_err.linux $i/errmsg.txt $i/errmsg.sys" \ >> $AVAILABLE_LANGUAGES_ERRORS_RULES ;; *) echo "$i/errmsg.sys: $i/errmsg.txt - \$(top_builddir)/extra/comp_err \$^ $i/errmsg.sys" \ + \$(top_builddir)/extra/comp_err $i/errmsg.txt $i/errmsg.sys" \ >> $AVAILABLE_LANGUAGES_ERRORS_RULES ;; esac @@ -444,7 +444,7 @@ if $PS p $$ 2> /dev/null | grep $0 > /dev/null then FIND_PROC="$PS p \$\$PID | grep mysqld > /dev/null" # Solaris -elif $PS -p $$ 2> /dev/null | grep $0 > /dev/null +elif $PS -fp $$ 2> /dev/null | grep $0 > /dev/null then FIND_PROC="$PS -p \$\$PID | grep mysqld > /dev/null" # BSD style @@ -939,8 +939,8 @@ MAX_CXX_OPTIMIZE="-O3" # workaround for Sun Forte/x86 see BUG#4681 case $SYSTEM_TYPE-$MACHINE_TYPE-$ac_cv_prog_gcc in *solaris*-i?86-no) - CFLAGS="$CFLAGS -DBIG_FILES" - CXXFLAGS="$CXXFLAGS -DBIG_FILES" + CFLAGS="$CFLAGS -DBIG_TABLES" + CXXFLAGS="$CXXFLAGS -DBIG_TABLES" ;; *) ;; esac @@ -2181,6 +2181,21 @@ else fi AC_SUBST(docs_dirs) +# Shall we build the man pages? +AC_ARG_WITH(man, + [ --without-man Skip building of the man pages.], + [with_man=$withval], + [with_man=yes] +) + +if test "$with_man" = "yes" +then + man_dirs="man" +else + man_dirs="" +fi +AC_SUBST(man_dirs) + # Shall we build the bench code? AC_ARG_WITH(bench, [ --without-bench Skip building of the benchmark suite.], @@ -2696,7 +2711,7 @@ AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile dnl pstack/Makefile pstack/aout/Makefile sql/Makefile sql/share/Makefile dnl merge/Makefile dbug/Makefile scripts/Makefile dnl include/Makefile sql-bench/Makefile tools/Makefile dnl - tests/Makefile Docs/Makefile support-files/Makefile dnl + tests/Makefile Docs/Makefile Docs/Images/Makefile support-files/Makefile dnl support-files/MacOSX/Makefile mysql-test/Makefile dnl netware/Makefile dnl include/mysql_version.h dnl diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index 515e816f473..f8a7995432b 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -100,7 +100,7 @@ static int get_options(int *argc,char ***argv) { int ho_error; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (*argc < 1) diff --git a/extra/mysql_install.c b/extra/mysql_install.c index ab44e1a055b..e2783f906b9 100644 --- a/extra/mysql_install.c +++ b/extra/mysql_install.c @@ -218,7 +218,7 @@ static int parse_args(int argc, char **argv) { int ho_error; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); return 0; diff --git a/extra/mysql_waitpid.c b/extra/mysql_waitpid.c index 0894d81a5ae..c228cc52c8b 100644 --- a/extra/mysql_waitpid.c +++ b/extra/mysql_waitpid.c @@ -67,7 +67,7 @@ int main(int argc, char *argv[]) progname= argv[0]; - if (handle_options(&argc, &argv, my_long_options, get_one_option, NULL)) + if (handle_options(&argc, &argv, my_long_options, get_one_option)) exit(-1); if (!argv[0] || !argv[1] || (pid= atoi(argv[0])) <= 0 || (t= atoi(argv[1])) <= 0) diff --git a/extra/perror.c b/extra/perror.c index 212b313ade4..b4aeaf00671 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -145,7 +145,7 @@ static int get_options(int *argc,char ***argv) { int ho_error; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (!*argc && !print_all_codes) diff --git a/extra/resolve_stack_dump.c b/extra/resolve_stack_dump.c index 8b72ab1d864..c54f17a186e 100644 --- a/extra/resolve_stack_dump.c +++ b/extra/resolve_stack_dump.c @@ -121,7 +121,7 @@ static int parse_args(int argc, char **argv) { int ho_error; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); /* diff --git a/extra/resolveip.c b/extra/resolveip.c index 23ea34abc42..d3caa9e1d45 100644 --- a/extra/resolveip.c +++ b/extra/resolveip.c @@ -90,7 +90,7 @@ static int get_options(int *argc,char ***argv) { int ho_error; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (*argc == 0) diff --git a/include/config-win.h b/include/config-win.h index bb6d663bd8d..152e85c8e68 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -218,7 +218,13 @@ inline double ulonglong2double(ulonglong value) ((uint32) (uchar) (A)[0]))) #define sint4korr(A) (*((long *) (A))) #define uint2korr(A) (*((uint16 *) (A))) -#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF) +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) #define uint4korr(A) (*((unsigned long *) (A))) #define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ (((uint32) ((uchar) (A)[1])) << 8) +\ diff --git a/include/my_getopt.h b/include/my_getopt.h index f5b847f7dda..e602773e181 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -50,15 +50,15 @@ struct my_option int app_type; /* To be used by an application */ }; -extern char *disabled_my_option; -extern my_bool my_getopt_print_errors; - typedef my_bool (* my_get_one_option) (int, const struct my_option *, char * ); typedef void (* my_error_reporter) (enum loglevel level, const char *format, ... ); +extern char *disabled_my_option; +extern my_bool my_getopt_print_errors; +extern my_error_reporter my_getopt_error_reporter; + extern int handle_options (int *argc, char ***argv, - const struct my_option *longopts, my_get_one_option, - my_error_reporter ); + const struct my_option *longopts, my_get_one_option); extern void my_print_help(const struct my_option *options); extern void my_print_variables(const struct my_option *options); diff --git a/include/my_global.h b/include/my_global.h index f24fc05471e..6871dfbf6c6 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -898,7 +898,13 @@ typedef char bool; /* Ordinary boolean values 0 1 */ (((uint32) ((uchar) (A)[1])) << 8) +\ (((uint32) ((uchar) (A)[2])) << 16)) #else -#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF) +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) #endif #define uint4korr(A) (*((unsigned long *) (A))) #define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ diff --git a/include/myisam.h b/include/myisam.h index 87a40b50c73..cad48e2d331 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -96,6 +96,7 @@ typedef struct st_mi_create_info ha_rows reloc_rows; ulonglong auto_increment; ulonglong data_file_length; + ulonglong key_file_length; uint raid_type,raid_chunks; ulong raid_chunksize; uint old_options; diff --git a/include/mysql.h b/include/mysql.h index 8abeb86e32a..08ea2da2e58 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -392,6 +392,8 @@ unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); unsigned long STDCALL mysql_escape_string(char *to,const char *from, unsigned long from_length); +unsigned long STDCALL mysql_hex_string(char *to,const char *from, + unsigned long from_length); unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c index 81eb32467ad..d1ef1a77a9f 100644 --- a/innobase/btr/btr0btr.c +++ b/innobase/btr/btr0btr.c @@ -609,8 +609,8 @@ btr_page_get_father_for_rec( fputs( "InnoDB: You should dump + drop + reimport the table to fix the\n" "InnoDB: corruption. If the crash happens at the database startup, see\n" -"InnoDB: section 6.1 of http://www.innodb.com/ibman.php about forcing\n" -"InnoDB: recovery. Then dump + drop + reimport.\n", stderr); +"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html about\n" +"InnoDB: forcing recovery. Then dump + drop + reimport.\n", stderr); } ut_a(btr_node_ptr_get_child_page_no(node_ptr) == diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index b744430a76e..aea3932eda7 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -1561,9 +1561,9 @@ buf_page_io_complete( "InnoDB: by dumping, dropping, and reimporting\n" "InnoDB: the corrupt table. You can use CHECK\n" "InnoDB: TABLE to scan your table for corruption.\n" - "InnoDB: Look also at section 6.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php about\n" - "InnoDB: forcing recovery.\n", stderr); + "InnoDB: See also " + "http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" + "InnoDB: about forcing recovery.\n", stderr); if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { fputs( diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index 31a601e68b0..e8261ab1e91 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -1011,6 +1011,12 @@ dict_create_or_check_foreign_constraint_tables(void) there are 2 secondary indexes on SYS_FOREIGN, and they are defined just like below */ + /* NOTE: when designing InnoDB's foreign key support in 2001, we made + an error and made the table names and the foreign key id of type + 'CHAR' (internally, really a VARCHAR). We should have made the type + VARBINARY, like in other InnoDB system tables, to get a clean + design. */ + str = (char *) "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n" "BEGIN\n" @@ -1227,9 +1233,17 @@ loop: fputs(".\nA foreign key constraint of name ", ef); ut_print_name(ef, foreign->id); fputs("\nalready exists." - " (Note that internally InnoDB adds 'databasename/'\n" + " (Note that internally InnoDB adds 'databasename/'\n" "in front of the user-defined constraint name).\n", ef); + fputs("Note that InnoDB's FOREIGN KEY system tables store\n" + "constraint names as case-insensitive, with the\n" + "MySQL standard latin1_swedish_ci collation. If you\n" + "create tables or databases whose names differ only in\n" + "the character case, then collisions in constraint\n" + "names can occur. Workaround: name your constraints\n" + "explicitly with unique names.\n", + ef); mutex_exit(&dict_foreign_err_mutex); diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index ccaa5720c20..aa5bab210ef 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -132,7 +132,7 @@ dict_index_build_internal_non_clust( dict_index_t* index); /* in: user representation of a non-clustered index */ /************************************************************************** -Removes a foreign constraint struct from the dictionet cache. */ +Removes a foreign constraint struct from the dictionary cache. */ static void dict_foreign_remove_from_cache( @@ -526,8 +526,10 @@ dict_index_contains_col_or_prefix( } /************************************************************************ -Looks for a matching field in an index. The column and the prefix len have -to be the same. */ +Looks for a matching field in an index. The column has to be the same. The +column in index must be complete, or must contain a prefix longer than the +column in index2. That is, we must be able to construct the prefix in index2 +from the prefix in index. */ ulint dict_index_get_nth_field_pos( @@ -555,7 +557,9 @@ dict_index_get_nth_field_pos( field = dict_index_get_nth_field(index, pos); if (field->col == field2->col - && field->prefix_len == field2->prefix_len) { + && (field->prefix_len == 0 + || (field->prefix_len >= field2->prefix_len + && field2->prefix_len != 0))) { return(pos); } @@ -577,7 +581,7 @@ dict_table_get_on_id( dict_table_t* table; if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0 - || trx->dict_operation) { + || trx->dict_operation_lock_mode == RW_X_LATCH) { /* It is a system table which will always exist in the table cache: we avoid acquiring the dictionary mutex, because if we are doing a rollback to handle an error in TABLE @@ -600,7 +604,7 @@ dict_table_get_on_id( } /************************************************************************ -Looks for column n postion in the clustered index. */ +Looks for column n position in the clustered index. */ ulint dict_table_get_nth_col_pos( @@ -2020,7 +2024,8 @@ dict_foreign_error_report( fputs("\nThe index in the foreign key in table is ", file); ut_print_name(file, fk->foreign_index->name); fputs( -"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", +"\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" +"for correct foreign key definition.\n", file); } mutex_exit(&dict_foreign_err_mutex); @@ -2135,8 +2140,8 @@ dict_foreign_add_to_cache( /************************************************************************* Scans from pointer onwards. Stops if is at the start of a copy of -'string' where characters are compared without case sensitivity. Stops -also at '\0'. */ +'string' where characters are compared without case sensitivity, and +only outside `` or "" quotes. Stops also at '\0'. */ static const char* dict_scan_to( @@ -2145,31 +2150,34 @@ dict_scan_to( const char* ptr, /* in: scan from */ const char* string) /* in: look for this */ { - ibool success; - ulint i; -loop: - if (*ptr == '\0') { - return(ptr); - } - - success = TRUE; - - for (i = 0; i < ut_strlen(string); i++) { - if (toupper((ulint)(ptr[i])) != toupper((ulint)(string[i]))) { - success = FALSE; - + char quote = '\0'; + + for (; *ptr; ptr++) { + if (*ptr == quote) { + /* Closing quote character: do not look for + starting quote or the keyword. */ + quote = '\0'; + } else if (quote) { + /* Within quotes: do nothing. */ + } else if (*ptr == '`' || *ptr == '"') { + /* Starting quote: remember the quote character. */ + quote = *ptr; + } else { + /* Outside quotes: look for the keyword. */ + ulint i; + for (i = 0; string[i]; i++) { + if (toupper((ulint)(ptr[i])) + != toupper((ulint)(string[i]))) { + goto nomatch; + } + } break; + nomatch: + ; } } - if (success) { - - return(ptr); - } - - ptr++; - - goto loop; + return(ptr); } /************************************************************************* @@ -2495,7 +2503,9 @@ dict_strip_comments( char* str; char* sptr; char* ptr; - + /* unclosed quote character (0 if none) */ + char quote = 0; + str = mem_alloc(strlen(sql_string) + 1); sptr = sql_string; @@ -2510,8 +2520,18 @@ scan_more: return(str); } - - if (*sptr == '#' + + if (*sptr == quote) { + /* Closing quote character: do not look for + starting quote or comments. */ + quote = 0; + } else if (quote) { + /* Within quotes: do not look for + starting quotes or comments. */ + } else if (*sptr == '"' || *sptr == '`') { + /* Starting quote: remember the quote character. */ + quote = *sptr; + } else if (*sptr == '#' || (0 == memcmp("-- ", sptr, 3))) { for (;;) { /* In Unix a newline is 0x0A while in Windows @@ -2526,9 +2546,7 @@ scan_more: sptr++; } - } - - if (*sptr == '/' && *(sptr + 1) == '*') { + } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') { for (;;) { if (*sptr == '*' && *(sptr + 1) == '/') { @@ -2747,13 +2765,13 @@ loop: ut_a(success); - if (!isspace(*ptr)) { + if (!isspace(*ptr) && *ptr != '"' && *ptr != '`') { goto loop; } - do { + while (isspace(*ptr)) { ptr++; - } while (isspace(*ptr)); + } /* read constraint name unless got "CONSTRAINT FOREIGN" */ if (ptr != ptr2) { @@ -2856,7 +2874,8 @@ col_loop1: ut_print_name(ef, name); fprintf(ef, " where the columns appear\n" "as the first columns. Constraint:\n%s\n" -"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", +"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" +"for correct foreign key definition.\n", start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); @@ -3121,7 +3140,8 @@ try_find_index: "Cannot find an index in the referenced table where the\n" "referenced columns appear as the first columns, or column types\n" "in the table and the referenced table do not match for constraint.\n" -"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", +"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" +"for correct foreign key definition.\n", start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 6a4d4c86824..a4637e09d07 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -19,6 +19,7 @@ Created 4/24/1996 Heikki Tuuri #include "mach0data.h" #include "dict0dict.h" #include "dict0boot.h" +#include "rem0cmp.h" /************************************************************************ Finds the first table name in the given database. */ @@ -1121,12 +1122,26 @@ loop: rec = btr_pcur_get_rec(&pcur); field = rec_get_nth_field(rec, 0, &len); - /* Check if the table name in record is the one searched for */ - if (len != ut_strlen(table_name) - || 0 != ut_memcmp(field, table_name, len)) { + /* Check if the table name in the record is the one searched for; the + following call does the comparison in the latin1_swedish_ci + charset-collation, in a case-insensitive way. */ + if (0 != cmp_data_data(dfield_get_type(dfield), + dfield_get_data(dfield), dfield_get_len(dfield), + field, len)) { + goto load_next_index; } + + /* Since table names in SYS_FOREIGN are stored in a case-insensitive + order, we have to check that the table name matches also in a binary + string comparison. On Unix, MySQL allows table names that only differ + in character case. */ + + if (0 != ut_memcmp(field, table_name, len)) { + + goto next_rec; + } if (rec_get_deleted_flag(rec)) { diff --git a/innobase/eval/eval0eval.c b/innobase/eval/eval0eval.c index ebb6cb1b7d9..5b2d1f857b1 100644 --- a/innobase/eval/eval0eval.c +++ b/innobase/eval/eval0eval.c @@ -627,7 +627,11 @@ eval_concat( } /********************************************************************* -Evaluates a predefined function node. */ +Evaluates a predefined function node. If the first argument is an integer, +this function looks at the second argument which is the integer length in +bytes, and converts the integer to a VARCHAR. +If the first argument is of some other type, this function converts it to +BINARY. */ UNIV_INLINE void eval_to_binary( @@ -638,12 +642,24 @@ eval_to_binary( que_node_t* arg2; dfield_t* dfield; byte* str1; + ulint len; ulint len1; arg1 = func_node->args; str1 = dfield_get_data(que_node_get_val(arg1)); + if (dtype_get_mtype(que_node_get_data_type(arg1)) != DATA_INT) { + + len = dfield_get_len(que_node_get_val(arg1)); + + dfield = que_node_get_val(func_node); + + dfield_set_data(dfield, str1, len); + + return; + } + arg2 = que_node_get_next(arg1); len1 = (ulint)eval_node_get_int_val(arg2); diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index 53f5e885df8..cb74c720ad9 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -2701,9 +2701,9 @@ fseg_free_page_low( "InnoDB: database!\n", page); crash: fputs( -"InnoDB: If the InnoDB recovery crashes here, see section 6.1\n" -"InnoDB: of http://www.innodb.com/ibman.php about forcing recovery.\n", - stderr); +"InnoDB: Please refer to\n" +"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" +"InnoDB: about forcing recovery.\n", stderr); ut_error; } diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index 835c2c2b2e6..9940be9832d 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -566,8 +566,10 @@ dict_index_contains_col_or_prefix( dict_index_t* index, /* in: index */ ulint n); /* in: column number */ /************************************************************************ -Looks for a matching field in an index. The column and the prefix len has -to be the same. */ +Looks for a matching field in an index. The column has to be the same. The +column in index must be complete, or must contain a prefix longer than the +column in index2. That is, we must be able to construct the prefix in index2 +from the prefix in index. */ ulint dict_index_get_nth_field_pos( diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 0ab70db2dea..bbd90434f39 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -508,9 +508,11 @@ struct row_prebuilt_struct { dtuple_t* clust_ref; /* prebuilt dtuple used in sel/upd/del */ ulint select_lock_type;/* LOCK_NONE, LOCK_S, or LOCK_X */ - ulint stored_select_lock_type;/* inside LOCK TABLES, either - LOCK_S or LOCK_X depending on the lock - type */ + ulint stored_select_lock_type;/* this field is used to + remember the original select_lock_type + that was decided in ha_innodb.cc, + ::store_lock(), ::external_lock(), + etc. */ ulint mysql_row_len; /* length in bytes of a row in the MySQL format */ ulint n_rows_fetched; /* number of rows fetched after diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 57ca1f84f26..c76a1917615 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -99,6 +99,7 @@ extern ibool srv_use_doublewrite_buf; extern ibool srv_set_thread_priorities; extern int srv_query_thread_priority; +extern ulint srv_max_purge_lag; /*-------------------------------------------*/ extern ulint srv_n_rows_inserted; @@ -152,6 +153,7 @@ extern ulint srv_test_array_size; extern ulint srv_activity_count; extern ulint srv_fatal_semaphore_wait_threshold; +extern ulint srv_dml_needed_delay; extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, query threads, and lock table: we allocate diff --git a/innobase/include/sync0arr.h b/innobase/include/sync0arr.h index 4324f2d3f2c..73496a2ea84 100644 --- a/innobase/include/sync0arr.h +++ b/innobase/include/sync0arr.h @@ -97,9 +97,11 @@ sync_arr_wake_threads_if_sema_free(void); /************************************************************************** Prints warnings of long semaphore waits to stderr. */ -void +ibool sync_array_print_long_waits(void); /*=============================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ /************************************************************************ Validates the integrity of the wait array. Checks that the number of reserved cells equals the count variable. */ diff --git a/innobase/include/trx0sys.h b/innobase/include/trx0sys.h index c7ef4d1929d..4d83c5eeaae 100644 --- a/innobase/include/trx0sys.h +++ b/innobase/include/trx0sys.h @@ -419,6 +419,10 @@ struct trx_sys_struct{ trx_rseg_t* rseg_array[TRX_SYS_N_RSEGS]; /* Pointer array to rollback segments; NULL if slot not in use */ + ulint rseg_history_len;/* Length of the TRX_RSEG_HISTORY + list (update undo logs for committed + transactions), protected by + rseg->mutex */ UT_LIST_BASE_NODE_T(read_view_t) view_list; /* List of read views sorted on trx no, biggest first */ diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 381d11e4cce..79432fbd511 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -685,10 +685,9 @@ failure: "InnoDB: To get mysqld to start up, set innodb_thread_concurrency in my.cnf\n" "InnoDB: to a lower value, for example, to 8. After an ERROR-FREE shutdown\n" "InnoDB: of mysqld you can adjust the size of ib_logfiles, as explained in\n" -"InnoDB: section 5 of http://www.innodb.com/ibman.php", +"InnoDB: http://dev.mysql.com/doc/mysql/en/Adding_and_removing.html\n" +"InnoDB: Cannot continue operation. Calling exit(1).\n", (ulong)srv_thread_concurrency); - fprintf(stderr, -"InnoDB: Cannot continue operation. Calling exit(1).\n"); exit(1); } diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 51941a14656..52e0b99cb24 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -514,8 +514,8 @@ recv_find_max_checkpoint( "InnoDB: If this error appears when you are creating an InnoDB database,\n" "InnoDB: the problem may be that during an earlier attempt you managed\n" "InnoDB: to create the InnoDB data files, but log file creation failed.\n" -"InnoDB: If that is the case, please refer to section 3.1 of\n" -"InnoDB: http://www.innodb.com/ibman.php\n"); +"InnoDB: If that is the case, please refer to\n" +"InnoDB: http://dev.mysql.com/doc/mysql/en/Error_creating_InnoDB.html\n"); return(DB_ERROR); } @@ -1840,7 +1840,7 @@ recv_report_corrupt_log( "InnoDB: far enough in recovery! Please run CHECK TABLE\n" "InnoDB: on your InnoDB tables to check that they are ok!\n" "InnoDB: If mysqld crashes after this recovery, look at\n" - "InnoDB: section 6.1 of http://www.innodb.com/ibman.php\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" "InnoDB: about forcing recovery.\n", stderr); fflush(stderr); diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 56f01568ead..6ed3720cc84 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -212,7 +212,8 @@ os_file_get_last_error(void) ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Operating system error number %lu in a file operation.\n" - "InnoDB: See http://www.innodb.com/ibman.php for installation help.\n", + "InnoDB: See http://dev.mysql.com/doc/mysql/en/InnoDB.html\n" + "InnoDB: for installation help.\n", err); if (err == ERROR_PATH_NOT_FOUND) { @@ -227,8 +228,9 @@ os_file_get_last_error(void) "InnoDB: of the same name as a data file.\n"); } else { fprintf(stderr, - "InnoDB: See section 13.2 at http://www.innodb.com/ibman.php\n" - "InnoDB: about operating system error numbers.\n"); + "InnoDB: Some operating system error numbers are described at\n" + "InnoDB: " + "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); } } @@ -251,7 +253,8 @@ os_file_get_last_error(void) fprintf(stderr, " InnoDB: Operating system error number %lu in a file operation.\n" - "InnoDB: See http://www.innodb.com/ibman.php for installation help.\n", + "InnoDB: See http://dev.mysql.com/doc/mysql/en/InnoDB.html\n" + "InnoDB: for installation help.\n", err); if (err == ENOENT) { @@ -270,8 +273,9 @@ os_file_get_last_error(void) } fprintf(stderr, - "InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" - "InnoDB: about operating system error numbers.\n"); + "InnoDB: Some operating system error numbers are described at\n" + "InnoDB: " + "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); } } @@ -1182,7 +1186,7 @@ os_file_pread( os_file_n_pending_preads++; os_mutex_exit(os_file_count_mutex); - n_bytes = pread(file, buf, n, offs); + n_bytes = pread(file, buf, (ssize_t)n, offs); os_mutex_enter(os_file_count_mutex); os_file_n_pending_preads--; @@ -1207,7 +1211,7 @@ os_file_pread( return(ret); } - ret = read(file, buf, n); + ret = read(file, buf, (ssize_t)n); os_mutex_exit(os_file_seek_mutexes[i]); @@ -1257,7 +1261,7 @@ os_file_pwrite( os_file_n_pending_pwrites++; os_mutex_exit(os_file_count_mutex); - ret = pwrite(file, buf, n, offs); + ret = pwrite(file, buf, (ssize_t)n, offs); os_mutex_enter(os_file_count_mutex); os_file_n_pending_pwrites--; @@ -1292,7 +1296,7 @@ os_file_pwrite( return(ret); } - ret = write(file, buf, n); + ret = write(file, buf, (ssize_t)n); if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC @@ -1465,8 +1469,9 @@ retry: fprintf(stderr, " InnoDB: Error: File pointer positioning to file %s failed at\n" "InnoDB: offset %lu %lu. Operating system error number %lu.\n" -"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.php\n" -"InnoDB: what the error number means.\n", +"InnoDB: Some operating system error numbers are described at\n" +"InnoDB: " +"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n", name, offset_high, offset, (ulint)GetLastError()); @@ -1523,8 +1528,9 @@ retry: } fprintf(stderr, -"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" -"InnoDB: about operating system error numbers.\n"); +"InnoDB: Some operating system error numbers are described at\n" +"InnoDB: " +"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); os_has_said_disk_full = TRUE; } @@ -1558,8 +1564,9 @@ retry: } fprintf(stderr, -"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" -"InnoDB: about operating system error numbers.\n"); +"InnoDB: Some operating system error numbers are described at\n" +"InnoDB: " +"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); os_has_said_disk_full = TRUE; } @@ -2581,6 +2588,8 @@ restart: /* NOTE! We only access constant fields in os_aio_array. Therefore we do not have to acquire the protecting mutex yet */ + srv_set_io_thread_op_info(global_segment, + "looking for i/o requests (a)"); ut_ad(os_aio_validate()); ut_ad(segment < array->n_segments); @@ -2599,6 +2608,9 @@ restart: os_mutex_enter(array->mutex); + srv_set_io_thread_op_info(global_segment, + "looking for i/o requests (b)"); + /* Check if there is a slot for which the i/o has already been done */ @@ -2711,6 +2723,8 @@ consecutive_loop: } } + srv_set_io_thread_op_info(global_segment, "consecutive i/o requests"); + /* We have now collected n_consecutive i/o requests in the array; allocate a single buffer which can hold all data, and perform the i/o */ @@ -2854,6 +2868,8 @@ slot_io_done: return(ret); wait_for_io: + srv_set_io_thread_op_info(global_segment, "resetting wait event"); + /* We wait here until there again can be i/os in the segment of this thread */ @@ -2945,9 +2961,17 @@ os_aio_print( ulint i; for (i = 0; i < srv_n_file_io_threads; i++) { - fprintf(file, "I/O thread %lu state: %s (%s)\n", i, + fprintf(file, "I/O thread %lu state: %s (%s)", i, srv_io_thread_op_info[i], srv_io_thread_function[i]); + +#ifndef __WIN__ + if (os_aio_segment_wait_events[i]->is_set) { + fprintf(file, " ev set"); + } +#endif + + fprintf(file, "\n"); } fputs("Pending normal aio reads:", file); diff --git a/innobase/pars/pars0opt.c b/innobase/pars/pars0opt.c index 5cc2e39b438..51aaf02b736 100644 --- a/innobase/pars/pars0opt.c +++ b/innobase/pars/pars0opt.c @@ -1094,6 +1094,19 @@ opt_clust_access( for (i = 0; i < n_fields; i++) { pos = dict_index_get_nth_field_pos(index, clust_index, i); + ut_a(pos != ULINT_UNDEFINED); + + /* We optimize here only queries to InnoDB's internal system + tables, and they should not contain column prefix indexes. */ + + if (dict_index_get_nth_field(index, pos)->prefix_len != 0 + || dict_index_get_nth_field(clust_index, i) + ->prefix_len != 0) { + fprintf(stderr, +"InnoDB: Error in pars0opt.c: table %s has prefix_len != 0\n", + index->table_name); + } + *(plan->clust_map + i) = pos; ut_ad((pos != ULINT_UNDEFINED) diff --git a/innobase/pars/pars0pars.c b/innobase/pars/pars0pars.c index a4124672df0..5be0e52d0c8 100644 --- a/innobase/pars/pars0pars.c +++ b/innobase/pars/pars0pars.c @@ -259,9 +259,13 @@ pars_resolve_func_data_type( dtype_set(que_node_get_data_type(node), DATA_VARCHAR, DATA_ENGLISH, 0, 0); } else if (func == PARS_TO_BINARY_TOKEN) { - ut_a(dtype_get_mtype(que_node_get_data_type(arg)) == DATA_INT); - dtype_set(que_node_get_data_type(node), DATA_VARCHAR, + if (dtype_get_mtype(que_node_get_data_type(arg)) == DATA_INT) { + dtype_set(que_node_get_data_type(node), DATA_VARCHAR, DATA_ENGLISH, 0, 0); + } else { + dtype_set(que_node_get_data_type(node), DATA_BINARY, + 0, 0, 0); + } } else if (func == PARS_TO_NUMBER_TOKEN) { ut_a(dtype_get_mtype(que_node_get_data_type(arg)) == DATA_VARCHAR); diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 458970da4e2..b9f860903cb 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -966,6 +966,23 @@ row_ins_foreign_check_on_constraint( err = row_update_cascade_for_mysql(thr, cascade, foreign->foreign_table); + + if (foreign->foreign_table->n_foreign_key_checks_running == 0) { + fprintf(stderr, +"InnoDB: error: table %s has the counter 0 though there is\n" +"InnoDB: a FOREIGN KEY check running on it.\n", + foreign->foreign_table->name); + } + + /* Release the data dictionary latch for a while, so that we do not + starve other threads from doing CREATE TABLE etc. if we have a huge + cascaded operation running. The counter n_foreign_key_checks_running + will prevent other users from dropping or ALTERing the table when we + release the latch. */ + + row_mysql_unfreeze_data_dictionary(thr_get_trx(thr)); + row_mysql_freeze_data_dictionary(thr_get_trx(thr)); + mtr_start(mtr); /* Restore pcur position */ diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 70743e3a753..2e8f7121d2c 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -89,6 +89,19 @@ row_mysql_is_system_table( || 0 == strcmp(name + 6, "user") || 0 == strcmp(name + 6, "db")); } + +/*********************************************************************** +Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */ +static +void +row_mysql_delay_if_needed(void) +/*===========================*/ +{ + if (srv_dml_needed_delay) { + os_thread_sleep(srv_dml_needed_delay); + } +} + /*********************************************************************** Reads a MySQL format variable-length field (like VARCHAR) length and returns pointer to the field data. */ @@ -310,8 +323,9 @@ handle_new_error: "InnoDB: a case of widespread corruption, dump all InnoDB\n" "InnoDB: tables and recreate the whole InnoDB tablespace.\n" "InnoDB: If the mysqld server crashes after the startup or when\n" - "InnoDB: you dump the tables, look at section 6.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php for help.\n", stderr); + "InnoDB: you dump the tables, look at\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html" + " for help.\n", stderr); } else { fprintf(stderr, "InnoDB: unknown error code %lu\n", err); @@ -855,6 +869,8 @@ row_insert_for_mysql( trx->op_info = (char *) "inserting"; + row_mysql_delay_if_needed(); + trx_start_if_not_started(trx); if (node == NULL) { @@ -1070,6 +1086,8 @@ row_update_for_mysql( trx->op_info = (char *) "updating or deleting"; + row_mysql_delay_if_needed(); + trx_start_if_not_started(trx); node = prebuilt->upd_node; @@ -1551,8 +1569,9 @@ row_create_table_for_mysql( "InnoDB: database and moving the .frm file to the current database.\n" "InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n" "InnoDB: succeed.\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n", stderr); + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n", stderr); } trx->error_state = DB_SUCCESS; @@ -1962,7 +1981,8 @@ row_drop_table_for_mysql( "WHILE found = 1 LOOP\n" " SELECT ID INTO foreign_id\n" " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = table_name;\n" + " WHERE FOR_NAME = table_name\n" + " AND TO_BINARY(FOR_NAME) = TO_BINARY(table_name);\n" " IF (SQL % NOTFOUND) THEN\n" " found := 0;\n" " ELSE" @@ -2049,6 +2069,7 @@ row_drop_table_for_mysql( memcpy(sql, str1, (sizeof str1) - 1); memcpy(sql + (sizeof str1) - 1, quoted_name, namelen); memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2); + mem_free(quoted_name); /* Serialize data dictionary operations with dictionary mutex: no deadlocks can occur then in these operations */ @@ -2089,8 +2110,9 @@ row_drop_table_for_mysql( "InnoDB: data dictionary though MySQL is trying to drop it.\n" "InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: MySQL database directory from another database?\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n", stderr); + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n", stderr); goto funct_exit; } @@ -2152,8 +2174,8 @@ row_drop_table_for_mysql( fputs(" InnoDB: You are trying to drop table ", stderr); ut_print_name(stderr, table->name); fputs("\n" - "InnoDB: though there are foreign key check running on it.\n" - "InnoDB: Adding the table to the background drop queue.\n", + "InnoDB: though there is a foreign key check running on it.\n" + "InnoDB: Adding the table to the background drop queue.\n", stderr); row_add_table_to_background_drop_list(table); @@ -2360,7 +2382,8 @@ row_rename_table_for_mysql( "WHILE found = 1 LOOP\n" " SELECT ID INTO foreign_id\n" " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = old_table_name;\n" + " WHERE FOR_NAME = old_table_name\n" + " AND TO_BINARY(FOR_NAME) = TO_BINARY(old_table_name);\n" " IF (SQL % NOTFOUND) THEN\n" " found := 0;\n" " ELSE\n" @@ -2393,7 +2416,8 @@ row_rename_table_for_mysql( " END IF;\n" "END LOOP;\n" "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" - "WHERE REF_NAME = old_table_name;\n"; + "WHERE REF_NAME = old_table_name\n" + " AND TO_BINARY(REF_NAME) = TO_BINARY(old_table_name);\n"; static const char str5[] = "END;\n"; @@ -2581,15 +2605,20 @@ row_rename_table_for_mysql( if (err == DB_DUPLICATE_KEY) { ut_print_timestamp(stderr); - fputs(" InnoDB: Error: table ", stderr); + fputs( + " InnoDB: Error; possible reasons:\n" + "InnoDB: 1) Table rename would cause two FOREIGN KEY constraints\n" + "InnoDB: to have the same internal name in case-insensitive comparison.\n" + "InnoDB: 2) table ", stderr); ut_print_name(stderr, new_name); fputs(" exists in the InnoDB internal data\n" "InnoDB: dictionary though MySQL is trying rename table ", stderr); ut_print_name(stderr, old_name); fputs(" to it.\n" "InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n" + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n" "InnoDB: If table ", stderr); ut_print_name(stderr, new_name); fputs( diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c index 680539764fd..f075caa7d75 100644 --- a/innobase/row/row0row.c +++ b/innobase/row/row0row.c @@ -334,6 +334,7 @@ row_build_row_ref( ulint ref_len; ulint pos; byte* buf; + ulint clust_col_prefix_len; ulint i; ut_ad(index && rec && heap); @@ -366,6 +367,22 @@ row_build_row_ref( field = rec_get_nth_field(rec, pos, &len); dfield_set_data(dfield, field, len); + + /* If the primary key contains a column prefix, then the + secondary index may contain a longer prefix of the same + column, or the full column, and we must adjust the length + accordingly. */ + + clust_col_prefix_len = + dict_index_get_nth_field(clust_index, i)->prefix_len; + + if (clust_col_prefix_len > 0) { + if (len != UNIV_SQL_NULL + && len > clust_col_prefix_len) { + + dfield_set_len(dfield, clust_col_prefix_len); + } + } } ut_ad(dtuple_check_typed(ref)); @@ -396,6 +413,7 @@ row_build_row_ref_in_tuple( ulint len; ulint ref_len; ulint pos; + ulint clust_col_prefix_len; ulint i; ut_a(ref && index && rec); @@ -433,6 +451,22 @@ row_build_row_ref_in_tuple( field = rec_get_nth_field(rec, pos, &len); dfield_set_data(dfield, field, len); + + /* If the primary key contains a column prefix, then the + secondary index may contain a longer prefix of the same + column, or the full column, and we must adjust the length + accordingly. */ + + clust_col_prefix_len = + dict_index_get_nth_field(clust_index, i)->prefix_len; + + if (clust_col_prefix_len > 0) { + if (len != UNIV_SQL_NULL + && len > clust_col_prefix_len) { + + dfield_set_len(dfield, clust_col_prefix_len); + } + } } ut_ad(dtuple_check_typed(ref)); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index d799ada1e20..0a814268a36 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -58,6 +58,10 @@ ulint srv_activity_count = 0; /* The following is the maximum allowed duration of a lock wait. */ ulint srv_fatal_semaphore_wait_threshold = 600; +/* How much data manipulation language (DML) statements need to be delayed, +in microseconds, in order to reduce the lagging of the purge thread. */ +ulint srv_dml_needed_delay = 0; + ibool srv_lock_timeout_and_monitor_active = FALSE; ibool srv_error_monitor_active = FALSE; @@ -841,6 +845,8 @@ srv_general_init(void) /*======================= InnoDB Server FIFO queue =======================*/ +/* Maximum allowable purge history length. <=0 means 'infinite'. */ +ulint srv_max_purge_lag = 0; /************************************************************************* Puts an OS thread to wait if there are too many concurrent threads @@ -1754,7 +1760,8 @@ srv_error_monitor_thread( /* in: a dummy parameter required by os_thread_create */ { - ulint cnt = 0; + /* number of successive fatal timeouts observed */ + ulint fatal_cnt = 0; #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "Error monitor thread starts, id %lu\n", @@ -1763,8 +1770,6 @@ srv_error_monitor_thread( loop: srv_error_monitor_active = TRUE; - cnt++; - os_thread_sleep(2000000); if (difftime(time(NULL), srv_last_monitor_time) > 60) { @@ -1774,7 +1779,20 @@ loop: srv_refresh_innodb_monitor_stats(); } - sync_array_print_long_waits(); + if (sync_array_print_long_waits()) { + fatal_cnt++; + if (fatal_cnt > 5) { + + fprintf(stderr, +"InnoDB: Error: semaphore wait has lasted > %lu seconds\n" +"InnoDB: We intentionally crash the server, because it appears to be hung.\n", + srv_fatal_semaphore_wait_threshold); + + ut_error; + } + } else { + fatal_cnt = 0; + } /* Flush stderr so that a database user gets the output to possible MySQL error file */ diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 176aedb6ae3..a443d630425 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -61,10 +61,7 @@ struct sync_cell_struct { thread */ ibool waiting; /* TRUE if the thread has already called sync_array_event_wait - on this cell but not yet - sync_array_free_cell (which - actually resets wait_object and thus - whole cell) */ + on this cell */ ibool event_set; /* TRUE if the event is set */ os_event_t event; /* operating system event semaphore handle */ @@ -892,15 +889,18 @@ sync_arr_wake_threads_if_sema_free(void) /************************************************************************** Prints warnings of long semaphore waits to stderr. */ -void +ibool sync_array_print_long_waits(void) /*=============================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ { sync_cell_t* cell; ibool old_val; ibool noticed = FALSE; ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; + ibool fatal = FALSE; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { @@ -917,13 +917,7 @@ sync_array_print_long_waits(void) if (cell->wait_object != NULL && difftime(time(NULL), cell->reservation_time) > fatal_timeout) { - - fprintf(stderr, -"InnoDB: Error: semaphore wait has lasted > %lu seconds\n" -"InnoDB: We intentionally crash the server, because it appears to be hung.\n", - fatal_timeout); - - ut_error; + fatal = TRUE; } } @@ -951,6 +945,8 @@ sync_array_print_long_waits(void) fprintf(stderr, "InnoDB: ###### Diagnostic info printed to the standard error stream\n"); } + + return(fatal); } /************************************************************************** diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c index a8b6b9fcc21..d772af47b29 100644 --- a/innobase/trx/trx0purge.c +++ b/innobase/trx/trx0purge.c @@ -295,6 +295,9 @@ trx_purge_add_update_undo_to_history( /* Add the log as the first in the history list */ flst_add_first(rseg_header + TRX_RSEG_HISTORY, undo_header + TRX_UNDO_HISTORY_NODE, mtr); + mutex_enter(&kernel_mutex); + trx_sys->rseg_history_len++; + mutex_exit(&kernel_mutex); /* Write the trx number to the undo log header */ mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); @@ -386,6 +389,12 @@ loop: flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY, log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr); + + mutex_enter(&kernel_mutex); + ut_ad(trx_sys->rseg_history_len >= n_removed_logs); + trx_sys->rseg_history_len -= n_removed_logs; + mutex_exit(&kernel_mutex); + freed = FALSE; while (!freed) { @@ -470,6 +479,11 @@ loop: } if (cmp >= 0) { + mutex_enter(&kernel_mutex); + ut_a(trx_sys->rseg_history_len >= n_removed_logs); + trx_sys->rseg_history_len -= n_removed_logs; + mutex_exit(&kernel_mutex); + flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY, log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr); @@ -1031,6 +1045,30 @@ trx_purge(void) purge_sys->view = NULL; mem_heap_empty(purge_sys->heap); + /* Determine how much data manipulation language (DML) statements + need to be delayed in order to reduce the lagging of the purge + thread. */ + srv_dml_needed_delay = 0; /* in microseconds; default: no delay */ + + /* If we cannot advance the 'purge view' because of an old + 'consistent read view', then the DML statements cannot be delayed. + Also, srv_max_purge_lag <= 0 means 'infinity'. */ + if (srv_max_purge_lag > 0 + && !UT_LIST_GET_LAST(trx_sys->view_list)) { + float ratio = (float) trx_sys->rseg_history_len + / srv_max_purge_lag; + if (ratio > ULINT_MAX / 10000) { + /* Avoid overflow: maximum delay is 4295 seconds */ + srv_dml_needed_delay = ULINT_MAX; + } else if (ratio > 1) { + /* If the history list length exceeds the + innodb_max_purge_lag, the + data manipulation statements are delayed + by at least 5000 microseconds. */ + srv_dml_needed_delay = (ulint) ((ratio - .5) * 10000); + } + } + purge_sys->view = read_view_oldest_copy_or_open_new(NULL, purge_sys->heap); mutex_exit(&kernel_mutex); diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c index 79fad312e8e..a5623b4d0c7 100644 --- a/innobase/trx/trx0rec.c +++ b/innobase/trx/trx0rec.c @@ -1257,7 +1257,7 @@ trx_undo_prev_version_build( ibool dummy_extern; byte* buf; ulint err; - ulint i; + #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ @@ -1367,7 +1367,18 @@ trx_undo_prev_version_build( } if (row_upd_changes_field_size_or_external(rec, index, update)) { - + ulint* ext_vect; + ulint n_ext_vect; + + /* We have to set the appropriate extern storage bits in the + old version of the record: the extern bits in rec for those + fields that update does NOT update, as well as the the bits for + those fields that update updates to become externally stored + fields. Store the info to ext_vect: */ + + ext_vect = mem_alloc(sizeof(ulint) * rec_get_n_fields(rec)); + n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, + update); entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals(entry, index, update, heap); @@ -1375,6 +1386,11 @@ trx_undo_prev_version_build( buf = mem_heap_alloc(heap, rec_get_converted_size(entry)); *old_vers = rec_convert_dtuple_to_rec(buf, entry); + + /* Now set the extern bits in the old version of the record */ + rec_set_field_extern_bits(*old_vers, ext_vect, n_ext_vect, + NULL); + mem_free(ext_vect); } else { buf = mem_heap_alloc(heap, rec_get_size(rec)); @@ -1383,15 +1399,5 @@ trx_undo_prev_version_build( row_upd_rec_in_place(*old_vers, update); } - for (i = 0; i < upd_get_n_fields(update); i++) { - - if (upd_get_nth_field(update, i)->extern_storage) { - - rec_set_nth_field_extern_bit(*old_vers, - upd_get_nth_field(update, i)->field_no, - TRUE, NULL); - } - } - return(DB_SUCCESS); } diff --git a/innobase/trx/trx0rseg.c b/innobase/trx/trx0rseg.c index e3885c86def..a01d4bb835d 100644 --- a/innobase/trx/trx0rseg.c +++ b/innobase/trx/trx0rseg.c @@ -135,6 +135,7 @@ trx_rseg_mem_create( trx_ulogf_t* undo_log_hdr; fil_addr_t node_addr; ulint sum_of_undo_sizes; + ulint len; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex)); @@ -166,7 +167,9 @@ trx_rseg_mem_create( MLOG_4BYTES, mtr) + 1 + sum_of_undo_sizes; - if (flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr) > 0) { + len = flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr); + if (len > 0) { + trx_sys->rseg_history_len += len; node_addr = trx_purge_get_log_from_hist( flst_get_last(rseg_header + TRX_RSEG_HISTORY, @@ -206,6 +209,8 @@ trx_rseg_list_and_array_init( UT_LIST_INIT(trx_sys->rseg_list); + trx_sys->rseg_history_len = 0; + for (i = 0; i < TRX_SYS_N_RSEGS; i++) { page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr); diff --git a/innobase/ut/ut0dbg.c b/innobase/ut/ut0dbg.c index 2a0cfe1f13a..0f6a27d35d9 100644 --- a/innobase/ut/ut0dbg.c +++ b/innobase/ut/ut0dbg.c @@ -31,8 +31,9 @@ const char* ut_dbg_msg_trap = "InnoDB: Submit a detailed bug report to http://bugs.mysql.com.\n" "InnoDB: If you get repeated assertion failures or crashes, even\n" "InnoDB: immediately after the mysqld startup, there may be\n" -"InnoDB: corruption in the InnoDB tablespace. See section 6.1 of\n" -"InnoDB: http://www.innodb.com/ibman.php about forcing recovery.\n"; +"InnoDB: corruption in the InnoDB tablespace. Please refer to\n" +"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" +"InnoDB: about forcing recovery.\n"; const char* ut_dbg_msg_stop = "InnoDB: Thread %lu stopped in file %s line %lu\n"; diff --git a/isam/isamchk.c b/isam/isamchk.c index 8603b436841..daa9464eb4f 100644 --- a/isam/isamchk.c +++ b/isam/isamchk.c @@ -670,7 +670,7 @@ static void get_options(register int *argc, register char ***argv) if (isatty(fileno(stdout))) testflag|=T_WRITE_LOOP; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (*argc == 0) diff --git a/isam/pack_isam.c b/isam/pack_isam.c index 59594ccc929..b2e21afc743 100644 --- a/isam/pack_isam.c +++ b/isam/pack_isam.c @@ -353,7 +353,7 @@ static void get_options(int *argc, char ***argv) { int ho_error; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); my_progname= argv[0][0]; diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index fefed7f079c..3c4e98e5053 100644 --- a/libmysql/Makefile.am +++ b/libmysql/Makefile.am @@ -31,7 +31,7 @@ include $(srcdir)/Makefile.shared libmysqlclient_la_SOURCES = $(target_sources) libmysqlclient_la_LIBADD = $(target_libadd) libmysqlclient_la_LDFLAGS = $(target_ldflags) -EXTRA_DIST = Makefile.shared +EXTRA_DIST = Makefile.shared libmysql.def # This is called from the toplevel makefile link_sources: diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index a591ad9317d..47f28e296b2 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3154,6 +3154,41 @@ void my_net_local_init(NET *net) } /* + This function is used to create HEX string that you + can use in a SQL statement in of the either ways: + INSERT INTO blob_column VALUES (0xAABBCC); (any MySQL version) + INSERT INTO blob_column VALUES (X'AABBCC'); (4.1 and higher) + + The string in "from" is encoded to a HEX string. + The result is placed in "to" and a terminating null byte is appended. + + The string pointed to by "from" must be "length" bytes long. + You must allocate the "to" buffer to be at least length*2+1 bytes long. + Each character needs two bytes, and you need room for the terminating + null byte. When mysql_hex_string() returns, the contents of "to" will + be a null-terminated string. The return value is the length of the + encoded string, not including the terminating null character. + + The return value does not contain any leading 0x or a leading X' and + trailing '. The caller must supply whichever of those is desired. +*/ + +ulong STDCALL +mysql_hex_string(char *to, const char *from, ulong length) +{ + char *to0= to; + const char *end; + + for (end= from + length; from < end; from++) + { + *to++= _dig_vec[((unsigned char) *from) >> 4]; + *to++= _dig_vec[((unsigned char) *from) & 0x0F]; + } + *to= '\0'; + return (ulong) (to-to0); +} + +/* Add escape characters to a string (blob?) to make it suitable for a insert to should at least have place for length*2+1 chars Returns the length of the to string diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index b0433a34cb3..51a4edda5aa 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -11,6 +11,7 @@ EXPORTS mysql_errno mysql_error mysql_escape_string + mysql_hex_string mysql_fetch_field mysql_fetch_field_direct mysql_fetch_fields diff --git a/ltmain.sh b/ltmain.sh index 62b9ed17e3f..92e438cbda6 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -51,6 +51,9 @@ fi # libtool 1.4.2 workaround SED=${SED:-sed} +# workaround against unset 'max_cmd_len': assume at least 4 kB +max_cmd_len=${max_cmd_len:-4096} + # The name of this program. progname=`$echo "$0" | ${SED} 's%^.*/%%'` modename="$progname" diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 13f46849210..1958619c2dd 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -161,7 +161,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, if (param.trunc) ftbw->flags|=FTB_FLAG_TRUNC; ftbw->weight=weight; ftbw->up=up; - ftbw->docid[0]=ftbw->docid[1]=HA_POS_ERROR; + ftbw->docid[0]=ftbw->docid[1]=HA_OFFSET_ERROR; ftbw->ndepth= (param.yesno<0) + depth; memcpy(ftbw->word+1, w.pos, w.len); ftbw->word[0]=w.len; @@ -177,7 +177,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, ftbe->weight=weight; ftbe->up=up; ftbe->ythresh=ftbe->yweaks=0; - ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR; + ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR; if ((ftbe->quot=param.quot)) ftb->with_scan|=2; if (param.yesno > 0) up->ythresh++; _ftb_parse_query(ftb, start, end, ftbe, depth+1); @@ -245,9 +245,9 @@ static void _ftb_init_index_search(FT_INFO *ftb) ftbe->up->ythresh - ftbe->up->yweaks >1) /* 1 */ { FTB_EXPR *top_ftbe=ftbe->up->up; - ftbw->docid[0]=HA_POS_ERROR; + ftbw->docid[0]=HA_OFFSET_ERROR; for (ftbe=ftbw->up; ftbe != top_ftbe; ftbe=ftbe->up) - if (ftbe->flags & FTB_FLAG_YES) + if (!(ftbe->flags & FTB_FLAG_NO)) ftbe->yweaks++; ftbe=0; break; @@ -255,7 +255,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) } if (!ftbe) continue; - /* 3 */ + /* 4 */ if (!is_tree_inited(& ftb->no_dupes)) init_tree(& ftb->no_dupes,0,0,sizeof(my_off_t), _ftb_no_dupes_cmp,0,0,0); @@ -319,7 +319,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, default_charset_info : info->s->keyinfo[keynr].seg->charset); ftb->with_scan=0; - ftb->lastpos=HA_POS_ERROR; + ftb->lastpos=HA_OFFSET_ERROR; bzero(& ftb->no_dupes, sizeof(TREE)); init_alloc_root(&ftb->mem_root, 1024, 1024); @@ -342,7 +342,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftbe->quot=0; ftbe->up=0; ftbe->ythresh=ftbe->yweaks=0; - ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR; + ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR; ftb->root=ftbe; _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0); ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root, @@ -496,7 +496,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) while (ftb->state == INDEX_SEARCH && (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) != - HA_POS_ERROR) + HA_OFFSET_ERROR) { while (curdoc==(ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0]) { @@ -521,7 +521,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) } if (r) /* not found */ { - ftbw->docid[0]=HA_POS_ERROR; + ftbw->docid[0]=HA_OFFSET_ERROR; if (ftbw->flags&FTB_FLAG_YES && ftbw->up->up==0) { /* @@ -580,7 +580,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) const byte *end; my_off_t docid=ftb->info->lastpos; - if (docid == HA_POS_ERROR) + if (docid == HA_OFFSET_ERROR) return -2.0; if (!ftb->queue.elements) return 0; @@ -592,9 +592,9 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) for (i=0; i < ftb->queue.elements; i++) { - ftb->list[i]->docid[1]=HA_POS_ERROR; + ftb->list[i]->docid[1]=HA_OFFSET_ERROR; for (x=ftb->list[i]->up; x; x=x->up) - x->docid[1]=HA_POS_ERROR; + x->docid[1]=HA_OFFSET_ERROR; } } diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 078f7787dc3..e78d831fde7 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -3520,7 +3520,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) create_info.raid_chunksize= share.base.raid_chunksize; create_info.language = (param->language ? param->language : share.state.header.language); - + create_info.key_file_length= status_info.key_file_length; /* We don't have to handle symlinks here because we are using HA_DONT_TOUCH_DATA */ if (mi_create(filename, diff --git a/myisam/mi_close.c b/myisam/mi_close.c index dbaaebb1143..2712f0ca283 100644 --- a/myisam/mi_close.c +++ b/myisam/mi_close.c @@ -70,6 +70,12 @@ int mi_close(register MI_INFO *info) error=my_errno; if (share->kfile >= 0) { + /* + If we are crashed, we can safely flush the current state as it will + not change the crashed state. + We can NOT write the state in other cases as other threads + may be using the file at this point + */ if (share->mode != O_RDONLY && mi_is_crashed(info)) mi_state_info_write(share->kfile, &share->state, 1); if (my_close(share->kfile,MYF(0))) diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 328450c70db..99e9ca5ba5f 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -46,7 +46,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ulong reclength, real_reclength,min_pack_length; char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; ulong pack_reclength; - ulonglong tot_length,max_rows; + ulonglong tot_length,max_rows, tmp; enum en_fieldtype type; MYISAM_SHARE share; MI_KEYDEF *keydef,tmp_keydef; @@ -442,10 +442,15 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, share.state.auto_increment=ci->auto_increment; share.options=options; share.base.rec_reflength=pointer; + /* Get estimate for index file length (this may be wrong for FT keys) */ + tmp= (tot_length + max_key_block_length * keys * + MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH; + /* + use maximum of key_file_length we calculated and key_file_length value we + got from MYI file header (see also myisampack.c:save_state) + */ share.base.key_reflength= - mi_get_pointer_length((tot_length + max_key_block_length * keys * - MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH, - 3); + mi_get_pointer_length(max(ci->key_file_length,tmp),3); share.base.keys= share.state.header.keys = keys; share.state.header.uniques= uniques; mi_int2store(share.state.header.key_parts,key_segs); diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index f3bfa8deb90..d5212cdee47 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -19,7 +19,7 @@ reads info from a isam-table. Must be first request before doing any furter calls to any isamfunktion. Is used to allow many process use the same isamdatabase. - */ +*/ #include "myisamdef.h" #ifdef __WIN__ @@ -35,12 +35,17 @@ int mi_lock_database(MI_INFO *info, int lock_type) MYISAM_SHARE *share=info->s; uint flag; DBUG_ENTER("mi_lock_database"); - DBUG_PRINT("info",("lock_type: %d", lock_type)); + DBUG_PRINT("enter",("lock_type: %d old lock %d r_locks: %u w_locks: %u " + "global_changed: %d open_count: %u name: '%s'", + lock_type, info->lock_type, share->r_locks, + share->w_locks, + share->global_changed, share->state.open_count, + share->index_file_name)); if (share->options & HA_OPTION_READ_ONLY_DATA || info->lock_type == lock_type) DBUG_RETURN(0); - if (lock_type == F_EXTRA_LCK) + if (lock_type == F_EXTRA_LCK) /* Used by TMP tables */ { ++share->w_locks; ++share->tot_locks; @@ -54,7 +59,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) { switch (lock_type) { case F_UNLCK: - DBUG_PRINT("info", ("old lock: %d", info->lock_type)); if (info->lock_type == F_RDLCK) count= --share->r_locks; else @@ -83,7 +87,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) share->state.process= share->last_process=share->this_process; share->state.unique= info->last_unique= info->this_unique; share->state.update_count= info->last_loop= ++info->this_loop; - if (mi_state_info_write(share->kfile, &share->state, 1)) + if (mi_state_info_write(share->kfile, &share->state, 1)) error=my_errno; share->changed=0; if (myisam_flush) @@ -121,11 +125,17 @@ int mi_lock_database(MI_INFO *info, int lock_type) break; case F_RDLCK: if (info->lock_type == F_WRLCK) - { /* Change RW to READONLY */ + { + /* + Change RW to READONLY + + mysqld does not turn write locks to read locks, + so we're never here in mysqld. + */ if (share->w_locks == 1) { flag=1; - if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, + if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, MYF(MY_SEEK_NOT_DONE))) { error=my_errno; @@ -333,9 +343,10 @@ int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer) } /* _mi_readinfo */ - /* Every isam-function that uppdates the isam-database must! end */ - /* with this request */ - /* ARGSUSED */ +/* + Every isam-function that uppdates the isam-database MUST end with this + request +*/ int _mi_writeinfo(register MI_INFO *info, uint operation) { @@ -402,12 +413,31 @@ int _mi_test_if_changed(register MI_INFO *info) } /* _mi_test_if_changed */ -/* Put a mark in the .MYI file that someone is updating the table */ +/* + Put a mark in the .MYI file that someone is updating the table + + + DOCUMENTATION + + state.open_count in the .MYI file is used the following way: + - For the first change of the .MYI file in this process open_count is + incremented by mi_mark_file_change(). (We have a write lock on the file + when this happens) + - In mi_close() it's decremented by _mi_decrement_open_count() if it + was incremented in the same process. + + This mean that if we are the only process using the file, the open_count + tells us if the MYISAM file wasn't properly closed. (This is true if + my_disable_locking is set). +*/ + int _mi_mark_file_changed(MI_INFO *info) { char buff[3]; register MYISAM_SHARE *share=info->s; + DBUG_ENTER("_mi_mark_file_changed"); + if (!(share->state.changed & STATE_CHANGED) || ! share->global_changed) { share->state.changed|=(STATE_CHANGED | STATE_NOT_ANALYZED | @@ -421,12 +451,12 @@ int _mi_mark_file_changed(MI_INFO *info) { mi_int2store(buff,share->state.open_count); buff[2]=1; /* Mark that it's changed */ - return (my_pwrite(share->kfile,buff,sizeof(buff), - sizeof(share->state.header), - MYF(MY_NABP))); + DBUG_RETURN(my_pwrite(share->kfile,buff,sizeof(buff), + sizeof(share->state.header), + MYF(MY_NABP))); } } - return 0; + DBUG_RETURN(0); } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 944a8af01e9..339ce2de291 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -188,7 +188,11 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share->state_diff_length=len-MI_STATE_INFO_SIZE; if (share->state.header.fulltext_keys) + { fprintf(stderr, "Warning: table file %s was created in MySQL 4.1+, use REPAIR TABLE ... USE_FRM to recreate it as a valid MySQL 4.0 table\n", name_buff); + my_errno=HA_ERR_UNSUPPORTED; + goto err; + } mi_state_info_read(disk_cache, &share->state); len= mi_uint2korr(share->state.header.base_info_length); diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c index 88e6c5c89d3..8ea97c8e489 100644 --- a/myisam/mi_test1.c +++ b/myisam/mi_test1.c @@ -643,7 +643,7 @@ static void get_options(int argc, char *argv[]) { int ho_error; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); return; diff --git a/myisam/myisam_ftdump.c b/myisam/myisam_ftdump.c index 35182bc8abb..838f90feae5 100644 --- a/myisam/myisam_ftdump.c +++ b/myisam/myisam_ftdump.c @@ -66,7 +66,7 @@ int main(int argc,char *argv[]) struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */ MY_INIT(argv[0]); - if (error=handle_options(&argc, &argv, my_long_options, get_one_option, NULL)) + if (error=handle_options(&argc, &argv, my_long_options, get_one_option)) exit(error); if (count || dump) verbose=0; diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index e8e85345897..5377ecc18a5 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -677,7 +677,7 @@ static void get_options(register int *argc,register char ***argv) if (isatty(fileno(stdout))) check_param.testflag|=T_WRITE_LOOP; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); /* If using repair, then update checksum if one uses --update-state */ diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 51f8ad1bb11..9f4e3bde65a 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -111,6 +111,8 @@ typedef struct st_isam_mrg { uint ref_length; uint max_blob_length; my_off_t records; + /* true if at least one source file has at least one disabled index */ + my_bool src_file_has_indexes_disabled; } PACK_MRG_INFO; @@ -350,7 +352,7 @@ static void get_options(int *argc,char ***argv) if (isatty(fileno(stdout))) write_loop=1; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (!*argc) @@ -413,10 +415,15 @@ static bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count) mrg->current=0; mrg->file=(MI_INFO**) my_malloc(sizeof(MI_INFO*)*count,MYF(MY_FAE)); mrg->free_file=1; + mrg->src_file_has_indexes_disabled= 0; for (i=0; i < count ; i++) { if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY))) goto error; + + mrg->src_file_has_indexes_disabled|= ((mrg->file[i]->s->state.key_map != + (((ulonglong) 1) << + mrg->file[i]->s->base. keys) - 1)); } /* Check that files are identical */ for (j=0 ; j < count-1 ; j++) @@ -2040,8 +2047,21 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->state.dellink= HA_OFFSET_ERROR; share->state.split=(ha_rows) mrg->records; share->state.version=(ulong) time((time_t*) 0); + if (share->state.key_map != (((ulonglong)1) << share->base.keys) - 1) + { + /* + Some indexes are disabled, cannot use current key_file_length value + as an estimate of upper bound of index file size. Use packed data file + size instead. + */ + share->state.state.key_file_length= new_length; + } + /* + If there are no disabled indexes, keep key_file_length value from + original file so "myisamchk -rq" can use this value (this is necessary + because index size cannot be easily calculated for fulltext keys) + */ share->state.key_map=0; - share->state.state.key_file_length=share->base.keystart; for (key=0 ; key < share->base.keys ; key++) share->state.key_root[key]= HA_OFFSET_ERROR; for (key=0 ; key < share->state.header.max_block_size ; key++) @@ -2050,8 +2070,7 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->changed=1; /* Force write of header */ share->state.open_count=0; share->global_changed=0; - VOID(my_chsize(share->kfile, share->state.state.key_file_length, 0, - MYF(0))); + VOID(my_chsize(share->kfile, share->base.keystart, 0, MYF(0))); if (share->base.keys) isamchk_neaded=1; DBUG_RETURN(mi_state_info_write(share->kfile,&share->state,1+2)); @@ -2074,7 +2093,12 @@ static int save_state_mrg(File file,PACK_MRG_INFO *mrg,my_off_t new_length, state.state.del=0; state.state.empty=0; state.state.records=state.split=(ha_rows) mrg->records; - state.state.key_file_length=isam_file->s->base.keystart; + /* See comment above in save_state about key_file_length handling. */ + if (mrg->src_file_has_indexes_disabled) + { + isam_file->s->state.state.key_file_length= + max(isam_file->s->state.state.key_file_length, new_length); + } state.dellink= HA_OFFSET_ERROR; state.version=(ulong) time((time_t*) 0); state.key_map=0; diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index 4c6ffb98ad5..a59ccb7d966 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -34,14 +34,17 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) { int save_errno,errpos=0; uint files=0,i,dir_length,length,key_parts; - ulonglong file_offset; + ulonglong file_offset=0; char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end; MYRG_INFO *m_info=0; File fd; IO_CACHE file; MI_INFO *isam=0; + uint found_merge_insert_method= 0; DBUG_ENTER("myrg_open"); + LINT_INIT(key_parts); + bzero((char*) &file,sizeof(file)); if ((fd=my_open(fn_format(name_buff,name,"",MYRG_NAME_EXT,4), O_RDONLY | O_SHARE,MYF(0))) < 0) @@ -69,10 +72,10 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) continue; /* Skip empty lines */ if (buff[0] == '#') { - if( !strncmp(buff+1,"INSERT_METHOD=",14)) + if (!strncmp(buff+1,"INSERT_METHOD=",14)) { /* Lookup insert method */ int tmp=find_type(buff+15,&merge_insert_method,2); - m_info->merge_insert_method = (uint) (tmp >= 0 ? tmp : 0); + found_merge_insert_method = (uint) (tmp >= 0 ? tmp : 0); } continue; /* Skip comments */ } @@ -84,8 +87,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) VOID(cleanup_dirname(buff,name_buff)); } if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0)))) - goto err; - if (!m_info) + goto err; + if (!m_info) /* First file */ { key_parts=isam->s->base.key_parts; if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO) + @@ -97,15 +100,10 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) { m_info->open_tables=(MYRG_TABLE *) (m_info+1); m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files); + m_info->tables= files; + files= 0; } - else - { - m_info->open_tables=0; - m_info->rec_per_key_part=0; - } - m_info->tables=files; m_info->reclength=isam->s->base.reclength; - file_offset=files=0; errpos=3; } m_info->open_tables[files].table= isam; @@ -122,14 +120,16 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) m_info->del+= isam->state->del; m_info->data_file_length+= isam->state->data_file_length; for (i=0; i < key_parts; i++) - m_info->rec_per_key_part[i]+=isam->s->state.rec_per_key_part[i] / m_info->tables; + m_info->rec_per_key_part[i]+= (isam->s->state.rec_per_key_part[i] / + m_info->tables); } if (!m_info && !(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO), - MYF(MY_WME|MY_ZEROFILL)))) + MYF(MY_WME | MY_ZEROFILL)))) goto err; /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */ m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA); + m_info->merge_insert_method= found_merge_insert_method; if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L) { diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index ba96c5947ba..8b0c096120a 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -32,6 +32,7 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r $(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.001 $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data install-data-local: $(mkinstalldirs) \ @@ -50,6 +51,7 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/*.dat $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.*001 $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(DESTDIR)$(testdir)/std_data SUFFIXES = .sh diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result index 28394d9533a..c4bf6b5a3a9 100644 --- a/mysql-test/r/ctype_latin1_de.result +++ b/mysql-test/r/ctype_latin1_de.result @@ -267,3 +267,18 @@ select * from t1 where word like CAST(0xDF as CHAR); word word2 ß ß drop table t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +autor varchar(80) NOT NULL default '', +PRIMARY KEY (autor) +); +INSERT INTO t1 VALUES ('Powell, B.'),('Powell, Bud.'),('Powell, L. H.'),('Power, H.'), +('Poynter, M. A. L. Lane'),('Poynting, J. H. und J. J. Thomson.'),('Pozzi, S(amuel-Jean).'), +('Pozzi, Samuel-Jean.'),('Pozzo, A.'),('Pozzoli, Serge.'); +SELECT * FROM t1 WHERE autor LIKE 'Poz%' ORDER BY autor; +autor +Pozzi, S(amuel-Jean). +Pozzi, Samuel-Jean. +Pozzo, A. +Pozzoli, Serge. +DROP TABLE t1; diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index abc8245e69f..7353e687ae7 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -50,3 +50,14 @@ select count(*) from t1; count(*) 0 drop table t1; +create table t1 (a int not null auto_increment primary key, b char(32)); +insert into t1 (b) values ('apple'), ('apple'); +select * from t1; +a b +1 apple +2 apple +delete t1 from t1, t1 as t2 where t1.b = t2.b and t1.a > t2.a; +select * from t1; +a b +1 apple +drop table t1; diff --git a/mysql-test/r/flush_table.result b/mysql-test/r/flush_table.result index cfba428e2e8..ff69291193f 100644 --- a/mysql-test/r/flush_table.result +++ b/mysql-test/r/flush_table.result @@ -7,58 +7,6 @@ check table t1; Table Op Msg_type Msg_text test.t1 check status OK drop table t1; -drop database if exists test_test; -create database test_test; -use test_test; -create table t1(table_id char(20) primary key); -insert into t1 values ('test_test.t1'); -insert into t1 values (''); -handler t1 open; -handler t1 read first limit 9; -table_id -test_test.t1 - -create table t2(table_id char(20) primary key); -insert into t2 values ('test_test.t2'); -insert into t2 values (''); -handler t2 open; -handler t2 read first limit 9; -table_id -test_test.t2 - -use test; -drop table if exists t1; -create table t1(table_id char(20) primary key); -insert into t1 values ('test.t1'); -insert into t1 values (''); -handler t1 open; -handler t1 read first limit 9; -table_id -test.t1 - -use test; -handler test.t1 read first limit 9; -table_id -test.t1 - -handler test.t2 read first limit 9; -Unknown table 't2' in HANDLER -handler test_test.t1 read first limit 9; -table_id -test_test.t1 - -handler test_test.t2 read first limit 9; -table_id -test_test.t2 - -handler test_test.t1 close; -drop table test_test.t1; -handler test_test.t2 close; -drop table test_test.t2; -drop database test_test; -use test; -handler test.t1 close; -drop table test.t1; drop table if exists t1; drop table if exists t2; create table t1(table_id char(20) primary key); @@ -84,14 +32,23 @@ test.t2 flush tables; handler a1 read first limit 9; -Unknown table 'a1' in HANDLER +table_id +test.t1 + handler a2 read first limit 9; -Unknown table 'a2' in HANDLER +table_id +test.t1 + handler t2 read first limit 9; -Unknown table 't2' in HANDLER +table_id +test.t2 + handler t1 open as a1; +Not unique table/alias: 'a1' handler t1 open as a2; +Not unique table/alias: 'a2' handler t2 open; +Not unique table/alias: 't2' handler a1 read first limit 9; table_id test.t1 @@ -106,15 +63,43 @@ test.t2 flush table t1; handler a1 read first limit 9; -Unknown table 'a1' in HANDLER +table_id +test.t1 + handler a2 read first limit 9; -Unknown table 'a2' in HANDLER +table_id +test.t1 + handler t2 read first limit 9; table_id test.t2 flush table t2; handler t2 close; -Unknown table 't2' in HANDLER drop table t1; drop table t2; +create table t1(table_id char(20) primary key); +insert into t1 values ('Record-01'); +insert into t1 values ('Record-02'); +insert into t1 values ('Record-03'); +insert into t1 values ('Record-04'); +insert into t1 values ('Record-05'); +handler t1 open; +handler t1 read first limit 1; +table_id +Record-01 +handler t1 read next limit 1; +table_id +Record-02 +handler t1 read next limit 1; +table_id +Record-03 +flush table t1; +handler t1 read next limit 1; +table_id +Record-01 +handler t1 read next limit 1; +table_id +Record-02 +handler t1 close; +drop table t1; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 19bd355f537..50f0a1dc120 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -162,6 +162,14 @@ a select * from t1 where match a against ("+aaa10 +(bbb*)" in boolean mode); a aaa10 bbb20 +select * from t1 where match a against ("+(+aaa* +bbb1*)" in boolean mode); +a +aaa20 bbb15 +aaa30 bbb10 +select * from t1 where match a against ("(+aaa* +bbb1*)" in boolean mode); +a +aaa20 bbb15 +aaa30 bbb10 drop table t1; CREATE TABLE t1 ( id int(11), @@ -298,3 +306,12 @@ t1_id name t2_id t1_id name select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode); t2_id t1_id name drop table t1,t2; +CREATE TABLE t1 (h text, FULLTEXT (h)); +INSERT INTO t1 VALUES ('Jesses Hasse Ling and his syncopators of Swing'); +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +select count(*) from t1; +count(*) +1 +drop table t1; diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index aee54ede324..72226588de3 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -64,3 +64,6 @@ select if(1>2,a,avg(a)) from t1; if(1>2,a,avg(a)) 1.5000 drop table t1; +SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL; +NULLIF(5,5) IS NULL NULLIF(5,5) IS NOT NULL +1 0 diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 12c1cf78f7c..d38a2edfa1a 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -167,6 +167,9 @@ length(quote(concat(char(0),"test"))) select hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))); hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))) 27E0E3E6E7E8EAEB27 +select concat('a', quote(NULL)); +concat('a', quote(NULL)) +aNULL select reverse(""); reverse("") @@ -278,7 +281,13 @@ insert into t1 values ('one'),(NULL),('two'),('four'); select a, quote(a), isnull(quote(a)), quote(a) is null, ifnull(quote(a), 'n') from t1; a quote(a) isnull(quote(a)) quote(a) is null ifnull(quote(a), 'n') one 'one' 0 0 'one' -NULL NULL 1 1 n +NULL NULL 0 0 NULL two 'two' 0 0 'two' four 'four' 0 0 'four' drop table t1; +select trim(trailing 'foo' from 'foo'); +trim(trailing 'foo' from 'foo') + +select trim(leading 'foo' from 'foo'); +trim(leading 'foo' from 'foo') + diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 877ca0e2d51..32034bf289d 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -470,3 +470,9 @@ unix_timestamp(@a) select unix_timestamp('1969-12-01 19:00:01'); unix_timestamp('1969-12-01 19:00:01') 0 +select from_unixtime(0); +from_unixtime(0) +NULL +select from_unixtime(2145916800); +from_unixtime(2145916800) +NULL diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index d4d8dd1f026..f0e5d16e916 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -150,3 +150,9 @@ GRANT SELECT ON `ab%`.* TO 'test11'@'localhost' GRANT SELECT ON `a%`.* TO 'test11'@'localhost' delete from mysql.user where user='test11'; delete from mysql.db where user='test11'; +create database db6123; +grant usage on db6123.* to test6123 identified by 'magic123'; +select host,db,user,select_priv,insert_priv from mysql.db where db="db6123"; +host db user select_priv insert_priv +delete from mysql.user where user='test6123'; +drop database db6123; diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 50d51cf14f4..5af153930d5 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -203,3 +203,247 @@ handler t1 read a=(1) where b=1; a b handler t1 close; drop table t1; +drop database if exists test_test; +create database test_test; +use test_test; +create table t1(table_id char(20) primary key); +insert into t1 values ('test_test.t1'); +insert into t1 values (''); +handler t1 open; +handler t1 read first limit 9; +table_id +test_test.t1 + +create table t2(table_id char(20) primary key); +insert into t2 values ('test_test.t2'); +insert into t2 values (''); +handler t2 open; +handler t2 read first limit 9; +table_id +test_test.t2 + +use test; +drop table if exists t1; +create table t1(table_id char(20) primary key); +insert into t1 values ('test.t1'); +insert into t1 values (''); +handler t1 open; +Not unique table/alias: 't1' +use test; +handler test.t1 read first limit 9; +Unknown table 'test.t1' in HANDLER +handler test_test.t1 read first limit 9; +table_id +test_test.t1 + +handler t1 read first limit 9; +table_id +test_test.t1 + +handler test_test.t2 read first limit 9; +table_id +test_test.t2 + +handler t2 read first limit 9; +table_id +test_test.t2 + +handler test_test.t1 close; +handler t1 close; +Unknown table 't1' in HANDLER +drop table test_test.t1; +handler test_test.t2 close; +handler t2 close; +Unknown table 't2' in HANDLER +drop table test_test.t2; +drop database test_test; +use test; +handler test.t1 close; +Unknown table 'test.t1' in HANDLER +handler t1 close; +Unknown table 't1' in HANDLER +drop table test.t1; +drop database if exists test_test; +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +create database test_test; +use test_test; +create table t1 (c1 char(20)); +insert into t1 values ('test_test.t1'); +create table t3 (c1 char(20)); +insert into t3 values ('test_test.t3'); +handler t1 open; +handler t1 read first limit 9; +c1 +test_test.t1 +handler t1 open h1; +handler h1 read first limit 9; +c1 +test_test.t1 +use test; +create table t1 (c1 char(20)); +create table t2 (c1 char(20)); +create table t3 (c1 char(20)); +insert into t1 values ('t1'); +insert into t2 values ('t2'); +insert into t3 values ('t3'); +handler t1 open; +Not unique table/alias: 't1' +handler t2 open t1; +Not unique table/alias: 't1' +handler t3 open t1; +Not unique table/alias: 't1' +handler t1 read first limit 9; +c1 +test_test.t1 +handler test.t1 close; +Unknown table 'test.t1' in HANDLER +handler test.t1 open h1; +Not unique table/alias: 'h1' +handler test_test.t1 open h1; +Not unique table/alias: 'h1' +handler test_test.t3 open h3; +handler test.t1 open h2; +handler t1 read first limit 9; +c1 +test_test.t1 +handler h1 read first limit 9; +c1 +test_test.t1 +handler h2 read first limit 9; +c1 +t1 +handler h3 read first limit 9; +c1 +test_test.t3 +handler test.h2 read first limit 9; +c1 +t1 +handler test.h1 close; +Unknown table 'test.h1' in HANDLER +handler test_test.t1 close; +handler test_test.h1 close; +handler h2 close; +handler t1 read first limit 9; +Unknown table 't1' in HANDLER +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +Unknown table 'h2' in HANDLER +handler h3 read first limit 9; +c1 +test_test.t3 +handler test_test.h3 read first limit 9; +c1 +test_test.t3 +use test_test; +handler h3 read first limit 9; +c1 +test_test.t3 +handler test.h3 read first limit 9; +Unknown table 'test.h3' in HANDLER +handler test_test.h3 close; +use test; +drop table t3; +drop table t2; +drop table t1; +drop database test_test; +create table t1 (c1 char(20)); +insert into t1 values ("t1"); +handler t1 open as h1; +handler h1 read first limit 9; +c1 +t1 +create table t2 (c1 char(20)); +insert into t2 values ("t2"); +handler t2 open as h2; +handler h2 read first limit 9; +c1 +t2 +create table t3 (c1 char(20)); +insert into t3 values ("t3"); +handler t3 open as h3; +handler h3 read first limit 9; +c1 +t3 +create table t4 (c1 char(20)); +insert into t4 values ("t4"); +handler t4 open as h4; +handler h4 read first limit 9; +c1 +t4 +create table t5 (c1 char(20)); +insert into t5 values ("t5"); +handler t5 open as h5; +handler h5 read first limit 9; +c1 +t5 +alter table t1 engine=MyISAM; +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +c1 +t2 +handler h3 read first limit 9; +c1 +t3 +handler h4 read first limit 9; +c1 +t4 +handler h5 read first limit 9; +c1 +t5 +alter table t5 engine=MyISAM; +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +c1 +t2 +handler h3 read first limit 9; +c1 +t3 +handler h4 read first limit 9; +c1 +t4 +handler h5 read first limit 9; +Unknown table 'h5' in HANDLER +alter table t3 engine=MyISAM; +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +c1 +t2 +handler h3 read first limit 9; +Unknown table 'h3' in HANDLER +handler h4 read first limit 9; +c1 +t4 +handler h5 read first limit 9; +Unknown table 'h5' in HANDLER +handler h2 close; +handler h4 close; +handler t1 open as h1_1; +handler t1 open as h1_2; +handler t1 open as h1_3; +handler h1_1 read first limit 9; +c1 +t1 +handler h1_2 read first limit 9; +c1 +t1 +handler h1_3 read first limit 9; +c1 +t1 +alter table t1 engine=MyISAM; +handler h1_1 read first limit 9; +Unknown table 'h1_1' in HANDLER +handler h1_2 read first limit 9; +Unknown table 'h1_2' in HANDLER +handler h1_3 read first limit 9; +Unknown table 'h1_3' in HANDLER +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; diff --git a/mysql-test/r/have_moscow_leap_timezone.require b/mysql-test/r/have_moscow_leap_timezone.require new file mode 100644 index 00000000000..f27452d7770 --- /dev/null +++ b/mysql-test/r/have_moscow_leap_timezone.require @@ -0,0 +1,2 @@ +from_unixtime(1072904422) +2004-01-01 00:00:00 diff --git a/mysql-test/r/innodb-lock.result b/mysql-test/r/innodb-lock.result index cf00adb30ae..4ace4065c34 100644 --- a/mysql-test/r/innodb-lock.result +++ b/mysql-test/r/innodb-lock.result @@ -1,4 +1,9 @@ +set global innodb_table_locks=1; +select @@innodb_table_locks; +@@innodb_table_locks +1 drop table if exists t1; +set @@innodb_table_locks=1; create table t1 (id integer, x integer) engine=INNODB; insert into t1 values(0, 0); set autocommit=0; @@ -20,3 +25,33 @@ id x 0 2 commit; drop table t1; +set @@innodb_table_locks=0; +create table t1 (id integer primary key, x integer) engine=INNODB; +insert into t1 values(0, 0),(1,1),(2,2); +commit; +SELECT * from t1 where id = 0 FOR UPDATE; +id x +0 0 +set autocommit=0; +set @@innodb_table_locks=0; +lock table t1 write; +update t1 set x=10 where id = 2; +SELECT * from t1 where id = 2; +id x +2 2 +UPDATE t1 set x=3 where id = 2; +commit; +SELECT * from t1; +id x +0 0 +1 1 +2 3 +commit; +unlock tables; +commit; +select * from t1; +id x +0 0 +1 1 +2 10 +drop table t1; diff --git a/mysql-test/r/key_primary.result b/mysql-test/r/key_primary.result index 87289f1cf54..3216ead667b 100644 --- a/mysql-test/r/key_primary.result +++ b/mysql-test/r/key_primary.result @@ -13,7 +13,7 @@ t1 AB% describe select * from t1 where t1="ABC"; table type possible_keys key key_len ref rows Extra -t1 const PRIMARY PRIMARY 3 const 1 +t1 const PRIMARY PRIMARY 3 const 1 Using index describe select * from t1 where t1="ABCD"; Comment Impossible WHERE noticed after reading const tables diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index b808fca0acf..b5672fe1791 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -17,6 +17,18 @@ unlock tables; n 1 drop table t1; +create table t1 (a int, b int); +create table t2 (c int, d int); +insert into t1 values(1,1); +insert into t1 values(2,2); +insert into t2 values(1,2); +lock table t1 read; + update t1,t2 set c=a where b=d; +select c from t2; +c +2 +drop table t1; +drop table t2; create table t1 (a int); create table t2 (a int); lock table t1 write, t2 write; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 7b2b9a47b0f..3585b8b0018 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -610,3 +610,12 @@ x y 1 3 1 2 drop table t1,t2,t3; +create table t1 (a int); +create table t2 (a int); +insert into t1 values (0); +insert into t2 values (1); +create table t3 engine=merge union=(t1, t2) select * from t1; +INSERT TABLE 't1' isn't allowed in FROM table list +create table t3 engine=merge union=(t1, t2) select * from t2; +INSERT TABLE 't2' isn't allowed in FROM table list +drop table t1, t2; diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 7b266544c92..93a647f673c 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -177,4 +177,25 @@ master-bin.001 79 Query 1 79 use `test`; BEGIN master-bin.001 119 Query 1 79 use `test`; insert into t1 values(16) master-bin.001 179 Query 1 79 use `test`; insert into t1 values(18) master-bin.001 239 Query 1 239 use `test`; COMMIT +delete from t1; +delete from t2; +alter table t2 type=MyISAM; +insert into t1 values (1); +begin; +select * from t1 for update; +a +1 +select (@before:=unix_timestamp())*0; +(@before:=unix_timestamp())*0 +0 +begin; + select * from t1 for update; +insert into t2 values (20); +Lock wait timeout exceeded; Try restarting transaction +select (@after:=unix_timestamp())*0; +(@after:=unix_timestamp())*0 +0 +select (@after-@before) >= 2; +(@after-@before) >= 2 +1 drop table t1,t2; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 12cb965f045..fc414f2f46b 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -151,7 +151,6 @@ Table 't2' was locked with a READ lock and can't be updated UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; Table 't2' was locked with a READ lock and can't be updated UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; -Table 't2' was locked with a READ lock and can't be updated unlock tables; LOCK TABLES t1 write, t2 write; UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index 009a3e06eb2..41b0ae26617 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -12,7 +12,7 @@ table type possible_keys key key_len ref rows Extra t1 ref a,b a 9 const,const 1 Using where; Using index explain select * from t1 where a=2 and b = 2; table type possible_keys key key_len ref rows Extra -t1 const a,b a 9 const,const 1 +t1 const a,b a 9 const,const 1 Using index explain select * from t1 where a<=>b limit 2; table type possible_keys key key_len ref rows Extra t1 index NULL a 9 NULL 12 Using where; Using index diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index a9e9f167e5f..85fe77b1f10 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -704,4 +704,17 @@ Qcache_queries_in_cache 1 unlock table; drop table t1,t2; set query_cache_wlock_invalidate=default; +CREATE TABLE t1 (id INT PRIMARY KEY); +insert into t1 values (1),(2),(3); +select * from t1; +id +1 +2 +3 +create temporary table t1 (a int not null auto_increment +primary key); +select * from t1; +a +drop table t1; +drop table t1; set GLOBAL query_cache_size=0; diff --git a/mysql-test/r/rpl_commit_after_flush.result b/mysql-test/r/rpl_commit_after_flush.result new file mode 100644 index 00000000000..8cdc7e986ab --- /dev/null +++ b/mysql-test/r/rpl_commit_after_flush.result @@ -0,0 +1,13 @@ +slave stop; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +slave start; +create table t1 (a int) type=innodb; +begin; +insert into t1 values(1); +flush tables with read lock; +commit; +unlock tables; +drop table t1; diff --git a/mysql-test/r/rpl_set_charset.result b/mysql-test/r/rpl_set_charset.result new file mode 100644 index 00000000000..9c7ea73c741 --- /dev/null +++ b/mysql-test/r/rpl_set_charset.result @@ -0,0 +1,51 @@ +slave stop; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +slave start; +drop database if exists mysqltest1; +create database mysqltest1 /*!40100 character set latin2 */; +use mysqltest1; +drop table if exists t1; +create table t1 (a varchar(255) character set latin2, b varchar(4)); +SET CHARACTER SET cp1250_latin2; +INSERT INTO t1 VALUES ('ŠŒŽ','80'); +INSERT INTO t1 VALUES ('šœžŸ','90'); +INSERT INTO t1 VALUES ('£¥ª¯','A0'); +INSERT INTO t1 VALUES ('³¹º¼¾¿','B0'); +INSERT INTO t1 VALUES ('ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ','C0'); +INSERT INTO t1 VALUES ('ÐÑÒÓÔÕÖרÙÚÛÜÝÞß','D0'); +INSERT INTO t1 VALUES ('àáâãäåæçèéêëìíîï','E0'); +INSERT INTO t1 VALUES ('ðñòóôõö÷øùúûüýþÿ','F0'); +select "--- on master ---"; +--- on master --- +--- on master --- +select hex(a),b from t1 order by b; +hex(a) b +A9A6ABAEAC 80 +B9B6BBBEBC 90 +A3A1AAAF A0 +B3B1BAA5B5BF B0 +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF C0 +D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF D0 +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF E0 +F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF F0 +show binlog events from 1979; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 1979 Query 1 1979 use `mysqltest1`; SET CHARACTER SET DEFAULT +use mysqltest1; +select "--- on slave ---"; +--- on slave --- +--- on slave --- +select hex(a),b from t1 order by b; +hex(a) b +A9A6ABAEAC 80 +B9B6BBBEBC 90 +A3A1AAAF A0 +B3B1BAA5B5BF B0 +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF C0 +D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF D0 +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF E0 +F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF F0 +drop database mysqltest1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 99041701cb8..3dd0603ed09 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2327,6 +2327,22 @@ select * from t2,t3 where t2.s = t3.s; s s two two drop table t1, t2, t3; +CREATE TABLE t1 ( +i int(11) NOT NULL default '0', +c char(10) NOT NULL default '', +PRIMARY KEY (i), +UNIQUE KEY c (c) +) TYPE=MyISAM; +INSERT INTO t1 VALUES (1,'a'); +INSERT INTO t1 VALUES (2,'b'); +INSERT INTO t1 VALUES (3,'c'); +EXPLAIN SELECT i FROM t1 WHERE i=1; +table type possible_keys key key_len ref rows Extra +t1 const PRIMARY PRIMARY 4 const 1 Using index +EXPLAIN SELECT i FROM t1 WHERE i=1; +table type possible_keys key key_len ref rows Extra +t1 const PRIMARY PRIMARY 4 const 1 Using index +DROP TABLE t1; create table t1 (a integer, b integer, index(a), index(b)); create table t2 (c integer, d integer, index(c), index(d)); insert into t1 values (1,2), (2,2), (3,2), (4,2); diff --git a/mysql-test/r/timezone3.result b/mysql-test/r/timezone3.result new file mode 100644 index 00000000000..2135dd33511 --- /dev/null +++ b/mysql-test/r/timezone3.result @@ -0,0 +1,41 @@ +drop table if exists t1; +create table t1 (i int, c varchar(20)); +insert into t1 values +(unix_timestamp("2004-01-01 00:00:00"), "2004-01-01 00:00:00"); +insert into t1 values +(unix_timestamp("2004-03-28 01:59:59"), "2004-03-28 01:59:59"), +(unix_timestamp("2004-03-28 02:30:00"), "2004-03-28 02:30:00"), +(unix_timestamp("2004-03-28 03:00:00"), "2004-03-28 03:00:00"); +insert into t1 values +(unix_timestamp('2004-05-01 00:00:00'),'2004-05-01 00:00:00'); +insert into t1 values +(unix_timestamp('2004-10-31 01:00:00'),'2004-10-31 01:00:00'), +(unix_timestamp('2004-10-31 02:00:00'),'2004-10-31 02:00:00'), +(unix_timestamp('2004-10-31 02:59:59'),'2004-10-31 02:59:59'), +(unix_timestamp('2004-10-31 04:00:00'),'2004-10-31 04:00:00'), +(unix_timestamp('2004-10-31 02:59:59'),'2004-10-31 02:59:59'); +insert into t1 values +(unix_timestamp('1981-07-01 03:59:59'),'1981-07-01 03:59:59'), +(unix_timestamp('1981-07-01 04:00:00'),'1981-07-01 04:00:00'); +select i, from_unixtime(i), c from t1; +i from_unixtime(i) c +1072904422 2004-01-01 00:00:00 2004-01-01 00:00:00 +1080428421 2004-03-28 01:59:59 2004-03-28 01:59:59 +1080428422 2004-03-28 03:00:00 2004-03-28 02:30:00 +1080428422 2004-03-28 03:00:00 2004-03-28 03:00:00 +1083355222 2004-05-01 00:00:00 2004-05-01 00:00:00 +1099170022 2004-10-31 01:00:00 2004-10-31 01:00:00 +1099177222 2004-10-31 02:00:00 2004-10-31 02:00:00 +1099180821 2004-10-31 02:59:59 2004-10-31 02:59:59 +1099184422 2004-10-31 04:00:00 2004-10-31 04:00:00 +1099180821 2004-10-31 02:59:59 2004-10-31 02:59:59 +362793608 1981-07-01 03:59:59 1981-07-01 03:59:59 +362793610 1981-07-01 04:00:00 1981-07-01 04:00:00 +drop table t1; +create table t1 (ts timestamp); +insert into t1 values (19730101235900), (20040101235900); +select * from t1; +ts +19730101235900 +20040101235900 +drop table t1; diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 752a5045eb0..6253fa96ba8 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -122,40 +122,41 @@ t2 t4 t6 t8 t10 t12 t14 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 drop table t1; +set new=0; create table t1 (t1 timestamp default '2003-01-01 00:00:00', t2 timestamp default '2003-01-01 00:00:00'); set TIMESTAMP=1000000000; insert into t1 values(); select * from t1; t1 t2 -2001-09-09 04:46:40 2003-01-01 00:00:00 +20010909044640 20030101000000 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `t1` timestamp(14) NOT NULL, - `t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00' + `t2` timestamp(14) NOT NULL default '20030101000000' ) TYPE=MyISAM show columns from t1; Field Type Null Key Default Extra t1 timestamp(14) YES NULL -t2 timestamp(14) YES 2003-01-01 00:00:00 +t2 timestamp(14) YES 20030101000000 show columns from t1 like 't2'; Field Type Null Key Default Extra -t2 timestamp(14) YES 2003-01-01 00:00:00 +t2 timestamp(14) YES 20030101000000 create table t2 (select * from t1); show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `t1` timestamp(14) NOT NULL, - `t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00' + `t2` timestamp(14) NOT NULL default '20030101000000' ) TYPE=MyISAM alter table t1 add column t0 timestamp first; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `t0` timestamp(14) NOT NULL, - `t1` timestamp(14) NOT NULL default '2003-01-01 00:00:00', - `t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00' + `t1` timestamp(14) NOT NULL default '20030101000000', + `t2` timestamp(14) NOT NULL default '20030101000000' ) TYPE=MyISAM drop table t1,t2; create table t1 (ts1 timestamp, ts2 timestamp); @@ -164,8 +165,8 @@ insert into t1 values (); insert into t1 values (DEFAULT, DEFAULT); select * from t1; ts1 ts2 -2001-09-09 04:46:40 0000-00-00 00:00:00 -2001-09-09 04:46:40 0000-00-00 00:00:00 +20010909044640 00000000000000 +20010909044640 00000000000000 drop table t1; create table t1 (ts timestamp(19)); show create table t1; @@ -179,3 +180,44 @@ select * from t1; ts 2001-09-09 04:46:40 drop table t1; +set new=1; +create table t1 (a char(2), t timestamp); +insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'), +('b', '2004-02-01 00:00:00'); +select max(t) from t1 group by a; +max(t) +2004-01-01 01:00:00 +2004-02-01 00:00:00 +drop table t1; +create table t1 (ts1 timestamp); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts1` timestamp(19) NOT NULL +) TYPE=MyISAM +alter table t1 add ts2 timestamp; +set new=0; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts1` timestamp(19) NOT NULL, + `ts2` timestamp(19) NOT NULL default '0000-00-00 00:00:00' +) TYPE=MyISAM +drop table t1; +create table t1 (ts1 timestamp); +insert into t1 values ('2004-01-01 00:00:00'), ('2004-01-01 01:00:00'); +select * from t1; +ts1 +20040101000000 +20040101010000 +set new=1; +select * from t1; +ts1 +2004-01-01 00:00:00 +2004-01-01 01:00:00 +set new=0; +select * from t1; +ts1 +20040101000000 +20040101010000 +drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 4b9555c334b..0db18b090bc 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -88,7 +88,6 @@ explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a l table type possible_keys key key_len ref rows Extra t1 ALL NULL NULL NULL NULL 4 t2 ALL NULL NULL NULL NULL 4 Using filesort -t1 ALL NULL NULL NULL NULL 4 (select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; a b 1 a @@ -420,6 +419,7 @@ a (SELECT * FROM t1) UNION all (SELECT SQL_CALC_FOUND_ROWS * FROM t2) LIMIT 1; Wrong usage/placement of 'SQL_CALC_FOUND_ROWS' create temporary table t1 select a from t1 union select a from t2; +drop table t1; create table t1 select a from t1 union select a from t2; INSERT TABLE 't1' isn't allowed in FROM table list select a from t1 union select a from t2 order by t2.a; @@ -429,3 +429,10 @@ select length(version()) > 1 as `*` UNION select 2; * 1 2 +create table t1 (a int); +insert into t1 values (0), (3), (1), (2); +explain (select * from t1) union (select * from t1) order by a; +table type possible_keys key key_len ref rows Extra +t1 ALL NULL NULL NULL NULL 4 +t1 ALL NULL NULL NULL NULL 4 +drop table t1; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 11aff8fe50a..c9405d71237 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -166,3 +166,40 @@ F1 F2 F3 cnt groupid 2 0 1 2 4 2 2 0 1 7 drop table t1; +CREATE TABLE t1 ( +`colA` int(10) unsigned NOT NULL auto_increment, +`colB` int(11) NOT NULL default '0', +PRIMARY KEY (`colA`) +); +INSERT INTO t1 VALUES (4433,5424); +CREATE TABLE t2 ( +`colC` int(10) unsigned NOT NULL default '0', +`colA` int(10) unsigned NOT NULL default '0', +`colD` int(10) unsigned NOT NULL default '0', +`colE` int(10) unsigned NOT NULL default '0', +`colF` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`colC`,`colA`,`colD`,`colE`) +); +INSERT INTO t2 VALUES (3,4433,10005,495,500); +INSERT INTO t2 VALUES (3,4433,10005,496,500); +INSERT INTO t2 VALUES (3,4433,10009,494,500); +INSERT INTO t2 VALUES (3,4433,10011,494,500); +INSERT INTO t2 VALUES (3,4433,10005,497,500); +INSERT INTO t2 VALUES (3,4433,10013,489,500); +INSERT INTO t2 VALUES (3,4433,10005,494,500); +INSERT INTO t2 VALUES (3,4433,10005,493,500); +INSERT INTO t2 VALUES (3,4433,10005,492,500); +UPDATE IGNORE t2,t1 set t2.colE = t2.colE + 1,colF=0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +SELECT * FROM t2; +colC colA colD colE colF +3 4433 10005 495 500 +3 4433 10005 496 500 +3 4433 10009 495 0 +3 4433 10011 495 0 +3 4433 10005 498 0 +3 4433 10013 490 0 +3 4433 10005 494 500 +3 4433 10005 493 500 +3 4433 10005 492 500 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/std_data/Moscow_leap b/mysql-test/std_data/Moscow_leap Binary files differnew file mode 100644 index 00000000000..4994c005595 --- /dev/null +++ b/mysql-test/std_data/Moscow_leap diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test index 3a0f2658969..d6c12683d94 100644 --- a/mysql-test/t/ctype_latin1_de.test +++ b/mysql-test/t/ctype_latin1_de.test @@ -72,3 +72,17 @@ select * from t1 where word like 'AE'; select * from t1 where word like 0xDF; select * from t1 where word like CAST(0xDF as CHAR); drop table t1; + +# +# Bug #5447 Select does not find records +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( + autor varchar(80) NOT NULL default '', + PRIMARY KEY (autor) +); +INSERT INTO t1 VALUES ('Powell, B.'),('Powell, Bud.'),('Powell, L. H.'),('Power, H.'), +('Poynter, M. A. L. Lane'),('Poynting, J. H. und J. J. Thomson.'),('Pozzi, S(amuel-Jean).'), +('Pozzi, Samuel-Jean.'),('Pozzo, A.'),('Pozzoli, Serge.'); +SELECT * FROM t1 WHERE autor LIKE 'Poz%' ORDER BY autor; +DROP TABLE t1; diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 904d959d148..07cb9155b3f 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -61,3 +61,13 @@ select count(*) from t1; drop table t1; +# +# Bug #5733: Table handler error with self-join multi-table DELETE +# + +create table t1 (a int not null auto_increment primary key, b char(32)); +insert into t1 (b) values ('apple'), ('apple'); +select * from t1; +delete t1 from t1, t1 as t2 where t1.b = t2.b and t1.a > t2.a; +select * from t1; +drop table t1; diff --git a/mysql-test/t/flush_table.test b/mysql-test/t/flush_table.test index ad81f266afc..58c12bad3fa 100644 --- a/mysql-test/t/flush_table.test +++ b/mysql-test/t/flush_table.test @@ -13,62 +13,9 @@ check table t1; drop table t1; # -# Check if two database names beginning the same are seen as different. -# -# This database begins like the usual 'test' database. -# ---disable_warnings -drop database if exists test_test; ---enable_warnings -create database test_test; -use test_test; -create table t1(table_id char(20) primary key); -insert into t1 values ('test_test.t1'); -insert into t1 values (''); -handler t1 open; -handler t1 read first limit 9; -create table t2(table_id char(20) primary key); -insert into t2 values ('test_test.t2'); -insert into t2 values (''); -handler t2 open; -handler t2 read first limit 9; -# -# This is the usual 'test' database. -# -use test; ---disable_warnings -drop table if exists t1; ---enable_warnings -create table t1(table_id char(20) primary key); -insert into t1 values ('test.t1'); -insert into t1 values (''); -handler t1 open; -handler t1 read first limit 9; -# -# Check accesibility of all the tables. -# -use test; -handler test.t1 read first limit 9; ---error 1109; -handler test.t2 read first limit 9; -handler test_test.t1 read first limit 9; -handler test_test.t2 read first limit 9; -# -# Cleanup. -# -handler test_test.t1 close; -drop table test_test.t1; -handler test_test.t2 close; -drop table test_test.t2; -drop database test_test; -# -use test; -handler test.t1 close; -drop table test.t1; - -# # In the following test FLUSH TABLES produces a deadlock -# (hang forever) if the fix for bug#3565 is missing. +# (hang forever) if the fix for BUG #3565 is missing. +# And it shows that handler tables are re-opened after flush (BUG #4286). # --disable_warnings drop table if exists t1; @@ -87,28 +34,43 @@ handler a1 read first limit 9; handler a2 read first limit 9; handler t2 read first limit 9; flush tables; ---error 1109; handler a1 read first limit 9; ---error 1109; handler a2 read first limit 9; ---error 1109; handler t2 read first limit 9; # +--error 1066 handler t1 open as a1; +--error 1066 handler t1 open as a2; +--error 1066 handler t2 open; handler a1 read first limit 9; handler a2 read first limit 9; handler t2 read first limit 9; flush table t1; ---error 1109; handler a1 read first limit 9; ---error 1109; handler a2 read first limit 9; handler t2 read first limit 9; flush table t2; ---error 1109; handler t2 close; drop table t1; drop table t2; +# +# The fix for BUG #4286 cannot restore the position after a flush. +# +create table t1(table_id char(20) primary key); +insert into t1 values ('Record-01'); +insert into t1 values ('Record-02'); +insert into t1 values ('Record-03'); +insert into t1 values ('Record-04'); +insert into t1 values ('Record-05'); +handler t1 open; +handler t1 read first limit 1; +handler t1 read next limit 1; +handler t1 read next limit 1; +flush table t1; +handler t1 read next limit 1; +handler t1 read next limit 1; +handler t1 close; +drop table t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index bd887bc63ee..b44854860f9 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -87,6 +87,8 @@ select * from t1 where match a against ("+aaa* +bbb*" in boolean mode); select * from t1 where match a against ("+aaa* +bbb1*" in boolean mode); select * from t1 where match a against ("+aaa* +ccc*" in boolean mode); select * from t1 where match a against ("+aaa10 +(bbb*)" in boolean mode); +select * from t1 where match a against ("+(+aaa* +bbb1*)" in boolean mode); +select * from t1 where match a against ("(+aaa* +bbb1*)" in boolean mode); drop table t1; # @@ -240,3 +242,13 @@ select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode); drop table t1,t2; +# +# icc -ip bug (ip = interprocedural optimization) +# bug#5528 +# +CREATE TABLE t1 (h text, FULLTEXT (h)); +INSERT INTO t1 VALUES ('Jesses Hasse Ling and his syncopators of Swing'); +REPAIR TABLE t1; +select count(*) from t1; +drop table t1; + diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test index 5e605dbe97b..f78cb5ade55 100644 --- a/mysql-test/t/func_if.test +++ b/mysql-test/t/func_if.test @@ -47,3 +47,7 @@ insert t1 values (1),(2); select if(1>2,a,avg(a)) from t1; drop table t1; +# +# Bug #5595 NULLIF() IS NULL returns false if NULLIF() returns NULL +# +SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL; diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 9b0c076f23e..1ae4db3a42a 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -70,6 +70,12 @@ select length(quote(concat(char(0),"test"))); select hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))); # +# Bug #6564: QUOTE(NULL +# + +select concat('a', quote(NULL)); + +# # Wrong usage of functions # @@ -172,3 +178,10 @@ create table t1(a char(4)); insert into t1 values ('one'),(NULL),('two'),('four'); select a, quote(a), isnull(quote(a)), quote(a) is null, ifnull(quote(a), 'n') from t1; drop table t1; + +# +# Bug #5498: TRIM fails with LEADING or TRAILING if remstr = str +# + +select trim(trailing 'foo' from 'foo'); +select trim(leading 'foo' from 'foo'); diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index fffda12c14e..da18269cf6a 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -225,3 +225,10 @@ drop table t1,t2,t3; select @a:=FROM_UNIXTIME(1); select unix_timestamp(@a); select unix_timestamp('1969-12-01 19:00:01'); + +# +# Test for bug #6439 "unix_timestamp() function returns wrong datetime +# values for too big argument". It should return error instead. +# +select from_unixtime(0); +select from_unixtime(2145916800); diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index a278b9d5928..21173a356ce 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -105,3 +105,12 @@ flush privileges; show grants for test11@localhost; delete from mysql.user where user='test11'; delete from mysql.db where user='test11'; + +# +# Bug#6123: GRANT USAGE inserts useless Db row +# +create database db6123; +grant usage on db6123.* to test6123 identified by 'magic123'; +select host,db,user,select_priv,insert_priv from mysql.db where db="db6123"; +delete from mysql.user where user='test6123'; +drop database db6123; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 1f7f32c930a..53fe8c0a059 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -135,3 +135,207 @@ handler t1 read a=(1) where b=1; handler t1 close; drop table t1; +# +# Check if two database names beginning the same are seen as different. +# +# This database begins like the usual 'test' database. +# +--disable_warnings +drop database if exists test_test; +--enable_warnings +create database test_test; +use test_test; +create table t1(table_id char(20) primary key); +insert into t1 values ('test_test.t1'); +insert into t1 values (''); +handler t1 open; +handler t1 read first limit 9; +create table t2(table_id char(20) primary key); +insert into t2 values ('test_test.t2'); +insert into t2 values (''); +handler t2 open; +handler t2 read first limit 9; +# +# This is the usual 'test' database. +# +use test; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1(table_id char(20) primary key); +insert into t1 values ('test.t1'); +insert into t1 values (''); +--error 1066 +handler t1 open; +# +# Check accesibility of all the tables. +# +use test; +--error 1109; +handler test.t1 read first limit 9; +handler test_test.t1 read first limit 9; +handler t1 read first limit 9; +handler test_test.t2 read first limit 9; +handler t2 read first limit 9; +# +# Cleanup. +# + +handler test_test.t1 close; +--error 1109; +handler t1 close; +drop table test_test.t1; +handler test_test.t2 close; +--error 1109; +handler t2 close; +drop table test_test.t2; +drop database test_test; +# +use test; +--error 1109; +handler test.t1 close; +--error 1109; +handler t1 close; +drop table test.t1; + +# +# BUG#4335 +# +--disable_warnings +drop database if exists test_test; +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +--enable_warnings +create database test_test; +use test_test; +create table t1 (c1 char(20)); +insert into t1 values ('test_test.t1'); +create table t3 (c1 char(20)); +insert into t3 values ('test_test.t3'); +handler t1 open; +handler t1 read first limit 9; +handler t1 open h1; +handler h1 read first limit 9; +use test; +create table t1 (c1 char(20)); +create table t2 (c1 char(20)); +create table t3 (c1 char(20)); +insert into t1 values ('t1'); +insert into t2 values ('t2'); +insert into t3 values ('t3'); +--error 1066 +handler t1 open; +--error 1066 +handler t2 open t1; +--error 1066 +handler t3 open t1; +handler t1 read first limit 9; +--error 1109 +handler test.t1 close; +--error 1066 +handler test.t1 open h1; +--error 1066 +handler test_test.t1 open h1; +handler test_test.t3 open h3; +handler test.t1 open h2; +handler t1 read first limit 9; +handler h1 read first limit 9; +handler h2 read first limit 9; +handler h3 read first limit 9; +handler test.h2 read first limit 9; +--error 1109 +handler test.h1 close; +handler test_test.t1 close; +handler test_test.h1 close; +handler h2 close; +--error 1109 +handler t1 read first limit 9; +--error 1109 +handler h1 read first limit 9; +--error 1109 +handler h2 read first limit 9; +handler h3 read first limit 9; +handler test_test.h3 read first limit 9; +use test_test; +handler h3 read first limit 9; +--error 1109 +handler test.h3 read first limit 9; +handler test_test.h3 close; +use test; +drop table t3; +drop table t2; +drop table t1; +drop database test_test; + +# +# Test if fix for BUG#4286 correctly closes handler tables. +# +create table t1 (c1 char(20)); +insert into t1 values ("t1"); +handler t1 open as h1; +handler h1 read first limit 9; +create table t2 (c1 char(20)); +insert into t2 values ("t2"); +handler t2 open as h2; +handler h2 read first limit 9; +create table t3 (c1 char(20)); +insert into t3 values ("t3"); +handler t3 open as h3; +handler h3 read first limit 9; +create table t4 (c1 char(20)); +insert into t4 values ("t4"); +handler t4 open as h4; +handler h4 read first limit 9; +create table t5 (c1 char(20)); +insert into t5 values ("t5"); +handler t5 open as h5; +handler h5 read first limit 9; +# close first +alter table t1 engine=MyISAM; +--error 1109; +handler h1 read first limit 9; +handler h2 read first limit 9; +handler h3 read first limit 9; +handler h4 read first limit 9; +handler h5 read first limit 9; +# close last +alter table t5 engine=MyISAM; +--error 1109; +handler h1 read first limit 9; +handler h2 read first limit 9; +handler h3 read first limit 9; +handler h4 read first limit 9; +--error 1109; +handler h5 read first limit 9; +# close middle +alter table t3 engine=MyISAM; +--error 1109; +handler h1 read first limit 9; +handler h2 read first limit 9; +--error 1109; +handler h3 read first limit 9; +handler h4 read first limit 9; +--error 1109; +handler h5 read first limit 9; +handler h2 close; +handler h4 close; +# close all depending handler tables +handler t1 open as h1_1; +handler t1 open as h1_2; +handler t1 open as h1_3; +handler h1_1 read first limit 9; +handler h1_2 read first limit 9; +handler h1_3 read first limit 9; +alter table t1 engine=MyISAM; +--error 1109; +handler h1_1 read first limit 9; +--error 1109; +handler h1_2 read first limit 9; +--error 1109; +handler h1_3 read first limit 9; +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 43a175508b4..a3b6f8993f2 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -1,13 +1,30 @@ -- source include/have_innodb.inc +# +# Check and select innodb lock type +# + +set global innodb_table_locks=1; + +select @@innodb_table_locks; + +# +# Testing of explicit table locks with enforced table locks +# + connect (con1,localhost,root,,); connect (con2,localhost,root,,); + +--disable_warnings drop table if exists t1; +--enable_warnings # -# Testing of explicit table locks +# Testing of explicit table locks with enforced table locks # +set @@innodb_table_locks=1; + connection con1; create table t1 (id integer, x integer) engine=INNODB; insert into t1 values(0, 0); @@ -38,3 +55,46 @@ select * from t1; commit; drop table t1; + +# +# Try with old lock method (where LOCK TABLE is ignored by InnoDB) +# + +set @@innodb_table_locks=0; + +create table t1 (id integer primary key, x integer) engine=INNODB; +insert into t1 values(0, 0),(1,1),(2,2); +commit; +SELECT * from t1 where id = 0 FOR UPDATE; + +connection con2; +set autocommit=0; +set @@innodb_table_locks=0; + +# The following statement should work becase innodb doesn't check table locks +lock table t1 write; + +connection con1; + +# This will be locked by MySQL +--send +update t1 set x=10 where id = 2; +--sleep 2 + +connection con2; + +# Note that we will get a deadlock if we try to select any rows marked +# for update by con1 ! + +SELECT * from t1 where id = 2; +UPDATE t1 set x=3 where id = 2; +commit; +SELECT * from t1; +commit; +unlock tables; + +connection con1; +reap; +commit; +select * from t1; +drop table t1; diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index 0295fca29e7..e20f8163751 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -51,6 +51,30 @@ reap; drop table t1; # +# Test problem when using locks with multi-updates +# It should not block when multi-update is reading on a read-locked table +# + +connection locker; +create table t1 (a int, b int); +create table t2 (c int, d int); +insert into t1 values(1,1); +insert into t1 values(2,2); +insert into t2 values(1,2); +lock table t1 read; +connection writer; +--sleep 2 +send update t1,t2 set c=a where b=d; +connection reader; +--sleep 2 +select c from t2; +connection writer; +reap; +connection locker; +drop table t1; +drop table t2; + +# # Test problem when using locks on many tables and droping a table that # is to-be-locked by another thread # diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 76382a9cd99..57770dc0a0b 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -250,3 +250,17 @@ select * from t3 where x = 1 and y < 5 order by y; # Bug is that followng query returns empty set while it must be same as above select * from t3 where x = 1 and y < 5 order by y desc; drop table t1,t2,t3; + +# +# Bug#5232: CREATE TABLE ... SELECT +# + +create table t1 (a int); +create table t2 (a int); +insert into t1 values (0); +insert into t2 values (1); +--error 1093 +create table t3 engine=merge union=(t1, t2) select * from t1; +--error 1093 +create table t3 engine=merge union=(t1, t2) select * from t2; +drop table t1, t2; diff --git a/mysql-test/t/mix_innodb_myisam_binlog-master.opt b/mysql-test/t/mix_innodb_myisam_binlog-master.opt new file mode 100644 index 00000000000..cb48f1aaf60 --- /dev/null +++ b/mysql-test/t/mix_innodb_myisam_binlog-master.opt @@ -0,0 +1 @@ +--loose-innodb_lock_wait_timeout=2 diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index be45c2c3133..5f3b778c61a 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -175,4 +175,36 @@ select a from t1 order by a; # check that savepoints work :) show binlog events from 79; +# Test for BUG#5714, where a MyISAM update in the transaction used to +# release row-level locks in InnoDB + +connect (con3,localhost,root,,); + +connection con3; +delete from t1; +delete from t2; +--disable_warnings +alter table t2 type=MyISAM; +--enable_warnings +insert into t1 values (1); +begin; +select * from t1 for update; + +connection con2; +select (@before:=unix_timestamp())*0; # always give repeatable output +begin; +send select * from t1 for update; + +connection con3; +insert into t2 values (20); + +connection con2; +--error 1205 +reap; +select (@after:=unix_timestamp())*0; # always give repeatable output +# verify that innodb_lock_wait_timeout was exceeded. When there was +# the bug, the reap would return immediately after the insert into t2. +select (@after-@before) >= 2; + +# cleanup drop table t1,t2; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 39ea136bde1..3494126f890 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -151,8 +151,6 @@ LOCK TABLES t1 write, t2 read; DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n; --error 1099 UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; -# The following should be fixed to not give an error ---error 1099 UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; unlock tables; LOCK TABLES t1 write, t2 write; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 8a07c0a53a0..61fbadde1e1 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -521,4 +521,16 @@ unlock table; drop table t1,t2; set query_cache_wlock_invalidate=default; +# +# hiding real table stored in query cache by temporary table +# +CREATE TABLE t1 (id INT PRIMARY KEY); +insert into t1 values (1),(2),(3); +select * from t1; +create temporary table t1 (a int not null auto_increment +primary key); +select * from t1; +drop table t1; +drop table t1; + set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index ebce3d0ac94..4f978af0bec 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -96,7 +96,7 @@ wait_for_slave_to_stop; # The following test can't be done because the result of Pos will differ # on different computers -# --replace_result 9306 9999 3334 9999 3335 9999 +# --replace_result $MASTER_MYPORT MASTER_PORT # show slave status; set global sql_slave_skip_counter=1; diff --git a/mysql-test/t/rpl_commit_after_flush.test b/mysql-test/t/rpl_commit_after_flush.test new file mode 100644 index 00000000000..edbbd1bfad6 --- /dev/null +++ b/mysql-test/t/rpl_commit_after_flush.test @@ -0,0 +1,17 @@ +source include/master-slave.inc; +source include/have_innodb.inc; +create table t1 (a int) type=innodb; +begin; +insert into t1 values(1); +flush tables with read lock; +commit; +save_master_pos; +connection slave; +sync_with_master; +# cleanup +connection master; +unlock tables; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl_set_charset.test b/mysql-test/t/rpl_set_charset.test new file mode 100644 index 00000000000..bd68ce17bbc --- /dev/null +++ b/mysql-test/t/rpl_set_charset.test @@ -0,0 +1,40 @@ +source include/master-slave.inc; +--disable_warnings +drop database if exists mysqltest1; +# 4.1 bases its conversion on the db's charset, +# while 4.0 uses the part of "SET CHARACTER SET" after "_". +# So for 4.1 we add a clause to CREATE DATABASE. +create database mysqltest1 /*!40100 character set latin2 */; +use mysqltest1; +drop table if exists t1; +--enable_warnings +create table t1 (a varchar(255) character set latin2, b varchar(4)); +SET CHARACTER SET cp1250_latin2; +INSERT INTO t1 VALUES ('ŠŒŽ','80'); +INSERT INTO t1 VALUES ('šœžŸ','90'); +INSERT INTO t1 VALUES ('£¥ª¯','A0'); +INSERT INTO t1 VALUES ('³¹º¼¾¿','B0'); +INSERT INTO t1 VALUES ('ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ','C0'); +INSERT INTO t1 VALUES ('ÐÑÒÓÔÕÖרÙÚÛÜÝÞß','D0'); +INSERT INTO t1 VALUES ('àáâãäåæçèéêëìíîï','E0'); +INSERT INTO t1 VALUES ('ðñòóôõö÷øùúûüýþÿ','F0'); +select "--- on master ---"; +select hex(a),b from t1 order by b; +# It's complicated to verify that the charset is reset to default in +# the binlog after each query, except by checking the binlog. When you +# merge this into 4.1/5.0, the 1979 will have to be changed; all you have +# to do is read the var/log/master-bin.0*01 with mysqlbinlog, verify +# that a SET CHARACTER SET DEFAULT is just after the last INSERT, and +# replace 1979 by its position (the "# at" line above the SET). +show binlog events from 1979; +save_master_pos; +connection slave; +sync_with_master; +use mysqltest1; +select "--- on slave ---"; +select hex(a),b from t1 order by b; +connection master; +drop database mysqltest1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 11b3ae6aed1..f897703789b 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1887,4 +1887,25 @@ explain select * from t1 left join t2 on a=c where d in (4); select * from t1 left join t2 on a=c where d in (4); explain select * from t1 left join t2 on a=c where d = 4; select * from t1 left join t2 on a=c where d = 4; -drop table t1, t2;
\ No newline at end of file +drop table t1, t2;R + +# +# Covering index is mentioned in EXPLAIN output for const tables (bug #5333) +# + +CREATE TABLE t1 ( + i int(11) NOT NULL default '0', + c char(10) NOT NULL default '', + PRIMARY KEY (i), + UNIQUE KEY c (c) +) TYPE=MyISAM; + +INSERT INTO t1 VALUES (1,'a'); +INSERT INTO t1 VALUES (2,'b'); +INSERT INTO t1 VALUES (3,'c'); + +EXPLAIN SELECT i FROM t1 WHERE i=1; + +EXPLAIN SELECT i FROM t1 WHERE i=1; + +DROP TABLE t1; diff --git a/mysql-test/t/timezone3-master.opt b/mysql-test/t/timezone3-master.opt new file mode 100644 index 00000000000..6910e6e6e8d --- /dev/null +++ b/mysql-test/t/timezone3-master.opt @@ -0,0 +1 @@ +--timezone=:$MYSQL_TEST_DIR/std_data/Moscow_leap diff --git a/mysql-test/t/timezone3.test b/mysql-test/t/timezone3.test new file mode 100644 index 00000000000..8910783cd85 --- /dev/null +++ b/mysql-test/t/timezone3.test @@ -0,0 +1,59 @@ +# +# Test of handling time zone with leap seconds. +# +# This test should be run with TZ=:$MYSQL_TEST_DIR/std_data/Moscow_leap +# This implies that this test should be run only on systems that interpret +# characters after colon in TZ variable as path to zoneinfo file. +# +# Check that we have successfully set time zone with leap seconds. +--require r/have_moscow_leap_timezone.require +disable_query_log; +select from_unixtime(1072904422); +enable_query_log; + +# Initial clean-up +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Let us check behavior of conversion from broken-down representation +# to time_t representation, for normal, non-existent and ambigious dates +# (This check is similar to the one in timezone2.test in 4.1) +# +create table t1 (i int, c varchar(20)); +# Normal value without DST +insert into t1 values + (unix_timestamp("2004-01-01 00:00:00"), "2004-01-01 00:00:00"); +# Values around and in spring time-gap +insert into t1 values + (unix_timestamp("2004-03-28 01:59:59"), "2004-03-28 01:59:59"), + (unix_timestamp("2004-03-28 02:30:00"), "2004-03-28 02:30:00"), + (unix_timestamp("2004-03-28 03:00:00"), "2004-03-28 03:00:00"); +# Normal value with DST +insert into t1 values + (unix_timestamp('2004-05-01 00:00:00'),'2004-05-01 00:00:00'); +# Ambiguos values (also check for determenism) +insert into t1 values + (unix_timestamp('2004-10-31 01:00:00'),'2004-10-31 01:00:00'), + (unix_timestamp('2004-10-31 02:00:00'),'2004-10-31 02:00:00'), + (unix_timestamp('2004-10-31 02:59:59'),'2004-10-31 02:59:59'), + (unix_timestamp('2004-10-31 04:00:00'),'2004-10-31 04:00:00'), + (unix_timestamp('2004-10-31 02:59:59'),'2004-10-31 02:59:59'); +# Test of leap +insert into t1 values + (unix_timestamp('1981-07-01 03:59:59'),'1981-07-01 03:59:59'), + (unix_timestamp('1981-07-01 04:00:00'),'1981-07-01 04:00:00'); + +select i, from_unixtime(i), c from t1; +drop table t1; + +# +# Test for bug #6387 "Queried timestamp values do not match the +# inserted". my_gmt_sec() function was not working properly if we +# had time zone with leap seconds +# +create table t1 (ts timestamp); +insert into t1 values (19730101235900), (20040101235900); +select * from t1; +drop table t1; diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 92bd20e846e..464ee63c137 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -71,6 +71,7 @@ select * from t1; set new=1; select * from t1; drop table t1; +set new=0; # # Bug #1885, bug #2539. @@ -116,3 +117,34 @@ set TIMESTAMP=1000000000; insert into t1 values (); select * from t1; drop table t1; + +# +# Test for bug #4131, TIMESTAMP columns missing minutes and seconds when +# using GROUP BY in @@new=1 mode. +# +set new=1; +create table t1 (a char(2), t timestamp); +insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'), + ('b', '2004-02-01 00:00:00'); +select max(t) from t1 group by a; +drop table t1; + +# +# More --new mode tests +# Both columns created before and during alter should have same length. +# +create table t1 (ts1 timestamp); +show create table t1; +alter table t1 add ts2 timestamp; +set new=0; +show create table t1; +drop table t1; +# Selecting from table in --new mode should not affect further selects. +create table t1 (ts1 timestamp); +insert into t1 values ('2004-01-01 00:00:00'), ('2004-01-01 01:00:00'); +select * from t1; +set new=1; +select * from t1; +set new=0; +select * from t1; +drop table t1; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index c978aef9ce0..eb2d8dd6efa 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -224,6 +224,7 @@ SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a desc LIMIT 1; (SELECT * FROM t1) UNION all (SELECT SQL_CALC_FOUND_ROWS * FROM t2) LIMIT 1; create temporary table t1 select a from t1 union select a from t2; +drop table t1; --error 1093 create table t1 select a from t1 union select a from t2; --error 1054 @@ -236,3 +237,11 @@ drop table t1,t2; select length(version()) > 1 as `*` UNION select 2; +# +# Bug #4980: problem with explain +# + +create table t1 (a int); +insert into t1 values (0), (3), (1), (2); +explain (select * from t1) union (select * from t1) order by a; +drop table t1; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 2e739dd927d..1850564418c 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -122,3 +122,36 @@ insert into t1 (F1,F2,F3,cnt,groupid) values ('0','0','0',1,6), delete from t1 using t1 m1,t1 m2 where m1.groupid=m2.groupid and (m1.cnt < m2.cnt or m1.cnt=m2.cnt and m1.F3>m2.F3); select * from t1; drop table t1; + +# +# Bug#5553 - Multi table UPDATE IGNORE fails on duplicate keys +# + +CREATE TABLE t1 ( + `colA` int(10) unsigned NOT NULL auto_increment, + `colB` int(11) NOT NULL default '0', + PRIMARY KEY (`colA`) +); +INSERT INTO t1 VALUES (4433,5424); +CREATE TABLE t2 ( + `colC` int(10) unsigned NOT NULL default '0', + `colA` int(10) unsigned NOT NULL default '0', + `colD` int(10) unsigned NOT NULL default '0', + `colE` int(10) unsigned NOT NULL default '0', + `colF` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`colC`,`colA`,`colD`,`colE`) +); +INSERT INTO t2 VALUES (3,4433,10005,495,500); +INSERT INTO t2 VALUES (3,4433,10005,496,500); +INSERT INTO t2 VALUES (3,4433,10009,494,500); +INSERT INTO t2 VALUES (3,4433,10011,494,500); +INSERT INTO t2 VALUES (3,4433,10005,497,500); +INSERT INTO t2 VALUES (3,4433,10013,489,500); +INSERT INTO t2 VALUES (3,4433,10005,494,500); +INSERT INTO t2 VALUES (3,4433,10005,493,500); +INSERT INTO t2 VALUES (3,4433,10005,492,500); +UPDATE IGNORE t2,t1 set t2.colE = t2.colE + 1,colF=0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +SELECT * FROM t2; +DROP TABLE t1; +DROP TABLE t2; + diff --git a/mysys/default.c b/mysys/default.c index 81290322223..364b2037f67 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -60,15 +60,20 @@ DATADIR, NullS, }; -#define default_ext ".cnf" /* extension for config file */ #ifdef __WIN__ -#include <winbase.h> -#define windows_ext ".ini" +static const char *f_extensions[]= { ".ini", ".cnf", 0 }; +#else +static const char *f_extensions[]= { ".cnf", 0 }; #endif static int search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc, const char *dir, const char *config_file, - const char *ext, TYPELIB *group); + TYPELIB *group); + +static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, + const char *dir, const char *ext, + const char *config_file, + TYPELIB *group); static char *remove_end_comment(char *ptr); @@ -115,7 +120,8 @@ int load_defaults(const char *conf_file, const char **groups, uint args_used=0; int error= 0; MEM_ROOT alloc; - char *ptr,**res; + char *ptr, **res; + DBUG_ENTER("load_defaults"); init_alloc_root(&alloc,512,0); @@ -163,14 +169,15 @@ int load_defaults(const char *conf_file, const char **groups, goto err; if (forced_default_file) { - if ((error= search_default_file(&args, &alloc, "", - forced_default_file, "", &group)) < 0) + if ((error= search_default_file_with_ext(&args, &alloc, "", "", + forced_default_file, + &group)) < 0) goto err; } else if (dirname_length(conf_file)) { if ((error= search_default_file(&args, &alloc, NullS, conf_file, - default_ext, &group)) < 0) + &group)) < 0) goto err; } else @@ -178,28 +185,30 @@ int load_defaults(const char *conf_file, const char **groups, #ifdef __WIN__ char system_dir[FN_REFLEN]; GetWindowsDirectory(system_dir,sizeof(system_dir)); - if ((search_default_file(&args, &alloc, system_dir, conf_file, - windows_ext, &group))) + if ((search_default_file(&args, &alloc, system_dir, conf_file, &group))) goto err; #endif #if defined(__EMX__) || defined(OS2) - if (getenv("ETC") && - (search_default_file(&args, &alloc, getenv("ETC"), conf_file, - default_ext, &group)) < 0) + { + const char *etc; + if ((etc= getenv("ETC")) && + (search_default_file(&args, &alloc, etc, conf_file, + &group)) < 0) goto err; + } #endif for (dirs=default_directories ; *dirs; dirs++) { if (**dirs) { if (search_default_file(&args, &alloc, *dirs, conf_file, - default_ext, &group) < 0) + &group) < 0) goto err; } else if (defaults_extra_file) { if (search_default_file(&args, &alloc, NullS, defaults_extra_file, - default_ext, &group) < 0) + &group) < 0) goto err; /* Fatal error */ } } @@ -261,11 +270,28 @@ void free_defaults(char **argv) } +static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, + const char *dir, + const char *config_file, TYPELIB *group) +{ + char **ext; + + for (ext= (char**) f_extensions; *ext; *ext++) + { + int error; + if ((error= search_default_file_with_ext(args, alloc, dir, *ext, + config_file, group)) < 0) + return error; + } + return 0; +} + + /* Open a configuration file (if exists) and read given options from it SYNOPSIS - search_default_file() + search_default_file_with_ext() args Store pointer to found options here alloc Allocate strings in this object dir directory to read @@ -280,9 +306,10 @@ void free_defaults(char **argv) 2 File is not a regular file (Warning) */ -static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, - const char *dir, const char *config_file, - const char *ext, TYPELIB *group) +static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, + const char *dir, const char *ext, + const char *config_file, + TYPELIB *group) { char name[FN_REFLEN+10],buff[4096],*ptr,*end,*value,*tmp; FILE *fp; @@ -476,10 +503,11 @@ static char *remove_end_comment(char *ptr) void print_defaults(const char *conf_file, const char **groups) { #ifdef __WIN__ - bool have_ext=fn_ext(conf_file)[0] != 0; + my_bool have_ext= fn_ext(conf_file)[0] != 0; #endif - char name[FN_REFLEN]; + char name[FN_REFLEN], **ext; const char **dirs; + puts("\nDefault options are read from the following files in the given order:"); if (dirname_length(conf_file)) @@ -488,27 +516,43 @@ void print_defaults(const char *conf_file, const char **groups) { #ifdef __WIN__ GetWindowsDirectory(name,sizeof(name)); - printf("%s\\%s%s ",name,conf_file,have_ext ? "" : windows_ext); + if (!have_ext) + { + for (ext= (char**) f_extensions; *ext; *ext++) + printf("%s\\%s%s ", name, conf_file, *ext); + } + else + printf("%s\\%s ", name, conf_file); #endif #if defined(__EMX__) || defined(OS2) - if (getenv("ETC")) - printf("%s\\%s%s ", getenv("ETC"), conf_file, default_ext); + { + const char *etc; + + if ((etc= getenv("ETC"))) + { + for (ext= (char**) f_extensions; *ext; *ext++) + printf("%s\\%s%s ", etc, conf_file, *ext); + } + } #endif for (dirs=default_directories ; *dirs; dirs++) { - const char *pos; - char *end; - if (**dirs) - pos= *dirs; - else if (defaults_extra_file) - pos= defaults_extra_file; - else - continue; - end=convert_dirname(name, pos, NullS); - if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ - *end++='.'; - strxmov(end,conf_file,default_ext," ",NullS); - fputs(name,stdout); + for (ext= (char**) f_extensions; *ext; *ext++) + { + const char *pos; + char *end; + if (**dirs) + pos= *dirs; + else if (defaults_extra_file) + pos= defaults_extra_file; + else + continue; + end= convert_dirname(name, pos, NullS); + if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ + *end++='.'; + strxmov(end, conf_file, *ext, " ", NullS); + fputs(name,stdout); + } } puts(""); } diff --git a/mysys/errors.c b/mysys/errors.c index 7d755718b16..e21609f6e94 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -41,7 +41,7 @@ const char * NEAR globerrs[GLOBERRS]= "Can't change dir to '%s' (Errcode: %d)", "Warning: '%s' had %d links", "%d files and %d streams is left open\n", - "Disk is full writing '%s'. Waiting for someone to free space...", + "Disk is full writing '%s' (Errcode: %d). Waiting for someone to free space... Retry in %d secs", "Can't create directory '%s' (Errcode: %d)", "Character set '%s' is not a compiled character set and is not specified in the '%s' file", "Out of resources when opening file '%s' (Errcode: %d)", diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c index 94f3aaf3464..0ad789e98ac 100644 --- a/mysys/my_fstream.c +++ b/mysys/my_fstream.c @@ -114,13 +114,15 @@ uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags) if (my_thread_var->abort) MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */ #endif - if (errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL)) + if ((errno == ENOSPC || errno == EDQUOT) && + (MyFlags & MY_WAIT_IF_FULL)) { - if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) - my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH)); - sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC); - VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0))); - continue; + if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) + my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH), + "[stream]",my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC); + VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); + VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0))); + continue; } #endif if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP))) diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index f9df4afb55d..71f8819756a 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -22,6 +22,9 @@ #include <mysys_err.h> #include <my_getopt.h> +static void default_reporter(enum loglevel level, const char *format, ...); +my_error_reporter my_getopt_error_reporter= &default_reporter; + static int findopt(char *optpat, uint length, const struct my_option **opt_res, char **ffname); @@ -56,7 +59,8 @@ char *disabled_my_option= (char*) "0"; my_bool my_getopt_print_errors= 1; -void default_reporter(enum loglevel level, const char *format, ...) +static void default_reporter(enum loglevel level __attribute__((unused)), + const char *format, ...) { va_list args; va_start(args, format); @@ -76,8 +80,7 @@ void default_reporter(enum loglevel level, const char *format, ...) int handle_options(int *argc, char ***argv, const struct my_option *longopts, - my_get_one_option get_one_option, - my_error_reporter reporter) + my_get_one_option get_one_option) { uint opt_found, argvpos= 0, length, i; my_bool end_of_options= 0, must_be_var, set_maximum_value, special_used, @@ -91,9 +94,6 @@ int handle_options(int *argc, char ***argv, (*argv)++; /* --- || ---- */ init_variables(longopts); - if (! reporter) - reporter= &default_reporter; - for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) { char *cur_arg= *pos; @@ -118,8 +118,9 @@ int handle_options(int *argc, char ***argv, if (!*++pos) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: Option '-O' requires an argument\n", progname); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Option '-O' requires an argument\n", + progname); return EXIT_ARGUMENT_REQUIRED; } cur_arg= *pos; @@ -135,9 +136,9 @@ int handle_options(int *argc, char ***argv, if (!*cur_arg) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: Option '--set-variable' requires an argument\n", - progname); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Option '--set-variable' requires an argument\n", + progname); return EXIT_ARGUMENT_REQUIRED; } } @@ -149,9 +150,9 @@ int handle_options(int *argc, char ***argv, if (!*++pos) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: Option '--set-variable' requires an argument\n", - progname); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Option '--set-variable' requires an argument\n", + progname); return EXIT_ARGUMENT_REQUIRED; } cur_arg= *pos; @@ -210,10 +211,11 @@ int handle_options(int *argc, char ***argv, if (opt_found > 1) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: ambiguous option '--%s-%s' (--%s-%s)\n", - progname, special_opt_prefix[i], cur_arg, - special_opt_prefix[i], prev_found); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: ambiguous option '--%s-%s' (--%s-%s)\n", + progname, special_opt_prefix[i], + cur_arg, special_opt_prefix[i], + prev_found); return EXIT_AMBIGUOUS_OPTION; } switch (i) { @@ -245,16 +247,20 @@ int handle_options(int *argc, char ***argv, if (must_be_var) { if (my_getopt_print_errors) - reporter(option_is_loose ? WARNING_LEVEL : ERROR_LEVEL, - "%s: unknown variable '%s'\n", progname, cur_arg); + my_getopt_error_reporter(option_is_loose ? + WARNING_LEVEL : ERROR_LEVEL, + "%s: unknown variable '%s'\n", + progname, cur_arg); if (!option_is_loose) return EXIT_UNKNOWN_VARIABLE; } else { if (my_getopt_print_errors) - reporter(option_is_loose ? WARNING_LEVEL : ERROR_LEVEL, - "%s: unknown option '--%s'\n", progname, cur_arg); + my_getopt_error_reporter(option_is_loose ? + WARNING_LEVEL : ERROR_LEVEL, + "%s: unknown option '--%s'\n", + progname, cur_arg); if (!option_is_loose) return EXIT_UNKNOWN_OPTION; } @@ -270,23 +276,27 @@ int handle_options(int *argc, char ***argv, if (must_be_var) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, "%s: variable prefix '%s' is not unique\n", - progname, cur_arg); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: variable prefix '%s' is not unique\n", + progname, cur_arg); return EXIT_VAR_PREFIX_NOT_UNIQUE; } else { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, "%s: ambiguous option '--%s' (%s, %s)\n", - progname, cur_arg, prev_found, optp->name); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: ambiguous option '--%s' (%s, %s)\n", + progname, cur_arg, prev_found, + optp->name); return EXIT_AMBIGUOUS_OPTION; } } if (must_be_var && optp->var_type == GET_NO_ARG) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, "%s: option '%s' cannot take an argument\n", - progname, optp->name); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '%s' cannot take an argument\n", + progname, optp->name); return EXIT_NO_ARGUMENT_ALLOWED; } if (optp->arg_type == NO_ARG) @@ -294,9 +304,9 @@ int handle_options(int *argc, char ***argv, if (optend && optp->var_type != GET_BOOL) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: option '--%s' cannot take an argument\n", - progname, optp->name); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '--%s' cannot take an argument\n", + progname, optp->name); return EXIT_NO_ARGUMENT_ALLOWED; } if (optp->var_type == GET_BOOL) @@ -333,9 +343,9 @@ int handle_options(int *argc, char ***argv, if (!*++pos) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: option '--%s' requires an argument\n", - progname, optp->name); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '--%s' requires an argument\n", + progname, optp->name); return EXIT_ARGUMENT_REQUIRED; } argument= *pos; @@ -384,9 +394,9 @@ int handle_options(int *argc, char ***argv, if (!pos[1]) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: option '-%c' requires an argument\n", - progname, optp->id); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '-%c' requires an argument\n", + progname, optp->id); return EXIT_ARGUMENT_REQUIRED; } argument= *++pos; @@ -396,9 +406,9 @@ int handle_options(int *argc, char ***argv, } if ((error= setval(optp, argument, set_maximum_value))) { - reporter(ERROR_LEVEL, - "%s: Error while setting value '%s' to '%s'\n", - progname, argument, optp->name); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Error while setting value '%s' to '%s'\n", + progname, argument, optp->name); return error; } get_one_option(optp->id, optp, argument); @@ -408,8 +418,9 @@ int handle_options(int *argc, char ***argv, if (!opt_found) { if (my_getopt_print_errors) - reporter(ERROR_LEVEL, - "%s: unknown option '-%c'\n", progname, *optend); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: unknown option '-%c'\n", + progname, *optend); return EXIT_UNKNOWN_OPTION; } } @@ -418,9 +429,9 @@ int handle_options(int *argc, char ***argv, } if ((error= setval(optp, argument, set_maximum_value))) { - reporter(ERROR_LEVEL, - "%s: Error while setting value '%s' to '%s'\n", - progname, argument, optp->name); + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Error while setting value '%s' to '%s'\n", + progname, argument, optp->name); return error; } get_one_option(optp->id, optp, argument); diff --git a/mysys/my_pread.c b/mysys/my_pread.c index 661ef48ab3e..f76233fc4cc 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -115,11 +115,12 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, if (my_thread_var->abort) MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */ #endif - if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL)) + if ((my_errno == ENOSPC || my_errno == EDQUOT) && + (MyFlags & MY_WAIT_IF_FULL)) { if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH), - my_filename(Filedes)); + my_filename(Filedes),my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC); VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } @@ -131,7 +132,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, { if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { - my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG), + my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG), my_filename(Filedes),my_errno); } DBUG_RETURN(MY_FILE_ERROR); /* Error on read */ @@ -142,4 +143,4 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, if (MyFlags & (MY_NABP | MY_FNABP)) DBUG_RETURN(0); /* Want only errors */ DBUG_RETURN(writenbytes+written); /* purecov: inspected */ -} /* my_write */ +} /* my_pwrite */ diff --git a/mysys/my_write.c b/mysys/my_write.c index 61fd6097e28..da378d115f1 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -48,12 +48,13 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) if (my_thread_var->abort) MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */ #endif - if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL) && + if ((my_errno == ENOSPC || my_errno == EDQUOT) && + (MyFlags & MY_WAIT_IF_FULL) && (uint) writenbytes != (uint) -1) { if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH), - my_filename(Filedes)); + my_filename(Filedes),my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC); VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index f79431a0b0b..d7aee04ae20 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -29,3 +29,11 @@ extern pthread_mutex_t THR_LOCK_charset; #else #include <my_no_pthread.h> #endif + +/* + EDQUOT is used only in 3 C files only in mysys/. If it does not exist on + system, we set it to some value which can never happen. +*/ +#ifndef EDQUOT +#define EDQUOT (-1) +#endif diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index d5236cb1ef9..935ed4ea282 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -552,8 +552,14 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) !lock->write_wait.data && lock->write.data->type == TL_WRITE_ALLOW_WRITE)) { - /* We have already got a write lock or all locks are - TL_WRITE_ALLOW_WRITE */ + /* + We have already got a write lock or all locks are + TL_WRITE_ALLOW_WRITE + */ + DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d", + (ulong) lock->write_wait.data, + lock->write.data->type)); + (*lock->write.last)=data; /* Add to running fifo */ data->prev=lock->write.last; lock->write.last= &data->next; @@ -568,6 +574,8 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) } else { + DBUG_PRINT("info", ("write_wait.data: 0x%lx", + (ulong) lock->write_wait.data)); if (!lock->write_wait.data) { /* no scheduled write locks */ if (lock_type == TL_WRITE_CONCURRENT_INSERT && diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 7b77bf449cd..da7e06f6c05 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -311,34 +311,37 @@ do fi if test ! -f $pid_file # This is removed if normal shutdown then + echo "STOPPING server from pid file $pid_file" break fi - if test @IS_LINUX@ -a $KILL_MYSQLD -eq 1 + if @IS_LINUX@ && test $KILL_MYSQLD -eq 1 then # Test if one process was hanging. # This is only a fix for Linux (running as base 3 mysqld processes) # but should work for the rest of the servers. # The only thing is ps x => redhat 5 gives warnings when using ps -x. # kill -9 is used or the process won't react on the kill. - numofproces=`ps xa | grep -v "grep" | grep -c $ledir/$MYSQLD` + numofproces=`ps xa | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"` + echo -e "\nNumber of processes running now: $numofproces" | tee -a $err_log I=1 while test "$I" -le "$numofproces" do - PROC=`ps xa | grep $ledir/$MYSQLD | grep -v "grep" | sed -n '$p'` - for T in $PROC - do - break - done - # echo "TEST $I - $T **" - if kill -9 $T - then - echo "$MYSQLD process hanging, pid $T - killed" | tee -a $err_log - else - break - fi - I=`expr $I + 1` + PROC=`ps xa | grep "$ledir/$MYSQLD\>" | grep -v "grep" | grep "pid-file=$pid_file" | sed -n '$p'` + + for T in $PROC + do + break + done + # echo "TEST $I - $T **" + if kill -9 $T + then + echo "$MYSQLD process hanging, pid $T - killed" | tee -a $err_log + else + break + fi + I=`expr $I + 1` done fi echo "`date +'%y%m%d %H:%M:%S'` mysqld restarted" | tee -a $err_log @@ -346,3 +349,4 @@ done echo "`date +'%y%m%d %H:%M:%S'` mysqld ended" | tee -a $err_log echo "" | tee -a $err_log + diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index af4e6084c59..f9e29e33195 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -8,7 +8,7 @@ use File::Path; use DBI; use Sys::Hostname; use File::Copy; -use File::Temp; +use File::Temp qw(tempfile); =head1 NAME @@ -39,7 +39,7 @@ WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. # Documentation continued at end of file -my $VERSION = "1.21"; +my $VERSION = "1.22"; my $opt_tmpdir = $ENV{TMPDIR} || "/tmp"; @@ -77,7 +77,7 @@ Usage: $0 db_name[./table_regex/] [new_db_name | directory] --record_log_pos=# record slave and master status in specified db.table --chroot=# base directory of chroot jail in which mysqld operates - Try \'perldoc $0 for more complete documentation\' + Try \'perldoc $0\' for more complete documentation _OPTIONS sub usage { @@ -654,8 +654,8 @@ sub copy_index } elsif ($opt{method} =~ /^scp\b/) { - my ($fh, $tmp)=tempfile('mysqlhotcopy-XXXXXX', DIR => $opt_tmpdir); - die "Can\'t create/open file in $opt_tmpdir\n"; + my ($fh, $tmp)= tempfile('mysqlhotcopy-XXXXXX', DIR => $opt_tmpdir) or + die "Can\'t create/open file in $opt_tmpdir\n"; if (syswrite($fh,$buff) != length($buff)) { die "Error when writing data to $tmp: $!\n"; diff --git a/sql/Makefile.am b/sql/Makefile.am index 0a664a120a5..0fc81a48c63 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -108,7 +108,7 @@ gen_lex_hash.o: gen_lex_hash.cc lex.h sql_yacc.cc: sql_yacc.yy sql_yacc.h: sql_yacc.yy -sql_yacc.o: sql_yacc.cc sql_yacc.h +sql_yacc.o: sql_yacc.cc sql_yacc.h $(noinst_HEADERS) @echo "Note: The following compile may take a long time." @echo "If it fails, re-run configure with --with-low-memory" $(CXXCOMPILE) $(LM_CFLAGS) -c $< diff --git a/sql/field.cc b/sql/field.cc index 394d53238c2..69ee6606be4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2467,8 +2467,7 @@ void Field_double::sql_type(String &res) const enum Item_result Field_timestamp::result_type() const { - return (!current_thd->variables.new_mode && - (field_length == 8 || field_length == 14) ? INT_RESULT : + return ((field_length == 8 || field_length == 14) ? INT_RESULT : STRING_RESULT); } @@ -2480,6 +2479,9 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, :Field_num(ptr_arg, len_arg, (uchar*) 0,0, unireg_check_arg, field_name_arg, table_arg, 0, 1, 1) +#if MYSQL_VERSION_ID < 40100 + , orig_field_length(len_arg) +#endif { if (table && !table->timestamp_field) { @@ -2697,7 +2699,7 @@ String *Field_timestamp::val_str(String *val_buffer, time_t time_arg; struct tm *l_time; struct tm tm_tmp; - my_bool new_format= (current_thd->variables.new_mode) || field_length == 19, + my_bool new_format= field_length == 19, full_year=(field_length == 8 || field_length == 14 || new_format); int real_field_length= new_format ? 19 : field_length; @@ -2859,22 +2861,6 @@ void Field_timestamp::set_time() longstore(ptr,tmp); } -/* - This is an exact copy of Field_num except that 'length' is depending - on --new mode -*/ - -void Field_timestamp::make_field(Send_field *field) -{ - field->table_name=table_name; - field->col_name=field_name; - /* If --new, then we are using "YYYY-MM-DD HH:MM:SS" format */ - field->length= current_thd->variables.new_mode ? 19 : field_length; - field->type=type(); - field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags; - field->decimals=dec; -} - /**************************************************************************** ** time type diff --git a/sql/field.h b/sql/field.h index d25ce8d4774..c42f5f63f0c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -546,6 +546,13 @@ public: class Field_timestamp :public Field_num { +#if MYSQL_VERSION_ID < 40100 + /* + We save the original field length here because field_length is + changed to a mock value in case when the 'new_mode' is in effect. + */ + uint32 orig_field_length; +#endif public: Field_timestamp(char *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const char *field_name_arg, @@ -587,7 +594,11 @@ public: void fill_and_store(char *from,uint len); bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); - void make_field(Send_field *field); + +#if MYSQL_VERSION_ID < 40100 + friend TABLE *open_table(THD *thd,const char *db,const char *table_name, + const char *alias,bool *refresh); +#endif }; diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 72ab1184533..1e78aa35195 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -384,7 +384,7 @@ static int get_options(int argc, char **argv) { int ho_error; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, 0))) + if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); if (argc >= 1) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3d3aca9cfd5..91f92c8cadb 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -285,8 +285,9 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) { - return(HA_ERR_ROW_IS_REFERENCED); - + return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit + misleading, a new MySQL error + code should be introduced */ } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { return(HA_ERR_CRASHED); @@ -766,6 +767,7 @@ ha_innobase::init_table_handle_for_HANDLER(void) if the trx isolation level would have been specified as SERIALIZABLE */ prebuilt->select_lock_type = LOCK_NONE; + prebuilt->stored_select_lock_type = LOCK_NONE; /* Always fetch all columns in the index record */ @@ -2170,8 +2172,9 @@ ha_innobase::write_row( same SQL statement! */ if (auto_inc == 0 && user_thd->next_insert_id != 0) { - auto_inc = user_thd->next_insert_id; - auto_inc_counter_for_this_stat = auto_inc; + + auto_inc_counter_for_this_stat + = user_thd->next_insert_id; } if (auto_inc == 0 && auto_inc_counter_for_this_stat) { @@ -2179,14 +2182,14 @@ ha_innobase::write_row( this SQL statement with SET INSERT_ID. We must assign sequential values from the counter. */ - auto_inc_counter_for_this_stat++; - incremented_auto_inc_for_stat = TRUE; - auto_inc = auto_inc_counter_for_this_stat; /* We give MySQL a new value to place in the auto-inc column */ user_thd->next_insert_id = auto_inc; + + auto_inc_counter_for_this_stat++; + incremented_auto_inc_for_stat = TRUE; } if (auto_inc != 0) { @@ -2283,7 +2286,9 @@ ha_innobase::write_row( if (error == DB_DUPLICATE_KEY && (user_thd->lex.sql_command == SQLCOM_REPLACE || user_thd->lex.sql_command - == SQLCOM_REPLACE_SELECT)) { + == SQLCOM_REPLACE_SELECT + || (user_thd->lex.sql_command == SQLCOM_LOAD + && user_thd->lex.duplicates == DUP_REPLACE))) { skip_auto_inc_decr= TRUE; } @@ -3047,7 +3052,7 @@ ha_innobase::index_last( { int error; - DBUG_ENTER("index_first"); + DBUG_ENTER("index_last"); statistic_increment(ha_read_last_count, &LOCK_status); error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY); @@ -4108,7 +4113,7 @@ ha_innobase::info( if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { - return; + DBUG_VOID_RETURN; } /* We do not know if MySQL can call this function before calling @@ -4561,40 +4566,40 @@ ha_innobase::start_stmt( prebuilt->select_lock_type = LOCK_X; } else { - /* When we first come here after LOCK TABLES, - select_lock_type is set to LOCK_S or LOCK_X. Store the value - in case we run also consistent reads and need to restore the - value later. */ + if (trx->isolation_level != TRX_ISO_SERIALIZABLE + && thd->lex.sql_command == SQLCOM_SELECT + && thd->lex.lock_option == TL_READ) { + + /* For other than temporary tables, we obtain + no lock for consistent read (plain SELECT). */ - if (prebuilt->select_lock_type != LOCK_NONE) { - prebuilt->stored_select_lock_type = - prebuilt->select_lock_type; + prebuilt->select_lock_type = LOCK_NONE; + } else { + /* Not a consistent read: restore the + select_lock_type value. The value of + stored_select_lock_type was decided in: + 1) ::store_lock(), + 2) ::external_lock(), and + 3) ::init_table_handle_for_HANDLER(). */ + + prebuilt->select_lock_type = + prebuilt->stored_select_lock_type; } if (prebuilt->stored_select_lock_type != LOCK_S && prebuilt->stored_select_lock_type != LOCK_X) { fprintf(stderr, -"InnoDB: Error: select_lock_type is %lu inside ::start_stmt()!\n", +"InnoDB: Error: stored_select_lock_type is %lu inside ::start_stmt()!\n", prebuilt->stored_select_lock_type); - ut_error; - } - - if (thd->lex.sql_command == SQLCOM_SELECT - && thd->lex.lock_option == TL_READ) { - - /* For other than temporary tables, we obtain - no lock for consistent read (plain SELECT) */ + /* Set the value to LOCK_X: this is just fault + tolerance, we do not know what the correct value + should be! */ - prebuilt->select_lock_type = LOCK_NONE; - } else { - /* Not a consistent read: restore the - select_lock_type value */ - prebuilt->select_lock_type = - prebuilt->stored_select_lock_type; + prebuilt->select_lock_type = LOCK_X; } } - + /* Set the MySQL flag to mark that there is an active transaction */ thd->transaction.all.innodb_active_trans = 1; @@ -4655,6 +4660,7 @@ ha_innobase::external_lock( /* If this is a SELECT, then it is in UPDATE TABLE ... or SELECT ... FOR UPDATE */ prebuilt->select_lock_type = LOCK_X; + prebuilt->stored_select_lock_type = LOCK_X; } if (lock_type != F_UNLCK) { @@ -4690,7 +4696,8 @@ ha_innobase::external_lock( } if (prebuilt->select_lock_type != LOCK_NONE) { - if (thd->in_lock_tables) { + if (thd->in_lock_tables && + thd->variables.innodb_table_locks) { ulint error; error = row_lock_table_for_mysql(prebuilt); @@ -4909,14 +4916,22 @@ ha_innobase::store_lock( { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - if (lock_type == TL_READ_WITH_SHARED_LOCKS || + if ((lock_type == TL_READ && thd->in_lock_tables) || + (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) || + lock_type == TL_READ_WITH_SHARED_LOCKS || lock_type == TL_READ_NO_INSERT) { - /* This is a SELECT ... IN SHARE MODE, or - we are doing a complex SQL statement like + /* The OR cases above are in this order: + 1) MySQL is doing LOCK TABLES ... READ LOCAL, or + 2) (we do not know when TL_READ_HIGH_PRIORITY is used), or + 3) this is a SELECT ... IN SHARE MODE, or + 4) we are doing a complex SQL statement like INSERT INTO ... SELECT ... and the logical logging (MySQL - binlog) requires the use of a locking read */ + binlog) requires the use of a locking read, or + MySQL is doing LOCK TABLES ... READ. */ prebuilt->select_lock_type = LOCK_S; + prebuilt->stored_select_lock_type = LOCK_S; + } else if (lock_type != TL_IGNORE) { /* In ha_berkeley.cc there is a comment that MySQL @@ -4927,6 +4942,7 @@ ha_innobase::store_lock( here even if this would be SELECT ... FOR UPDATE */ prebuilt->select_lock_type = LOCK_NONE; + prebuilt->stored_select_lock_type = LOCK_NONE; } if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 5736f70c65c..74acc0640c9 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -207,6 +207,7 @@ extern my_bool innobase_log_archive, innobase_create_status_file; extern "C" { extern ulong srv_max_buf_pool_modified_pct; +extern ulong srv_max_purge_lag; } extern TYPELIB innobase_lock_typelib; diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index d5bbf9b5a92..d79ea4adda0 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -525,6 +525,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) { + int error; if (!file) return HA_ADMIN_INTERNAL_ERROR; MI_CHECK param; @@ -534,7 +535,14 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) param.testflag = (check_opt->flags | T_SILENT | T_FORCE_CREATE | T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX); param.sort_buffer_length= check_opt->sort_buffer_size; - return repair(thd,param,1); + if ((error= repair(thd,param,1)) && param.retry_repair) + { + sql_print_warning("Warning: Optimize table got errno %d, retrying", + my_errno); + param.testflag&= ~T_REP_BY_SORT; + error= repair(thd,param,1); + } + return error; } @@ -744,7 +752,13 @@ bool ha_myisam::activate_all_index(THD *thd) param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; param.tmpdir=mysql_tmpdir; - error=repair(thd,param,0) != HA_ADMIN_OK; + if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair) + { + sql_print_warning("Warning: Enabling keys got errno %d, retrying", + my_errno); + param.testflag&= ~(T_REP_BY_SORT | T_QUICK); + error= (repair(thd,param,0) != HA_ADMIN_OK); + } info(HA_STATUS_CONST); thd->proc_info=save_proc_info; } @@ -998,6 +1012,7 @@ int ha_myisam::delete_table(const char *name) return mi_delete_table(name); } + int ha_myisam::external_lock(THD *thd, int lock_type) { return mi_lock_database(file, !table->tmp_table ? @@ -1005,7 +1020,6 @@ int ha_myisam::external_lock(THD *thd, int lock_type) F_UNLCK : F_EXTRA_LCK)); } - THR_LOCK_DATA **ha_myisam::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) diff --git a/sql/handler.cc b/sql/handler.cc index 9eb129fab45..65078a485c5 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -348,7 +348,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) if (trans == &thd->transaction.all && my_b_tell(&thd->transaction.trans_log)) { - if (error= wait_if_global_read_lock(thd, 0, 0)) + if ((error= wait_if_global_read_lock(thd, 0, 0))) { /* Note that ROLLBACK [TO SAVEPOINT] does not have this test; it's diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 013304d9df5..fbc1ad97e76 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -654,6 +654,15 @@ Item_func_nullif::val_str(String *str) return res; } + +bool +Item_func_nullif::is_null() +{ + if (!(this->*cmp_func)()) + return null_value=1; + return 0; +} + /* CASE expression Return the matching ITEM or NULL if all compares (including else) failed diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a4f8118f21d..d36429ab61e 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -240,6 +240,7 @@ public: void fix_length_and_dec(); const char *func_name() const { return "nullif"; } table_map not_null_tables() const { return 0; } + bool is_null(); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 5d017b3a27a..53a9d3fe219 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1135,7 +1135,7 @@ String *Item_func_ltrim::val_str(String *str) { const char *r_ptr=remove_str->ptr(); end-=remove_length; - while (ptr < end && !memcmp(ptr,r_ptr,remove_length)) + while (ptr <= end && !memcmp(ptr, r_ptr, remove_length)) ptr+=remove_length; end+=remove_length; } @@ -1206,8 +1206,8 @@ String *Item_func_rtrim::val_str(String *str) else #endif /* USE_MB */ { - while (ptr + remove_length < end && - !memcmp(end-remove_length,r_ptr,remove_length)) + while (ptr + remove_length <= end && + !memcmp(end-remove_length, r_ptr, remove_length)) end-=remove_length; } } @@ -2142,9 +2142,12 @@ String* Item_func_inet_ntoa::val_str(String* str) This function is very useful when you want to generate SQL statements - RETURN VALUES + NOTE + QUOTE(NULL) returns the string 'NULL' (4 letters, without quotes). + + RETURN VALUES str Quoted string - NULL Argument to QUOTE() was NULL or out of memory. + NULL Out of memory. */ #define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7)) @@ -2168,7 +2171,12 @@ String *Item_func_quote::val_str(String *str) String *arg= args[0]->val_str(str); uint arg_length, new_length; if (!arg) // Null argument - goto null; + { + str->copy("NULL", 4); // Return the string 'NULL' + null_value= 0; + return str; + } + arg_length= arg->length(); new_length= arg_length+2; /* for beginning and ending ' signs */ diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ed950a33166..d188310be24 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -919,21 +919,14 @@ String *Item_func_date_format::val_str(String *str) String *Item_func_from_unixtime::val_str(String *str) { - struct tm tm_tmp,*start; - time_t tmp=(time_t) args[0]->val_int(); - if ((null_value=args[0]->null_value)) + TIME ltime; + if (get_date(<ime, 0)) return 0; - localtime_r(&tmp,&tm_tmp); - start=&tm_tmp; if (str->alloc(20)) return str; /* purecov: inspected */ sprintf((char*) str->ptr(),"%04d-%02d-%02d %02d:%02d:%02d", - (int) start->tm_year+1900, - (int) start->tm_mon+1, - (int) start->tm_mday, - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); + (int) ltime.year, (int) ltime.month, (int) ltime.day, + (int) ltime.hour, (int) ltime.minute, (int) ltime.second); str->length(19); return str; } @@ -941,37 +934,33 @@ String *Item_func_from_unixtime::val_str(String *str) longlong Item_func_from_unixtime::val_int() { - time_t tmp=(time_t) (ulong) args[0]->val_int(); - if ((null_value=args[0]->null_value)) + TIME ltime; + if (get_date(<ime, 0)) return 0; - struct tm tm_tmp,*start; - localtime_r(&tmp,&tm_tmp); - start= &tm_tmp; - return ((longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+ - (((uint) start->tm_mon+1)*100+ - (uint) start->tm_mday))*LL(1000000)+ - (longlong) ((ulong) ((uint) start->tm_hour)*10000L+ - (ulong) (((uint) start->tm_min)*100L+ - (uint) start->tm_sec))); + return ((longlong)(ltime.year*10000L+ltime.month*100+ltime.day)*LL(1000000)+ + (longlong)(ltime.hour*10000L+ltime.minute*100+ltime.second)); } bool Item_func_from_unixtime::get_date(TIME *ltime, bool fuzzy_date __attribute__((unused))) { - time_t tmp=(time_t) (ulong) args[0]->val_int(); - if ((null_value=args[0]->null_value)) + struct tm tm_tmp; + time_t tmp; + longlong arg= args[0]->val_int(); + if ((null_value= (args[0]->null_value || + arg < TIMESTAMP_MIN_VALUE || + arg > TIMESTAMP_MAX_VALUE))) return 1; - struct tm tm_tmp,*start; + tmp= arg; localtime_r(&tmp,&tm_tmp); - start= &tm_tmp; - ltime->year= start->tm_year+1900; - ltime->month= start->tm_mon+1; - ltime->day= start->tm_mday; - ltime->hour= start->tm_hour; - ltime->minute=start->tm_min; - ltime->second=start->tm_sec; - ltime->second_part=0; - ltime->neg=0; + ltime->year= tm_tmp.tm_year+1900; + ltime->month= tm_tmp.tm_mon+1; + ltime->day= tm_tmp.tm_mday; + ltime->hour= tm_tmp.tm_hour; + ltime->minute= tm_tmp.tm_min; + ltime->second= tm_tmp.tm_sec; + ltime->second_part= 0; + ltime->neg= 0; return 0; } diff --git a/sql/lock.cc b/sql/lock.cc index dd2b61b65d2..bf0160291f8 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -751,9 +751,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commi { if (thd->global_read_lock) // This thread had the read locks { - my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0)); + if (is_not_commit) + my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0)); (void) pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(1); + /* + We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does. + This allowance is needed to not break existing versions of innobackup + which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT. + */ + DBUG_RETURN(is_not_commit); } old_message=thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting for release of readlock"); diff --git a/sql/log.cc b/sql/log.cc index 55ef2e72960..b2d015c1a14 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1221,7 +1221,7 @@ bool MYSQL_LOG::write(Log_event* event_info) if (e.write(file)) goto err; } -#if MYSQL_VERSION_ID < 40100 +#if MYSQL_VERSION_ID < 40100 if (thd->variables.convert_set) { Query_log_event e(thd, "SET CHARACTER SET DEFAULT", 25, 0); @@ -1254,7 +1254,8 @@ bool MYSQL_LOG::write(Log_event* event_info) if (flush_io_cache(file)) goto err; - if (opt_using_transactions && !my_b_tell(&thd->transaction.trans_log)) + if (opt_using_transactions && + !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { /* LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog @@ -1370,6 +1371,14 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback) { Query_log_event qinfo(thd, "BEGIN", 5, TRUE); /* + Imagine this is rollback due to net timeout, after all statements of + the transaction succeeded. Then we want a zero-error code in BEGIN. + In other words, if there was a really serious error code it's already + in the statement's events. + This is safer than thd->clear_error() against kills at shutdown. + */ + qinfo.error_code= 0; + /* Now this Query_log_event has artificial log_pos 0. It must be adjusted to reflect the real position in the log. Not doing it would confuse the slave: it would prevent this one from knowing where he is in the @@ -1402,6 +1411,7 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback) commit_or_rollback ? "COMMIT" : "ROLLBACK", commit_or_rollback ? 6 : 8, TRUE); + qinfo.error_code= 0; qinfo.set_log_pos(this); if (qinfo.write(&log_file) || flush_io_cache(&log_file)) goto err; @@ -1682,22 +1692,6 @@ void MYSQL_LOG::set_max_size(ulong max_size_arg) } -Disable_binlog::Disable_binlog(THD *thd_arg) : - thd(thd_arg), - save_options(thd_arg->options), save_master_access(thd_arg->master_access) -{ - thd_arg->options&= ~OPTION_BIN_LOG; - thd_arg->master_access|= SUPER_ACL; // unneeded in 4.1 -}; - - -Disable_binlog::~Disable_binlog() -{ - thd->options= save_options; - thd->master_access= save_master_access; -} - - /* Check if a string is a valid number @@ -1761,15 +1755,21 @@ void print_buffer_to_file(enum loglevel level, const char *buffer) skr=time(NULL); localtime_r(&skr, &tm_tmp); start=&tm_tmp; +#if MYSQL_VERSION_ID > 40100 fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n", - start->tm_year % 100, - start->tm_mon+1, - start->tm_mday, - start->tm_hour, - start->tm_min, - start->tm_sec, +#else + fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d %s\n", +#endif + start->tm_year % 100, + start->tm_mon+1, + start->tm_mday, + start->tm_hour, + start->tm_min, + start->tm_sec, +#if MYSQL_VERSION_ID > 40100 (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ? "WARNING" : "INFORMATION"), +#endif buffer); fflush(stderr); diff --git a/sql/log_event.cc b/sql/log_event.cc index 5526795c9d1..007bb6e7b85 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1612,7 +1612,7 @@ void Create_file_log_event::print(FILE* file, bool short_form, if (enable_local) { - Load_log_event::print(file, 1, last_db, !check_fname_outside_temp_buf()); + Load_log_event::print(file, short_form, last_db, !check_fname_outside_temp_buf()); /* That one is for "file_id: etc" below: in mysqlbinlog we want the #, in SHOW BINLOG EVENTS we don't. @@ -1806,7 +1806,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) { int expected_error, actual_error= 0; init_sql_alloc(&thd->mem_root, thd->variables.query_alloc_block_size,0); - thd->db= (char*) rewrite_db(db); + thd->db= (char*) rewrite_db(db); // thd->db_length is set later if needed /* InnoDB internally stores the master log position it has processed so far; @@ -1836,6 +1836,11 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) { thd->set_time((time_t)when); thd->current_tablenr = 0; + /* + We cannot use db_len from event to fill thd->db_length, because + rewrite_db() may have changed db. + */ + thd->db_length= thd->db ? strlen(thd->db) : 0; thd->query_length= q_len; thd->query= (char *) query; VOID(pthread_mutex_lock(&LOCK_thread_count)); @@ -1930,7 +1935,7 @@ end: VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->db= 0; // prevent db from being freed thd->query= 0; // just to be sure - thd->query_length= 0; + thd->query_length= thd->db_length =0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); close_thread_tables(thd); free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC)); @@ -1968,7 +1973,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, { char *load_data_query= 0; init_sql_alloc(&thd->mem_root, thd->variables.query_alloc_block_size, 0); - thd->db= (char*) rewrite_db(db); + thd->db= (char*) rewrite_db(db); // thd->db_length is set later if needed DBUG_ASSERT(thd->query == 0); clear_all_errors(thd, rli); @@ -2001,6 +2006,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, { thd->set_time((time_t)when); thd->current_tablenr = 0; + thd->db_length= thd->db ? strlen(thd->db) : 0; VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id = query_id++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); @@ -2117,7 +2123,7 @@ Slave: load data infile on table '%s' at log position %s in log \ VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->db= 0; thd->query= 0; - thd->query_length= 0; + thd->query_length= thd->db_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); close_thread_tables(thd); if (load_data_query) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index acc07eb6188..b123927d09e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -540,14 +540,18 @@ int mysql_find_files(THD *thd,List<char> *files, const char *db, const char *path, const char *wild, bool dir); /* sql_handler.cc */ -int mysql_ha_open(THD *thd, TABLE_LIST *tables); -int mysql_ha_close(THD *thd, TABLE_LIST *tables, - bool dont_send_ok=0, bool dont_lock=0, bool no_alias=0); -int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed=0); +int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen= 0); +int mysql_ha_close(THD *thd, TABLE_LIST *tables); int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags); +/* mysql_ha_flush mode_flags bits */ +#define MYSQL_HA_CLOSE_FINAL 0x00 +#define MYSQL_HA_REOPEN_ON_USAGE 0x01 +#define MYSQL_HA_FLUSH_ALL 0x02 /* sql_base.cc */ +#define TMP_TABLE_KEY_EXTRA 8 void set_item_name(Item *item,char *pos,uint length); bool add_field_to_list(char *field_name, enum enum_field_types type, char *length, char *decimal, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1068c5ec9a1..768acd77c27 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -414,6 +414,7 @@ char mysql_real_data_home[FN_REFLEN], max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file; char *language_ptr= language; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; +struct passwd *user_info; #ifndef EMBEDDED_LIBRARY bool mysql_embedded=0; #else @@ -1028,27 +1029,26 @@ static void set_ports() } } -/* Change to run as another user if started with --user */ -static void set_user(const char *user) +static struct passwd *check_user(const char *user) { -#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) - struct passwd *ent; +#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) + struct passwd *user_info; uid_t user_id= geteuid(); - - // don't bother if we aren't superuser + + // Don't bother if we aren't superuser if (user_id) { if (user) { - /* Don't give a warning, if real user is same as given with --user */ - struct passwd *user_info= getpwnam(user); + // Don't give a warning, if real user is same as given with --user + user_info= getpwnam(user); if ((!user_info || user_id != user_info->pw_uid) && - global_system_variables.log_warnings) - fprintf(stderr, - "Warning: One can only use the --user switch if running as root\n"); + global_system_variables.log_warnings) + fprintf(stderr, + "Warning: One can only use the --user switch if running as root\n"); } - return; + return NULL; } if (!user) { @@ -1057,38 +1057,52 @@ static void set_user(const char *user) fprintf(stderr,"Fatal error: Please read \"Security\" section of the manual to find out how to run mysqld as root!\n"); unireg_abort(1); } - return; + return NULL; } if (!strcmp(user,"root")) - return; // Avoid problem with dynamic libraries - - uid_t uid; - if (!(ent = getpwnam(user))) + return NULL; // Avoid problem with dynamic libraries + if (!(user_info= getpwnam(user))) { - // allow a numeric uid to be used + // Allow a numeric uid to be used const char *pos; - for (pos=user; isdigit(*pos); pos++) ; - if (*pos) // Not numeric id - { - fprintf(stderr,"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user); - unireg_abort(1); - } - uid=atoi(user); // Use numberic uid + for (pos= user; isdigit(*pos); pos++); + if (*pos) // Not numeric id + goto err; + if (!(user_info= getpwuid(atoi(user)))) + goto err; + else + return user_info; } else { + return user_info; + } + +err: + fprintf(stderr, + "Fatal error: Can't change to run as user '%s'. Please check that the user exists!\n", + user); + unireg_abort(1); + return NULL; +#else + return NULL; +#endif +} + + +static void set_user(const char *user, struct passwd *user_info) +{ +#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) + DBUG_ASSERT(user_info); #ifdef HAVE_INITGROUPS - initgroups((char*) user,ent->pw_gid); + initgroups((char*) user, user_info->pw_gid); #endif - if (setgid(ent->pw_gid) == -1) - { - sql_perror("setgid"); - unireg_abort(1); - } - uid=ent->pw_uid; + if (setgid(user_info->pw_gid) == -1) + { + sql_perror("setgid"); + unireg_abort(1); } - - if (setuid(uid) == -1) + if (setuid(user_info->pw_uid) == -1) { sql_perror("setuid"); unireg_abort(1); @@ -1096,6 +1110,24 @@ static void set_user(const char *user) #endif } +static void set_effective_user(struct passwd *user_info) +{ +#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) + DBUG_ASSERT(user_info); + if (setregid((gid_t)-1,user_info->pw_gid) == -1) + { + sql_perror("setregid"); + unireg_abort(1); + } + if (setreuid((uid_t)-1,user_info->pw_uid) == -1) + { + sql_perror("setreuid"); + unireg_abort(1); + } +#endif +} + + /* Change root user if started with --chroot */ static void set_root(const char *path) @@ -1171,7 +1203,18 @@ static void server_init(void) unireg_abort(1); } } - set_user(mysqld_user); // Works also with mysqld_user==NULL + + if ((user_info= check_user(mysqld_user))) + { +#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) + if (locked_in_memory && !getuid()) + set_effective_user(user_info); + else + set_user(mysqld_user, user_info); +#else + set_user(mysqld_user, user_info); +#endif + } #ifdef __NT__ /* create named pipe */ @@ -2037,8 +2080,7 @@ static void check_data_home(const char *path) /* ARGSUSED */ -extern "C" int my_message_sql(uint error, const char *str, - myf MyFlags __attribute__((unused))) +extern "C" int my_message_sql(uint error, const char *str, myf MyFlags) { NET *net; DBUG_ENTER("my_message_sql"); @@ -2051,7 +2093,7 @@ extern "C" int my_message_sql(uint error, const char *str, net->last_errno=error ? error : ER_UNKNOWN_ERROR; } } - else + if (!net || MyFlags & ME_NOREFRESH) sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */ DBUG_RETURN(0); } @@ -2466,8 +2508,13 @@ You should consider changing lower_case_table_names to 1 or 2", } ha_key_cache(); #if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) - if (locked_in_memory && !geteuid()) + if (locked_in_memory && !getuid()) { + if (setreuid((uid_t)-1,0) == -1) + { // this should never happen + sql_perror("setreuid"); + unireg_abort(1); + } if (mlockall(MCL_CURRENT)) { if (global_system_variables.log_warnings) @@ -2475,6 +2522,8 @@ You should consider changing lower_case_table_names to 1 or 2", } else locked_in_memory=1; + if (user_info) + set_user(mysqld_user, user_info); } #else locked_in_memory=0; @@ -2669,6 +2718,13 @@ server."); pthread_mutex_unlock(&LOCK_thread_count); } #else +#ifdef __WIN__ + if ( !have_tcpip || opt_disable_networking) + { + sql_print_error("TCP/IP unavailable or disabled with --skip-networking; no available interfaces"); + unireg_abort(1); + } +#endif handle_connections_sockets(0); #ifdef EXTRA_DEBUG2 sql_print_error("Exiting main thread"); @@ -3464,12 +3520,14 @@ enum options_mysqld { OPT_INNODB_LOG_BUFFER_SIZE, OPT_INNODB_BUFFER_POOL_SIZE, OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE, + OPT_INNODB_MAX_PURGE_LAG, OPT_INNODB_FILE_IO_THREADS, OPT_INNODB_LOCK_WAIT_TIMEOUT, OPT_INNODB_THREAD_CONCURRENCY, OPT_INNODB_FORCE_RECOVERY, OPT_INNODB_STATUS_FILE, OPT_INNODB_MAX_DIRTY_PAGES_PCT, + OPT_INNODB_TABLE_LOCKS, OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, @@ -3643,7 +3701,16 @@ struct my_option my_long_options[] = {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, "Percentage of dirty pages allowed in bufferpool", (gptr*) &srv_max_buf_pool_modified_pct, (gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, - + {"innodb_max_purge_lag", OPT_INNODB_MAX_PURGE_LAG, + "Desired maximum length of the purge queue (0 = no limit)", + (gptr*) &srv_max_purge_lag, + (gptr*) &srv_max_purge_lag, 0, GET_LONG, REQUIRED_ARG, 0, 0, ~0L, + 0, 1L, 0}, + {"innodb_table_locks", OPT_INNODB_TABLE_LOCKS, + "Enable InnoDB locking in LOCK TABLES", + (gptr*) &global_system_variables.innodb_table_locks, + (gptr*) &global_system_variables.innodb_table_locks, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -4088,7 +4155,7 @@ replicating a LOAD DATA INFILE command", {"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_ULL, - REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, + REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, UINT_MAX32, 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.", @@ -5119,8 +5186,8 @@ static void get_options(int argc,char **argv) { int ho_error; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, - option_error_reporter))) + my_getopt_error_reporter= option_error_reporter; + if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); #if defined(HAVE_BROKEN_REALPATH) diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc index cc9147fe90a..df77d0347f2 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -132,6 +132,10 @@ net_printf(NET *net, uint errcode, ...) length=sizeof(net->last_error)-1; /* purecov: inspected */ va_end(args); + /* Replication slave relies on net->last_* to see if there was error */ + net->last_errno= errcode; + strmake(net->last_error, text_pos, sizeof(net->last_error)-1); + if (net->vio == 0) { if (thd && thd->bootstrap) diff --git a/sql/records.cc b/sql/records.cc index 415e75a467b..98aede52416 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -131,17 +131,26 @@ void end_read_record(READ_RECORD *info) static int rr_quick(READ_RECORD *info) { - int tmp=info->select->quick->get_next(); - if (tmp) + int tmp; + while ((tmp= info->select->quick->get_next())) { - if (tmp == HA_ERR_END_OF_FILE) - tmp= -1; - else + if (info->thd->killed) { - if (info->print_error) - info->file->print_error(tmp,MYF(0)); - if (tmp < 0) // Fix negative BDB errno - tmp=1; + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + return 1; + } + if (tmp != HA_ERR_RECORD_DELETED) + { + if (tmp == HA_ERR_END_OF_FILE) + tmp= -1; + else + { + if (info->print_error) + info->file->print_error(tmp,MYF(0)); + if (tmp < 0) // Fix negative BDB errno + tmp=1; + } + break; } } return tmp; @@ -249,9 +258,10 @@ static int init_rr_cache(READ_RECORD *info) rec_cache_size=info->cache_records*info->reclength; info->rec_cache_size=info->cache_records*info->ref_length; + // We have to allocate one more byte to use uint3korr (see comments for it) if (info->cache_records <= 2 || !(info->cache=(byte*) my_malloc_lock(rec_cache_size+info->cache_records* - info->struct_length, + info->struct_length+1, MYF(0)))) DBUG_RETURN(1); #ifdef HAVE_purify diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 604938a8ed0..9fa6ea843f1 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -14,8 +14,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// Sasha Pachev <sasha@mysql.com> is currently in charge of this file - #include "mysql_priv.h" #include "repl_failsafe.h" #include "sql_repl.h" diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h index ae8bb2bc4d5..eb0e97c2820 100644 --- a/sql/repl_failsafe.h +++ b/sql/repl_failsafe.h @@ -1,3 +1,19 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha + + 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 */ + #ifndef REPL_FAILSAFE_H #define REPL_FAILSAFE_H diff --git a/sql/set_var.cc b/sql/set_var.cc index 4b66a621f62..d5aadbfbdab 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -263,6 +263,10 @@ sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", #ifdef HAVE_INNOBASE_DB sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); +sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag", + &srv_max_purge_lag); +sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks", + &SV::innodb_table_locks); #endif @@ -449,6 +453,8 @@ sys_var *sys_variables[]= &sys_os, #ifdef HAVE_INNOBASE_DB &sys_innodb_max_dirty_pages_pct, + &sys_innodb_max_purge_lag, + &sys_innodb_table_locks, #endif &sys_unique_checks }; @@ -520,6 +526,8 @@ struct show_var_st init_vars[]= { {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, + {sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS}, + {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index b6737df91e1..88ecaed386b 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -1,3 +1,19 @@ +/* Copyright (C) 2003 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 */ + /* Modifikoval Petr -B©najdr, snajdr@pvt.net, snajdr@cpress.cz v.0.01 ISO LATIN-8852-2 diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index ba50c78e92c..6210bf7788c 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ /* Knud Riishøjgård knudriis@post.tele.dk 99 && Carsten H. Pedersen, carsten.pedersen@bitbybit.dk oct. 1999 / aug. 2001. */ diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 1b9c1025e69..c3607f4cd0f 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -1,6 +1,20 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind +/* Copyright (C) 2003 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 */ + +/* Dutch error messages (share/dutch/errmsg.txt) 2001-08-02 - Arjen Lentz (agl@bitbike.com) Completed earlier partial translation; worked on consistency and spelling. diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index edbf2357ff8..796751210dc 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ "hashchk", "isamchk", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 8ec5d4b29f0..8157a33836e 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -1,9 +1,22 @@ +/* Copyright (C) 2003 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 */ + /* - Copyright Abandoned 1997 MySQL AB - This file is public domain and comes with NO WARRANTY of any kind Esialgne tõlge: Tõnu Samuel (tonu@spam.ee) Parandanud ja täiendanud: Indrek Siitan (tfr@mysql.com) - */ "hashchk", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 3c5c827aa62..3c88ccc0378 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ "hashchk", "isamchk", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 3960dcc2122..91f3f91a464 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -1,6 +1,20 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind +/* Copyright (C) 2003 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 */ + +/* Dirk Munzinger (dmun@4t2.com) Version: 07.06.2001 */ diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 3e9a68f2b4b..aff7f8ba3c2 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ "hashchk", "isamchk", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 9da878981b0..60dc3204bb4 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -1,7 +1,23 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB +/* Copyright (C) 2003 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 */ + +/* Translated by Feher Peter. Forditotta Feher Peter (feherp@mail.matav.hu) 1998 Updated May, 2000 - This file is public domain and comes with NO WARRANTY of any kind */ +*/ "hashchk", "isamchk", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 30dff93ebef..c51c69cf298 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ "hashchk", "isamchk", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 7e267261a2e..fb604923e4e 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -1,5 +1,20 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind +/* Copyright (C) 2003 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 */ + +/* 3.22.10-beta euc-japanese (ujis) text */ diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 1ad5432f4db..764cbb78740 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This ÈÀÏ is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ "hashchk", "isamchk", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 234a53b53fb..424530ecf87 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ /* Roy-Magne Mo rmo@www.hivolda.no 97 */ diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index e582786dc6e..73314ea647b 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ /* Roy-Magne Mo rmo@www.hivolda.no 97 */ diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index a4d11046ea4..f24a54ec8e8 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -1,6 +1,20 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind +/* Copyright (C) 2003 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 */ + +/* Changed by Jaroslaw Lewandowski <jotel@itnet.com.pl> Charset ISO-8859-2 */ diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 14c14270dc0..2810ac134b1 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -1,6 +1,21 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ + /* Updated by Thiago Delgado Pinto - thiagodp@ieg.com.br - 06.07.2002 */ + "hashchk", "isamchk", "NÃO", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 8d2decdf23f..552b532c0a2 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -1,6 +1,20 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind +/* Copyright (C) 2003 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 */ + +/* Translated into Romanian by Stefan Saroiu e-mail: tzoompy@cs.washington.edu */ diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 42845b57d76..172ee97c883 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -1,6 +1,22 @@ -/* Copyright 2003 MySQL AB; +/* Copyright (C) 2003 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 */ + +/* Translation done in 2003 by Egor Egorov; Ensita.NET, http://www.ensita.net/ - This file is public domain and comes with NO WARRANTY of any kind */ +*/ /* charset: KOI8-R */ "hashchk", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 52ed69a238d..8467fad5b11 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ /* Translated from both E n g l i s h & C z e c h error messages diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 2ed3c19b68e..4ab76a64ca7 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -1,5 +1,20 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind +/* Copyright (C) 2003 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 */ + +/* Traduccion por Miguel Angel Fernandez Roiz -- LoboCom Sistemas, s.l. From June 28, 2001 translated by Miguel Solorzano miguel@mysql.com */ "hashchk", diff --git a/sql/share/swedish/errmsg.OLD b/sql/share/swedish/errmsg.OLD deleted file mode 100644 index 3dd14c8b613..00000000000 --- a/sql/share/swedish/errmsg.OLD +++ /dev/null @@ -1,221 +0,0 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ - -"hashchk", -"isamchk", -"NO", -"YES", -"Kan inte skapa filen: '%-.64s' (Felkod: %d)", -"Kan inte skapa tabellen: '%-.64s' (Felkod: %d)", -"Kan inte skapa databasen '%-.64s'. (Felkod: %d)", -"Databasen '%-.64s' existerar redan", -"Kan inte radera databasen '%-.64s'. Databasen finns inte", -"Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)", -"Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)", -"Kan inte radera filen: '%-.64s' (Felkod: %d)", -"Hittar inte posten i systemregistret", -"Kan inte läsa filinformationen (stat) från '%-.64s' (Felkod: %d)", -"Kan inte inte läsa aktivt bibliotek. (Felkod: %d)", -"Kan inte låsa filen. (Felkod: %d)", -"Kan inte använda: '%-.64s'. (Felkod: %d)", -"Hittar inte filen: '%-.64s'. (Felkod: %d)", -"Kan inte läsa från bibliotek '%-.64s'. (Felkod: %d)", -"Kan inte byta till: '%-.64s'. (Felkod: %d)", -"Posten har förändrats sedan den lästes i register '%-.64s'", -"Disken är full (%s). Väntar tills det finns ledigt utrymme....", -"Kan inte skriva, dubbel söknyckel i register '%-.64s'", -"Fick fel vid stängning av '%-.64s' (Felkod: %d)", -"Fick fel vid läsning av '%-.64s' (Felkod %d)", -"Kan inte byta namn från '%-.64s' till '%-.64s' (Felkod: %d)", -"Fick fel vid skrivning till '%-.64s' (Felkod %d)", -"'%-.64s' är låst mot användning", -"Sorteringen avbruten", -"Formulär '%-.64s' finns inte i '%-.64s'", -"Fick felkod %d från databashanteraren", -"Registrets databas har inte denna facilitet", -"Hittar inte posten", -"Felaktig fil: '%-.64s'", -"Fatalt fel vid hantering av register '%-.64s'. Kör en reparation", -"Gammal nyckelfil '%-.64s'; Reparera registret", -"'%-.64s' är skyddad mot förändring", -"Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)", -"Sorteringsbufferten räcker inte till. Kontrollera startparametrarna", -"Oväntat filslut vid läsning från '%-.64s' (Felkod: %d)", -"För många anslutningar", -"Fick slut på minnet. Kontrollera ifall mysqld eller någon annan process använder allt tillgängligt minne. Ifall inte, försök använda 'ulimit' eller allokera mera swap", -"Kan inte hitta 'hostname' för din adress", -"Fel vid initiering av kommunikationen med klienten", -"Användare '%-.32s@%-.64s' är ej berättigad att använda databasen %-.64s", -"Användare '%-.32s@%-.64s' är ej berättigad att logga in (Använder lösen: %s)", -"Ingen databas i användning", -"Okänt commando", -"Kolumn '%-.64s' får inte vara NULL", -"Okänd database '%-.64s'", -"Tabellen '%-.64s' finns redan", -"Okänd tabell '%-.64s'", -"Kolumn: '%-.64s' i %s är inte unik", -"Servern går nu ned", -"Okänd kolumn '%-.64s' i %s", -"'%-.64s' finns inte i GROUP BY", -"Kan inte använda GROUP BY med '%-.64s'", -"Kommandot har både sum functions och enkla funktioner", -"Antalet kolumner motsvarar inte antalet värden", -"Kolumn namn '%-.64s' är för långt", -"Kolumn namn '%-64s finns flera gånger", -"Nyckel namn '%-.64s' finns flera gånger", -"Dubbel nyckel '%-.64s' för nyckel: %d", -"Felaktigt kolumn typ för kolumn: '%-.64s'", -"%s nära '%-.64s' på rad %d", -"Frågan var tom", -"Icke unikt tabell/alias: '%-.64s'", -"Ogiltigt DEFAULT värde för '%-.64s'", -"Flera PRIMARY KEY använda", -"För många nycklar använda. Man får ha högst %d nycklar", -"För många nyckel delar använda. Man får ha högst %d nyckeldelar", -"För lång nyckel. Högsta tillåtna nyckellängd är %d", -"Nyckel kolumn '%-.64s' finns inte", -"En BLOB '%-.64s' kan inte vara nyckel med den använda tabellen typen", -"För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället", -"Det får finnas endast ett AUTO_INCREMENT fält och detta måste vara en nyckel", -"%s: klar att ta emot klienter\n", -"%s: Normal avslutning\n", -"%s: Fick signal %d. Avslutar!\n", -"%s: Avslutning klar\n", -"%s: Stänger av tråd %ld användare: '%-.64s'\n", -"Kan inte skapa IP socket", -"Tabellen '%-.64s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen", -"Fält separatorerna är inte emotsägande eller för långa. Kontrollera mot manualen", -"Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'." -"Textfilen '%' måste finnas i databas biblioteket eller vara läsbar för alla", -"Filen '%-.64s' existerar redan", -"Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld", -"Rader: %ld Dubletter: %ld", -"Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden", -"Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället", -"Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns", -"Rader: %ld Dubletter: %ld Varningar: %ld", -"INSERT table '%-.64s' får inte finnas i FROM tabell-listan", -"Finns inget thread med id %lu", -"Du är inte ägare till thread %lu", -"Inga tabeller angivna", -"För många alternativ till kolumn %s för SET", -"Kan inte generera ett unikt filnamn %s.(1-999)\n", -"Tabell '%-.64s' kan inte uppdateras emedan den är låst för läsning", -"Tabell '%-.64s' är inte låst med LOCK TABLES", -"BLOB fält '%-.64s' kan inte ha ett DEFAULT värde" -"Felaktigt databas namn '%-.64s'", -"Felaktigt tabell namn '%-.64s'", -"Den angivna frågan skulle troligen ta mycket long tid! Kontrollar din WHERE och använd SET OPTION SQL_BIG_SELECTS=1 ifall du vill hantera stora joins", -"Oidentifierat fel", -"Okänd procedur: %s", -"Felaktigt antal parametrar till procedur %s", -"Felaktiga parametrar till procedur %s", -"Okänd tabell '%-.64s' i '%-.64s'", -"Fält '%-.64s' är redan använt", -"Felaktig användning av SQL grupp function", -"Tabell '%-.64s' har en extension som inte finns i denna version av MySQL", -"Tabeller måste ha minst 1 kolumn", -"Tabellen '%-.64s' är full", -"Okänt karaktärset: '%-.64s'", -"För många tabeller. MySQL can ha högst %d tabeller i en och samma join" -"För många fält", -"För stor total rad längd. Den högst tillåtna rad-längden, förutom BLOBs, är %d. Ändra några av dina fält till BLOB", -"Tråd-stacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld -O thread_stack=#' ifall du behöver en större stack", -"Felaktigt referens i OUTER JOIN. Kontrollera ON uttrycket", -"Kolumn '%-.32s' är använd med UNIQUE eller INDEX men är inte definerad med NOT NULL", -"Kan inte ladda funktionen '%-.64s'", -"Kan inte initialisera funktionen '%-.64s'; '%-.80s'", -"Man får inte ange sökväg för dynamiska bibliotek", -"Funktionen '%-.64s' finns redan", -"Kan inte öppna det dynamiska biblioteket '%-.64s' (Felkod: %d %s)", -"Hittar inte funktionen '%-.64s' in det dynamiska biblioteket", -"Funktionen '%-.64s' är inte definierad", -"Denna dator '%-.64s' är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna", -"Denna dator '%-.64s' har inte privileger att använda denna MySQL server", -"Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord", -"För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql databasen", -"Hittade inte användaren i 'user' tabellen", -"Rader: %ld Uppdaterade: %ld Varningar: %ld", -"Kan inte skapa en ny tråd (errno %d)" -"Antalet kolumner motsvarar inte antalet värden på rad: %ld", -"Kunde inte stänga och öppna tabell: '%-.64s', -"Felaktig använding av NULL", -"Fix fel '%-.64s' från REGEXP", -"Man får ha både GROUP kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY del", -"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'", -"%-.16s ej tillåtet för '%-.32s@%-.64s' för tabell '%-.64s'", -"%-.16s ej tillåtet för '%-.32s@%-.64s'\n för kolumn '%-.64s' i tabell '%-.64s'", -"Felaktigt GRANT privilegium använt", -"Felaktigt maskinnamn eller användarnamn använt med GRANT", -"Det finns ingen tabell som heter '%-64s.%s'" -"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s' för tabell '%-.64s'", -"Du kan inte använda detta kommando med denna MySQL version", -"Du har något fel i din syntax", -"DELAYED INSERT tråden kunde inte låsa tabell '%-.64s'", -"Det finns redan 'max_delayed_threads' trådar i använding", -"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.64s' (%s)", -"Kommunkationspaketet är större än 'max_allowed_packet'", -"Fick läsfel från klienten vid läsning från 'PIPE'", -"Fick fatalt fel från 'fcntl()'", -"Kommunikationspaketen kom i fel ordning", -"Kunde inte packa up kommunikationspaketet", -"Fick ett fel vid läsning från klienten", -"Fick 'timeout' vid läsning från klienten", -"Fick ett fel vid skrivning till klienten", -"Fick 'timeout' vid skrivning till klienten", -"Resultat strängen är längre än max_allowed_packet", -"Den använda tabell typen kan inte hantera BLOB/TEXT kolumner", -"Den använda tabell typen kan inte hantera AUTO_INCREMENT kolumner", -"INSERT DELAYED kan inte användas med tabell '%-.64s', emedan den är låst med LOCK TABLES", -"Felaktigt column namn '%-.100s'", -"Den använda tabell typen kan inte indexera kolumn '%-.64s'", -"Tabellerna i MERGE tabellen är inte identiskt definierade", -"Kan inte skriva till tabell '%-.64s'; UNIQUE test", -"Du har inte angett en nyckel längd för BLOB '%-.64s'", -"Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället", -"Resultet bestod av mera än en rad", -"Denna tabell typ kräver en PRIMARY KEY", -"Denna version av MySQL är inte kompilerad med RAID", -"Du använder 'säker uppdaterings mod' och försökte uppdatera en table utan en WHERE sats som använder sig av en nyckel", -"Nyckel '%-.64s' finns inte in tabell '%-.64s'", -"Kan inte öppna tabellen", -"Tabellhanteraren för denna tabell kan inte göra check/repair", -"Du får inte utföra detta kommando i en transaktion", -"Fick fel %d vid COMMIT", -"Fick fel %d vid ROLLBACK", -"Fick fel %d vid FLUSH_LOGS", -"Fick fel %d vid CHECKPOINT", -"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.32s' Host: '%-.64s' (%.-64s)", -"Tabellhanteraren klarar inte en binär kopiering av tabellen", -"Binärloggen stängdes medan vi gjorde FLUSH MASTER", -"Failed rebuilding the index of dumped table '%-.64s'", -"Fick en master: '%-.64s'", -"Fick nätverksfel vid läsning från master", -"Fick nätverksfel vid skrivning till master", -"Hittar inte ett FULLTEXT index i kolumnlistan", -"Kan inte exekvera kommandot emedan du har en låst tabell eller an aktiv transaktion", -"Okänd system variabel '%-.64'", -"Tabell '%-.64s' är crashad och bör repareras med REPAIR TABLE", -"Tabell '%-.64s' är crashad och senast (automatiska?) reparation misslyckades", -"Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK", -"Transaktionen krävde mera än 'max_binlog_cache_size' minne. Utöka denna mysqld variabel och försök på nytt", -"Denna operation kan inte göras under replikering; Gör SLAVE STOP först", -"Denna operation kan endast göras under replikering; Konfigurera slaven och gör SLAVE START", -"Servern är inte konfigurerade som en replikations slav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO", -"Kunde inte initializera replications-strukturerna. Kontrollera privilegerna för 'master.info'", -"Kunde inte starta en tråd för replikering", -"Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar", -"Man kan endast använda konstant-uttryck med SET", -"Fick inte ett lås i tid", -"Antal lås överskrider antalet reserverade lås", -"Updaterings-lås kan inte göras när man använder READ UNCOMMITTED", -"DROP DATABASE är inte tillåtet när man har ett globalt läs-lås", -"CREATE DATABASE är inte tillåtet när man har ett globalt läs-lås", -"Felaktiga argument till %s", -"%-.32s@%-.64s har inte rättigheter att skapa nya användare", -"Fick fel vid anslutning till master: %-.128s", -"Fick fel vid utförande av command på mastern: %-.128s", -"Fick fel vid utförande av %s: %-.128s", -"Felaktig använding av %s and %s", -"SELECT kommandona har olika antal kolumner" -"Kan inte utföra kommandot emedan du har ett READ lås", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 4fd05875b43..352a226ef23 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -1,5 +1,18 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - This file is public domain and comes with NO WARRANTY of any kind */ +/* Copyright (C) 2003 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 */ "hashchk", "isamchk", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 6036f4be2d5..188523ecf45 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -1,6 +1,20 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB - * This ÆÁÊÌ is public domain and comes with NO WARRANTY of any kind - * +/* Copyright (C) 2003 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 */ + +/* * Ukrainian translation by Roman Festchook <roma@orta.zt.ua> * Encoding: KOI8-U * Version: 13/09/2001 mysql-3.23.41 diff --git a/sql/slave.cc b/sql/slave.cc index 4416a2544ef..18e0ec5929f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1124,6 +1124,7 @@ slaves can't replicate a 5.0 or newer master."; Used by fetch_master_table (used by LOAD TABLE tblname FROM MASTER and LOAD DATA FROM MASTER). Drops the table (if 'overwrite' is true) and recreates it from the dump. Honours replication inclusion/exclusion rules. + db must be non-zero (guarded by assertion). RETURN VALUES 0 success @@ -1134,8 +1135,8 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, const char* table_name, bool overwrite) { ulong packet_len = my_net_read(net); // read create table statement - char *query; - char* save_db; + char *query, *save_db; + uint32 save_db_length; Vio* save_vio; HA_CHECK_OPT check_opt; TABLE_LIST tables; @@ -1193,9 +1194,13 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, thd->proc_info = "Creating table from master dump"; // save old db in case we are creating in a different database save_db = thd->db; + save_db_length= thd->db_length; thd->db = (char*)db; + DBUG_ASSERT(thd->db); + thd->db_length= strlen(thd->db); mysql_parse(thd, thd->query, packet_len); // run create table thd->db = save_db; // leave things the way the were before + thd->db_length= save_db_length; thd->options = save_options; if (thd->query_error) @@ -2689,7 +2694,7 @@ err: IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff)); VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety - thd->query_length = 0; + thd->query_length= thd->db_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (mysql) { @@ -2838,7 +2843,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ err: VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety - thd->query_length = 0; + thd->query_length= thd->db_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->proc_info = "Waiting for slave mutex on exit"; pthread_mutex_lock(&rli->run_lock); diff --git a/sql/slave.h b/sql/slave.h index 0cd8545338d..eb54e258a96 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -1,3 +1,19 @@ +/* Copyright (C) 2000-2003 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 */ + #ifndef SLAVE_H #define SLAVE_H diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 58d0fe9a7fa..67ca62357ec 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -106,7 +106,7 @@ static HASH acl_check_hosts, hash_tables; static DYNAMIC_ARRAY acl_wild_hosts; static hash_filo *acl_cache; static uint grant_version=0; -static ulong get_access(TABLE *form,uint fieldnr); +static ulong get_access(TABLE *form, uint fieldnr, uint *next_field); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); static ulong get_sort(uint count,...); static void init_check_host(void); @@ -191,7 +191,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ACL_HOST host; update_hostname(&host.host,get_field(&mem, table,0)); host.db= get_field(&mem, table,1); - host.access= get_access(table,2); + host.access= get_access(table,2,0); host.access= fix_rights_for_db(host.access); host.sort= get_sort(2,host.host.hostname,host.db); #ifndef TO_BE_REMOVED @@ -241,14 +241,15 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) user.host.hostname ? user.host.hostname : ""); /* purecov: tested */ continue; /* purecov: tested */ } + uint next_field; get_salt_from_password(user.salt,user.password); - user.access=get_access(table,3) & GLOBAL_ACLS; + user.access=get_access(table,3,&next_field) & GLOBAL_ACLS; user.sort=get_sort(2,user.host.hostname,user.user); user.hostname_length= (user.host.hostname ? (uint) strlen(user.host.hostname) : 0); if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ { - char *ssl_type=get_field(&mem, table, 24); + char *ssl_type=get_field(&mem, table, next_field++); if (!ssl_type) user.ssl_type=SSL_TYPE_NONE; else if (!strcmp(ssl_type, "ANY")) @@ -258,16 +259,16 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) else /* !strcmp(ssl_type, "SPECIFIED") */ user.ssl_type=SSL_TYPE_SPECIFIED; - user.ssl_cipher= get_field(&mem, table, 25); - user.x509_issuer= get_field(&mem, table, 26); - user.x509_subject= get_field(&mem, table, 27); + user.ssl_cipher= get_field(&mem, table, next_field++); + user.x509_issuer= get_field(&mem, table, next_field++); + user.x509_subject= get_field(&mem, table, next_field++); - char *ptr = get_field(&mem, table, 28); - user.user_resource.questions=atoi(ptr); - ptr = get_field(&mem, table, 29); - user.user_resource.updates=atoi(ptr); - ptr = get_field(&mem, table, 30); - user.user_resource.connections=atoi(ptr); + char *ptr = get_field(&mem, table, next_field++); + user.user_resource.questions= ptr ? atoi(ptr) : 0; + ptr = get_field(&mem, table, next_field++); + user.user_resource.updates= ptr ? atoi(ptr): 0; + ptr = get_field(&mem, table, next_field++); + user.user_resource.connections=ptr ? atoi(ptr) : 0; if (user.user_resource.questions || user.user_resource.updates || user.user_resource.connections) mqh_used=1; @@ -313,7 +314,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) continue; } db.user=get_field(&mem, table,2); - db.access=get_access(table,3); + db.access=get_access(table,3,0); db.access=fix_rights_for_db(db.access); db.sort=get_sort(3,db.host.hostname,db.db,db.user); #ifndef TO_BE_REMOVED @@ -423,11 +424,24 @@ void acl_reload(THD *thd) /* Get all access bits from table after fieldnr - We know that the access privileges ends when there is no more fields - or the field is not an enum with two elements. + + IMPLEMENTATION + We know that the access privileges ends when there is no more fields + or the field is not an enum with two elements. + + SYNOPSIS + get_access() + form an open table to read privileges from. + The record should be already read in table->record[0] + fieldnr number of the first privilege (that is ENUM('N','Y') field + next_field on return - number of the field next to the last ENUM + (unless next_field == 0) + + RETURN VALUE + privilege mask */ -static ulong get_access(TABLE *form, uint fieldnr) +static ulong get_access(TABLE *form, uint fieldnr, uint *next_field) { ulong access_bits=0,bit; char buff[2]; @@ -437,12 +451,14 @@ static ulong get_access(TABLE *form, uint fieldnr) for (pos=form->field+fieldnr, bit=1; *pos && (*pos)->real_type() == FIELD_TYPE_ENUM && ((Field_enum*) (*pos))->typelib->count == 2 ; - pos++ , bit<<=1) + pos++, fieldnr++, bit<<=1) { (*pos)->val_str(&res,&res); if (toupper(res[0]) == 'Y') access_bits|= bit; } + if (next_field) + *next_field=fieldnr; return access_bits; } @@ -469,7 +485,7 @@ static ulong get_sort(uint count,...) uint chars= 0; uint wild_pos= 0; /* first wildcard position */ - if (start= str) + if ((start= str)) { for (; *str ; str++) { @@ -1395,7 +1411,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, if (priv & rights) // set requested privileges (*tmp_field)->store(&what,1); } - rights=get_access(table,3); + rights=get_access(table,3,0); DBUG_PRINT("info",("table->fields: %d",table->fields)); if (table->fields >= 31) /* From 4.0.0 we have more fields */ { @@ -1554,7 +1570,7 @@ static int replace_db_table(TABLE *table, const char *db, if (priv & store_rights) // do it if priv is chosen table->field [i]->store(&what,1); // set requested privileges } - rights=get_access(table,3); + rights=get_access(table,3,0); rights=fix_rights_for_db(rights); if (old_row_exists) @@ -1571,7 +1587,7 @@ static int replace_db_table(TABLE *table, const char *db, goto table_error; /* purecov: deadcode */ } } - else if ((error=table->file->write_row(table->record[0]))) + else if (rights && (error=table->file->write_row(table->record[0]))) { if (error && error != HA_ERR_FOUND_DUPP_KEY) /* purecov: inspected */ goto table_error; /* purecov: deadcode */ @@ -1581,6 +1597,7 @@ static int replace_db_table(TABLE *table, const char *db, if (old_row_exists) acl_update_db(combo.user.str,combo.host.str,db,rights); else + if (rights) acl_insert_db(combo.user.str,combo.host.str,db,rights); table->file->index_end(); DBUG_RETURN(0); diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 3847849d6a7..0723c274a17 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -810,6 +810,13 @@ void field_real::get_opt_type(String *answer, if (min_arg >= 0) answer->append(" UNSIGNED"); } + else if (item->decimals == NOT_FIXED_DEC) + { + if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX) + answer->append("FLOAT", 5); + else + answer->append("DOUBLE", 6); + } else { if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8fd7273fd78..ddc81053357 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -389,7 +389,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_close_list(thd, tables); + mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", ("Waiting for others threads to close their open tables")); @@ -816,8 +816,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, for (table=thd->temporary_tables; table ; table=table->next) { - if (table->key_length == key_length+8 && - !memcmp(table->table_cache_key,key,key_length+8)) + if (table->key_length == key_length + TMP_TABLE_KEY_EXTRA && + !memcmp(table->table_cache_key, key, + key_length + TMP_TABLE_KEY_EXTRA)) { if (table->query_id == thd->query_id) { @@ -826,6 +827,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, DBUG_RETURN(0); } table->query_id=thd->query_id; + DBUG_PRINT("info",("Using temporary table")); goto reset; } } @@ -840,6 +842,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->query_id != thd->query_id) { table->query_id=thd->query_id; + DBUG_PRINT("info",("Using locked table")); goto reset; } } @@ -859,7 +862,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, } /* close handler tables which are marked for flush */ - mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; @@ -941,6 +944,31 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, for (uint i=0 ; i < table->fields ; i++) table->field[i]->table_name=table->table_name; } +#if MYSQL_VERSION_ID < 40100 + /* + If per-connection "new" variable (represented by variables.new_mode) + is set then we should pretend that the length of TIMESTAMP field is 19. + The cheapest (from perfomance viewpoint) way to achieve that is to set + field_length of all Field_timestamp objects in a table after opening + it (to 19 if new_mode is true or to original field length otherwise). + We save value of new_mode variable in TABLE::timestamp_mode to + not perform this setup if new_mode value is the same between sequential + table opens. + */ + my_bool new_mode= thd->variables.new_mode; + if (table->timestamp_mode != new_mode) + { + for (uint i=0 ; i < table->fields ; i++) + { + Field *field= table->field[i]; + + if (field->type() == FIELD_TYPE_TIMESTAMP) + field->field_length= new_mode ? 19 : + ((Field_timestamp *)(field))->orig_field_length; + } + table->timestamp_mode= new_mode; + } +#endif /* These variables are also set in reopen_table() */ table->tablenr=thd->current_tablenr++; table->used_fields=0; @@ -1226,7 +1254,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 5118421464b..f503a63e752 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -971,9 +971,38 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) for (; block_table != block_table_end; block_table++) { TABLE_LIST table_list; - bzero((char*) &table_list,sizeof(table_list)); + TABLE *tmptable; Query_cache_table *table = block_table->parent; + + /* + Check that we have not temporary tables with same names of tables + of this query. If we have such tables, we will not send data from + query cache, because temporary tables hide real tables by which + query in query cache was made. + */ + for (tmptable= thd->temporary_tables; tmptable ; tmptable= tmptable->next) + { + if (tmptable->key_length - TMP_TABLE_KEY_EXTRA == table->key_len() && + !memcmp(tmptable->table_cache_key, table->data(), + table->key_len())) + { + DBUG_PRINT("qcache", + ("Temporary table detected: '%s.%s'", + table_list.db, table_list.alias)); + STRUCT_UNLOCK(&structure_guard_mutex); + /* + We should not store result of this query because it contain + temporary tables => assign following variable to make check + faster. + */ + thd->safe_to_cache_query=0; + BLOCK_UNLOCK_RD(query_block); + DBUG_RETURN(-1); + } + } + + bzero((char*) &table_list,sizeof(table_list)); table_list.db = table->db(); table_list.alias= table_list.real_name= table->table(); if (check_table_access(thd,SELECT_ACL,&table_list,1)) @@ -1843,7 +1872,6 @@ inline ulong Query_cache::get_min_append_result_data_size() /* Allocate one or more blocks to hold data */ - my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, ulong data_len, Query_cache_block *query_block, @@ -1851,55 +1879,55 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, { ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) + ALIGN_SIZE(sizeof(Query_cache_result))); - ulong len= data_len + all_headers_len; - ulong align_len= ALIGN_SIZE(len); - DBUG_ENTER("Query_cache::allocate_data_chain"); - DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu", - data_len, all_headers_len)); - ulong min_size = (first_block_arg ? get_min_first_result_data_size(): get_min_append_result_data_size()); - *result_block = allocate_block(max(min_size, align_len), - min_result_data_size == 0, - all_headers_len + min_result_data_size, - 1); - my_bool success = (*result_block != 0); - if (success) + Query_cache_block *prev_block= NULL; + Query_cache_block *new_block; + DBUG_ENTER("Query_cache::allocate_data_chain"); + DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu", + data_len, all_headers_len)); + + do { - Query_cache_block *new_block= *result_block; + ulong len= data_len + all_headers_len; + ulong align_len= ALIGN_SIZE(len); + + if (!(new_block= allocate_block(max(min_size, align_len), + min_result_data_size == 0, + all_headers_len + min_result_data_size, + 1))) + { + DBUG_PRINT("warning", ("Can't allocate block for results")); + DBUG_RETURN(FALSE); + } + new_block->n_tables = 0; - new_block->used = 0; + new_block->used = min(len, new_block->length); new_block->type = Query_cache_block::RES_INCOMPLETE; new_block->next = new_block->prev = new_block; Query_cache_result *header = new_block->result(); header->parent(query_block); - if (new_block->length < len) - { - /* - We got less memory then we need (no big memory blocks) => - Continue to allocated more blocks until we got everything we need. - */ - Query_cache_block *next_block; - if ((success = allocate_data_chain(&next_block, - len - new_block->length, - query_block, first_block_arg))) - double_linked_list_join(new_block, next_block); - } - if (success) - { - new_block->used = min(len, new_block->length); - - DBUG_PRINT("qcache", ("Block len %lu used %lu", + DBUG_PRINT("qcache", ("Block len %lu used %lu", new_block->length, new_block->used)); - } + + if (prev_block) + double_linked_list_join(prev_block, new_block); else - DBUG_PRINT("warning", ("Can't allocate block for continue")); - } - else - DBUG_PRINT("warning", ("Can't allocate block for results")); - DBUG_RETURN(success); + *result_block= new_block; + if (new_block->length >= len) + break; + + /* + We got less memory then we need (no big memory blocks) => + Continue to allocated more blocks until we got everything we need. + */ + data_len= len - new_block->length; + prev_block= new_block; + } while(1); + + DBUG_RETURN(TRUE); } /***************************************************************************** @@ -2067,6 +2095,7 @@ Query_cache::insert_table(uint key_len, char *key, } char *db = header->db(); header->table(db + db_length + 1); + header->key_len(key_len); } Query_cache_block_table *list_root = table_block->table(0); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 0c6579250ab..454f0318c12 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -144,10 +144,13 @@ struct Query_cache_query struct Query_cache_table { char *tbl; + uint32 key_length; inline char *db() { return (char *) data(); } inline char *table() { return tbl; } inline void table(char *table) { tbl = table; } + inline uint32 key_len() { return key_length; } + inline void key_len(uint32 len) { key_length= len; } inline gptr data() { return (gptr)(((byte*)this)+ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index eb6e74a58c4..c829778151b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -78,9 +78,9 @@ extern "C" void free_user_var(user_var_entry *entry) ** Thread specific functions ****************************************************************************/ -THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), - insert_id_used(0),rand_used(0),in_lock_tables(0), - global_read_lock(0),bootstrap(0) +THD::THD():user_time(0),global_read_lock(0),fatal_error(0), + last_insert_id_used(0),insert_id_used(0),rand_used(0), + in_lock_tables(0),bootstrap(0) { host=user=priv_user=db=query=ip=0; host_or_ip= "connecting host"; @@ -90,6 +90,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), query_error=0; next_insert_id=last_insert_id=0; open_tables=temporary_tables=handler_tables=0; + hash_clear(&handler_tables_hash); current_tablenr=0; handler_items=0; tmp_table=0; @@ -215,11 +216,9 @@ void THD::cleanup(void) lock=locked_tables; locked_tables=0; close_thread_tables(this); } - if (handler_tables) - { - open_tables=handler_tables; handler_tables=0; - close_thread_tables(this); - } + mysql_ha_flush(this, (TABLE_LIST*) 0, + MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); + hash_free(&handler_tables_hash); close_temporary_tables(this); hash_free(&user_vars); if (global_read_lock) diff --git a/sql/sql_class.h b/sql/sql_class.h index 30947041b7d..4250ebdd568 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -338,6 +338,9 @@ struct system_variables my_bool low_priority_updates; my_bool new_mode; my_bool query_cache_wlock_invalidate; +#ifdef HAVE_INNOBASE_DB + my_bool innodb_table_locks; +#endif /* HAVE_INNOBASE_DB */ CONVERT *convert_set; }; @@ -421,6 +424,7 @@ public: and are still in use by this thread */ TABLE *open_tables,*temporary_tables, *handler_tables; + HASH handler_tables_hash; // TODO: document the variables below MYSQL_LOCK *lock,*locked_tables; ULL *ull; @@ -639,27 +643,6 @@ public: #define SYSTEM_THREAD_SLAVE_SQL 4 /* - Disables binary logging for one thread, and resets it back to what it was - before being disabled. - Some functions (like the internal mysql_create_table() when it's called by - mysql_alter_table()) must NOT write to the binlog (binlogging is done at the - at a later stage of the command already, and must be, for locking reasons); - so we internally disable it temporarily by creating the Disable_binlog - object and reset the state by destroying the object (don't forget that! or - write code so that the object gets automatically destroyed when leaving a - block, see example in sql_table.cc). -*/ -class Disable_binlog { -private: - THD *thd; - ulong save_options; - ulong save_master_access; -public: - Disable_binlog(THD *thd_arg); - ~Disable_binlog(); -}; - -/* Used to hold information about file and file structure in exchainge via non-DB file (...INTO OUTFILE..., ...LOAD DATA...) */ diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 3d877403813..c8874701aa1 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -385,6 +385,15 @@ err: } +/* + Changes the current database. + + NOTES + Do as little as possible in this function, as it is not called for the + replication slave SQL thread (for that thread, setting of thd->db is done + in ::exec_event() methods of log_event.cc). +*/ + bool mysql_change_db(THD *thd,const char *name) { int length, db_length; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 555e63b9e32..92193e3abf2 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -282,6 +282,8 @@ multi_delete::initialize_tables(JOIN *join) walk=walk->next; /* Don't use KEYREAD optimization on this table */ tbl->no_keyread=1; + /* Don't use record cache */ + tbl->no_cache= 1; tbl->used_keys= 0; if (tbl->file->has_transactions()) log_delayed= transactional_tables= 1; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 272289b6176..5bfcc897fc7 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -17,10 +17,6 @@ /* HANDLER ... commands - direct access to ISAM */ -#include "mysql_priv.h" -#include "sql_select.h" -#include <assert.h> - /* TODO: HANDLER blabla OPEN [ AS foobar ] [ (column-list) ] @@ -38,183 +34,399 @@ all the sql_alloc'ed memory. It's harder to work around... */ +/* + There are two containers holding information about open handler tables. + The first is 'thd->handler_tables'. It is a linked list of TABLE objects. + It is used like 'thd->open_tables' in the table cache. The trick is to + exchange these two lists during open and lock of tables. Thus the normal + table cache code can be used. + The second container is a HASH. It holds objects of the type TABLE_LIST. + Despite its name, no lists of tables but only single structs are hashed + (the 'next' pointer is always NULL). The reason for theis second container + is, that we want handler tables to survive FLUSH TABLE commands. A table + affected by FLUSH TABLE must be closed so that other threads are not + blocked by handler tables still in use. Since we use the normal table cache + functions with 'thd->handler_tables', the closed tables are removed from + this list. Hence we need the original open information for the handler + table in the case that it is used again. This information is handed over + to mysql_ha_open() as a TABLE_LIST. So we store this information in the + second container, where it is not affected by FLUSH TABLE. The second + container is implemented as a hash for performance reasons. Consequently, + we use it not only for re-opening a handler table, but also for the + HANDLER ... READ commands. For this purpose, we store a pointer to the + TABLE structure (in the first container) in the TBALE_LIST object in the + second container. When the table is flushed, the pointer is cleared. +*/ + +#include "mysql_priv.h" +#include "sql_select.h" +#include <assert.h> + +#define HANDLER_TABLES_HASH_SIZE 120 + +static enum enum_ha_read_modes rkey_to_rnext[]= + { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV }; + #define HANDLER_TABLES_HACK(thd) { \ TABLE *tmp=thd->open_tables; \ thd->open_tables=thd->handler_tables; \ thd->handler_tables=tmp; } -static TABLE **find_table_ptr_by_name(THD *thd,const char *db, - const char *table_name, - bool is_alias, bool dont_lock, - bool *was_flushed); +static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags); + + +/* + Get hash key and hash key length. -int mysql_ha_open(THD *thd, TABLE_LIST *tables) + SYNOPSIS + mysql_ha_hash_get_key() + tables Pointer to the hash object. + key_len_p (out) Pointer to the result for key length. + first Unused. + + DESCRIPTION + The hash object is an TABLE_LIST struct. + The hash key is the alias name. + The hash key length is the alias name length plus one for the + terminateing NUL character. + + RETURN + Pointer to the TABLE_LIST struct. +*/ + +static char *mysql_ha_hash_get_key(TABLE_LIST *tables, uint *key_len_p, + my_bool first __attribute__((unused))) { - HANDLER_TABLES_HACK(thd); - int err=open_tables(thd,tables); - HANDLER_TABLES_HACK(thd); - if (err) - return -1; + *key_len_p= strlen(tables->alias) + 1 ; /* include '\0' in comparisons */ + return tables->alias; +} - // there can be only one table in *tables - if (!(tables->table->file->table_flags() & HA_CAN_SQL_HANDLER)) - { - my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias); - mysql_ha_close(thd, tables,1); - return -1; - } - send_ok(&thd->net); - return 0; +/* + Free an hash object. + + SYNOPSIS + mysql_ha_hash_free() + tables Pointer to the hash object. + + DESCRIPTION + The hash object is an TABLE_LIST struct. + + RETURN + Nothing +*/ + +static void mysql_ha_hash_free(TABLE_LIST *tables) +{ + my_free((char*) tables, MYF(0)); } /* - Close a HANDLER table. + Open a HANDLER table. SYNOPSIS - mysql_ha_close() + mysql_ha_open() thd Thread identifier. - tables A list of tables with the first entry to close. - dont_send_ok Suppresses the commands' ok message and - error message and error return. - dont_lock Suppresses the normal locking of LOCK_open. + tables A list of tables with the first entry to open. + reopen Re-open a previously opened handler table. DESCRIPTION Though this function takes a list of tables, only the first list entry - will be closed. Broadcasts a COND_refresh condition. - If mysql_ha_close() is not called from the parser, 'dont_send_ok' - must be set. - If the caller did already lock LOCK_open, it must set 'dont_lock'. - - IMPLEMENTATION - find_table_ptr_by_name() closes the table, if a FLUSH TABLE is outstanding. - It returns a NULL pointer in this case, but flags the situation in - 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages - is suppressed. + will be opened. + 'reopen' is set when a handler table is to be re-opened. In this case, + 'tables' is the pointer to the hashed TABLE_LIST object which has been + saved on the original open. + 'reopen' is also used to suppress the sending of an 'ok' message or + error messages. RETURN - 0 ok - -1 error + 0 ok + != 0 error */ -int mysql_ha_close(THD *thd, TABLE_LIST *tables, - bool dont_send_ok, bool dont_lock, bool no_alias) +int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) { - TABLE **table_ptr; - bool was_flushed; - - table_ptr= find_table_ptr_by_name(thd, tables->db, tables->alias, - !no_alias, dont_lock, &was_flushed); - if (*table_ptr) + TABLE_LIST *hash_tables; + char *db; + char *name; + char *alias; + uint dblen; + uint namelen; + uint aliaslen; + int err; + DBUG_ENTER("mysql_ha_open"); + DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d", + tables->db, tables->real_name, tables->alias, + (int) reopen)); + + if (! hash_inited(&thd->handler_tables_hash)) + { + /* + HASH entries are of type TABLE_LIST. + */ + if (hash_init(&thd->handler_tables_hash, HANDLER_TABLES_HASH_SIZE, 0, 0, + (hash_get_key) mysql_ha_hash_get_key, + (hash_free_key) mysql_ha_hash_free, 0)) + goto err; + } + else if (! reopen) /* Otherwise we have 'tables' already. */ { - if (!dont_lock) - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, table_ptr)) + if (hash_search(&thd->handler_tables_hash, (byte*) tables->alias, + strlen(tables->alias) + 1)) { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); + DBUG_PRINT("info",("duplicate '%s'", tables->alias)); + if (! reopen) + my_printf_error(ER_NONUNIQ_TABLE, ER(ER_NONUNIQ_TABLE), + MYF(0), tables->alias); + goto err; } - if (!dont_lock) - VOID(pthread_mutex_unlock(&LOCK_open)); } - else if (!was_flushed && !dont_send_ok) + + /* + open_tables() will set 'tables->table' if successful. + It must be NULL for a real open when calling open_tables(). + */ + DBUG_ASSERT(! tables->table); + HANDLER_TABLES_HACK(thd); + err=open_tables(thd,tables); + HANDLER_TABLES_HACK(thd); + if (err) + goto err; + + /* There can be only one table in '*tables'. */ + if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER)) { - my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), - tables->alias, "HANDLER"); - return -1; + if (! reopen) + my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias); + mysql_ha_close(thd, tables); + goto err; + } + + if (! reopen) + { + /* copy the TABLE_LIST struct */ + dblen= strlen(tables->db) + 1; + namelen= strlen(tables->real_name) + 1; + aliaslen= strlen(tables->alias) + 1; + if (!(my_multi_malloc(MYF(MY_WME), + &hash_tables, sizeof(*hash_tables), + &db, dblen, + &name, namelen, + &alias, aliaslen, + NullS))) + goto err; + /* structure copy */ + *hash_tables= *tables; + hash_tables->db= db; + hash_tables->real_name= name; + hash_tables->alias= alias; + memcpy(hash_tables->db, tables->db, dblen); + memcpy(hash_tables->real_name, tables->real_name, namelen); + memcpy(hash_tables->alias, tables->alias, aliaslen); + + /* add to hash */ + if (hash_insert(&thd->handler_tables_hash, (byte*) hash_tables)) + { + mysql_ha_close(thd, tables); + goto err; + } } - if (!dont_send_ok) + + if (! reopen) send_ok(&thd->net); - return 0; + DBUG_PRINT("exit",("OK")); + DBUG_RETURN(0); + +err: + DBUG_PRINT("exit",("ERROR")); + DBUG_RETURN(-1); } /* - Close a list of HANDLER tables. + Close a HANDLER table. SYNOPSIS - mysql_ha_close_list() + mysql_ha_close() thd Thread identifier. - tables The list of tables to close. If NULL, - close all HANDLER tables. - flushed Close only tables which are marked flushed. - Used only if tables is NULL. + tables A list of tables with the first entry to close. DESCRIPTION - The list of HANDLER tables may be NULL, in which case all HANDLER - tables are closed. Broadcasts a COND_refresh condition, for - every table closed. If 'tables' is NULL and 'flushed' is set, - all HANDLER tables marked for flush are closed. - The caller must lock LOCK_open. - - IMPLEMENTATION - find_table_ptr_by_name() closes the table, if it is marked for flush. - It returns a NULL pointer in this case, but flags the situation in - 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages - is suppressed. + Though this function takes a list of tables, only the first list entry + will be closed. Broadcasts a COND_refresh condition. RETURN - 0 ok + 0 ok + != 0 error */ -int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed) +int mysql_ha_close(THD *thd, TABLE_LIST *tables) { - TABLE_LIST *tl_item; + TABLE_LIST *hash_tables; TABLE **table_ptr; + DBUG_ENTER("mysql_ha_close"); + DBUG_PRINT("enter",("'%s'.'%s' as '%s'", + tables->db, tables->real_name, tables->alias)); - if (tables) + if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, + (byte*) tables->alias, + strlen(tables->alias) + 1))) { - for (tl_item= tables ; tl_item; tl_item= tl_item->next) + /* + Though we could take the table pointer from hash_tables->table, + we must follow the thd->handler_tables chain anyway, as we need the + address of the 'next' pointer referencing this table + for close_thread_table(). + */ + for (table_ptr= &(thd->handler_tables); + *table_ptr && (*table_ptr != hash_tables->table); + table_ptr= &(*table_ptr)->next); + +#if MYSQL_VERSION_ID < 40100 + if (*tables->db && strcmp(hash_tables->db, tables->db)) { - mysql_ha_close(thd, tl_item, /*dont_send_ok*/ 1, - /*dont_lock*/ 1, /*no_alias*/ 1); + DBUG_PRINT("info",("wrong db")); + hash_tables= NULL; } - } - else - { - table_ptr= &(thd->handler_tables); - while (*table_ptr) + else +#endif { - if (! flushed || ((*table_ptr)->version != refresh_version)) + if (*table_ptr) { + VOID(pthread_mutex_lock(&LOCK_open)); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ VOID(pthread_cond_broadcast(&COND_refresh)); } - continue; + VOID(pthread_mutex_unlock(&LOCK_open)); } - table_ptr= &((*table_ptr)->next); + + hash_delete(&thd->handler_tables_hash, (byte*) hash_tables); } } - return 0; + + if (! hash_tables) + { +#if MYSQL_VERSION_ID < 40100 + char buff[MAX_DBKEY_LENGTH]; + if (*tables->db) + strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS); + else + strncpy(buff, tables->alias, sizeof(buff)); + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + buff, "HANDLER"); +#else + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + tables->alias, "HANDLER"); +#endif + DBUG_PRINT("exit",("ERROR")); + DBUG_RETURN(-1); + } + + send_ok(&thd->net); + DBUG_PRINT("exit", ("OK")); + DBUG_RETURN(0); } -static enum enum_ha_read_modes rkey_to_rnext[]= - { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV }; +/* + Read from a HANDLER table. + SYNOPSIS + mysql_ha_read() + thd Thread identifier. + tables A list of tables with the first entry to read. + mode + keyname + key_expr + ha_rkey_mode + cond + select_limit + offset_limit + + RETURN + 0 ok + != 0 error +*/ + int mysql_ha_read(THD *thd, TABLE_LIST *tables, enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr, enum ha_rkey_function ha_rkey_mode, Item *cond, ha_rows select_limit,ha_rows offset_limit) { - int err, keyno=-1; - bool was_flushed; - TABLE *table= *find_table_ptr_by_name(thd, tables->db, tables->alias, - /*is_alias*/ 1, /*dont_lock*/ 0, - &was_flushed); + TABLE_LIST *hash_tables; + TABLE *table; + int err; + int keyno=-1; + uint num_rows; + MYSQL_LOCK *lock; + DBUG_ENTER("mysql_ha_read"); + DBUG_PRINT("enter",("'%s'.'%s' as '%s'", + tables->db, tables->real_name, tables->alias)); + + List<Item> list; + list.push_front(new Item_field(NULL,NULL,"*")); + List_iterator<Item> it(list); + it++; + + if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, + (byte*) tables->alias, + strlen(tables->alias) + 1))) + { + table= hash_tables->table; + DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", + hash_tables->db, hash_tables->real_name, + hash_tables->alias, table)); + if (!table) + { + /* + The handler table has been closed. Re-open it. + */ + if (mysql_ha_open(thd, hash_tables, 1)) + { + DBUG_PRINT("exit",("reopen failed")); + goto err0; + } + + table= hash_tables->table; + DBUG_PRINT("info",("re-opened '%s'.'%s' as '%s' tab %p", + hash_tables->db, hash_tables->real_name, + hash_tables->alias, table)); + } + +#if MYSQL_VERSION_ID < 40100 + if (*tables->db && strcmp(table->table_cache_key, tables->db)) + { + DBUG_PRINT("info",("wrong db")); + table= NULL; + } +#endif + } + else + table= NULL; + if (!table) { - my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0), - tables->alias,"HANDLER"); - return -1; +#if MYSQL_VERSION_ID < 40100 + char buff[MAX_DBKEY_LENGTH]; + if (*tables->db) + strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS); + else + strncpy(buff, tables->alias, sizeof(buff)); + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + buff, "HANDLER"); +#else + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + tables->alias, "HANDLER"); +#endif + goto err0; } tables->table=table; if (cond && cond->fix_fields(thd,tables)) - return -1; + goto err0; table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it @@ -224,24 +436,19 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, { my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0), keyname,tables->alias); - return -1; + goto err0; } table->file->index_init(keyno); } - List<Item> list; - list.push_front(new Item_field(NULL,NULL,"*")); - List_iterator<Item> it(list); - uint num_rows; - it++; - - insert_fields(thd,tables,tables->db,tables->alias,&it); + if (insert_fields(thd,tables,tables->db,tables->alias,&it)) + goto err0; select_limit+=offset_limit; send_fields(thd,list,1); HANDLER_TABLES_HACK(thd); - MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1); + lock= mysql_lock_tables(thd, &tables->table, 1); HANDLER_TABLES_HACK(thd); byte *key; @@ -363,83 +570,150 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, ok: mysql_unlock_tables(thd,lock); send_eof(&thd->net); - return 0; + DBUG_PRINT("exit",("OK")); + DBUG_RETURN(0); + err: mysql_unlock_tables(thd,lock); err0: - return -1; + DBUG_PRINT("exit",("ERROR")); + DBUG_RETURN(-1); } /* - Find a HANDLER table by name. + Flush (close) a list of HANDLER tables. SYNOPSIS - find_table_ptr_by_name() + mysql_ha_flush() thd Thread identifier. - db Database (schema) name. - table_name Table name ;-). - is_alias Table name may be an alias name. - dont_lock Suppresses the normal locking of LOCK_open. + tables The list of tables to close. If NULL, + close all HANDLER tables [marked as flushed]. + mode_flags MYSQL_HA_CLOSE_FINAL finally close the table. + MYSQL_HA_REOPEN_ON_USAGE mark for reopen. + MYSQL_HA_FLUSH_ALL flush all tables, not only + those marked for flush. DESCRIPTION - Find the table 'db'.'table_name' in the list of HANDLER tables of the - thread 'thd'. If the table has been marked by FLUSH TABLE(S), close it, - flag this situation in '*was_flushed' and broadcast a COND_refresh - condition. - An empty database (schema) name matches all database (schema) names. - If the caller did already lock LOCK_open, it must set 'dont_lock'. - - IMPLEMENTATION - Just in case that the table is twice in 'thd->handler_tables' (!?!), - the loop does not break when the table was flushed. If another table - by that name was found and not flushed, '*was_flushed' is cleared again, - since a pointer to an open HANDLER table is returned. + The list of HANDLER tables may be NULL, in which case all HANDLER + tables are closed (if MYSQL_HA_FLUSH_ALL) is set. + If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set, + all HANDLER tables marked for flush are closed. + Broadcasts a COND_refresh condition, for every table closed. + The caller must lock LOCK_open. + + NOTE + Since mysql_ha_flush() is called when the base table has to be closed, + we compare real table names, not aliases. Hence, database names matter. RETURN - *was_flushed Table has been closed due to FLUSH TABLE. - NULL A HANDLER Table by that name does not exist (any more). - != NULL Pointer to the TABLE structure. + 0 ok */ -static TABLE **find_table_ptr_by_name(THD *thd, const char *db, - const char *table_name, - bool is_alias, bool dont_lock, - bool *was_flushed) +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) { - int dblen; - TABLE **table_ptr; - - DBUG_ASSERT(db); - dblen= *db ? strlen(db)+1 : 0; - table_ptr= &(thd->handler_tables); - *was_flushed= FALSE; + TABLE_LIST *tmp_tables; + TABLE **table_ptr; + DBUG_ENTER("mysql_ha_flush"); + DBUG_PRINT("enter", ("tables: %p mode_flags: 0x%02x", tables, mode_flags)); - for (TABLE *table=*table_ptr; table ; table=*table_ptr) + if (tables) { - if ((!dblen || !memcmp(table->table_cache_key, db, dblen)) && - !my_strcasecmp((is_alias ? table->table_name : table->real_name), - table_name)) + /* Close all tables in the list. */ + for (tmp_tables= tables ; tmp_tables; tmp_tables= tmp_tables->next) { - if (table->version != refresh_version) + DBUG_PRINT("info-in-tables-list",("'%s'.'%s' as '%s'", + tmp_tables->db, tmp_tables->real_name, + tmp_tables->alias)); + /* Close all currently open handler tables with the same base table. */ + table_ptr= &(thd->handler_tables); + while (*table_ptr) { - if (!dont_lock) - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, table_ptr)) + if ((! *tmp_tables->db || + ! my_strcasecmp((*table_ptr)->table_cache_key, tmp_tables->db)) && + ! my_strcasecmp((*table_ptr)->real_name, tmp_tables->real_name)) { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); + DBUG_PRINT("info",("*table_ptr '%s'.'%s' as '%s'", + (*table_ptr)->table_cache_key, + (*table_ptr)->real_name, + (*table_ptr)->table_name)); + mysql_ha_flush_table(thd, table_ptr, mode_flags); + continue; } - if (!dont_lock) - VOID(pthread_mutex_unlock(&LOCK_open)); - *was_flushed= TRUE; + table_ptr= &(*table_ptr)->next; + } + /* end of handler_tables list */ + } + /* end of flush tables list */ + } + else + { + /* Close all currently open tables [which are marked for flush]. */ + table_ptr= &(thd->handler_tables); + while (*table_ptr) + { + if ((mode_flags & MYSQL_HA_FLUSH_ALL) || + ((*table_ptr)->version != refresh_version)) + { + mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } - *was_flushed= FALSE; - break; + table_ptr= &(*table_ptr)->next; } - table_ptr=&(table->next); } - return table_ptr; + + DBUG_RETURN(0); +} + +/* + Flush (close) a table. + + SYNOPSIS + mysql_ha_flush_table() + thd Thread identifier. + table The table to close. + mode_flags MYSQL_HA_CLOSE_FINAL finally close the table. + MYSQL_HA_REOPEN_ON_USAGE mark for reopen. + + DESCRIPTION + Broadcasts a COND_refresh condition, for every table closed. + The caller must lock LOCK_open. + + RETURN + 0 ok +*/ + +static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) +{ + TABLE_LIST *hash_tables; + TABLE *table= *table_ptr; + DBUG_ENTER("mysql_ha_flush_table"); + DBUG_PRINT("enter",("'%s'.'%s' as '%s' flags: 0x%02x", + table->table_cache_key, table->real_name, + table->table_name, mode_flags)); + + if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, + (byte*) (*table_ptr)->table_name, + strlen((*table_ptr)->table_name) + 1))) + { + if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) + { + /* This is a final close. Remove from hash. */ + hash_delete(&thd->handler_tables_hash, (byte*) hash_tables); + } + else + { + /* Mark table as closed, ready for re-open. */ + hash_tables->table= NULL; + } + } + + if (close_thread_table(thd, table_ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } + + DBUG_RETURN(0); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 14fc748c288..6b3723d89c4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1142,7 +1142,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_access(thd,CREATE_ACL,db,0,1)) break; mysql_log.write(thd,command,packet); - mysql_create_db(thd,(lower_case_table_names == 2 ? alias : db),0,0); + if (mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db), + 0, 0) < 0) + send_error(&thd->net, thd->killed ? ER_SERVER_SHUTDOWN : 0); break; } case COM_DROP_DB: // QQ: To be removed @@ -1163,7 +1165,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } mysql_log.write(thd,command,db); - mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db), 0, 0); + if (mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db), + 0, 0) < 0) + send_error(&thd->net, thd->killed ? ER_SERVER_SHUTDOWN : 0); break; } case COM_BINLOG_DUMP: @@ -1655,6 +1659,19 @@ mysql_execute_command(void) net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; } + if (lex->create_info.used_fields & HA_CREATE_USED_UNION) + { + TABLE_LIST *tab; + for (tab= tables; tab; tab= tab->next) + { + if (check_dup(tables->db, tab->real_name, + (TABLE_LIST*)lex->create_info.merge_list.first)) + { + net_printf(&thd->net, ER_INSERT_TABLE_USED, tab->real_name); + DBUG_VOID_RETURN; + } + } + } if (tables->next) { TABLE_LIST *table; @@ -1752,7 +1769,7 @@ mysql_execute_command(void) if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN)) { net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name); - res=0; + res= 1; break; } if (!select_lex->db) @@ -1914,21 +1931,26 @@ mysql_execute_command(void) send_error(&thd->net,ER_WRONG_VALUE_COUNT); DBUG_VOID_RETURN; } - if (select_lex->table_list.elements == 1) - { - if (check_one_table_access(thd, UPDATE_ACL, tables, 0)) - goto error; /* purecov: inspected */ + if (check_one_table_access(thd, UPDATE_ACL, tables, 0)) + goto error; /* purecov: inspected */ - res= mysql_update(thd,tables, - select_lex->item_list, - lex->value_list, - select_lex->where, - (ORDER *) select_lex->order_list.first, - select_lex->select_limit, - lex->duplicates); + res= mysql_update(thd,tables, + select_lex->item_list, + lex->value_list, + select_lex->where, + (ORDER *) select_lex->order_list.first, + select_lex->select_limit, + lex->duplicates); + break; + case SQLCOM_MULTI_UPDATE: + if (check_db_used(thd,tables)) + goto error; + if (select_lex->item_list.elements != lex->value_list.elements) + { + send_error(&thd->net,ER_WRONG_VALUE_COUNT); + DBUG_VOID_RETURN; } - else { const char *msg= 0; TABLE_LIST *table; @@ -3229,7 +3251,18 @@ bool add_field_to_list(char *field_name, enum_field_types type, } break; case FIELD_TYPE_TIMESTAMP: +#if MYSQL_VERSION_ID < 40100 + /* + When in in --new mode, we should create TIMESTAMP(19) fields by default; + otherwise we will have problems with ALTER TABLE changing lengths of + existing TIMESTAMP fields to 19 and adding new fields with length 14. + */ + if (thd->variables.new_mode) + new_field->length= 19; + else if (!length) +#else if (!length) +#endif new_field->length= 14; // Full date YYYYMMDDHHMMSS else if (new_field->length != 19) { diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index cff36eaa388..514fed226d2 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -14,8 +14,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// Sasha Pachev <sasha@mysql.com> is currently in charge of this file - #include "mysql_priv.h" #include "sql_repl.h" #include "sql_acl.h" diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 570c41c98f7..5eac754c25c 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -1,3 +1,19 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha + + 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 */ + #include "slave.h" typedef struct st_slave_info diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cf5e8a75f85..e46b7fb8b97 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4907,6 +4907,15 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) } else { + if (!table->key_read && + (table->used_keys & ((key_map) 1 << tab->ref.key)) && + !table->no_keyread && + (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY) + { + table->key_read=1; + table->file->extra(HA_EXTRA_KEYREAD); + tab->index= tab->ref.key; + } if ((error=join_read_const(tab))) { tab->info="unique row not found"; @@ -7623,7 +7632,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, sprintf(buff3,"%.0f",join->best_positions[i].records_read); item_list.push_back(new Item_string(buff3,strlen(buff3))); my_bool key_read=table->key_read; - if (tab->type == JT_NEXT && + if ((tab->type == JT_NEXT || tab->type == JT_CONST) && ((table->used_keys & ((key_map) 1 << tab->index)))) key_read=1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6784cd64465..2506033cda5 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -193,27 +193,23 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, { /* Return databases */ #ifdef USE_SYMDIR char *ext; + char buff[FN_REFLEN]; if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym")) { /* Only show the sym file if it points to a directory */ - char buff[FN_REFLEN], *end; - MY_STAT status; + char *end; *ext=0; /* Remove extension */ unpack_dirname(buff, file->name); end= strend(buff); if (end != buff && end[-1] == FN_LIBCHAR) end[-1]= 0; // Remove end FN_LIBCHAR - if (!my_stat(buff, &status, MYF(0)) || - !MY_S_ISDIR(status.st_mode)) - continue; - } - else + if (!my_stat(buff, file->mystat, MYF(0))) + continue; + } #endif - { if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) || (wild && wild_compare(file->name,wild, 0))) continue; - } } else { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 96eebd98ac3..1e5237b1428 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -30,6 +30,16 @@ #include <io.h> #endif +#include "sql_acl.h" // for SUPER_ACL +# define tmp_disable_binlog(A) \ + ulong save_options= (A)->options, save_master_access= (A)->master_access; \ + (A)->options&= ~OPTION_BIN_LOG; \ + (A)->master_access|= SUPER_ACL; /* unneeded in 4.1 */ + +#define reenable_binlog(A) \ + (A)->options= save_options; \ + (A)->master_access= save_master_access; + extern HASH open_cache; static const char *primary_key_name="PRIMARY"; @@ -176,7 +186,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, for (table=tables ; table ; table=table->next) { char *db=table->db; - mysql_ha_close(thd, table, /*dont_send_ok*/ 1, /*dont_lock*/ 1); + mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); if (!close_temporary_table(thd, db, table->real_name)) { tmp_table_deleted=1; @@ -840,9 +850,8 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, MYSQL_LOCK **lock) { TABLE tmp_table; // Used during 'create_field()' - TABLE *table; + TABLE *table= 0; tmp_table.table_name=0; - Disable_binlog disable_binlog(thd); DBUG_ENTER("create_table_from_items"); /* Add selected items to field list */ @@ -872,23 +881,25 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, extra_fields->push_back(cr_field); } /* create and lock table */ - /* QQ: This should be done atomic ! */ - /* We don't log the statement, it will be logged later */ - if (mysql_create_table(thd,db,name,create_info,*extra_fields, - *keys,0)) - DBUG_RETURN(0); + /* QQ: create and open should be done atomic ! */ /* + We don't log the statement, it will be logged later. If this is a HEAP table, the automatic DELETE FROM which is written to the binlog when a HEAP table is opened for the first time since startup, must not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we don't want to delete from it) 2) it would be written before the CREATE - TABLE, which is a wrong order. So we keep binary logging disabled. + TABLE, which is a wrong order. So we keep binary logging disabled when we + open_table(). */ - if (!(table=open_table(thd,db,name,name,(bool*) 0))) + tmp_disable_binlog(thd); + if (!mysql_create_table(thd,db,name,create_info,*extra_fields,*keys,0)) { - quick_rm_table(create_info->db_type,db,table_case_name(create_info,name)); - DBUG_RETURN(0); + if (!(table=open_table(thd,db,name,name,(bool*) 0))) + quick_rm_table(create_info->db_type,db,table_case_name(create_info,name)); } + reenable_binlog(thd); + if (!table) + DBUG_RETURN(0); table->reginfo.lock_type=TL_WRITE; if (!((*lock)=mysql_lock_tables(thd,&table,1))) { @@ -900,7 +911,6 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } table->file->extra(HA_EXTRA_WRITE_CACHE); DBUG_RETURN(table); - /* Note that leaving the function resets binlogging properties */ } @@ -1242,7 +1252,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (send_fields(thd, field_list, 1)) DBUG_RETURN(-1); - mysql_ha_close(thd, tables, /*dont_send_ok*/ 1, /*dont_lock*/ 1); + mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL); for (table = tables; table; table = table->next) { char table_name[NAME_LEN*2+2]; @@ -1257,9 +1267,13 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (prepare_func) { switch ((*prepare_func)(thd, table, check_opt)) { - case 1: continue; // error, message written to net - case -1: goto err; // error, message could be written to net - default: ; // should be 0 otherwise + case 1: // error, message written to net + close_thread_tables(thd); + continue; + case -1: // error, message could be written to net + goto err; + default: // should be 0 otherwise + ; } } @@ -1503,7 +1517,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } used_fields=create_info->used_fields; - mysql_ha_close(thd, table_list, /*dont_send_ok*/ 1, /*dont_lock*/ 1); + mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL); if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) DBUG_RETURN(-1); @@ -1603,7 +1617,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); - error= table->file->activate_all_index(thd); + error= (table->file->activate_all_index(thd) ? -1 : 0); /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: @@ -1925,14 +1939,12 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, else create_info->data_file_name=create_info->index_file_name=0; { - /* - We don't log the statement, it will be logged later. Using a block so - that disable_binlog is deleted when we leave it in either way. - */ - Disable_binlog disable_binlog(thd); - if ((error=mysql_create_table(thd, new_db, tmp_name, - create_info, - create_list,key_list,1))) + /* We don't log the statement, it will be logged later. */ + tmp_disable_binlog(thd); + error= mysql_create_table(thd, new_db, tmp_name, + create_info,create_list,key_list,1); + reenable_binlog(thd); + if (error) DBUG_RETURN(error); } if (table->tmp_table) @@ -2199,7 +2211,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (!(copy= new Copy_field[to->fields])) DBUG_RETURN(-1); /* purecov: inspected */ - to->file->external_lock(thd,F_WRLCK); + if (to->file->external_lock(thd, F_WRLCK)) + DBUG_RETURN(-1); to->file->extra(HA_EXTRA_WRITE_CACHE); from->file->info(HA_STATUS_VARIABLE); to->file->deactivate_non_unique_index(from->file->records); @@ -2299,11 +2312,12 @@ copy_data_between_tables(TABLE *from,TABLE *to, error=1; if (ha_commit(thd)) error=1; - if (to->file->external_lock(thd,F_UNLCK)) - error=1; + err: free_io_cache(from); *copied= found_count; *deleted=delete_count; + if (to->file->external_lock(thd,F_UNLCK)) + error=1; DBUG_RETURN(error > 0 ? -1 : 0); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 8088737c0de..f9c21079851 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -39,6 +39,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first; TMP_TABLE_PARAM tmp_table_param; select_union *union_result; + ha_rows examined_rows= 0; DBUG_ENTER("mysql_union"); /* Fix tables 'to-be-unioned-from' list to point at opened tables */ @@ -148,6 +149,10 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) { ha_rows records_at_start; lex->select=sl; +#if MYSQL_VERSION_ID < 40100 + if (describe && sl->linkage == NOT_A_SELECT) + break; // Skip extra item in case of 'explain' +#endif /* Don't use offset for the last union if there is no braces */ if (sl != lex_sl) { @@ -198,6 +203,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) union_result); if (res) goto exit; + examined_rows+= thd->examined_row_count; /* Needed for the following test and for records_at_start in next loop */ table->file->info(HA_STATUS_VARIABLE); if (found_rows_for_union & sl->options) @@ -254,12 +260,15 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) if (describe) thd->select_limit= HA_POS_ERROR; // no limit - res=mysql_select(thd,&result_table_list, + res= mysql_select(thd,&result_table_list, item_list, NULL, (describe) ? 0 : order, (ORDER*) NULL, NULL, (ORDER*) NULL, thd->options, result); if (!res) - thd->limit_found_rows = (ulonglong)table->file->records + add_rows; + { + thd->limit_found_rows= (ulonglong)table->file->records + add_rows; + thd->examined_row_count+= examined_rows; + } } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 02d2fe2c442..cdcc90e8651 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -387,6 +387,24 @@ err: ***************************************************************************/ /* + Get table map for list of Item_field +*/ + +static table_map get_table_map(List<Item> *items) +{ + List_iterator_fast<Item> item_it(*items); + Item_field *item; + table_map map= 0; + + while ((item= (Item_field *) item_it++)) + map|= item->used_tables(); + DBUG_PRINT("info",("table_map: 0x%08x", map)); + return map; +} + + + +/* Setup multi-update handling and call SELECT to do the join */ @@ -401,25 +419,109 @@ int mysql_multi_update(THD *thd, int res; multi_update *result; TABLE_LIST *tl; + const bool using_lock_tables= thd->locked_tables != 0; DBUG_ENTER("mysql_multi_update"); - if ((res=open_and_lock_tables(thd,table_list))) - DBUG_RETURN(res); - - thd->select_limit=HA_POS_ERROR; + thd->select_limit= HA_POS_ERROR; - /* - Ensure that we have update privilege for all tables and columns in the - SET part - */ - for (tl= table_list ; tl ; tl=tl->next) + for (;;) { - TABLE *table= tl->table; - table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); - } + table_map update_map; + int tnr; + + if ((res= open_tables(thd, table_list))) + DBUG_RETURN(res); - if (setup_fields(thd, table_list, *fields, 1, 0, 0)) - DBUG_RETURN(-1); + /* Only need to call lock_tables if we are not using LOCK TABLES */ + if (!using_lock_tables && ((res= lock_tables(thd, table_list)))) + DBUG_RETURN(res); + + /* + Ensure that we have update privilege for all tables and columns in the + SET part + While we are here, initialize the table->map field. + */ + for (tl= table_list,tnr=0 ; tl ; tl=tl->next) + { + TABLE *table= tl->table; + table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); + table->map= (table_map) 1 << (tnr++); + } + + if (setup_fields(thd, table_list, *fields, 1, 0, 0)) + DBUG_RETURN(-1); + + update_map= get_table_map(fields); + + /* Unlock the tables in preparation for relocking */ + if (!using_lock_tables) + { + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; + } + + /* + Set the table locking strategy according to the update map + */ + for (tl= table_list ; tl ; tl=tl->next) + { + TABLE *table= tl->table; + if (update_map & table->map) + { + DBUG_PRINT("info",("setting table `%s` for update", tl->alias)); + tl->lock_type= thd->lex.lock_option; + tl->updating= 1; + } + else + { + DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias)); + tl->lock_type= TL_READ; + tl->updating= 0; + } + if (!using_lock_tables) + tl->table->reginfo.lock_type= tl->lock_type; + } + + /* Relock the tables with the correct modes */ + res= lock_tables(thd,table_list); + if (using_lock_tables) + { + if (res) + DBUG_RETURN(res); + break; // Don't have to do setup_field() + } + + /* + We must setup fields again as the file may have been reopened + during lock_tables + */ + + { + List_iterator_fast<Item> field_it(*fields); + Item_field *item; + + while ((item= (Item_field *) field_it++)) +#if MYSQL_VERSION < 40100 + item->field= item->result_field= 0; +#else + item->cleanup(); +#endif + } + if (setup_fields(thd, table_list, *fields, 1, 0, 0)) + DBUG_RETURN(-1); + /* + If lock succeded and the table map didn't change since the above lock + we can continue. + */ + if (!res && update_map == get_table_map(fields)) + break; + + /* + There was some very unexpected changes in the table definition between + open tables and lock tables. Close tables and try again. + */ + close_thread_tables(thd); + } /* Count tables and setup timestamp handling @@ -472,7 +574,7 @@ int multi_update::prepare(List<Item> ¬_used_values) { TABLE_LIST *table_ref; SQL_LIST update; - table_map tables_to_update= 0; + table_map tables_to_update; Item_field *item; List_iterator_fast<Item> field_it(*fields); List_iterator_fast<Item> value_it(*values); @@ -483,8 +585,7 @@ int multi_update::prepare(List<Item> ¬_used_values) thd->cuted_fields=0L; thd->proc_info="updating main table"; - while ((item= (Item_field *) field_it++)) - tables_to_update|= item->used_tables(); + tables_to_update= get_table_map(fields); if (!tables_to_update) { @@ -548,7 +649,6 @@ int multi_update::prepare(List<Item> ¬_used_values) /* Split fields into fields_for_table[] and values_by_table[] */ - field_it.rewind(); while ((item= (Item_field *) field_it++)) { Item *value= value_it++; @@ -792,9 +892,13 @@ bool multi_update::send_data(List<Item> ¬_used_values) if ((error=table->file->update_row(table->record[1], table->record[0]))) { - table->file->print_error(error,MYF(0)); updated--; - DBUG_RETURN(1); + if (handle_duplicates != DUP_IGNORE || + error != HA_ERR_FOUND_DUPP_KEY) + { + table->file->print_error(error,MYF(0)); + DBUG_RETURN(1); + } } } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2199a0c8be5..7b72c73a915 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2751,10 +2751,18 @@ update: lex->select->order_list.next= (byte**) &lex->select->order_list.first; } opt_low_priority opt_ignore join_table_list - SET update_list where_clause opt_order_clause delete_limit_clause + SET update_list { - set_lock_for_tables($3); + if (Lex->select->table_list.elements > 1) + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_MULTI_UPDATE; + lex->lock_option= $3; + } + else + set_lock_for_tables($3); } + where_clause opt_order_clause delete_limit_clause {} ; update_list: @@ -2917,7 +2925,7 @@ show_param: lex->select->select_limit= lex->thd->variables.select_limit; lex->select->offset_limit= 0L; } limit_clause - | keys_or_index FROM table_ident opt_db + | keys_or_index from_or_in table_ident opt_db { Lex->sql_command= SQLCOM_SHOW_KEYS; if ($4) diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 73a7ecdc7ba..fa9ab093f26 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -197,7 +197,7 @@ terribly wrong...\n"); fprintf(stderr, "Stack trace seems successful - bottom reached\n"); end: - fprintf(stderr, "Please read http://www.mysql.com/doc/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\ + fprintf(stderr, "Please read http://dev.mysql.com/doc/mysql/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\ stack trace is much more helpful in diagnosing the problem, so please do \n\ resolve it\n"); } diff --git a/sql/table.h b/sql/table.h index f3b0e148cc0..84df7ba127e 100644 --- a/sql/table.h +++ b/sql/table.h @@ -106,6 +106,14 @@ struct st_table { *found_next_number_field, /* Set on open */ *rowid_field; Field_timestamp *timestamp_field; +#if MYSQL_VERSION_ID < 40100 + /* + Indicates whenever we have to set field_length members of all TIMESTAMP + fields to 19 (to honour 'new_mode' variable) or to original + field_length values. + */ + my_bool timestamp_mode; +#endif my_string comment; /* Comment about table */ REGINFO reginfo; /* field connections */ MEM_ROOT mem_root; diff --git a/sql/time.cc b/sql/time.cc index 0363d764100..38670db054f 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -81,6 +81,10 @@ long my_gmt_sec(TIME *t, long *my_timezone) I couldn't come up with a better way to get a repeatable result :( We can't use mktime() as it's buggy on many platforms and not thread safe. + + Note: this code assumes that our time_t estimation is not too far away + from real value (we assume that localtime_r(tmp) will return something + within 24 hrs from t) which is probably true for all current time zones. */ tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) - (long) days_at_timestart)*86400L + (long) t->hour*3600L + @@ -93,7 +97,8 @@ long my_gmt_sec(TIME *t, long *my_timezone) for (loop=0; loop < 2 && (t->hour != (uint) l_time->tm_hour || - t->minute != (uint) l_time->tm_min); + t->minute != (uint) l_time->tm_min || + t->second != (uint) l_time->tm_sec); loop++) { /* One check should be enough ? */ /* Get difference in days */ @@ -103,15 +108,22 @@ long my_gmt_sec(TIME *t, long *my_timezone) else if (days > 1) days= -1; diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) + - (long) (60*((int) t->minute - (int) l_time->tm_min))); + (long) (60*((int) t->minute - (int) l_time->tm_min)) + + (long) ((int) t->second - (int) l_time->tm_sec)); current_timezone+= diff+3600; // Compensate for -3600 above tmp+= (time_t) diff; localtime_r(&tmp,&tm_tmp); l_time=&tm_tmp; } /* - Fix that if we are in the not existing daylight saving time hour - we move the start of the next real hour + Fix that if we are in the non existing daylight saving time hour + we move the start of the next real hour. + + This code doesn't handle such exotical thing as time-gaps whose length + is more than one hour or non-integer (latter can theoretically happen + if one of seconds will be removed due leap correction, or because of + general time correction like it happened for Africa/Monrovia time zone + in year 1972). */ if (loop == 2 && t->hour != (uint) l_time->tm_hour) { @@ -121,7 +133,8 @@ long my_gmt_sec(TIME *t, long *my_timezone) else if (days > 1) days= -1; diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour))+ - (long) (60*((int) t->minute - (int) l_time->tm_min))); + (long) (60*((int) t->minute - (int) l_time->tm_min)) + + (long) ((int) t->second - (int) l_time->tm_sec)); if (diff == 3600) tmp+=3600 - t->minute*60 - t->second; // Move to next hour else if (diff == -3600) diff --git a/strings/ctype-latin1_de.c b/strings/ctype-latin1_de.c index 5b7a68fb967..bc4327e921d 100644 --- a/strings/ctype-latin1_de.c +++ b/strings/ctype-latin1_de.c @@ -248,7 +248,7 @@ int my_strxfrm_latin1_de(uchar * dest, const uchar * src, int len) */ #define min_sort_char ((char) 0) -#define max_sort_char ((char) 255) +#define max_sort_char ((char) 0xF7) #define wild_one '_' #define wild_many '%' diff --git a/tools/mysqlmanager.c b/tools/mysqlmanager.c index 12b5519ae9c..ade6da895c6 100644 --- a/tools/mysqlmanager.c +++ b/tools/mysqlmanager.c @@ -1333,7 +1333,7 @@ static int parse_args(int argc, char **argv) { int ho_error; - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option, NULL))) + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); return 0; |