diff options
author | unknown <monty@mashka.mysql.fi> | 2003-08-11 22:44:43 +0300 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2003-08-11 22:44:43 +0300 |
commit | 034b44cb9ff914ceb6d32706a3a284eda00891b3 (patch) | |
tree | 3c0ddcb446b8be099c3ab2616c459a573ee3cf92 | |
parent | f4646c0d063fb541f48dd2824ecccea464a9958d (diff) | |
parent | 6db21de014d603477952c7a16449bcae40a70e5c (diff) | |
download | mariadb-git-034b44cb9ff914ceb6d32706a3a284eda00891b3.tar.gz |
Merge with 4.0.14
BitKeeper/etc/logging_ok:
auto-union
scripts/make_win_src_distribution.old:
Merge rename: scripts/make_win_src_distribution.sh -> scripts/make_win_src_distribution.old
BUILD/compile-pentium-debug-max:
Auto merged
BitKeeper/deleted/.del-sel000001.result~383913ae4505ec86:
Auto merged
BitKeeper/deleted/.del-sel000001.test~9567c1646058cc:
Auto merged
Build-tools/Bootstrap:
Auto merged
Build-tools/Do-compile:
Auto merged
Docs/Makefile.am:
Auto merged
client/get_password.c:
Auto merged
client/mysql.cc:
Auto merged
client/mysqltest.c:
Auto merged
extra/perror.c:
Auto merged
include/config-win.h:
Auto merged
include/my_sys.h:
Auto merged
innobase/btr/btr0cur.c:
Auto merged
innobase/btr/btr0pcur.c:
Auto merged
innobase/buf/buf0buf.c:
Auto merged
innobase/buf/buf0flu.c:
Auto merged
innobase/dict/dict0dict.c:
Auto merged
innobase/dict/dict0load.c:
Auto merged
innobase/include/buf0buf.h:
Auto merged
innobase/include/log0recv.h:
Auto merged
innobase/include/row0sel.h:
Auto merged
innobase/include/srv0srv.h:
Auto merged
innobase/include/ut0mem.h:
Auto merged
innobase/lock/lock0lock.c:
Auto merged
innobase/log/log0log.c:
Auto merged
innobase/mem/mem0pool.c:
Auto merged
innobase/os/os0file.c:
Auto merged
innobase/row/row0mysql.c:
Auto merged
innobase/row/row0sel.c:
Auto merged
innobase/srv/srv0srv.c:
Auto merged
innobase/srv/srv0start.c:
Auto merged
innobase/trx/trx0sys.c:
Auto merged
innobase/trx/trx0trx.c:
Auto merged
innobase/ut/ut0mem.c:
Auto merged
innobase/ut/ut0ut.c:
Auto merged
myisam/ft_boolean_search.c:
Auto merged
myisam/mi_check.c:
Auto merged
myisam/mi_extra.c:
Auto merged
myisam/mi_key.c:
Auto merged
myisam/myisamdef.h:
Auto merged
myisammrg/myrg_queue.c:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
mysql-test/r/ctype_latin1_de.result:
Auto merged
mysql-test/r/flush.result:
Auto merged
mysql-test/r/func_time.result:
Auto merged
mysql-test/r/grant_cache.result:
Auto merged
mysql-test/r/join.result:
Auto merged
mysql-test/r/join_outer.result:
Auto merged
mysql-test/r/range.result:
Auto merged
mysql-test/r/rpl000018.result:
Auto merged
mysql-test/r/rpl_insert_id.result:
Auto merged
mysql-test/r/rpl_master_pos_wait.result:
Auto merged
mysql-test/r/rpl_relayspace.result:
Auto merged
mysql-test/r/select_safe.result:
Auto merged
mysql-test/r/symlink.result:
Auto merged
mysql-test/r/type_date.result:
Auto merged
mysql-test/r/type_datetime.result:
Auto merged
mysql-test/t/alias.test:
Auto merged
mysql-test/t/ctype_latin1_de.test:
Auto merged
mysql-test/t/fulltext_left_join.test:
Auto merged
mysql-test/t/func_time.test:
Auto merged
mysql-test/t/handler.test:
Auto merged
mysql-test/t/heap.test:
Auto merged
mysql-test/t/join.test:
Auto merged
mysql-test/t/join_outer.test:
Auto merged
mysql-test/t/order_by.test:
Auto merged
mysql-test/t/range.test:
Auto merged
mysql-test/t/rpl000001.test:
Auto merged
mysql-test/t/rpl000018.test:
Auto merged
mysql-test/t/rpl_insert_id.test:
Auto merged
mysql-test/t/sel000100.test:
Auto merged
mysql-test/t/select_safe.test:
Auto merged
mysql-test/t/type_date.test:
Auto merged
mysql-test/t/type_datetime.test:
Auto merged
mysql-test/t/user_var.test:
Auto merged
mysys/default.c:
Auto merged
mysys/mf_format.c:
Auto merged
mysys/my_getopt.c:
Auto merged
mysys/thr_lock.c:
Auto merged
mysys/tree.c:
Auto merged
scripts/Makefile.am:
Auto merged
scripts/mysql_install_db.sh:
Auto merged
scripts/mysqld_safe.sh:
Auto merged
sql/Makefile.am:
Auto merged
sql/field_conv.cc:
Auto merged
sql/ha_innodb.h:
Auto merged
sql/ha_myisam.cc:
Auto merged
sql/ha_myisammrg.h:
Auto merged
sql/handler.cc:
Auto merged
sql/handler.h:
Auto merged
sql/item.h:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_timefunc.cc:
Auto merged
sql/net_serv.cc:
Auto merged
sql/nt_servc.cc:
Auto merged
sql/opt_range.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_cache.h:
Auto merged
sql/sql_db.cc:
Auto merged
sql/sql_delete.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_list.h:
Auto merged
sql/sql_load.cc:
Auto merged
sql/sql_rename.cc:
Auto merged
sql/sql_repl.h:
Auto merged
sql/sql_update.cc:
Auto merged
sql/table.cc:
Auto merged
sql/table.h:
Auto merged
sql/uniques.cc:
Auto merged
support-files/mysql.spec.sh:
Auto merged
vio/viosocket.c:
Auto merged
BitKeeper/deleted/.del-ctype-latin1_de.c~c5d8f9208bceb98e:
merge
BitKeeper/deleted/.del-mini_client.cc~8677895ec8169183:
merge
acinclude.m4:
Merge with 4.0 (openssl patch)
client/mysqlbinlog.cc:
Merge with 4.0 in which we had added code from 4.1
(We are basicly only using the 4.1 code here)
configure.in:
Keep 4.1 file
heap/hp_open.c:
merge with 4.0
include/my_base.h:
merge with 4.0
include/my_global.h:
merge with 4.0
include/mysqld_error.h:
merge with 4.0
innobase/ha/ha0ha.c:
merge with 4.0
(Code should be same but we use indentaion from 4.0)
innobase/log/log0recv.c:
merge with 4.0
libmysql/libmysql.c:
Remove with 4.0 code that was ported from 4.1
libmysqld/lib_sql.cc:
merge with 4.0
myisam/mi_open.c:
Remove 4.0 specific code
myisam/myisamchk.c:
merge with 4.0
myisammrg/myrg_rkey.c:
merge with 4.0
mysql-test/r/alter_table.result:
May need to be fixed after merge
mysql-test/r/create.result:
May need to be fixed after merge
mysql-test/r/distinct.result:
May need to be fixed after merge
mysql-test/r/drop.result:
May need to be fixed after merge
mysql-test/r/fulltext.result:
May need to be fixed after merge
mysql-test/r/func_set.result:
May need to be fixed after merge
mysql-test/r/func_str.result:
May need to be fixed after merge
mysql-test/r/func_test.result:
May need to be fixed after merge
mysql-test/r/grant.result:
May need to be fixed after merge
mysql-test/r/group_by.result:
May need to be fixed after merge
mysql-test/r/handler.result:
May need to be fixed after merge
mysql-test/r/heap.result:
May need to be fixed after merge
mysql-test/r/innodb.result:
May need to be fixed after merge
mysql-test/r/insert.result:
May need to be fixed after merge
mysql-test/r/insert_select.result:
May need to be fixed after merge
mysql-test/r/key_diff.result:
May need to be fixed after merge
mysql-test/r/merge.result:
May need to be fixed after merge
mysql-test/r/myisam.result:
May need to be fixed after merge
mysql-test/r/order_by.result:
May need to be fixed after merge
mysql-test/r/query_cache.result:
May need to be fixed after merge
mysql-test/r/rpl_flush_log_loop.result:
May need to be fixed after merge
mysql-test/r/rpl_loaddata.result:
May need to be fixed after merge
mysql-test/r/rpl_log.result:
May need to be fixed after merge
mysql-test/r/rpl_log_pos.result:
May need to be fixed after merge
mysql-test/r/rpl_rotate_logs.result:
May need to be fixed after merge
mysql-test/r/select.result:
May need to be fixed after merge
mysql-test/r/union.result:
May need to be fixed after merge
mysql-test/r/user_var.result:
May need to be fixed after merge
mysql-test/t/alter_table.test:
merge with 4.0
mysql-test/t/create.test:
merge with 4.0
mysql-test/t/distinct.test:
merge with 4.0
mysql-test/t/drop.test:
merge with 4.0
mysql-test/t/flush.test:
merge with 4.0
mysql-test/t/fulltext.test:
merge with 4.0
mysql-test/t/func_set.test:
merge with 4.0
mysql-test/t/func_str.test:
merge with 4.0
mysql-test/t/func_test.test:
merge with 4.0
mysql-test/t/grant.test:
merge with 4.0
mysql-test/t/grant_cache.test:
merge with 4.0
mysql-test/t/innodb.test:
Add back EXPLAIN and SHOW KEYS statements, but make them independent of number of rows returned by InnoDB
mysql-test/t/insert.test:
merge with 4.0
mysql-test/t/insert_select.test:
merge with 4.0
mysql-test/t/merge.test:
merge with 4.0
mysql-test/t/query_cache.test:
merge with 4.0
mysql-test/t/rpl_flush_log_loop.test:
merge with 4.0
mysql-test/t/rpl_loaddata.test:
merge with 4.0
mysql-test/t/rpl_rotate_logs.test:
merge with 4.0
mysql-test/t/select.test:
merge with 4.0
mysql-test/t/symlink.test:
merge with 4.0
mysql-test/t/union.test:
merge with 4.0
mysys/charset.c:
merge with 4.0
scripts/mysql_fix_privilege_tables.sh:
merge with 4.0 (Add quoting for some variables)
sql/field.h:
merge with 4.0
sql/ha_innodb.cc:
merge with 4.0
sql/item_cmpfunc.cc:
merge with 4.0
sql/item_cmpfunc.h:
merge with 4.0
sql/item_func.h:
merge with 4.0
sql/item_strfunc.cc:
merge with 4.0
Fixed null handling with ELT()
sql/item_timefunc.h:
merge with 4.0
sql/lex.h:
merge with 4.0
sql/log.cc:
merge with 4.0
sql/log_event.cc:
Merge with 4.0
Cleanups:
- Indentation
- #endif comments
- Replace strmov() with *pos++= for two byte strings
- Moved variable declarations to start of functions
- Merged identical code (LOAD_EVENT)
- Added casts when subtracting pointers
Did a full diff between this and 4.0 to ensure that the file is correct after merge.
sql/log_event.h:
merge with 4.0
sql/mysql_priv.h:
merge with 4.0
sql/mysqld.cc:
merge with 4.0
sql/repl_failsafe.cc:
merge with 4.0
sql/set_var.cc:
merge with 4.0
sql/set_var.h:
merge with 4.0
sql/share/czech/errmsg.txt:
merge with 4.0
sql/share/danish/errmsg.txt:
merge with 4.0
sql/share/dutch/errmsg.txt:
merge with 4.0
sql/share/english/errmsg.txt:
merge with 4.0
sql/share/estonian/errmsg.txt:
merge with 4.0
sql/share/french/errmsg.txt:
merge with 4.0
sql/share/german/errmsg.txt:
merge with 4.0
sql/share/greek/errmsg.txt:
merge with 4.0
sql/share/hungarian/errmsg.txt:
merge with 4.0
sql/share/italian/errmsg.txt:
merge with 4.0
sql/share/japanese/errmsg.txt:
merge with 4.0
sql/share/korean/errmsg.txt:
merge with 4.0
sql/share/norwegian-ny/errmsg.txt:
merge with 4.0
sql/share/norwegian/errmsg.txt:
merge with 4.0
sql/share/polish/errmsg.txt:
merge with 4.0
sql/share/portuguese/errmsg.txt:
merge with 4.0
sql/share/romanian/errmsg.txt:
merge with 4.0
sql/share/russian/errmsg.txt:
merge with 4.0
sql/share/slovak/errmsg.txt:
merge with 4.0
sql/share/spanish/errmsg.txt:
merge with 4.0
sql/share/swedish/errmsg.txt:
merge with 4.0
sql/share/ukrainian/errmsg.txt:
merge with 4.0
sql/slave.cc:
Merge + some indentation fixes
sql/slave.h:
merge with 4.0
sql/sql_acl.cc:
merge with 4.0
Some end space removal to make it easier to do future merges
sql/sql_acl.h:
merge with 4.0
sql/sql_cache.cc:
merge with 4.0
sql/sql_class.h:
merge with 4.0
sql/sql_handler.cc:
merge with 4.0
sql/sql_lex.cc:
merge with 4.0
sql/sql_lex.h:
merge with 4.0
sql/sql_parse.cc:
merge with 4.0
sql/sql_repl.cc:
merge with 4.0
sql/sql_select.cc:
merge with 4.0
sql/sql_table.cc:
merge with 4.0
sql/sql_union.cc:
Merge with 4.0
Note that I couldn't find out how to merge OPTION_FOUND_ROWS handling so this has to be fixed later
sql/sql_yacc.yy:
merge with 4.0
Removed end space to make merge easier
vio/Makefile.am:
merge with 4.0
363 files changed, 13808 insertions, 2884 deletions
diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index 2fca6ac8dc2..b23648e4d91 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -3,7 +3,7 @@ path=`dirname $0` . "$path/SETUP.sh" -extra_flags="$pentium_cflags $debug_cflags -DBIG_TABLES" +extra_flags="$pentium_cflags $debug_cflags" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" extra_configs="$pentium_configs $debug_configs" diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index f858af82736..299c12c1f4a 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -63,6 +63,7 @@ miguel@hegel.br miguel@hegel.local miguel@light. miguel@light.local +miguel@sartre.local mmatthew@markslaptop. monty@bitch.mysql.fi monty@butch. @@ -86,6 +87,7 @@ nick@mysql.com nick@nick.leippe.com papa@gbichot.local paul@central.snake.net +paul@ice.local paul@ice.snake.net paul@teton.kitebird.com pem@mysql.com diff --git a/Build-tools/Bootstrap b/Build-tools/Bootstrap index 25c256d614b..33eca958ae0 100755 --- a/Build-tools/Bootstrap +++ b/Build-tools/Bootstrap @@ -38,12 +38,14 @@ $opt_export_only= undef; $opt_help= $opt_verbose= 0; $opt_log= undef; $opt_mail= ""; +$opt_revision= undef; $opt_suffix= ""; $opt_test= undef; $opt_skip_check= undef; $opt_skip_manual= undef; $opt_win_dist= undef; $version= "unknown"; +$major=$minor=$release=0; GetOptions( "build-command|b=s", @@ -151,6 +153,7 @@ if (!$opt_dry_run) { m/^AM_INIT_AUTOMAKE\(mysql, ([1-9]\.[0-9]{1,2}\.[0-9]{1,2}.*)\)/; $version= $1; + ($major, $minor, $release) = split(/\./,$version); } &logger("Found version string: $version"); @@ -220,7 +223,7 @@ if (defined $opt_changelog) { if (!$opt_revision) { - $revision= `bk changes -t -d':REV:' -n $REPO | head -1`; + $revision= `bk changes -t -d':REV:::TAG:' -n $REPO | grep mysql-$major.$minor | head -1 | cut -f1 -d ":"`; } else { diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index 07657c0bdeb..1e404f9c509 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -248,7 +248,8 @@ if ($opt_stage <= 1) $opt_config_options.= $opt_with_other_libc; } - check_system("$opt_config_env ./configure --prefix=/usr/local/mysql --with-comment=\"Official MySQL$opt_version_suffix binary\" --with-extra-charsets=complex --with-server-suffix=\"$opt_version_suffix\" --enable-thread-safe-client --enable-local-infile $opt_config_options","Thank you for choosing MySQL"); + $prefix="/usr/local/mysql"; + check_system("$opt_config_env ./configure --prefix=$prefix --localstatedir=$prefix/data --libexecdir=$prefix/bin --with-comment=\"Official MySQL$opt_version_suffix binary\" --with-extra-charsets=complex --with-server-suffix=\"$opt_version_suffix\" --enable-thread-safe-client --enable-local-infile $opt_config_options","Thank you for choosing MySQL"); if (-d "$pwd/$host/include-mysql") { safe_system("cp -r $pwd/$host/include-mysql/* $pwd/$host/$ver/include"); diff --git a/Docs/Makefile.am b/Docs/Makefile.am index cf0a4632eda..cfe613c8e2e 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -41,10 +41,10 @@ paper: manual_a4.ps manual_letter.ps $(PDFMANUAL) # The Makefile contains the previous version so we can not use that include.texi: ../configure.in echo "@c This file is autogenerated by the Makefile" > $@ - echo -n "@set mysql_version " >> $@ + echo -n "@set mysqlversion " >> $@ grep "AM_INIT_AUTOMAKE(mysql, " ../configure.in | \ sed -e 's;AM_INIT_AUTOMAKE(mysql, ;;' -e 's;);;' >> $@ - echo -n "@set default_port " >> $@ + echo -n "@set defaultport " >> $@ grep "MYSQL_TCP_PORT_DEFAULT=" ../configure.in | \ sed -e 's;MYSQL_TCP_PORT_DEFAULT=;;' >> $@ @@ -207,7 +207,7 @@ INSTALL-BINARY: mysql.info $(GT) perl -w $(GT) mysql.info "LGPL license" "Function Index" > $@ ../support-files/MacOSX/ReadMe.txt: mysql.info $(GT) - perl -w $(GT) mysql.info "Mac OS X installation" "Netware installation" > $@ + perl -w $(GT) mysql.info "Mac OS X installation" "NetWare installation" > $@ # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/Docs/Support/generate-text-files.pl b/Docs/Support/generate-text-files.pl index 570e579d926..6470baaa6e9 100755 --- a/Docs/Support/generate-text-files.pl +++ b/Docs/Support/generate-text-files.pl @@ -1,11 +1,11 @@ -#!/my/gnu/bin/perl -w -*- perl -*- +#!/usr/bin/perl -w -*- perl -*- # Generate text files from top directory from the manual. $from = shift(@ARGV); $fnode = shift(@ARGV); $tnode = shift(@ARGV); -open(IN, "$from") || die; +open(IN, "$from") || die "Cannot open $from: $!"; $in = 0; @@ -19,7 +19,7 @@ while (<IN>) } elsif (/^File: mysql.info/ || (/^/)) { - # Just Skip node begginigs + # Just Skip node beginnings } else { @@ -38,3 +38,6 @@ while (<IN>) } close(IN); + +die "Could not find node \"$tnode\"" if ($in == 1); +exit 0; diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/.fgl b/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/.fgl new file mode 100644 index 00000000000..81e474f9be8 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/.fgl @@ -0,0 +1,37 @@ +[General] +Type=FILELIST +Version=1.00.000 + +[topdir] +subdir0=<WINDIR> +subdir1=<PROGRAMFILES> +subdir2=<TARGETDIR> +subdir3=USERDEFINED + +[<WINDIR>] +DISPLAYTEXT=Windows Operating System +TYPE=TEXTSUBFIXED +subdir0=<WINDIR>\<WINSYSDIR> + +[<WINDIR>\<WINSYSDIR>] +DISPLAYTEXT=Windows System Folder +TYPE=TEXTSUBFIXED + +[<PROGRAMFILES>] +DISPLAYTEXT=Program Files Folder +TYPE=TEXTSUBFIXED +subdir0=<PROGRAMFILES>\<COMMONFILES> + +[<PROGRAMFILES>\<COMMONFILES>] +DISPLAYTEXT=Common Files Folder +TYPE=TEXTSUBFIXED + +[<TARGETDIR>] +DISPLAYTEXT=General Application Destination +TYPE=TEXTSUBFIXED + +[USERDEFINED] +DISPLAYTEXT=Script-defined Folders +TYPE=USERSTART + + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/Default.cdf b/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/Default.cdf new file mode 100644 index 00000000000..48d37800cd1 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/Default.cdf @@ -0,0 +1,192 @@ +[Development] +required0=Servers +SELECTED=Yes +FILENEED=STANDARD +required1=Grant Tables +HTTPLOCATION= +STATUS=Examples, Libraries, Includes and Script files +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=Examples, Libraries, Includes and Script files +DISPLAYTEXT=Examples, Libraries, Includes and Script files +IMAGE= +DEFSELECTION=Yes +filegroup0=Development +COMMENT= +INCLUDEINBUILD=Yes +INSTALLATION=ALWAYSOVERWRITE +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[Grant Tables] +required0=Servers +SELECTED=Yes +FILENEED=CRITICAL +HTTPLOCATION= +STATUS=The Grant Tables and Core Files +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The Grant Tables and Core Files +DISPLAYTEXT=The Grant Tables and Core Files +IMAGE= +DEFSELECTION=Yes +filegroup0=Grant Tables +requiredby0=Development +COMMENT= +INCLUDEINBUILD=Yes +requiredby1=Clients and Tools +INSTALLATION=NEVEROVERWRITE +requiredby2=Documentation +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[Components] +component0=Development +component1=Grant Tables +component2=Servers +component3=Clients and Tools +component4=Documentation + +[TopComponents] +component0=Servers +component1=Clients and Tools +component2=Documentation +component3=Development +component4=Grant Tables + +[SetupType] +setuptype0=Compact +setuptype1=Typical +setuptype2=Custom + +[Clients and Tools] +required0=Servers +SELECTED=Yes +FILENEED=HIGHLYRECOMMENDED +required1=Grant Tables +HTTPLOCATION= +STATUS=The MySQL clients and Maintenance Tools +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The MySQL clients and Maintenance Tools +DISPLAYTEXT=The MySQL clients and Maintenance Tools +IMAGE= +DEFSELECTION=Yes +filegroup0=Clients and Tools +COMMENT= +INCLUDEINBUILD=Yes +INSTALLATION=NEWERDATE +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[Servers] +SELECTED=Yes +FILENEED=CRITICAL +HTTPLOCATION= +STATUS=The MySQL Servers +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The MySQL Servers +DISPLAYTEXT=The MySQL Servers +IMAGE= +DEFSELECTION=Yes +filegroup0=Servers +requiredby0=Development +COMMENT= +INCLUDEINBUILD=Yes +requiredby1=Grant Tables +INSTALLATION=ALWAYSOVERWRITE +requiredby2=Clients and Tools +requiredby3=Documentation +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[SetupTypeItem-Compact] +Comment= +item0=Grant Tables +item1=Servers +item2=Clients and Tools +item3=Documentation +Descrip= +DisplayText= + +[SetupTypeItem-Custom] +Comment= +item0=Development +item1=Grant Tables +item2=Servers +item3=Clients and Tools +Descrip= +item4=Documentation +DisplayText= + +[Info] +Type=CompDef +Version=1.00.000 +Name= + +[SetupTypeItem-Typical] +Comment= +item0=Development +item1=Grant Tables +item2=Servers +item3=Clients and Tools +Descrip= +item4=Documentation +DisplayText= + +[Documentation] +required0=Servers +SELECTED=Yes +FILENEED=HIGHLYRECOMMENDED +required1=Grant Tables +HTTPLOCATION= +STATUS=The MySQL Documentation with different formats +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The MySQL Documentation with different formats +DISPLAYTEXT=The MySQL Documentation with different formats +IMAGE= +DEFSELECTION=Yes +filegroup0=Documentation +COMMENT= +INCLUDEINBUILD=Yes +INSTALLATION=ALWAYSOVERWRITE +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/Default.fgl b/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/Default.fgl new file mode 100644 index 00000000000..4e20dcea4ab --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Component Definitions/Default.fgl @@ -0,0 +1,42 @@ +[<PROGRAMFILES>\<COMMONFILES>] +DISPLAYTEXT=Common Files Folder +TYPE=TEXTSUBFIXED +fulldirectory= + +[<WINDIR>\<WINSYSDIR>] +DISPLAYTEXT=Windows System Folder +TYPE=TEXTSUBFIXED +fulldirectory= + +[USERDEFINED] +DISPLAYTEXT=Script-defined Folders +TYPE=USERSTART +fulldirectory= + +[<PROGRAMFILES>] +DISPLAYTEXT=Program Files Folder +SubDir0=<PROGRAMFILES>\<COMMONFILES> +TYPE=TEXTSUBFIXED +fulldirectory= + +[<TARGETDIR>] +DISPLAYTEXT=General Application Destination +TYPE=TEXTSUBFIXED +fulldirectory= + +[<WINDIR>] +DISPLAYTEXT=Windows Operating System +SubDir0=<WINDIR>\<WINSYSDIR> +TYPE=TEXTSUBFIXED +fulldirectory= + +[TopDir] +SubDir0=<WINDIR> +SubDir1=<PROGRAMFILES> +SubDir2=<TARGETDIR> +SubDir3=USERDEFINED + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Clients and Tools.fgl b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Clients and Tools.fgl new file mode 100644 index 00000000000..7f30ff9f64b --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Clients and Tools.fgl @@ -0,0 +1,35 @@ +[bin] +file15=C:\mysql\bin\pack_isam.exe +file16=C:\mysql\bin\perror.exe +file0=C:\mysql\bin\isamchk.exe +file17=C:\mysql\bin\replace.exe +file1=C:\mysql\bin\myisamchk.exe +file18=C:\mysql\bin\winmysqladmin.cnt +file2=C:\mysql\bin\myisamlog.exe +file19=C:\mysql\bin\winmysqladmin.exe +file3=C:\mysql\bin\myisampack.exe +file4=C:\mysql\bin\mysql.exe +file5=C:\mysql\bin\mysqladmin.exe +file6=C:\mysql\bin\mysqlbinlog.exe +file7=C:\mysql\bin\mysqlc.exe +file8=C:\mysql\bin\mysqlcheck.exe +file9=C:\mysql\bin\mysqldump.exe +file20=C:\mysql\bin\WINMYSQLADMIN.HLP +file21=C:\mysql\bin\cygwinb19.dll +file10=C:\mysql\bin\mysqlimport.exe +fulldirectory= +file22=C:\mysql\bin\libmySQL.dll +file11=C:\mysql\bin\MySqlManager.exe +file23=C:\mysql\bin\my_print_defaults.exe +file12=C:\mysql\bin\mysqlshow.exe +file24=C:\mysql\bin\comp-err.exe +file13=C:\mysql\bin\mysqlshutdown.exe +file14=C:\mysql\bin\mysqlwatch.exe + +[TopDir] +SubDir0=bin + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Default.fdf b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Default.fdf new file mode 100644 index 00000000000..8096a4b74bf --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Default.fdf @@ -0,0 +1,82 @@ +[FileGroups] +group0=Development +group1=Grant Tables +group2=Servers +group3=Clients and Tools +group4=Documentation + +[Development] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Grant Tables] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Clients and Tools] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM=0000000000000000 +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Servers] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Info] +Type=FileGrp +Version=1.00.000 +Name= + +[Documentation] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Default.fgl b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Default.fgl new file mode 100644 index 00000000000..94344a6ff69 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Default.fgl @@ -0,0 +1,4 @@ +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Development.fgl b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Development.fgl new file mode 100644 index 00000000000..e7b8cc7cd0f --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Development.fgl @@ -0,0 +1,191 @@ +[bench\Data\Wisconsin] +file0=C:\mysql\bench\Data\Wisconsin\onek.data +file1=C:\mysql\bench\Data\Wisconsin\tenk.data +fulldirectory= + +[lib\debug] +file0=C:\mysql\lib\debug\libmySQL.dll +file1=C:\mysql\lib\debug\libmySQL.lib +file2=C:\mysql\lib\debug\mysqlclient.lib +file3=C:\mysql\lib\debug\zlib.lib +fulldirectory= + +[bench\output] +fulldirectory= + +[examples\libmysqltest] +file0=C:\mysql\examples\libmysqltest\myTest.c +file1=C:\mysql\examples\libmysqltest\myTest.dsp +file2=C:\mysql\examples\libmysqltest\myTest.dsw +file3=C:\mysql\examples\libmysqltest\myTest.exe +file4=C:\mysql\examples\libmysqltest\myTest.mak +file5=C:\mysql\examples\libmysqltest\myTest.ncb +file6=C:\mysql\examples\libmysqltest\myTest.opt +file7=C:\mysql\examples\libmysqltest\readme +fulldirectory= + +[include] +file0=C:\mysql\include\raid.h +file1=C:\mysql\include\errmsg.h +file2=C:\mysql\include\Libmysql.def +file3=C:\mysql\include\m_ctype.h +file4=C:\mysql\include\m_string.h +file5=C:\mysql\include\my_list.h +file6=C:\mysql\include\my_pthread.h +file7=C:\mysql\include\my_sys.h +file8=C:\mysql\include\mysql.h +file9=C:\mysql\include\mysql_com.h +file10=C:\mysql\include\mysql_version.h +fulldirectory= +file11=C:\mysql\include\mysqld_error.h +file12=C:\mysql\include\dbug.h +file13=C:\mysql\include\my_global.h +file14=C:\mysql\include\config-win.h + +[examples] +SubDir0=examples\libmysqltest +SubDir1=examples\tests +fulldirectory= + +[lib\opt] +file0=C:\mysql\lib\opt\libmySQL.dll +file1=C:\mysql\lib\opt\libmySQL.lib +file2=C:\mysql\lib\opt\mysqlclient.lib +file3=C:\mysql\lib\opt\zlib.lib +fulldirectory= + +[bench\Data] +SubDir0=bench\Data\ATIS +SubDir1=bench\Data\Wisconsin +fulldirectory= + +[bench\limits] +file15=C:\mysql\bench\limits\pg.comment +file16=C:\mysql\bench\limits\solid.cfg +file0=C:\mysql\bench\limits\access.cfg +file17=C:\mysql\bench\limits\solid-nt4.cfg +file1=C:\mysql\bench\limits\access.comment +file18=C:\mysql\bench\limits\sybase.cfg +file2=C:\mysql\bench\limits\Adabas.cfg +file3=C:\mysql\bench\limits\Adabas.comment +file4=C:\mysql\bench\limits\Db2.cfg +file5=C:\mysql\bench\limits\empress.cfg +file6=C:\mysql\bench\limits\empress.comment +file7=C:\mysql\bench\limits\Informix.cfg +file8=C:\mysql\bench\limits\Informix.comment +file9=C:\mysql\bench\limits\msql.cfg +file10=C:\mysql\bench\limits\ms-sql.cfg +fulldirectory= +file11=C:\mysql\bench\limits\Ms-sql65.cfg +file12=C:\mysql\bench\limits\mysql.cfg +file13=C:\mysql\bench\limits\oracle.cfg +file14=C:\mysql\bench\limits\pg.cfg + +[TopDir] +SubDir0=bench +SubDir1=examples +SubDir2=include +SubDir3=lib +SubDir4=scripts + +[bench] +file15=C:\mysql\bench\test-create +file16=C:\mysql\bench\test-insert +file0=C:\mysql\bench\uname.bat +file17=C:\mysql\bench\test-select +file1=C:\mysql\bench\compare-results +file18=C:\mysql\bench\test-wisconsin +file2=C:\mysql\bench\copy-db +file19=C:\mysql\bench\bench-init.pl +file3=C:\mysql\bench\crash-me +file4=C:\mysql\bench\example.bat +file5=C:\mysql\bench\print-limit-table +file6=C:\mysql\bench\pwd.bat +file7=C:\mysql\bench\Readme +SubDir0=bench\Data +file8=C:\mysql\bench\run.bat +SubDir1=bench\limits +file9=C:\mysql\bench\run-all-tests +SubDir2=bench\output +file10=C:\mysql\bench\server-cfg +fulldirectory= +file11=C:\mysql\bench\test-alter-table +file12=C:\mysql\bench\test-ATIS +file13=C:\mysql\bench\test-big-tables +file14=C:\mysql\bench\test-connect + +[examples\tests] +file15=C:\mysql\examples\tests\lock_test.res +file16=C:\mysql\examples\tests\mail_to_db.pl +file0=C:\mysql\examples\tests\unique_users.tst +file17=C:\mysql\examples\tests\table_types.pl +file1=C:\mysql\examples\tests\auto_increment.tst +file18=C:\mysql\examples\tests\test_delayed_insert.pl +file2=C:\mysql\examples\tests\big_record.pl +file19=C:\mysql\examples\tests\udf_test +file3=C:\mysql\examples\tests\big_record.res +file4=C:\mysql\examples\tests\czech-sorting +file5=C:\mysql\examples\tests\deadlock-script.pl +file6=C:\mysql\examples\tests\export.pl +file7=C:\mysql\examples\tests\fork_test.pl +file8=C:\mysql\examples\tests\fork2_test.pl +file9=C:\mysql\examples\tests\fork3_test.pl +file20=C:\mysql\examples\tests\udf_test.res +file21=C:\mysql\examples\tests\auto_increment.res +file10=C:\mysql\examples\tests\function.res +fulldirectory= +file11=C:\mysql\examples\tests\function.tst +file12=C:\mysql\examples\tests\grant.pl +file13=C:\mysql\examples\tests\grant.res +file14=C:\mysql\examples\tests\lock_test.pl + +[bench\Data\ATIS] +file26=C:\mysql\bench\Data\ATIS\stop1.txt +file15=C:\mysql\bench\Data\ATIS\flight_class.txt +file27=C:\mysql\bench\Data\ATIS\time_interval.txt +file16=C:\mysql\bench\Data\ATIS\flight_day.txt +file0=C:\mysql\bench\Data\ATIS\transport.txt +file28=C:\mysql\bench\Data\ATIS\time_zone.txt +file17=C:\mysql\bench\Data\ATIS\flight_fare.txt +file1=C:\mysql\bench\Data\ATIS\airline.txt +file29=C:\mysql\bench\Data\ATIS\aircraft.txt +file18=C:\mysql\bench\Data\ATIS\food_service.txt +file2=C:\mysql\bench\Data\ATIS\airport.txt +file19=C:\mysql\bench\Data\ATIS\ground_service.txt +file3=C:\mysql\bench\Data\ATIS\airport_service.txt +file4=C:\mysql\bench\Data\ATIS\city.txt +file5=C:\mysql\bench\Data\ATIS\class_of_service.txt +file6=C:\mysql\bench\Data\ATIS\code_description.txt +file7=C:\mysql\bench\Data\ATIS\compound_class.txt +file8=C:\mysql\bench\Data\ATIS\connect_leg.txt +file9=C:\mysql\bench\Data\ATIS\date_day.txt +file20=C:\mysql\bench\Data\ATIS\month_name.txt +file21=C:\mysql\bench\Data\ATIS\restrict_carrier.txt +file10=C:\mysql\bench\Data\ATIS\day_name.txt +fulldirectory= +file22=C:\mysql\bench\Data\ATIS\restrict_class.txt +file11=C:\mysql\bench\Data\ATIS\dual_carrier.txt +file23=C:\mysql\bench\Data\ATIS\restriction.txt +file12=C:\mysql\bench\Data\ATIS\fare.txt +file24=C:\mysql\bench\Data\ATIS\state.txt +file13=C:\mysql\bench\Data\ATIS\fconnection.txt +file25=C:\mysql\bench\Data\ATIS\stop.txt +file14=C:\mysql\bench\Data\ATIS\flight.txt + +[General] +Type=FILELIST +Version=1.00.000 + +[scripts] +file0=C:\mysql\scripts\mysql_find_rows.pl +file1=C:\mysql\scripts\mysql_setpermission.pl +file2=C:\mysql\scripts\mysqlhotcopy.pl +file3=C:\mysql\scripts\Readme +fulldirectory= + +[lib] +file0=C:\mysql\lib\Readme +SubDir0=lib\debug +SubDir1=lib\opt +fulldirectory= + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Documentation.fgl b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Documentation.fgl new file mode 100644 index 00000000000..80fe777cf0f --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Documentation.fgl @@ -0,0 +1,99 @@ +[Docs\Flags] +file59=C:\mysql\Docs\Flags\romania.gif +file48=C:\mysql\Docs\Flags\kroatia.eps +file37=C:\mysql\Docs\Flags\iceland.gif +file26=C:\mysql\Docs\Flags\france.eps +file15=C:\mysql\Docs\Flags\china.gif +file49=C:\mysql\Docs\Flags\kroatia.gif +file38=C:\mysql\Docs\Flags\ireland.eps +file27=C:\mysql\Docs\Flags\france.gif +file16=C:\mysql\Docs\Flags\croatia.eps +file0=C:\mysql\Docs\Flags\usa.gif +file39=C:\mysql\Docs\Flags\ireland.gif +file28=C:\mysql\Docs\Flags\germany.eps +file17=C:\mysql\Docs\Flags\croatia.gif +file1=C:\mysql\Docs\Flags\argentina.gif +file29=C:\mysql\Docs\Flags\germany.gif +file18=C:\mysql\Docs\Flags\czech-republic.eps +file2=C:\mysql\Docs\Flags\australia.eps +file19=C:\mysql\Docs\Flags\czech-republic.gif +file3=C:\mysql\Docs\Flags\australia.gif +file80=C:\mysql\Docs\Flags\usa.eps +file4=C:\mysql\Docs\Flags\austria.eps +file81=C:\mysql\Docs\Flags\argentina.eps +file70=C:\mysql\Docs\Flags\spain.eps +file5=C:\mysql\Docs\Flags\austria.gif +file71=C:\mysql\Docs\Flags\spain.gif +file60=C:\mysql\Docs\Flags\russia.eps +file6=C:\mysql\Docs\Flags\brazil.eps +file72=C:\mysql\Docs\Flags\sweden.eps +file61=C:\mysql\Docs\Flags\russia.gif +file50=C:\mysql\Docs\Flags\latvia.eps +file7=C:\mysql\Docs\Flags\brazil.gif +file73=C:\mysql\Docs\Flags\sweden.gif +file62=C:\mysql\Docs\Flags\singapore.eps +file51=C:\mysql\Docs\Flags\latvia.gif +file40=C:\mysql\Docs\Flags\island.eps +file8=C:\mysql\Docs\Flags\bulgaria.eps +file74=C:\mysql\Docs\Flags\switzerland.eps +file63=C:\mysql\Docs\Flags\singapore.gif +file52=C:\mysql\Docs\Flags\netherlands.eps +file41=C:\mysql\Docs\Flags\island.gif +file30=C:\mysql\Docs\Flags\great-britain.eps +file9=C:\mysql\Docs\Flags\bulgaria.gif +file75=C:\mysql\Docs\Flags\switzerland.gif +file64=C:\mysql\Docs\Flags\south-africa.eps +file53=C:\mysql\Docs\Flags\netherlands.gif +file42=C:\mysql\Docs\Flags\israel.eps +file31=C:\mysql\Docs\Flags\great-britain.gif +file20=C:\mysql\Docs\Flags\denmark.eps +file76=C:\mysql\Docs\Flags\taiwan.eps +file65=C:\mysql\Docs\Flags\south-africa.gif +file54=C:\mysql\Docs\Flags\poland.eps +file43=C:\mysql\Docs\Flags\israel.gif +file32=C:\mysql\Docs\Flags\greece.eps +file21=C:\mysql\Docs\Flags\denmark.gif +file10=C:\mysql\Docs\Flags\canada.eps +fulldirectory= +file77=C:\mysql\Docs\Flags\taiwan.gif +file66=C:\mysql\Docs\Flags\south-africa1.eps +file55=C:\mysql\Docs\Flags\poland.gif +file44=C:\mysql\Docs\Flags\italy.eps +file33=C:\mysql\Docs\Flags\greece.gif +file22=C:\mysql\Docs\Flags\estonia.eps +file11=C:\mysql\Docs\Flags\canada.gif +file78=C:\mysql\Docs\Flags\ukraine.eps +file67=C:\mysql\Docs\Flags\south-africa1.gif +file56=C:\mysql\Docs\Flags\portugal.eps +file45=C:\mysql\Docs\Flags\italy.gif +file34=C:\mysql\Docs\Flags\hungary.eps +file23=C:\mysql\Docs\Flags\estonia.gif +file12=C:\mysql\Docs\Flags\chile.eps +file79=C:\mysql\Docs\Flags\ukraine.gif +file68=C:\mysql\Docs\Flags\south-korea.eps +file57=C:\mysql\Docs\Flags\portugal.gif +file46=C:\mysql\Docs\Flags\japan.eps +file35=C:\mysql\Docs\Flags\hungary.gif +file24=C:\mysql\Docs\Flags\finland.eps +file13=C:\mysql\Docs\Flags\chile.gif +file69=C:\mysql\Docs\Flags\south-korea.gif +file58=C:\mysql\Docs\Flags\romania.eps +file47=C:\mysql\Docs\Flags\japan.gif +file36=C:\mysql\Docs\Flags\iceland.eps +file25=C:\mysql\Docs\Flags\finland.gif +file14=C:\mysql\Docs\Flags\china.eps + +[Docs] +file0=C:\mysql\Docs\manual_toc.html +file1=C:\mysql\Docs\manual.html +file2=C:\mysql\Docs\manual.txt +SubDir0=Docs\Flags +fulldirectory= + +[TopDir] +SubDir0=Docs + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Grant Tables.fgl b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Grant Tables.fgl new file mode 100644 index 00000000000..178065a7003 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Grant Tables.fgl @@ -0,0 +1,36 @@ +[data\test] +fulldirectory= + +[data\mysql] +file15=C:\mysql\data\mysql\func.frm +file16=C:\mysql\data\mysql\func.MYD +file0=C:\mysql\data\mysql\columns_priv.frm +file17=C:\mysql\data\mysql\func.MYI +file1=C:\mysql\data\mysql\columns_priv.MYD +file2=C:\mysql\data\mysql\columns_priv.MYI +file3=C:\mysql\data\mysql\db.frm +file4=C:\mysql\data\mysql\db.MYD +file5=C:\mysql\data\mysql\db.MYI +file6=C:\mysql\data\mysql\host.frm +file7=C:\mysql\data\mysql\host.MYD +file8=C:\mysql\data\mysql\host.MYI +file9=C:\mysql\data\mysql\tables_priv.frm +file10=C:\mysql\data\mysql\tables_priv.MYD +fulldirectory= +file11=C:\mysql\data\mysql\tables_priv.MYI +file12=C:\mysql\data\mysql\user.frm +file13=C:\mysql\data\mysql\user.MYD +file14=C:\mysql\data\mysql\user.MYI + +[TopDir] +SubDir0=data + +[data] +SubDir0=data\mysql +SubDir1=data\test +fulldirectory= + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Servers.fgl b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Servers.fgl new file mode 100644 index 00000000000..b23e2f90595 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/File Groups/Servers.fgl @@ -0,0 +1,184 @@ +[share\polish] +file0=C:\mysql\share\polish\errmsg.sys +file1=C:\mysql\share\polish\errmsg.txt +fulldirectory= + +[share\dutch] +file0=C:\mysql\share\dutch\errmsg.sys +file1=C:\mysql\share\dutch\errmsg.txt +fulldirectory= + +[share\spanish] +file0=C:\mysql\share\spanish\errmsg.sys +file1=C:\mysql\share\spanish\errmsg.txt +fulldirectory= + +[share\english] +file0=C:\mysql\share\english\errmsg.sys +file1=C:\mysql\share\english\errmsg.txt +fulldirectory= + +[bin] +file0=C:\mysql\bin\mysqld-opt.exe +file1=C:\mysql\bin\mysqld-max.exe +file2=C:\mysql\bin\mysqld-max-nt.exe +file3=C:\mysql\bin\mysqld-nt.exe +file4=C:\mysql\bin\mysqld.exe +fulldirectory= + +[share\korean] +file0=C:\mysql\share\korean\errmsg.sys +file1=C:\mysql\share\korean\errmsg.txt +fulldirectory= + +[share\charsets] +file15=C:\mysql\share\charsets\latin1.conf +file16=C:\mysql\share\charsets\latin2.conf +file0=C:\mysql\share\charsets\win1251ukr.conf +file17=C:\mysql\share\charsets\latin5.conf +file1=C:\mysql\share\charsets\cp1257.conf +file18=C:\mysql\share\charsets\Readme +file2=C:\mysql\share\charsets\croat.conf +file19=C:\mysql\share\charsets\swe7.conf +file3=C:\mysql\share\charsets\danish.conf +file4=C:\mysql\share\charsets\dec8.conf +file5=C:\mysql\share\charsets\dos.conf +file6=C:\mysql\share\charsets\estonia.conf +file7=C:\mysql\share\charsets\german1.conf +file8=C:\mysql\share\charsets\greek.conf +file9=C:\mysql\share\charsets\hebrew.conf +file20=C:\mysql\share\charsets\usa7.conf +file21=C:\mysql\share\charsets\win1250.conf +file10=C:\mysql\share\charsets\hp8.conf +fulldirectory= +file22=C:\mysql\share\charsets\win1251.conf +file11=C:\mysql\share\charsets\hungarian.conf +file23=C:\mysql\share\charsets\cp1251.conf +file12=C:\mysql\share\charsets\Index +file13=C:\mysql\share\charsets\koi8_ru.conf +file14=C:\mysql\share\charsets\koi8_ukr.conf + +[share\ukrainian] +file0=C:\mysql\share\ukrainian\errmsg.sys +file1=C:\mysql\share\ukrainian\errmsg.txt +fulldirectory= + +[share\hungarian] +file0=C:\mysql\share\hungarian\errmsg.sys +file1=C:\mysql\share\hungarian\errmsg.txt +fulldirectory= + +[share\german] +file0=C:\mysql\share\german\errmsg.sys +file1=C:\mysql\share\german\errmsg.txt +fulldirectory= + +[share\portuguese] +file0=C:\mysql\share\portuguese\errmsg.sys +file1=C:\mysql\share\portuguese\errmsg.txt +fulldirectory= + +[share\estonian] +file0=C:\mysql\share\estonian\errmsg.sys +file1=C:\mysql\share\estonian\errmsg.txt +fulldirectory= + +[share\romanian] +file0=C:\mysql\share\romanian\errmsg.sys +file1=C:\mysql\share\romanian\errmsg.txt +fulldirectory= + +[share\french] +file0=C:\mysql\share\french\errmsg.sys +file1=C:\mysql\share\french\errmsg.txt +fulldirectory= + +[share\swedish] +file0=C:\mysql\share\swedish\errmsg.sys +file1=C:\mysql\share\swedish\errmsg.txt +fulldirectory= + +[share\slovak] +file0=C:\mysql\share\slovak\errmsg.sys +file1=C:\mysql\share\slovak\errmsg.txt +fulldirectory= + +[share\greek] +file0=C:\mysql\share\greek\errmsg.sys +file1=C:\mysql\share\greek\errmsg.txt +fulldirectory= + +[TopDir] +file0=C:\mysql\mysqlbug.txt +file1=C:\mysql\my-small.cnf +file2=C:\mysql\my-large.cnf +file3=C:\mysql\my-medium.cnf +file4=C:\mysql\my-huge.cnf +SubDir0=bin +SubDir1=share + +[share] +SubDir8=share\hungarian +SubDir9=share\charsets +SubDir20=share\spanish +SubDir21=share\swedish +SubDir10=share\italian +SubDir22=share\ukrainian +SubDir11=share\japanese +SubDir12=share\korean +SubDir13=share\norwegian +SubDir14=share\norwegian-ny +SubDir15=share\polish +SubDir16=share\portuguese +SubDir0=share\czech +SubDir17=share\romanian +SubDir1=share\danish +SubDir18=share\russian +SubDir2=share\dutch +SubDir19=share\slovak +SubDir3=share\english +fulldirectory= +SubDir4=share\estonian +SubDir5=share\french +SubDir6=share\german +SubDir7=share\greek + +[share\norwegian-ny] +file0=C:\mysql\share\norwegian-ny\errmsg.sys +file1=C:\mysql\share\norwegian-ny\errmsg.txt +fulldirectory= + +[share\danish] +file0=C:\mysql\share\danish\errmsg.sys +file1=C:\mysql\share\danish\errmsg.txt +fulldirectory= + +[share\czech] +file0=C:\mysql\share\czech\errmsg.sys +file1=C:\mysql\share\czech\errmsg.txt +fulldirectory= + +[General] +Type=FILELIST +Version=1.00.000 + +[share\russian] +file0=C:\mysql\share\russian\errmsg.sys +file1=C:\mysql\share\russian\errmsg.txt +fulldirectory= + +[share\norwegian] +file0=C:\mysql\share\norwegian\errmsg.sys +file1=C:\mysql\share\norwegian\errmsg.txt +fulldirectory= + +[share\japanese] +file0=C:\mysql\share\japanese\errmsg.sys +file1=C:\mysql\share\japanese\errmsg.txt +fulldirectory= + +[share\italian] +file0=C:\mysql\share\italian\errmsg.sys +file1=C:\mysql\share\italian\errmsg.txt +fulldirectory= + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/MySQL 3.23.XX-GPL.ipr b/VC++Files/InstallShield/3.23.XX-gpl/MySQL 3.23.XX-GPL.ipr new file mode 100644 index 00000000000..de15790e744 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/MySQL 3.23.XX-GPL.ipr @@ -0,0 +1,51 @@ +[Language] +LanguageSupport0=0009 + +[OperatingSystem] +OSSupport=0000000000010010 + +[Data] +CurrentMedia= +CurrentComponentDef=Default.cdf +ProductName=MySQL Servers and Clients +set_mifserial= +DevEnvironment=Microsoft Visual C++ 6 +AppExe= +set_dlldebug=No +EmailAddresss= +Instructions=Instructions.txt +set_testmode=No +set_mif=No +SummaryText= +Department= +HomeURL= +Author= +Type=Database Application +InstallRoot=C:\MySQL-Install\3.23.XX-gpl +Version=1.00.000 +InstallationGUID=40744a4d-efed-4cff-84a9-9e6389550f5c +set_level=Level 3 +CurrentFileGroupDef=Default.fdf +Notes=Notes.txt +set_maxerr=50 +set_args= +set_miffile=Status.mif +set_dllcmdline= +Copyright= +set_warnaserr=No +CurrentPlatform= +Category= +set_preproc= +CurrentLanguage=English +CompanyName=MySQL +Description=Description.txt +set_maxwarn=50 +set_crc=Yes +set_compileb4build=No + +[MediaInfo] + +[General] +Type=INSTALLMAIN +Version=1.10.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Registry Entries/Default.rge b/VC++Files/InstallShield/3.23.XX-gpl/Registry Entries/Default.rge new file mode 100644 index 00000000000..537dfd82e48 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Registry Entries/Default.rge @@ -0,0 +1,4 @@ +[General] +Type=REGISTRYDATA +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.dbg b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.dbg Binary files differnew file mode 100644 index 00000000000..0c6d4e6b708 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.dbg diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.ino b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.ino Binary files differnew file mode 100644 index 00000000000..204d8ea0f36 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.ino diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.ins b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.ins Binary files differnew file mode 100644 index 00000000000..759009b5c84 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.ins diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.obs b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.obs Binary files differnew file mode 100644 index 00000000000..5fcfcb62c4e --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.obs diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.rul b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.rul new file mode 100644 index 00000000000..0db8417a62c --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Script Files/Setup.rul @@ -0,0 +1,641 @@ + +//////////////////////////////////////////////////////////////////////////////// +// +// IIIIIII SSSSSS +// II SS InstallShield (R) +// II SSSSSS (c) 1996-1997, InstallShield Software Corporation +// II SS (c) 1990-1996, InstallShield Corporation +// IIIIIII SSSSSS All Rights Reserved. +// +// +// This code is generated as a starting setup template. You should +// modify it to provide all necessary steps for your setup. +// +// +// File Name: Setup.rul +// +// Description: InstallShield script +// +// Comments: This template script performs a basic setup on a +// Windows 95 or Windows NT 4.0 platform. With minor +// modifications, this template can be adapted to create +// new, customized setups. +// +//////////////////////////////////////////////////////////////////////////////// + + + // Include header file +#include "sdlang.h" +#include "sddialog.h" + +////////////////////// string defines //////////////////////////// + +#define UNINST_LOGFILE_NAME "Uninst.isu" + +//////////////////// installation declarations /////////////////// + + // ----- DLL prototypes ----- + + + // your DLL prototypes + + + // ---- script prototypes ----- + + // generated + prototype ShowDialogs(); + prototype MoveFileData(); + prototype HandleMoveDataError( NUMBER ); + prototype ProcessBeforeDataMove(); + prototype ProcessAfterDataMove(); + prototype SetupRegistry(); + prototype SetupFolders(); + prototype CleanUpInstall(); + prototype SetupInstall(); + prototype SetupScreen(); + prototype CheckRequirements(); + prototype DialogShowSdWelcome(); + prototype DialogShowSdShowInfoList(); + prototype DialogShowSdAskDestPath(); + prototype DialogShowSdSetupType(); + prototype DialogShowSdComponentDialog2(); + prototype DialogShowSdFinishReboot(); + + // your prototypes + + + // ----- global variables ------ + + // generated + BOOL bWinNT, bIsShellExplorer, bInstallAborted, bIs32BitSetup; + STRING svDir; + STRING svName, svCompany, svSerial; + STRING szAppPath; + STRING svSetupType; + + + // your global variables + + +/////////////////////////////////////////////////////////////////////////////// +// +// MAIN PROGRAM +// +// The setup begins here by hiding the visible setup +// window. This is done to allow all the titles, images, etc. to +// be established before showing the main window. The following +// logic then performs the setup in a series of steps. +// +/////////////////////////////////////////////////////////////////////////////// +program + Disable( BACKGROUND ); + + CheckRequirements(); + + SetupInstall(); + + SetupScreen(); + + if (ShowDialogs()<0) goto end_install; + + if (ProcessBeforeDataMove()<0) goto end_install; + + if (MoveFileData()<0) goto end_install; + + if (ProcessAfterDataMove()<0) goto end_install; + + if (SetupRegistry()<0) goto end_install; + + if (SetupFolders()<0) goto end_install; + + + end_install: + + CleanUpInstall(); + + // If an unrecoverable error occurred, clean up the partial installation. + // Otherwise, exit normally. + + if (bInstallAborted) then + abort; + endif; + +endprogram + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: ShowDialogs // +// // +// Purpose: This function manages the display and navigation // +// the standard dialogs that exist in a setup. // +// // +/////////////////////////////////////////////////////////////////////////////// +function ShowDialogs() + NUMBER nResult; + begin + + Dlg_Start: + // beginning of dialogs label + + Dlg_SdWelcome: + nResult = DialogShowSdWelcome(); + if (nResult = BACK) goto Dlg_Start; + + Dlg_SdShowInfoList: + nResult = DialogShowSdShowInfoList(); + if (nResult = BACK) goto Dlg_SdWelcome; + + Dlg_SdAskDestPath: + nResult = DialogShowSdAskDestPath(); + if (nResult = BACK) goto Dlg_SdShowInfoList; + + Dlg_SdSetupType: + nResult = DialogShowSdSetupType(); + if (nResult = BACK) goto Dlg_SdAskDestPath; + + Dlg_SdComponentDialog2: + if ((nResult = BACK) && (svSetupType != "Custom") && (svSetupType != "")) then + goto Dlg_SdSetupType; + endif; + nResult = DialogShowSdComponentDialog2(); + if (nResult = BACK) goto Dlg_SdSetupType; + + return 0; + + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: ProcessBeforeDataMove // +// // +// Purpose: This function performs any necessary operations prior to the // +// actual data move operation. // +// // +/////////////////////////////////////////////////////////////////////////////// +function ProcessBeforeDataMove() + STRING svLogFile; + NUMBER nResult; + begin + + InstallationInfo( @COMPANY_NAME, @PRODUCT_NAME, @PRODUCT_VERSION, @PRODUCT_KEY ); + + svLogFile = UNINST_LOGFILE_NAME; + + nResult = DeinstallStart( svDir, svLogFile, @UNINST_KEY, 0 ); + if (nResult < 0) then + MessageBox( @ERROR_UNINSTSETUP, WARNING ); + endif; + + szAppPath = TARGETDIR; // TODO : if your application .exe is in a subdir of TARGETDIR then add subdir + + if ((bIs32BitSetup) && (bIsShellExplorer)) then + RegDBSetItem( REGDB_APPPATH, szAppPath ); + RegDBSetItem( REGDB_APPPATH_DEFAULT, szAppPath ^ @PRODUCT_KEY ); + RegDBSetItem( REGDB_UNINSTALL_NAME, @UNINST_DISPLAY_NAME ); + endif; + + // TODO : update any items you want to process before moving the data + // + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: MoveFileData // +// // +// Purpose: This function handles the data movement for // +// the setup. // +// // +/////////////////////////////////////////////////////////////////////////////// +function MoveFileData() + NUMBER nResult, nDisk; + begin + + nDisk = 1; + SetStatusWindow( 0, "" ); + Disable( DIALOGCACHE ); + Enable( STATUS ); + StatusUpdate( ON, 100 ); + nResult = ComponentMoveData( MEDIA, nDisk, 0 ); + + HandleMoveDataError( nResult ); + + Disable( STATUS ); + + return nResult; + + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: HandleMoveDataError // +// // +// Purpose: This function handles the error (if any) during the move data // +// operation. // +// // +/////////////////////////////////////////////////////////////////////////////// +function HandleMoveDataError( nResult ) + STRING szErrMsg, svComponent , svFileGroup , svFile; + begin + + svComponent = ""; + svFileGroup = ""; + svFile = ""; + + switch (nResult) + case 0: + return 0; + default: + ComponentError ( MEDIA , svComponent , svFileGroup , svFile , nResult ); + szErrMsg = @ERROR_MOVEDATA + "\n\n" + + @ERROR_COMPONENT + " " + svComponent + "\n" + + @ERROR_FILEGROUP + " " + svFileGroup + "\n" + + @ERROR_FILE + " " + svFile; + SprintfBox( SEVERE, @TITLE_CAPTIONBAR, szErrMsg, nResult ); + bInstallAborted = TRUE; + return nResult; + endswitch; + + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: ProcessAfterDataMove // +// // +// Purpose: This function performs any necessary operations needed after // +// all data has been moved. // +// // +/////////////////////////////////////////////////////////////////////////////// +function ProcessAfterDataMove() + begin + + // TODO : update self-registered files and other processes that + // should be performed after the data has been moved. + + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: SetupRegistry // +// // +// Purpose: This function makes the registry entries for this setup. // +// // +/////////////////////////////////////////////////////////////////////////////// +function SetupRegistry() + NUMBER nResult; + + begin + + // TODO : Add all your registry entry keys here + // + // + // RegDBCreateKeyEx, RegDBSetKeyValueEx.... + // + + nResult = CreateRegistrySet( "" ); + + return nResult; + end; + +/////////////////////////////////////////////////////////////////////////////// +// +// Function: SetupFolders +// +// Purpose: This function creates all the folders and shortcuts for the +// setup. This includes program groups and items for Windows 3.1. +// +/////////////////////////////////////////////////////////////////////////////// +function SetupFolders() + NUMBER nResult; + + begin + + + // TODO : Add all your folder (program group) along with shortcuts (program items) + // + // + // CreateProgramFolder, AddFolderIcon.... + // + + nResult = CreateShellObjects( "" ); + + return nResult; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: CleanUpInstall // +// // +// Purpose: This cleans up the setup. Anything that should // +// be released or deleted at the end of the setup should // +// be done here. // +// // +/////////////////////////////////////////////////////////////////////////////// +function CleanUpInstall() + begin + + + if (bInstallAborted) then + return 0; + endif; + + DialogShowSdFinishReboot(); + + if (BATCH_INSTALL) then // ensure locked files are properly written + CommitSharedFiles(0); + endif; + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: SetupInstall // +// // +// Purpose: This will setup the installation. Any general initialization // +// needed for the installation should be performed here. // +// // +/////////////////////////////////////////////////////////////////////////////// +function SetupInstall() + begin + + Enable( CORECOMPONENTHANDLING ); + + bInstallAborted = FALSE; + + if (bIs32BitSetup) then + svDir = "C:\\mysql"; //PROGRAMFILES ^ @COMPANY_NAME ^ @PRODUCT_NAME; + else + svDir = "C:\\mysql"; //PROGRAMFILES ^ @COMPANY_NAME16 ^ @PRODUCT_NAME16; // use shorten names + endif; + + TARGETDIR = svDir; + + SdProductName( @PRODUCT_NAME ); + + Enable( DIALOGCACHE ); + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: SetupScreen // +// // +// Purpose: This function establishes the screen look. This includes // +// colors, fonts, and text to be displayed. // +// // +/////////////////////////////////////////////////////////////////////////////// +function SetupScreen() + begin + + Enable( FULLWINDOWMODE ); + Enable( INDVFILESTATUS ); + SetTitle( @TITLE_MAIN, 24, WHITE ); + + SetTitle( @TITLE_CAPTIONBAR, 0, BACKGROUNDCAPTION ); // Caption bar text. + + Enable( BACKGROUND ); + + Delay( 1 ); + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: CheckRequirements // +// // +// Purpose: This function checks all minimum requirements for the // +// application being installed. If any fail, then the user // +// is informed and the setup is terminated. // +// // +/////////////////////////////////////////////////////////////////////////////// +function CheckRequirements() + NUMBER nvDx, nvDy, nvResult; + STRING svResult; + + begin + + bWinNT = FALSE; + bIsShellExplorer = FALSE; + + // Check screen resolution. + GetExtents( nvDx, nvDy ); + + if (nvDy < 480) then + MessageBox( @ERROR_VGARESOLUTION, WARNING ); + abort; + endif; + + // set 'setup' operation mode + bIs32BitSetup = TRUE; + GetSystemInfo( ISTYPE, nvResult, svResult ); + if (nvResult = 16) then + bIs32BitSetup = FALSE; // running 16-bit setup + return 0; // no additional information required + endif; + + // --- 32-bit testing after this point --- + + // Determine the target system's operating system. + GetSystemInfo( OS, nvResult, svResult ); + + if (nvResult = IS_WINDOWSNT) then + // Running Windows NT. + bWinNT = TRUE; + + // Check to see if the shell being used is EXPLORER shell. + if (GetSystemInfo( OSMAJOR, nvResult, svResult ) = 0) then + if (nvResult >= 4) then + bIsShellExplorer = TRUE; + endif; + endif; + + elseif (nvResult = IS_WINDOWS95 ) then + bIsShellExplorer = TRUE; + + endif; + +end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdWelcome // +// // +// Purpose: This function handles the standard welcome dialog. // +// // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdWelcome() + NUMBER nResult; + STRING szTitle, szMsg; + begin + + szTitle = ""; + szMsg = ""; + nResult = SdWelcome( szTitle, szMsg ); + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdShowInfoList // +// // +// Purpose: This function displays the general information list dialog. // +// // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdShowInfoList() + NUMBER nResult; + LIST list; + STRING szTitle, szMsg, szFile; + begin + + szFile = SUPPORTDIR ^ "infolist.txt"; + + list = ListCreate( STRINGLIST ); + ListReadFromFile( list, szFile ); + szTitle = ""; + szMsg = " "; + nResult = SdShowInfoList( szTitle, szMsg, list ); + + ListDestroy( list ); + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdAskDestPath // +// // +// Purpose: This function asks the user for the destination directory. // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdAskDestPath() + NUMBER nResult; + STRING szTitle, szMsg; + begin + + szTitle = ""; + szMsg = ""; + nResult = SdAskDestPath( szTitle, szMsg, svDir, 0 ); + + TARGETDIR = svDir; + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdSetupType // +// // +// Purpose: This function displays the standard setup type dialog. // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdSetupType() + NUMBER nResult, nType; + STRING szTitle, szMsg; + begin + + switch (svSetupType) + case "Typical": + nType = TYPICAL; + case "Custom": + nType = CUSTOM; + case "Compact": + nType = COMPACT; + case "": + svSetupType = "Typical"; + nType = TYPICAL; + endswitch; + + szTitle = ""; + szMsg = ""; + nResult = SetupType( szTitle, szMsg, "", nType, 0 ); + + switch (nResult) + case COMPACT: + svSetupType = "Compact"; + case TYPICAL: + svSetupType = "Typical"; + case CUSTOM: + svSetupType = "Custom"; + endswitch; + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdComponentDialog2 // +// // +// Purpose: This function displays the custom component dialog. // +// // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdComponentDialog2() + NUMBER nResult; + STRING szTitle, szMsg; + begin + + if ((svSetupType != "Custom") && (svSetupType != "")) then + return 0; + endif; + + szTitle = ""; + szMsg = ""; + nResult = SdComponentDialog2( szTitle, szMsg, svDir, "" ); + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdFinishReboot // +// // +// Purpose: This function will show the last dialog of the product. // +// It will allow the user to reboot and/or show some readme text. // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdFinishReboot() + NUMBER nResult, nDefOptions; + STRING szTitle, szMsg1, szMsg2, szOption1, szOption2; + NUMBER bOpt1, bOpt2; + begin +/* + if (!BATCH_INSTALL) then + bOpt1 = FALSE; + bOpt2 = FALSE; + szMsg1 = ""; + szMsg2 = ""; + szOption1 = ""; + szOption2 = ""; + nResult = SdFinish( szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2 ); + return 0; + endif; + + nDefOptions = SYS_BOOTMACHINE; + szTitle = ""; + szMsg1 = ""; + szMsg2 = ""; + nResult = SdFinishReboot( szTitle, szMsg1, nDefOptions, szMsg2, 0 ); +*/ + return nResult; + end; + + // --- include script file section --- + +#include "sddialog.rul" + + + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Setup Files/Compressed Files/Language Independent/OS Independent/infolist.txt b/VC++Files/InstallShield/3.23.XX-gpl/Setup Files/Compressed Files/Language Independent/OS Independent/infolist.txt new file mode 100644 index 00000000000..2f561d29d81 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Setup Files/Compressed Files/Language Independent/OS Independent/infolist.txt @@ -0,0 +1,24 @@ +This is a release of MySQL 3.23.56 for Win32. + +NOTE: If you install MySQL in a folder other than +C:\MYSQL or you intend to start MySQL on NT/Win2000 +as a service, you must create a file named C:\MY.CNF +or \Windows\my.ini or \winnt\my.ini with the following +information:: + +[mysqld] +basedir=E:/installation-path/ +datadir=E:/data-path/ + +After your have installed MySQL, the installation +directory which contains the files named 'my-size.cnf'. +You can use this as a starting point for your own +C:\my.cnf file. + +If you have any problems, you can mail them to +win32@lists.mysql.com after you have consulted the +MySQL manual and the MySQL mailing list archive +(http://www.mysql.com/documentation/index.html) + +On behalf of the MySQL AB gang, +Michael Widenius
\ No newline at end of file diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Setup Files/Uncompressed Files/Language Independent/OS Independent/SETUP.BMP b/VC++Files/InstallShield/3.23.XX-gpl/Setup Files/Uncompressed Files/Language Independent/OS Independent/SETUP.BMP Binary files differnew file mode 100644 index 00000000000..3229d50c9bf --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Setup Files/Uncompressed Files/Language Independent/OS Independent/SETUP.BMP diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Shell Objects/Default.shl b/VC++Files/InstallShield/3.23.XX-gpl/Shell Objects/Default.shl new file mode 100644 index 00000000000..187cb651307 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Shell Objects/Default.shl @@ -0,0 +1,12 @@ +[Data] +Folder3=<FOLDER_STARTUP> +Group0=Main +Group1=Startup +Folder0=<FOLDER_DESKTOP> +Folder1=<FOLDER_STARTMENU> +Folder2=<FOLDER_PROGRAMS> + +[Info] +Type=ShellObject +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/String Tables/0009-English/value.shl b/VC++Files/InstallShield/3.23.XX-gpl/String Tables/0009-English/value.shl new file mode 100644 index 00000000000..687c58b7b21 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/String Tables/0009-English/value.shl @@ -0,0 +1,23 @@ +[Data] +TITLE_MAIN=MySQL Servers and Clients 3.23.56 +COMPANY_NAME=MySQL AB +ERROR_COMPONENT=Component: +COMPANY_NAME16=Company +PRODUCT_VERSION=3.23.56 +ERROR_MOVEDATA=An error occurred during the move data process: %d +ERROR_FILEGROUP=File Group: +UNINST_KEY=MySQL Servers and Clients 3.23.56 +TITLE_CAPTIONBAR=MySQL Servers and Clients 3.23.56 Setup +PRODUCT_NAME16=Product +ERROR_VGARESOLUTION=This program requires VGA or better resolution. +ERROR_FILE=File: +UNINST_DISPLAY_NAME=MySQL Servers and Clients 3.23.56 +PRODUCT_KEY=yourapp.Exe +PRODUCT_NAME=MySQL Servers and Clients 3.23.56 +ERROR_UNINSTSETUP=unInstaller setup failed to initialize. You may not be able to uninstall this product. + +[General] +Language=0009 +Type=STRINGTABLESPECIFIC +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/String Tables/Default.shl b/VC++Files/InstallShield/3.23.XX-gpl/String Tables/Default.shl new file mode 100644 index 00000000000..d4dc4925ab1 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/String Tables/Default.shl @@ -0,0 +1,74 @@ +[TITLE_MAIN] +Comment= + +[COMPANY_NAME] +Comment= + +[ERROR_COMPONENT] +Comment= + +[COMPANY_NAME16] +Comment= + +[PRODUCT_VERSION] +Comment= + +[ERROR_MOVEDATA] +Comment= + +[ERROR_FILEGROUP] +Comment= + +[Language] +Lang0=0009 +CurrentLang=0 + +[UNINST_KEY] +Comment= + +[TITLE_CAPTIONBAR] +Comment= + +[Data] +Entry0=ERROR_VGARESOLUTION +Entry1=TITLE_MAIN +Entry2=TITLE_CAPTIONBAR +Entry3=UNINST_KEY +Entry4=UNINST_DISPLAY_NAME +Entry5=COMPANY_NAME +Entry6=PRODUCT_NAME +Entry7=PRODUCT_VERSION +Entry8=PRODUCT_KEY +Entry9=ERROR_MOVEDATA +Entry10=ERROR_UNINSTSETUP +Entry11=COMPANY_NAME16 +Entry12=PRODUCT_NAME16 +Entry13=ERROR_COMPONENT +Entry14=ERROR_FILEGROUP +Entry15=ERROR_FILE + +[PRODUCT_NAME16] +Comment= + +[ERROR_VGARESOLUTION] +Comment= + +[ERROR_FILE] +Comment= + +[General] +Type=STRINGTABLE +Version=1.00.000 + +[UNINST_DISPLAY_NAME] +Comment= + +[PRODUCT_KEY] +Comment= + +[PRODUCT_NAME] +Comment= + +[ERROR_UNINSTSETUP] +Comment= + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Text Substitutions/Build.tsb b/VC++Files/InstallShield/3.23.XX-gpl/Text Substitutions/Build.tsb new file mode 100644 index 00000000000..3949bd4c066 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Text Substitutions/Build.tsb @@ -0,0 +1,56 @@ +[<HKUS>] +Value= +KeyType=4 + +[<HKCR>] +Value= +KeyType=4 + +[<PROGRAMFILES>] +Value= +KeyType=4 + +[<WINSYSDIR>] +Value= +KeyType=4 + +[<COMMONFILES>] +Value= +KeyType=4 + +[<WINDIR>] +Value= +KeyType=4 + +[Data] +Key0=<PROGRAMFILES> +Key1=<COMMONFILES> +Key2=<WINDIR> +Key3=<WINSYSDIR> +Key4=<HKLM> +Key5=<HKCU> +Key6=<HKCC> +Key7=<HKDD> +Key8=<HKUS> +Key9=<HKCR> + +[General] +Type=TEXTSUB +Version=1.00.000 + +[<HKLM>] +Value= +KeyType=4 + +[<HKCU>] +Value= +KeyType=4 + +[<HKCC>] +Value= +KeyType=4 + +[<HKDD>] +Value= +KeyType=4 + diff --git a/VC++Files/InstallShield/3.23.XX-gpl/Text Substitutions/Setup.tsb b/VC++Files/InstallShield/3.23.XX-gpl/Text Substitutions/Setup.tsb new file mode 100644 index 00000000000..b0c5a509f0b --- /dev/null +++ b/VC++Files/InstallShield/3.23.XX-gpl/Text Substitutions/Setup.tsb @@ -0,0 +1,76 @@ +[<SRCDIR>] +Value= +KeyType=4 + +[<HKUS>] +Value= +KeyType=4 + +[<HKCR>] +Value= +KeyType=4 + +[<PROGRAMFILES>] +Value= +KeyType=4 + +[<TARGETDIR>] +Value= +KeyType=4 + +[<WINSYSDIR>] +Value= +KeyType=4 + +[<COMMONFILES>] +Value= +KeyType=4 + +[<WINDIR>] +Value= +KeyType=4 + +[Data] +Key0=<PROGRAMFILES> +Key1=<COMMONFILES> +Key2=<WINDIR> +Key3=<WINSYSDIR> +Key4=<TARGETDIR> +Key5=<SUPPORTDIR> +Key10=<HKDD> +Key6=<SRCDIR> +Key11=<HKUS> +Key7=<HKLM> +Key12=<HKCR> +Key8=<HKCU> +Key13=<SHELL_OBJECT_FOLDER> +Key9=<HKCC> + +[<SUPPORTDIR>] +Value= +KeyType=4 + +[<SHELL_OBJECT_FOLDER>] +Value= +KeyType=4 + +[General] +Type=TEXTSUB +Version=1.00.000 + +[<HKLM>] +Value= +KeyType=4 + +[<HKCU>] +Value= +KeyType=4 + +[<HKCC>] +Value= +KeyType=4 + +[<HKDD>] +Value= +KeyType=4 + diff --git a/VC++Files/InstallShield/3.23.XXcom/Component Definitions/.fgl b/VC++Files/InstallShield/3.23.XXcom/Component Definitions/.fgl new file mode 100644 index 00000000000..81e474f9be8 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Component Definitions/.fgl @@ -0,0 +1,37 @@ +[General] +Type=FILELIST +Version=1.00.000 + +[topdir] +subdir0=<WINDIR> +subdir1=<PROGRAMFILES> +subdir2=<TARGETDIR> +subdir3=USERDEFINED + +[<WINDIR>] +DISPLAYTEXT=Windows Operating System +TYPE=TEXTSUBFIXED +subdir0=<WINDIR>\<WINSYSDIR> + +[<WINDIR>\<WINSYSDIR>] +DISPLAYTEXT=Windows System Folder +TYPE=TEXTSUBFIXED + +[<PROGRAMFILES>] +DISPLAYTEXT=Program Files Folder +TYPE=TEXTSUBFIXED +subdir0=<PROGRAMFILES>\<COMMONFILES> + +[<PROGRAMFILES>\<COMMONFILES>] +DISPLAYTEXT=Common Files Folder +TYPE=TEXTSUBFIXED + +[<TARGETDIR>] +DISPLAYTEXT=General Application Destination +TYPE=TEXTSUBFIXED + +[USERDEFINED] +DISPLAYTEXT=Script-defined Folders +TYPE=USERSTART + + diff --git a/VC++Files/InstallShield/3.23.XXcom/Component Definitions/Default.cdf b/VC++Files/InstallShield/3.23.XXcom/Component Definitions/Default.cdf new file mode 100644 index 00000000000..f44131f754e --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Component Definitions/Default.cdf @@ -0,0 +1,192 @@ +[Development] +required0=Servers +SELECTED=Yes +FILENEED=STANDARD +required1=Grant Tables +HTTPLOCATION= +STATUS=Examples, Libraries, Includes and Script files +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=Examples, Libraries, Includes and Script files +DISPLAYTEXT=Examples, Libraries, Includes and Script files +IMAGE= +DEFSELECTION=Yes +filegroup0=Development +COMMENT= +INCLUDEINBUILD=Yes +INSTALLATION=ALWAYSOVERWRITE +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[Grant Tables] +required0=Servers +SELECTED=Yes +FILENEED=CRITICAL +HTTPLOCATION= +STATUS=The Grant Tables and Core Files +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The Grant Tables and Core Files +DISPLAYTEXT=The Grant Tables and Core Files +IMAGE= +DEFSELECTION=Yes +filegroup0=Grant Tables +requiredby0=Development +COMMENT= +INCLUDEINBUILD=Yes +requiredby1=Clients and Tools +INSTALLATION=NEVEROVERWRITE +requiredby2=Documentation +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[Components] +component0=Development +component1=Grant Tables +component2=Clients and Tools +component3=Servers +component4=Documentation + +[TopComponents] +component0=Servers +component1=Clients and Tools +component2=Documentation +component3=Development +component4=Grant Tables + +[SetupType] +setuptype0=Compact +setuptype1=Typical +setuptype2=Custom + +[Servers] +SELECTED=Yes +FILENEED=CRITICAL +HTTPLOCATION= +STATUS=The MySQL Servers +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The MySQL Servers +DISPLAYTEXT=The MySQL Servers +IMAGE= +DEFSELECTION=Yes +filegroup0=Servers +requiredby0=Development +COMMENT= +INCLUDEINBUILD=Yes +requiredby1=Grant Tables +INSTALLATION=ALWAYSOVERWRITE +requiredby2=Clients and Tools +requiredby3=Documentation +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[Clients and Tools] +required0=Servers +SELECTED=Yes +FILENEED=HIGHLYRECOMMENDED +required1=Grant Tables +HTTPLOCATION= +STATUS=The MySQL clients and Maintenance Tools +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The MySQL clients and Maintenance Tools +DISPLAYTEXT=The MySQL clients and Maintenance Tools +IMAGE= +DEFSELECTION=Yes +filegroup0=Clients and Tools +COMMENT= +INCLUDEINBUILD=Yes +INSTALLATION=NEWERDATE +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + +[SetupTypeItem-Compact] +Comment= +item0=Grant Tables +item1=Clients and Tools +item2=Servers +item3=Documentation +Descrip= +DisplayText= + +[SetupTypeItem-Custom] +Comment= +item0=Development +item1=Grant Tables +item2=Clients and Tools +item3=Servers +Descrip= +item4=Documentation +DisplayText= + +[Info] +Type=CompDef +Version=1.00.000 +Name= + +[SetupTypeItem-Typical] +Comment= +item0=Development +item1=Grant Tables +item2=Clients and Tools +item3=Servers +Descrip= +item4=Documentation +DisplayText= + +[Documentation] +required0=Servers +SELECTED=Yes +FILENEED=HIGHLYRECOMMENDED +required1=Grant Tables +HTTPLOCATION= +STATUS=The MySQL Documentation with different formats +UNINSTALLABLE=Yes +TARGET=<TARGETDIR> +FTPLOCATION= +VISIBLE=Yes +DESCRIPTION=The MySQL Documentation with different formats +DISPLAYTEXT=The MySQL Documentation with different formats +IMAGE= +DEFSELECTION=Yes +filegroup0=Documentation +COMMENT= +INCLUDEINBUILD=Yes +INSTALLATION=ALWAYSOVERWRITE +COMPRESSIFSEPARATE=No +MISC= +ENCRYPT=No +DISK=ANYDISK +TARGETDIRCDROM= +PASSWORD= +TARGETHIDDEN=General Application Destination + diff --git a/VC++Files/InstallShield/3.23.XXcom/Component Definitions/Default.fgl b/VC++Files/InstallShield/3.23.XXcom/Component Definitions/Default.fgl new file mode 100644 index 00000000000..4e20dcea4ab --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Component Definitions/Default.fgl @@ -0,0 +1,42 @@ +[<PROGRAMFILES>\<COMMONFILES>] +DISPLAYTEXT=Common Files Folder +TYPE=TEXTSUBFIXED +fulldirectory= + +[<WINDIR>\<WINSYSDIR>] +DISPLAYTEXT=Windows System Folder +TYPE=TEXTSUBFIXED +fulldirectory= + +[USERDEFINED] +DISPLAYTEXT=Script-defined Folders +TYPE=USERSTART +fulldirectory= + +[<PROGRAMFILES>] +DISPLAYTEXT=Program Files Folder +SubDir0=<PROGRAMFILES>\<COMMONFILES> +TYPE=TEXTSUBFIXED +fulldirectory= + +[<TARGETDIR>] +DISPLAYTEXT=General Application Destination +TYPE=TEXTSUBFIXED +fulldirectory= + +[<WINDIR>] +DISPLAYTEXT=Windows Operating System +SubDir0=<WINDIR>\<WINSYSDIR> +TYPE=TEXTSUBFIXED +fulldirectory= + +[TopDir] +SubDir0=<WINDIR> +SubDir1=<PROGRAMFILES> +SubDir2=<TARGETDIR> +SubDir3=USERDEFINED + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/File Groups/Clients and Tools.fgl b/VC++Files/InstallShield/3.23.XXcom/File Groups/Clients and Tools.fgl new file mode 100644 index 00000000000..7f30ff9f64b --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/File Groups/Clients and Tools.fgl @@ -0,0 +1,35 @@ +[bin] +file15=C:\mysql\bin\pack_isam.exe +file16=C:\mysql\bin\perror.exe +file0=C:\mysql\bin\isamchk.exe +file17=C:\mysql\bin\replace.exe +file1=C:\mysql\bin\myisamchk.exe +file18=C:\mysql\bin\winmysqladmin.cnt +file2=C:\mysql\bin\myisamlog.exe +file19=C:\mysql\bin\winmysqladmin.exe +file3=C:\mysql\bin\myisampack.exe +file4=C:\mysql\bin\mysql.exe +file5=C:\mysql\bin\mysqladmin.exe +file6=C:\mysql\bin\mysqlbinlog.exe +file7=C:\mysql\bin\mysqlc.exe +file8=C:\mysql\bin\mysqlcheck.exe +file9=C:\mysql\bin\mysqldump.exe +file20=C:\mysql\bin\WINMYSQLADMIN.HLP +file21=C:\mysql\bin\cygwinb19.dll +file10=C:\mysql\bin\mysqlimport.exe +fulldirectory= +file22=C:\mysql\bin\libmySQL.dll +file11=C:\mysql\bin\MySqlManager.exe +file23=C:\mysql\bin\my_print_defaults.exe +file12=C:\mysql\bin\mysqlshow.exe +file24=C:\mysql\bin\comp-err.exe +file13=C:\mysql\bin\mysqlshutdown.exe +file14=C:\mysql\bin\mysqlwatch.exe + +[TopDir] +SubDir0=bin + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/File Groups/Default.fdf b/VC++Files/InstallShield/3.23.XXcom/File Groups/Default.fdf new file mode 100644 index 00000000000..282fae9d19b --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/File Groups/Default.fdf @@ -0,0 +1,82 @@ +[FileGroups] +group0=Development +group1=Grant Tables +group2=Clients and Tools +group3=Servers +group4=Documentation + +[Development] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Grant Tables] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Servers] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Clients and Tools] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM=0000000000000000 +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + +[Info] +Type=FileGrp +Version=1.00.000 +Name= + +[Documentation] +SELFREGISTERING=No +HTTPLOCATION= +LANGUAGE= +OPERATINGSYSTEM= +FTPLOCATION= +FILETYPE=No +INFOTYPE=Standard +COMMENT= +COMPRESS=Yes +COMPRESSDLL= +POTENTIALLY=No +MISC= + diff --git a/VC++Files/InstallShield/3.23.XXcom/File Groups/Default.fgl b/VC++Files/InstallShield/3.23.XXcom/File Groups/Default.fgl new file mode 100644 index 00000000000..94344a6ff69 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/File Groups/Default.fgl @@ -0,0 +1,4 @@ +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/File Groups/Development.fgl b/VC++Files/InstallShield/3.23.XXcom/File Groups/Development.fgl new file mode 100644 index 00000000000..a1cf53f880a --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/File Groups/Development.fgl @@ -0,0 +1,190 @@ +[bench\Data\Wisconsin] +file0=C:\mysql\bench\Data\Wisconsin\onek.data +file1=C:\mysql\bench\Data\Wisconsin\tenk.data +fulldirectory= + +[lib\debug] +file0=C:\mysql\lib\debug\libmySQL.dll +file1=C:\mysql\lib\debug\libmySQL.lib +file2=C:\mysql\lib\debug\mysqlclient.lib +file3=C:\mysql\lib\debug\zlib.lib +fulldirectory= + +[bench\output] +fulldirectory= + +[examples\libmysqltest] +file0=C:\mysql\examples\libmysqltest\myTest.c +file1=C:\mysql\examples\libmysqltest\myTest.dsp +file2=C:\mysql\examples\libmysqltest\myTest.dsw +file3=C:\mysql\examples\libmysqltest\myTest.exe +file4=C:\mysql\examples\libmysqltest\myTest.mak +file5=C:\mysql\examples\libmysqltest\myTest.ncb +file6=C:\mysql\examples\libmysqltest\myTest.opt +file7=C:\mysql\examples\libmysqltest\readme +fulldirectory= + +[include] +file0=C:\mysql\include\raid.h +file1=C:\mysql\include\errmsg.h +file2=C:\mysql\include\Libmysql.def +file3=C:\mysql\include\m_ctype.h +file4=C:\mysql\include\m_string.h +file5=C:\mysql\include\my_list.h +file6=C:\mysql\include\my_pthread.h +file7=C:\mysql\include\my_sys.h +file8=C:\mysql\include\mysql.h +file9=C:\mysql\include\mysql_com.h +file10=C:\mysql\include\mysql_version.h +fulldirectory= +file11=C:\mysql\include\mysqld_error.h +file12=C:\mysql\include\dbug.h +file13=C:\mysql\include\my_global.h +file14=C:\mysql\include\config-win.h + +[examples] +SubDir0=examples\libmysqltest +SubDir1=examples\tests +fulldirectory= + +[lib\opt] +file0=C:\mysql\lib\opt\libmySQL.dll +file1=C:\mysql\lib\opt\libmySQL.lib +file2=C:\mysql\lib\opt\mysqlclient.lib +file3=C:\mysql\lib\opt\zlib.lib +fulldirectory= + +[bench\Data] +SubDir0=bench\Data\ATIS +SubDir1=bench\Data\Wisconsin +fulldirectory= + +[bench\limits] +file15=C:\mysql\bench\limits\pg.comment +file16=C:\mysql\bench\limits\solid.cfg +file0=C:\mysql\bench\limits\access.cfg +file17=C:\mysql\bench\limits\solid-nt4.cfg +file1=C:\mysql\bench\limits\access.comment +file18=C:\mysql\bench\limits\sybase.cfg +file2=C:\mysql\bench\limits\Adabas.cfg +file3=C:\mysql\bench\limits\Adabas.comment +file4=C:\mysql\bench\limits\Db2.cfg +file5=C:\mysql\bench\limits\empress.cfg +file6=C:\mysql\bench\limits\empress.comment +file7=C:\mysql\bench\limits\Informix.cfg +file8=C:\mysql\bench\limits\Informix.comment +file9=C:\mysql\bench\limits\msql.cfg +file10=C:\mysql\bench\limits\ms-sql.cfg +fulldirectory= +file11=C:\mysql\bench\limits\Ms-sql65.cfg +file12=C:\mysql\bench\limits\mysql.cfg +file13=C:\mysql\bench\limits\oracle.cfg +file14=C:\mysql\bench\limits\pg.cfg + +[TopDir] +SubDir0=bench +SubDir1=examples +SubDir2=include +SubDir3=lib +SubDir4=scripts + +[bench] +file15=C:\mysql\bench\test-create +file16=C:\mysql\bench\test-insert +file0=C:\mysql\bench\uname.bat +file17=C:\mysql\bench\test-select +file1=C:\mysql\bench\compare-results +file18=C:\mysql\bench\test-wisconsin +file2=C:\mysql\bench\copy-db +file19=C:\mysql\bench\bench-init.pl +file3=C:\mysql\bench\crash-me +file4=C:\mysql\bench\example.bat +file5=C:\mysql\bench\print-limit-table +file6=C:\mysql\bench\pwd.bat +file7=C:\mysql\bench\Readme +SubDir0=bench\Data +file8=C:\mysql\bench\run.bat +SubDir1=bench\limits +file9=C:\mysql\bench\run-all-tests +SubDir2=bench\output +file10=C:\mysql\bench\server-cfg +fulldirectory= +file11=C:\mysql\bench\test-alter-table +file12=C:\mysql\bench\test-ATIS +file13=C:\mysql\bench\test-big-tables +file14=C:\mysql\bench\test-connect + +[examples\tests] +file15=C:\mysql\examples\tests\lock_test.res +file16=C:\mysql\examples\tests\mail_to_db.pl +file0=C:\mysql\examples\tests\unique_users.tst +file17=C:\mysql\examples\tests\table_types.pl +file1=C:\mysql\examples\tests\auto_increment.tst +file18=C:\mysql\examples\tests\test_delayed_insert.pl +file2=C:\mysql\examples\tests\big_record.pl +file19=C:\mysql\examples\tests\udf_test +file3=C:\mysql\examples\tests\big_record.res +file4=C:\mysql\examples\tests\czech-sorting +file5=C:\mysql\examples\tests\deadlock-script.pl +file6=C:\mysql\examples\tests\export.pl +file7=C:\mysql\examples\tests\fork_test.pl +file8=C:\mysql\examples\tests\fork2_test.pl +file9=C:\mysql\examples\tests\fork3_test.pl +file20=C:\mysql\examples\tests\udf_test.res +file21=C:\mysql\examples\tests\auto_increment.res +file10=C:\mysql\examples\tests\function.res +fulldirectory= +file11=C:\mysql\examples\tests\function.tst +file12=C:\mysql\examples\tests\grant.pl +file13=C:\mysql\examples\tests\grant.res +file14=C:\mysql\examples\tests\lock_test.pl + +[bench\Data\ATIS] +file26=C:\mysql\bench\Data\ATIS\stop1.txt +file15=C:\mysql\bench\Data\ATIS\flight_class.txt +file27=C:\mysql\bench\Data\ATIS\time_interval.txt +file16=C:\mysql\bench\Data\ATIS\flight_day.txt +file0=C:\mysql\bench\Data\ATIS\transport.txt +file28=C:\mysql\bench\Data\ATIS\time_zone.txt +file17=C:\mysql\bench\Data\ATIS\flight_fare.txt +file1=C:\mysql\bench\Data\ATIS\airline.txt +file29=C:\mysql\bench\Data\ATIS\aircraft.txt +file18=C:\mysql\bench\Data\ATIS\food_service.txt +file2=C:\mysql\bench\Data\ATIS\airport.txt +file19=C:\mysql\bench\Data\ATIS\ground_service.txt +file3=C:\mysql\bench\Data\ATIS\airport_service.txt +file4=C:\mysql\bench\Data\ATIS\city.txt +file5=C:\mysql\bench\Data\ATIS\class_of_service.txt +file6=C:\mysql\bench\Data\ATIS\code_description.txt +file7=C:\mysql\bench\Data\ATIS\compound_class.txt +file8=C:\mysql\bench\Data\ATIS\connect_leg.txt +file9=C:\mysql\bench\Data\ATIS\date_day.txt +file20=C:\mysql\bench\Data\ATIS\month_name.txt +file21=C:\mysql\bench\Data\ATIS\restrict_carrier.txt +file10=C:\mysql\bench\Data\ATIS\day_name.txt +fulldirectory= +file22=C:\mysql\bench\Data\ATIS\restrict_class.txt +file11=C:\mysql\bench\Data\ATIS\dual_carrier.txt +file23=C:\mysql\bench\Data\ATIS\restriction.txt +file12=C:\mysql\bench\Data\ATIS\fare.txt +file24=C:\mysql\bench\Data\ATIS\state.txt +file13=C:\mysql\bench\Data\ATIS\fconnection.txt +file25=C:\mysql\bench\Data\ATIS\stop.txt +file14=C:\mysql\bench\Data\ATIS\flight.txt + +[General] +Type=FILELIST +Version=1.00.000 + +[scripts] +file0=C:\mysql\scripts\mysql_find_rows.pl +file1=C:\mysql\scripts\mysql_setpermission.pl +file2=C:\mysql\scripts\mysqlhotcopy.pl +file3=C:\mysql\scripts\Readme +fulldirectory= + +[lib] +SubDir0=lib\debug +SubDir1=lib\opt +fulldirectory= + diff --git a/VC++Files/InstallShield/3.23.XXcom/File Groups/Documentation.fgl b/VC++Files/InstallShield/3.23.XXcom/File Groups/Documentation.fgl new file mode 100644 index 00000000000..d36acb64538 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/File Groups/Documentation.fgl @@ -0,0 +1,98 @@ +[Docs\Flags] +file59=C:\mysql\Docs\Flags\romania.gif +file48=C:\mysql\Docs\Flags\kroatia.eps +file37=C:\mysql\Docs\Flags\iceland.gif +file26=C:\mysql\Docs\Flags\france.eps +file15=C:\mysql\Docs\Flags\china.gif +file49=C:\mysql\Docs\Flags\kroatia.gif +file38=C:\mysql\Docs\Flags\ireland.eps +file27=C:\mysql\Docs\Flags\france.gif +file16=C:\mysql\Docs\Flags\croatia.eps +file0=C:\mysql\Docs\Flags\usa.gif +file39=C:\mysql\Docs\Flags\ireland.gif +file28=C:\mysql\Docs\Flags\germany.eps +file17=C:\mysql\Docs\Flags\croatia.gif +file1=C:\mysql\Docs\Flags\argentina.gif +file29=C:\mysql\Docs\Flags\germany.gif +file18=C:\mysql\Docs\Flags\czech-republic.eps +file2=C:\mysql\Docs\Flags\australia.eps +file19=C:\mysql\Docs\Flags\czech-republic.gif +file3=C:\mysql\Docs\Flags\australia.gif +file80=C:\mysql\Docs\Flags\usa.eps +file4=C:\mysql\Docs\Flags\austria.eps +file81=C:\mysql\Docs\Flags\argentina.eps +file70=C:\mysql\Docs\Flags\spain.eps +file5=C:\mysql\Docs\Flags\austria.gif +file71=C:\mysql\Docs\Flags\spain.gif +file60=C:\mysql\Docs\Flags\russia.eps +file6=C:\mysql\Docs\Flags\brazil.eps +file72=C:\mysql\Docs\Flags\sweden.eps +file61=C:\mysql\Docs\Flags\russia.gif +file50=C:\mysql\Docs\Flags\latvia.eps +file7=C:\mysql\Docs\Flags\brazil.gif +file73=C:\mysql\Docs\Flags\sweden.gif +file62=C:\mysql\Docs\Flags\singapore.eps +file51=C:\mysql\Docs\Flags\latvia.gif +file40=C:\mysql\Docs\Flags\island.eps +file8=C:\mysql\Docs\Flags\bulgaria.eps +file74=C:\mysql\Docs\Flags\switzerland.eps +file63=C:\mysql\Docs\Flags\singapore.gif +file52=C:\mysql\Docs\Flags\netherlands.eps +file41=C:\mysql\Docs\Flags\island.gif +file30=C:\mysql\Docs\Flags\great-britain.eps +file9=C:\mysql\Docs\Flags\bulgaria.gif +file75=C:\mysql\Docs\Flags\switzerland.gif +file64=C:\mysql\Docs\Flags\south-africa.eps +file53=C:\mysql\Docs\Flags\netherlands.gif +file42=C:\mysql\Docs\Flags\israel.eps +file31=C:\mysql\Docs\Flags\great-britain.gif +file20=C:\mysql\Docs\Flags\denmark.eps +file76=C:\mysql\Docs\Flags\taiwan.eps +file65=C:\mysql\Docs\Flags\south-africa.gif +file54=C:\mysql\Docs\Flags\poland.eps +file43=C:\mysql\Docs\Flags\israel.gif +file32=C:\mysql\Docs\Flags\greece.eps +file21=C:\mysql\Docs\Flags\denmark.gif +file10=C:\mysql\Docs\Flags\canada.eps +fulldirectory= +file77=C:\mysql\Docs\Flags\taiwan.gif +file66=C:\mysql\Docs\Flags\south-africa1.eps +file55=C:\mysql\Docs\Flags\poland.gif +file44=C:\mysql\Docs\Flags\italy.eps +file33=C:\mysql\Docs\Flags\greece.gif +file22=C:\mysql\Docs\Flags\estonia.eps +file11=C:\mysql\Docs\Flags\canada.gif +file78=C:\mysql\Docs\Flags\ukraine.eps +file67=C:\mysql\Docs\Flags\south-africa1.gif +file56=C:\mysql\Docs\Flags\portugal.eps +file45=C:\mysql\Docs\Flags\italy.gif +file34=C:\mysql\Docs\Flags\hungary.eps +file23=C:\mysql\Docs\Flags\estonia.gif +file12=C:\mysql\Docs\Flags\chile.eps +file79=C:\mysql\Docs\Flags\ukraine.gif +file68=C:\mysql\Docs\Flags\south-korea.eps +file57=C:\mysql\Docs\Flags\portugal.gif +file46=C:\mysql\Docs\Flags\japan.eps +file35=C:\mysql\Docs\Flags\hungary.gif +file24=C:\mysql\Docs\Flags\finland.eps +file13=C:\mysql\Docs\Flags\chile.gif +file69=C:\mysql\Docs\Flags\south-korea.gif +file58=C:\mysql\Docs\Flags\romania.eps +file47=C:\mysql\Docs\Flags\japan.gif +file36=C:\mysql\Docs\Flags\iceland.eps +file25=C:\mysql\Docs\Flags\finland.gif +file14=C:\mysql\Docs\Flags\china.eps + +[Docs] +file0=C:\mysql\Docs\manual_toc.html +file1=C:\mysql\Docs\manual.html +SubDir0=Docs\Flags +fulldirectory= + +[TopDir] +SubDir0=Docs + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/File Groups/Grant Tables.fgl b/VC++Files/InstallShield/3.23.XXcom/File Groups/Grant Tables.fgl new file mode 100644 index 00000000000..178065a7003 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/File Groups/Grant Tables.fgl @@ -0,0 +1,36 @@ +[data\test] +fulldirectory= + +[data\mysql] +file15=C:\mysql\data\mysql\func.frm +file16=C:\mysql\data\mysql\func.MYD +file0=C:\mysql\data\mysql\columns_priv.frm +file17=C:\mysql\data\mysql\func.MYI +file1=C:\mysql\data\mysql\columns_priv.MYD +file2=C:\mysql\data\mysql\columns_priv.MYI +file3=C:\mysql\data\mysql\db.frm +file4=C:\mysql\data\mysql\db.MYD +file5=C:\mysql\data\mysql\db.MYI +file6=C:\mysql\data\mysql\host.frm +file7=C:\mysql\data\mysql\host.MYD +file8=C:\mysql\data\mysql\host.MYI +file9=C:\mysql\data\mysql\tables_priv.frm +file10=C:\mysql\data\mysql\tables_priv.MYD +fulldirectory= +file11=C:\mysql\data\mysql\tables_priv.MYI +file12=C:\mysql\data\mysql\user.frm +file13=C:\mysql\data\mysql\user.MYD +file14=C:\mysql\data\mysql\user.MYI + +[TopDir] +SubDir0=data + +[data] +SubDir0=data\mysql +SubDir1=data\test +fulldirectory= + +[General] +Type=FILELIST +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/File Groups/Servers.fgl b/VC++Files/InstallShield/3.23.XXcom/File Groups/Servers.fgl new file mode 100644 index 00000000000..6f91a474d80 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/File Groups/Servers.fgl @@ -0,0 +1,183 @@ +[share\polish] +file0=C:\mysql\share\polish\errmsg.sys +file1=C:\mysql\share\polish\errmsg.txt +fulldirectory= + +[share\dutch] +file0=C:\mysql\share\dutch\errmsg.sys +file1=C:\mysql\share\dutch\errmsg.txt +fulldirectory= + +[share\spanish] +file0=C:\mysql\share\spanish\errmsg.sys +file1=C:\mysql\share\spanish\errmsg.txt +fulldirectory= + +[share\english] +file0=C:\mysql\share\english\errmsg.sys +file1=C:\mysql\share\english\errmsg.txt +fulldirectory= + +[bin] +file0=C:\mysql\bin\mysqld-opt.exe +file1=C:\mysql\bin\mysqld-max.exe +file2=C:\mysql\bin\mysqld-max-nt.exe +file3=C:\mysql\bin\mysqld-nt.exe +file4=C:\mysql\bin\mysqld.exe +fulldirectory= + +[share\korean] +file0=C:\mysql\share\korean\errmsg.sys +file1=C:\mysql\share\korean\errmsg.txt +fulldirectory= + +[share\charsets] +file15=C:\mysql\share\charsets\latin1.conf +file16=C:\mysql\share\charsets\latin2.conf +file0=C:\mysql\share\charsets\win1251ukr.conf +file17=C:\mysql\share\charsets\latin5.conf +file1=C:\mysql\share\charsets\cp1257.conf +file18=C:\mysql\share\charsets\Readme +file2=C:\mysql\share\charsets\croat.conf +file19=C:\mysql\share\charsets\swe7.conf +file3=C:\mysql\share\charsets\danish.conf +file4=C:\mysql\share\charsets\dec8.conf +file5=C:\mysql\share\charsets\dos.conf +file6=C:\mysql\share\charsets\estonia.conf +file7=C:\mysql\share\charsets\german1.conf +file8=C:\mysql\share\charsets\greek.conf +file9=C:\mysql\share\charsets\hebrew.conf +file20=C:\mysql\share\charsets\usa7.conf +file21=C:\mysql\share\charsets\win1250.conf +file10=C:\mysql\share\charsets\hp8.conf +fulldirectory= +file22=C:\mysql\share\charsets\win1251.conf +file11=C:\mysql\share\charsets\hungarian.conf +file23=C:\mysql\share\charsets\cp1251.conf +file12=C:\mysql\share\charsets\Index +file13=C:\mysql\share\charsets\koi8_ru.conf +file14=C:\mysql\share\charsets\koi8_ukr.conf + +[share\ukrainian] +file0=C:\mysql\share\ukrainian\errmsg.sys +file1=C:\mysql\share\ukrainian\errmsg.txt +fulldirectory= + +[share\hungarian] +file0=C:\mysql\share\hungarian\errmsg.sys +file1=C:\mysql\share\hungarian\errmsg.txt +fulldirectory= + +[share\german] +file0=C:\mysql\share\german\errmsg.sys +file1=C:\mysql\share\german\errmsg.txt +fulldirectory= + +[share\portuguese] +file0=C:\mysql\share\portuguese\errmsg.sys +file1=C:\mysql\share\portuguese\errmsg.txt +fulldirectory= + +[share\estonian] +file0=C:\mysql\share\estonian\errmsg.sys +file1=C:\mysql\share\estonian\errmsg.txt +fulldirectory= + +[share\romanian] +file0=C:\mysql\share\romanian\errmsg.sys +file1=C:\mysql\share\romanian\errmsg.txt +fulldirectory= + +[share\french] +file0=C:\mysql\share\french\errmsg.sys +file1=C:\mysql\share\french\errmsg.txt +fulldirectory= + +[share\swedish] +file0=C:\mysql\share\swedish\errmsg.sys +file1=C:\mysql\share\swedish\errmsg.txt +fulldirectory= + +[share\slovak] +file0=C:\mysql\share\slovak\errmsg.sys +file1=C:\mysql\share\slovak\errmsg.txt +fulldirectory= + +[share\greek] +file0=C:\mysql\share\greek\errmsg.sys +file1=C:\mysql\share\greek\errmsg.txt +fulldirectory= + +[TopDir] +file0=C:\mysql\my-small.cnf +file1=C:\mysql\my-large.cnf +file2=C:\mysql\my-medium.cnf +file3=C:\mysql\my-huge.cnf +SubDir0=bin +SubDir1=share + +[share] +SubDir8=share\hungarian +SubDir9=share\charsets +SubDir20=share\spanish +SubDir21=share\swedish +SubDir10=share\italian +SubDir22=share\ukrainian +SubDir11=share\japanese +SubDir12=share\korean +SubDir13=share\norwegian +SubDir14=share\norwegian-ny +SubDir15=share\polish +SubDir16=share\portuguese +SubDir0=share\czech +SubDir17=share\romanian +SubDir1=share\danish +SubDir18=share\russian +SubDir2=share\dutch +SubDir19=share\slovak +SubDir3=share\english +fulldirectory= +SubDir4=share\estonian +SubDir5=share\french +SubDir6=share\german +SubDir7=share\greek + +[share\norwegian-ny] +file0=C:\mysql\share\norwegian-ny\errmsg.sys +file1=C:\mysql\share\norwegian-ny\errmsg.txt +fulldirectory= + +[share\danish] +file0=C:\mysql\share\danish\errmsg.sys +file1=C:\mysql\share\danish\errmsg.txt +fulldirectory= + +[share\czech] +file0=C:\mysql\share\czech\errmsg.sys +file1=C:\mysql\share\czech\errmsg.txt +fulldirectory= + +[General] +Type=FILELIST +Version=1.00.000 + +[share\russian] +file0=C:\mysql\share\russian\errmsg.sys +file1=C:\mysql\share\russian\errmsg.txt +fulldirectory= + +[share\norwegian] +file0=C:\mysql\share\norwegian\errmsg.sys +file1=C:\mysql\share\norwegian\errmsg.txt +fulldirectory= + +[share\japanese] +file0=C:\mysql\share\japanese\errmsg.sys +file1=C:\mysql\share\japanese\errmsg.txt +fulldirectory= + +[share\italian] +file0=C:\mysql\share\italian\errmsg.sys +file1=C:\mysql\share\italian\errmsg.txt +fulldirectory= + diff --git a/VC++Files/InstallShield/3.23.XXcom/MySQL 3.23.com.ipr b/VC++Files/InstallShield/3.23.XXcom/MySQL 3.23.com.ipr new file mode 100644 index 00000000000..811d69717d8 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/MySQL 3.23.com.ipr @@ -0,0 +1,51 @@ +[Language] +LanguageSupport0=0009 + +[OperatingSystem] +OSSupport=0000000000010010 + +[Data] +CurrentMedia= +set_mifserial= +ProductName=MySQL Servers and Clients +CurrentComponentDef=Default.cdf +set_dlldebug=No +AppExe= +DevEnvironment=Microsoft Visual C++ 6 +set_mif=No +set_testmode=No +Instructions=Instructions.txt +EmailAddresss= +SummaryText= +Department= +Type=Database Application +Author= +HomeURL= +InstallRoot=C:\MySQL-Install\3.23.XXcom +set_level=Level 3 +InstallationGUID=40744a4d-efed-4cff-84a9-9e6389550f5c +Version=1.00.000 +set_miffile=Status.mif +set_args= +set_maxerr=50 +Notes=Notes.txt +CurrentFileGroupDef=Default.fdf +set_dllcmdline= +set_warnaserr=No +Copyright= +set_preproc= +Category= +CurrentPlatform= +set_compileb4build=No +set_crc=Yes +set_maxwarn=50 +Description=Description.txt +CompanyName=MySQL +CurrentLanguage=English + +[MediaInfo] + +[General] +Type=INSTALLMAIN +Version=1.10.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/Registry Entries/Default.rge b/VC++Files/InstallShield/3.23.XXcom/Registry Entries/Default.rge new file mode 100644 index 00000000000..537dfd82e48 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Registry Entries/Default.rge @@ -0,0 +1,4 @@ +[General] +Type=REGISTRYDATA +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.dbg b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.dbg Binary files differnew file mode 100644 index 00000000000..0c6d4e6b708 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.dbg diff --git a/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.ino b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.ino Binary files differnew file mode 100644 index 00000000000..204d8ea0f36 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.ino diff --git a/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.ins b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.ins Binary files differnew file mode 100644 index 00000000000..759009b5c84 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.ins diff --git a/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.obs b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.obs Binary files differnew file mode 100644 index 00000000000..5fcfcb62c4e --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.obs diff --git a/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.rul b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.rul new file mode 100644 index 00000000000..0db8417a62c --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Script Files/Setup.rul @@ -0,0 +1,641 @@ + +//////////////////////////////////////////////////////////////////////////////// +// +// IIIIIII SSSSSS +// II SS InstallShield (R) +// II SSSSSS (c) 1996-1997, InstallShield Software Corporation +// II SS (c) 1990-1996, InstallShield Corporation +// IIIIIII SSSSSS All Rights Reserved. +// +// +// This code is generated as a starting setup template. You should +// modify it to provide all necessary steps for your setup. +// +// +// File Name: Setup.rul +// +// Description: InstallShield script +// +// Comments: This template script performs a basic setup on a +// Windows 95 or Windows NT 4.0 platform. With minor +// modifications, this template can be adapted to create +// new, customized setups. +// +//////////////////////////////////////////////////////////////////////////////// + + + // Include header file +#include "sdlang.h" +#include "sddialog.h" + +////////////////////// string defines //////////////////////////// + +#define UNINST_LOGFILE_NAME "Uninst.isu" + +//////////////////// installation declarations /////////////////// + + // ----- DLL prototypes ----- + + + // your DLL prototypes + + + // ---- script prototypes ----- + + // generated + prototype ShowDialogs(); + prototype MoveFileData(); + prototype HandleMoveDataError( NUMBER ); + prototype ProcessBeforeDataMove(); + prototype ProcessAfterDataMove(); + prototype SetupRegistry(); + prototype SetupFolders(); + prototype CleanUpInstall(); + prototype SetupInstall(); + prototype SetupScreen(); + prototype CheckRequirements(); + prototype DialogShowSdWelcome(); + prototype DialogShowSdShowInfoList(); + prototype DialogShowSdAskDestPath(); + prototype DialogShowSdSetupType(); + prototype DialogShowSdComponentDialog2(); + prototype DialogShowSdFinishReboot(); + + // your prototypes + + + // ----- global variables ------ + + // generated + BOOL bWinNT, bIsShellExplorer, bInstallAborted, bIs32BitSetup; + STRING svDir; + STRING svName, svCompany, svSerial; + STRING szAppPath; + STRING svSetupType; + + + // your global variables + + +/////////////////////////////////////////////////////////////////////////////// +// +// MAIN PROGRAM +// +// The setup begins here by hiding the visible setup +// window. This is done to allow all the titles, images, etc. to +// be established before showing the main window. The following +// logic then performs the setup in a series of steps. +// +/////////////////////////////////////////////////////////////////////////////// +program + Disable( BACKGROUND ); + + CheckRequirements(); + + SetupInstall(); + + SetupScreen(); + + if (ShowDialogs()<0) goto end_install; + + if (ProcessBeforeDataMove()<0) goto end_install; + + if (MoveFileData()<0) goto end_install; + + if (ProcessAfterDataMove()<0) goto end_install; + + if (SetupRegistry()<0) goto end_install; + + if (SetupFolders()<0) goto end_install; + + + end_install: + + CleanUpInstall(); + + // If an unrecoverable error occurred, clean up the partial installation. + // Otherwise, exit normally. + + if (bInstallAborted) then + abort; + endif; + +endprogram + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: ShowDialogs // +// // +// Purpose: This function manages the display and navigation // +// the standard dialogs that exist in a setup. // +// // +/////////////////////////////////////////////////////////////////////////////// +function ShowDialogs() + NUMBER nResult; + begin + + Dlg_Start: + // beginning of dialogs label + + Dlg_SdWelcome: + nResult = DialogShowSdWelcome(); + if (nResult = BACK) goto Dlg_Start; + + Dlg_SdShowInfoList: + nResult = DialogShowSdShowInfoList(); + if (nResult = BACK) goto Dlg_SdWelcome; + + Dlg_SdAskDestPath: + nResult = DialogShowSdAskDestPath(); + if (nResult = BACK) goto Dlg_SdShowInfoList; + + Dlg_SdSetupType: + nResult = DialogShowSdSetupType(); + if (nResult = BACK) goto Dlg_SdAskDestPath; + + Dlg_SdComponentDialog2: + if ((nResult = BACK) && (svSetupType != "Custom") && (svSetupType != "")) then + goto Dlg_SdSetupType; + endif; + nResult = DialogShowSdComponentDialog2(); + if (nResult = BACK) goto Dlg_SdSetupType; + + return 0; + + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: ProcessBeforeDataMove // +// // +// Purpose: This function performs any necessary operations prior to the // +// actual data move operation. // +// // +/////////////////////////////////////////////////////////////////////////////// +function ProcessBeforeDataMove() + STRING svLogFile; + NUMBER nResult; + begin + + InstallationInfo( @COMPANY_NAME, @PRODUCT_NAME, @PRODUCT_VERSION, @PRODUCT_KEY ); + + svLogFile = UNINST_LOGFILE_NAME; + + nResult = DeinstallStart( svDir, svLogFile, @UNINST_KEY, 0 ); + if (nResult < 0) then + MessageBox( @ERROR_UNINSTSETUP, WARNING ); + endif; + + szAppPath = TARGETDIR; // TODO : if your application .exe is in a subdir of TARGETDIR then add subdir + + if ((bIs32BitSetup) && (bIsShellExplorer)) then + RegDBSetItem( REGDB_APPPATH, szAppPath ); + RegDBSetItem( REGDB_APPPATH_DEFAULT, szAppPath ^ @PRODUCT_KEY ); + RegDBSetItem( REGDB_UNINSTALL_NAME, @UNINST_DISPLAY_NAME ); + endif; + + // TODO : update any items you want to process before moving the data + // + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: MoveFileData // +// // +// Purpose: This function handles the data movement for // +// the setup. // +// // +/////////////////////////////////////////////////////////////////////////////// +function MoveFileData() + NUMBER nResult, nDisk; + begin + + nDisk = 1; + SetStatusWindow( 0, "" ); + Disable( DIALOGCACHE ); + Enable( STATUS ); + StatusUpdate( ON, 100 ); + nResult = ComponentMoveData( MEDIA, nDisk, 0 ); + + HandleMoveDataError( nResult ); + + Disable( STATUS ); + + return nResult; + + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: HandleMoveDataError // +// // +// Purpose: This function handles the error (if any) during the move data // +// operation. // +// // +/////////////////////////////////////////////////////////////////////////////// +function HandleMoveDataError( nResult ) + STRING szErrMsg, svComponent , svFileGroup , svFile; + begin + + svComponent = ""; + svFileGroup = ""; + svFile = ""; + + switch (nResult) + case 0: + return 0; + default: + ComponentError ( MEDIA , svComponent , svFileGroup , svFile , nResult ); + szErrMsg = @ERROR_MOVEDATA + "\n\n" + + @ERROR_COMPONENT + " " + svComponent + "\n" + + @ERROR_FILEGROUP + " " + svFileGroup + "\n" + + @ERROR_FILE + " " + svFile; + SprintfBox( SEVERE, @TITLE_CAPTIONBAR, szErrMsg, nResult ); + bInstallAborted = TRUE; + return nResult; + endswitch; + + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: ProcessAfterDataMove // +// // +// Purpose: This function performs any necessary operations needed after // +// all data has been moved. // +// // +/////////////////////////////////////////////////////////////////////////////// +function ProcessAfterDataMove() + begin + + // TODO : update self-registered files and other processes that + // should be performed after the data has been moved. + + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: SetupRegistry // +// // +// Purpose: This function makes the registry entries for this setup. // +// // +/////////////////////////////////////////////////////////////////////////////// +function SetupRegistry() + NUMBER nResult; + + begin + + // TODO : Add all your registry entry keys here + // + // + // RegDBCreateKeyEx, RegDBSetKeyValueEx.... + // + + nResult = CreateRegistrySet( "" ); + + return nResult; + end; + +/////////////////////////////////////////////////////////////////////////////// +// +// Function: SetupFolders +// +// Purpose: This function creates all the folders and shortcuts for the +// setup. This includes program groups and items for Windows 3.1. +// +/////////////////////////////////////////////////////////////////////////////// +function SetupFolders() + NUMBER nResult; + + begin + + + // TODO : Add all your folder (program group) along with shortcuts (program items) + // + // + // CreateProgramFolder, AddFolderIcon.... + // + + nResult = CreateShellObjects( "" ); + + return nResult; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: CleanUpInstall // +// // +// Purpose: This cleans up the setup. Anything that should // +// be released or deleted at the end of the setup should // +// be done here. // +// // +/////////////////////////////////////////////////////////////////////////////// +function CleanUpInstall() + begin + + + if (bInstallAborted) then + return 0; + endif; + + DialogShowSdFinishReboot(); + + if (BATCH_INSTALL) then // ensure locked files are properly written + CommitSharedFiles(0); + endif; + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: SetupInstall // +// // +// Purpose: This will setup the installation. Any general initialization // +// needed for the installation should be performed here. // +// // +/////////////////////////////////////////////////////////////////////////////// +function SetupInstall() + begin + + Enable( CORECOMPONENTHANDLING ); + + bInstallAborted = FALSE; + + if (bIs32BitSetup) then + svDir = "C:\\mysql"; //PROGRAMFILES ^ @COMPANY_NAME ^ @PRODUCT_NAME; + else + svDir = "C:\\mysql"; //PROGRAMFILES ^ @COMPANY_NAME16 ^ @PRODUCT_NAME16; // use shorten names + endif; + + TARGETDIR = svDir; + + SdProductName( @PRODUCT_NAME ); + + Enable( DIALOGCACHE ); + + return 0; + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: SetupScreen // +// // +// Purpose: This function establishes the screen look. This includes // +// colors, fonts, and text to be displayed. // +// // +/////////////////////////////////////////////////////////////////////////////// +function SetupScreen() + begin + + Enable( FULLWINDOWMODE ); + Enable( INDVFILESTATUS ); + SetTitle( @TITLE_MAIN, 24, WHITE ); + + SetTitle( @TITLE_CAPTIONBAR, 0, BACKGROUNDCAPTION ); // Caption bar text. + + Enable( BACKGROUND ); + + Delay( 1 ); + end; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: CheckRequirements // +// // +// Purpose: This function checks all minimum requirements for the // +// application being installed. If any fail, then the user // +// is informed and the setup is terminated. // +// // +/////////////////////////////////////////////////////////////////////////////// +function CheckRequirements() + NUMBER nvDx, nvDy, nvResult; + STRING svResult; + + begin + + bWinNT = FALSE; + bIsShellExplorer = FALSE; + + // Check screen resolution. + GetExtents( nvDx, nvDy ); + + if (nvDy < 480) then + MessageBox( @ERROR_VGARESOLUTION, WARNING ); + abort; + endif; + + // set 'setup' operation mode + bIs32BitSetup = TRUE; + GetSystemInfo( ISTYPE, nvResult, svResult ); + if (nvResult = 16) then + bIs32BitSetup = FALSE; // running 16-bit setup + return 0; // no additional information required + endif; + + // --- 32-bit testing after this point --- + + // Determine the target system's operating system. + GetSystemInfo( OS, nvResult, svResult ); + + if (nvResult = IS_WINDOWSNT) then + // Running Windows NT. + bWinNT = TRUE; + + // Check to see if the shell being used is EXPLORER shell. + if (GetSystemInfo( OSMAJOR, nvResult, svResult ) = 0) then + if (nvResult >= 4) then + bIsShellExplorer = TRUE; + endif; + endif; + + elseif (nvResult = IS_WINDOWS95 ) then + bIsShellExplorer = TRUE; + + endif; + +end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdWelcome // +// // +// Purpose: This function handles the standard welcome dialog. // +// // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdWelcome() + NUMBER nResult; + STRING szTitle, szMsg; + begin + + szTitle = ""; + szMsg = ""; + nResult = SdWelcome( szTitle, szMsg ); + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdShowInfoList // +// // +// Purpose: This function displays the general information list dialog. // +// // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdShowInfoList() + NUMBER nResult; + LIST list; + STRING szTitle, szMsg, szFile; + begin + + szFile = SUPPORTDIR ^ "infolist.txt"; + + list = ListCreate( STRINGLIST ); + ListReadFromFile( list, szFile ); + szTitle = ""; + szMsg = " "; + nResult = SdShowInfoList( szTitle, szMsg, list ); + + ListDestroy( list ); + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdAskDestPath // +// // +// Purpose: This function asks the user for the destination directory. // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdAskDestPath() + NUMBER nResult; + STRING szTitle, szMsg; + begin + + szTitle = ""; + szMsg = ""; + nResult = SdAskDestPath( szTitle, szMsg, svDir, 0 ); + + TARGETDIR = svDir; + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdSetupType // +// // +// Purpose: This function displays the standard setup type dialog. // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdSetupType() + NUMBER nResult, nType; + STRING szTitle, szMsg; + begin + + switch (svSetupType) + case "Typical": + nType = TYPICAL; + case "Custom": + nType = CUSTOM; + case "Compact": + nType = COMPACT; + case "": + svSetupType = "Typical"; + nType = TYPICAL; + endswitch; + + szTitle = ""; + szMsg = ""; + nResult = SetupType( szTitle, szMsg, "", nType, 0 ); + + switch (nResult) + case COMPACT: + svSetupType = "Compact"; + case TYPICAL: + svSetupType = "Typical"; + case CUSTOM: + svSetupType = "Custom"; + endswitch; + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdComponentDialog2 // +// // +// Purpose: This function displays the custom component dialog. // +// // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdComponentDialog2() + NUMBER nResult; + STRING szTitle, szMsg; + begin + + if ((svSetupType != "Custom") && (svSetupType != "")) then + return 0; + endif; + + szTitle = ""; + szMsg = ""; + nResult = SdComponentDialog2( szTitle, szMsg, svDir, "" ); + + return nResult; + end; + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Function: DialogShowSdFinishReboot // +// // +// Purpose: This function will show the last dialog of the product. // +// It will allow the user to reboot and/or show some readme text. // +// // +/////////////////////////////////////////////////////////////////////////////// +function DialogShowSdFinishReboot() + NUMBER nResult, nDefOptions; + STRING szTitle, szMsg1, szMsg2, szOption1, szOption2; + NUMBER bOpt1, bOpt2; + begin +/* + if (!BATCH_INSTALL) then + bOpt1 = FALSE; + bOpt2 = FALSE; + szMsg1 = ""; + szMsg2 = ""; + szOption1 = ""; + szOption2 = ""; + nResult = SdFinish( szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2 ); + return 0; + endif; + + nDefOptions = SYS_BOOTMACHINE; + szTitle = ""; + szMsg1 = ""; + szMsg2 = ""; + nResult = SdFinishReboot( szTitle, szMsg1, nDefOptions, szMsg2, 0 ); +*/ + return nResult; + end; + + // --- include script file section --- + +#include "sddialog.rul" + + + diff --git a/VC++Files/InstallShield/3.23.XXcom/Setup Files/Compressed Files/Language Independent/OS Independent/infolist.txt b/VC++Files/InstallShield/3.23.XXcom/Setup Files/Compressed Files/Language Independent/OS Independent/infolist.txt new file mode 100644 index 00000000000..2f561d29d81 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Setup Files/Compressed Files/Language Independent/OS Independent/infolist.txt @@ -0,0 +1,24 @@ +This is a release of MySQL 3.23.56 for Win32. + +NOTE: If you install MySQL in a folder other than +C:\MYSQL or you intend to start MySQL on NT/Win2000 +as a service, you must create a file named C:\MY.CNF +or \Windows\my.ini or \winnt\my.ini with the following +information:: + +[mysqld] +basedir=E:/installation-path/ +datadir=E:/data-path/ + +After your have installed MySQL, the installation +directory which contains the files named 'my-size.cnf'. +You can use this as a starting point for your own +C:\my.cnf file. + +If you have any problems, you can mail them to +win32@lists.mysql.com after you have consulted the +MySQL manual and the MySQL mailing list archive +(http://www.mysql.com/documentation/index.html) + +On behalf of the MySQL AB gang, +Michael Widenius
\ No newline at end of file diff --git a/VC++Files/InstallShield/3.23.XXcom/Setup Files/Uncompressed Files/Language Independent/OS Independent/SETUP.BMP b/VC++Files/InstallShield/3.23.XXcom/Setup Files/Uncompressed Files/Language Independent/OS Independent/SETUP.BMP Binary files differnew file mode 100644 index 00000000000..3229d50c9bf --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Setup Files/Uncompressed Files/Language Independent/OS Independent/SETUP.BMP diff --git a/VC++Files/InstallShield/3.23.XXcom/Shell Objects/Default.shl b/VC++Files/InstallShield/3.23.XXcom/Shell Objects/Default.shl new file mode 100644 index 00000000000..187cb651307 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Shell Objects/Default.shl @@ -0,0 +1,12 @@ +[Data] +Folder3=<FOLDER_STARTUP> +Group0=Main +Group1=Startup +Folder0=<FOLDER_DESKTOP> +Folder1=<FOLDER_STARTMENU> +Folder2=<FOLDER_PROGRAMS> + +[Info] +Type=ShellObject +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/String Tables/0009-English/value.shl b/VC++Files/InstallShield/3.23.XXcom/String Tables/0009-English/value.shl new file mode 100644 index 00000000000..dd998365667 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/String Tables/0009-English/value.shl @@ -0,0 +1,23 @@ +[Data] +TITLE_MAIN=MySQL Commercial Servers and Clients 3.23.56 +ERROR_COMPONENT=Component: +COMPANY_NAME=MySQL AB +COMPANY_NAME16=Company +ERROR_FILEGROUP=File Group: +ERROR_MOVEDATA=An error occurred during the move data process: %d +PRODUCT_VERSION=3.23.56 +UNINST_KEY=MySQL Commercial Servers and Clients 3.23.56 +TITLE_CAPTIONBAR=MySQL Commercial Servers and Clients 3.23.56 Setup +PRODUCT_NAME16=Product +ERROR_FILE=File: +ERROR_VGARESOLUTION=This program requires VGA or better resolution. +PRODUCT_KEY=yourapp.Exe +UNINST_DISPLAY_NAME=MySQL Commercial Servers and Clients 3.23.56 +ERROR_UNINSTSETUP=unInstaller setup failed to initialize. You may not be able to uninstall this product. +PRODUCT_NAME=MySQL Commercial Servers and Clients 3.23.56 + +[General] +Language=0009 +Type=STRINGTABLESPECIFIC +Version=1.00.000 + diff --git a/VC++Files/InstallShield/3.23.XXcom/String Tables/Default.shl b/VC++Files/InstallShield/3.23.XXcom/String Tables/Default.shl new file mode 100644 index 00000000000..f197667992e --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/String Tables/Default.shl @@ -0,0 +1,74 @@ +[TITLE_MAIN] +Comment= + +[ERROR_COMPONENT] +Comment= + +[COMPANY_NAME] +Comment= + +[COMPANY_NAME16] +Comment= + +[ERROR_FILEGROUP] +Comment= + +[ERROR_MOVEDATA] +Comment= + +[PRODUCT_VERSION] +Comment= + +[UNINST_KEY] +Comment= + +[Language] +Lang0=0009 +CurrentLang=0 + +[TITLE_CAPTIONBAR] +Comment= + +[PRODUCT_NAME16] +Comment= + +[Data] +Entry0=ERROR_VGARESOLUTION +Entry1=TITLE_MAIN +Entry2=TITLE_CAPTIONBAR +Entry3=UNINST_KEY +Entry4=UNINST_DISPLAY_NAME +Entry5=COMPANY_NAME +Entry6=PRODUCT_NAME +Entry7=PRODUCT_VERSION +Entry8=PRODUCT_KEY +Entry10=ERROR_UNINSTSETUP +Entry9=ERROR_MOVEDATA +Entry11=COMPANY_NAME16 +Entry12=PRODUCT_NAME16 +Entry13=ERROR_COMPONENT +Entry14=ERROR_FILEGROUP +Entry15=ERROR_FILE + +[ERROR_FILE] +Comment= + +[ERROR_VGARESOLUTION] +Comment= + +[PRODUCT_KEY] +Comment= + +[UNINST_DISPLAY_NAME] +Comment= + +[General] +Type=STRINGTABLE +Version=1.00.000 + +[ERROR_UNINSTSETUP] +Comment= + +[PRODUCT_NAME] +Comment= + diff --git a/VC++Files/InstallShield/3.23.XXcom/Text Substitutions/Build.tsb b/VC++Files/InstallShield/3.23.XXcom/Text Substitutions/Build.tsb new file mode 100644 index 00000000000..0478df14bff --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Text Substitutions/Build.tsb @@ -0,0 +1,56 @@ +[<HKCR>] +KeyType=4 +Value= + +[<HKUS>] +KeyType=4 +Value= + +[<PROGRAMFILES>] +KeyType=4 +Value= + +[<WINSYSDIR>] +KeyType=4 +Value= + +[<COMMONFILES>] +KeyType=4 +Value= + +[<WINDIR>] +KeyType=4 +Value= + +[Data] +Key0=<PROGRAMFILES> +Key1=<COMMONFILES> +Key2=<WINDIR> +Key3=<WINSYSDIR> +Key4=<HKLM> +Key5=<HKCU> +Key6=<HKCC> +Key7=<HKDD> +Key8=<HKUS> +Key9=<HKCR> + +[General] +Type=TEXTSUB +Version=1.00.000 + +[<HKCU>] +KeyType=4 +Value= + +[<HKLM>] +KeyType=4 +Value= + +[<HKDD>] +KeyType=4 +Value= + +[<HKCC>] +KeyType=4 +Value= + diff --git a/VC++Files/InstallShield/3.23.XXcom/Text Substitutions/Setup.tsb b/VC++Files/InstallShield/3.23.XXcom/Text Substitutions/Setup.tsb new file mode 100644 index 00000000000..258173c7a48 --- /dev/null +++ b/VC++Files/InstallShield/3.23.XXcom/Text Substitutions/Setup.tsb @@ -0,0 +1,76 @@ +[<HKCR>] +KeyType=4 +Value= + +[<HKUS>] +KeyType=4 +Value= + +[<SRCDIR>] +KeyType=4 +Value= + +[<PROGRAMFILES>] +KeyType=4 +Value= + +[<TARGETDIR>] +KeyType=4 +Value= + +[<WINSYSDIR>] +KeyType=4 +Value= + +[<COMMONFILES>] +KeyType=4 +Value= + +[<WINDIR>] +KeyType=4 +Value= + +[Data] +Key0=<PROGRAMFILES> +Key1=<COMMONFILES> +Key2=<WINDIR> +Key3=<WINSYSDIR> +Key4=<TARGETDIR> +Key10=<HKDD> +Key5=<SUPPORTDIR> +Key11=<HKUS> +Key6=<SRCDIR> +Key12=<HKCR> +Key7=<HKLM> +Key13=<SHELL_OBJECT_FOLDER> +Key8=<HKCU> +Key9=<HKCC> + +[<SHELL_OBJECT_FOLDER>] +KeyType=4 +Value= + +[<SUPPORTDIR>] +KeyType=4 +Value= + +[General] +Type=TEXTSUB +Version=1.00.000 + +[<HKCU>] +KeyType=4 +Value= + +[<HKLM>] +KeyType=4 +Value= + +[<HKDD>] +KeyType=4 +Value= + +[<HKCC>] +KeyType=4 +Value= + diff --git a/acinclude.m4 b/acinclude.m4 index 2b91d52d749..01edc6050da 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -90,7 +90,7 @@ mysql_cv_btype_last_arg_accept=none ], [int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0); return (a != 0);], mysql_cv_btype_last_arg_accept=socklen_t)] -if test $mysql_cv_btype_last_arg_accept = none; then +if test "$mysql_cv_btype_last_arg_accept" = "none"; then [AC_TRY_COMPILE([#if defined(inline) #undef inline #endif @@ -101,7 +101,7 @@ if test $mysql_cv_btype_last_arg_accept = none; then [int a = accept(1, (struct sockaddr *) 0, (size_t *) 0); return (a != 0);], mysql_cv_btype_last_arg_accept=size_t)] fi -if test $mysql_cv_btype_last_arg_accept = none; then +if test "$mysql_cv_btype_last_arg_accept" = "none"; then mysql_cv_btype_last_arg_accept=int fi) AC_LANG_RESTORE @@ -166,12 +166,19 @@ AC_DEFUN(MYSQL_CHECK_ZLIB_WITH_COMPRESS, [ save_LIBS="$LIBS" LIBS="-l$1 $LIBS" AC_CACHE_CHECK([if libz with compress], mysql_cv_compress, -[AC_TRY_LINK([#include <zlib.h> +[AC_TRY_RUN([#include <zlib.h> #ifdef __cplusplus extern "C" #endif -], -[ return compress(0, (unsigned long*) 0, "", 0); +int main(int argv, char **argc) +{ + return 0; +} + +int link_test() +{ + return compress(0, (unsigned long*) 0, "", 0); +} ], mysql_cv_compress=yes, mysql_cv_compress=no)]) if test "$mysql_cv_compress" = "yes" then @@ -386,11 +393,11 @@ AC_CACHE_VAL(mysql_cv_termcap_lib, [AC_CHECK_LIB(termcap, tgetent, mysql_cv_termcap_lib=libtermcap, mysql_cv_termcap_lib=NOT_FOUND)])])]) AC_MSG_CHECKING(for termcap functions library) -if test $mysql_cv_termcap_lib = NOT_FOUND; then +if test "$mysql_cv_termcap_lib" = "NOT_FOUND"; then AC_MSG_ERROR([No curses/termcap library found]) -elif test $mysql_cv_termcap_lib = libtermcap; then +elif test "$mysql_cv_termcap_lib" = "libtermcap"; then TERMCAP_LIB=-ltermcap -elif test $mysql_cv_termcap_lib = libncurses; then +elif test "$mysql_cv_termcap_lib" = "libncurses"; then TERMCAP_LIB=-lncurses else TERMCAP_LIB=-lcurses @@ -446,7 +453,7 @@ AC_CACHE_VAL(mysql_cv_can_redecl_getpw, extern struct passwd *getpwent();], [struct passwd *z; z = getpwent();], mysql_cv_can_redecl_getpw=yes,mysql_cv_can_redecl_getpw=no)]) AC_MSG_RESULT($mysql_cv_can_redecl_getpw) -if test $mysql_cv_can_redecl_getpw = no; then +if test "$mysql_cv_can_redecl_getpw" = "no"; then AC_DEFINE(HAVE_GETPW_DECLS) fi ]) @@ -458,7 +465,7 @@ AC_CACHE_VAL(mysql_cv_tiocgwinsz_in_ioctl, #include <sys/ioctl.h>], [int x = TIOCGWINSZ;], mysql_cv_tiocgwinsz_in_ioctl=yes,mysql_cv_tiocgwinsz_in_ioctl=no)]) AC_MSG_RESULT($mysql_cv_tiocgwinsz_in_ioctl) -if test $mysql_cv_tiocgwinsz_in_ioctl = yes; then +if test "$mysql_cv_tiocgwinsz_in_ioctl" = "yes"; then AC_DEFINE(GWINSZ_IN_SYS_IOCTL) fi ]) @@ -470,7 +477,7 @@ AC_CACHE_VAL(mysql_cv_fionread_in_ioctl, #include <sys/ioctl.h>], [int x = FIONREAD;], mysql_cv_fionread_in_ioctl=yes,mysql_cv_fionread_in_ioctl=no)]) AC_MSG_RESULT($mysql_cv_fionread_in_ioctl) -if test $mysql_cv_fionread_in_ioctl = yes; then +if test "$mysql_cv_fionread_in_ioctl" = "yes"; then AC_DEFINE(FIONREAD_IN_SYS_IOCTL) fi ]) @@ -482,7 +489,7 @@ AC_CACHE_VAL(mysql_cv_tiocstat_in_ioctl, #include <sys/ioctl.h>], [int x = TIOCSTAT;], mysql_cv_tiocstat_in_ioctl=yes,mysql_cv_tiocstat_in_ioctl=no)]) AC_MSG_RESULT($mysql_cv_tiocstat_in_ioctl) -if test $mysql_cv_tiocstat_in_ioctl = yes; then +if test "$mysql_cv_tiocstat_in_ioctl" = "yes"; then AC_DEFINE(TIOCSTAT_IN_SYS_IOCTL) fi ]) @@ -515,7 +522,7 @@ AC_CACHE_VAL(mysql_cv_dirent_has_dino, struct dirent d; int z; z = d.d_ino; ], mysql_cv_dirent_has_dino=yes, mysql_cv_dirent_has_dino=no)]) AC_MSG_RESULT($mysql_cv_dirent_has_dino) -if test $mysql_cv_dirent_has_dino = yes; then +if test "$mysql_cv_dirent_has_dino" = "yes"; then AC_DEFINE(STRUCT_DIRENT_HAS_D_INO) fi ]) @@ -534,7 +541,7 @@ extern "C" void (*signal ()) ();], [int i;], mysql_cv_void_sighandler=yes, mysql_cv_void_sighandler=no)])dnl AC_MSG_RESULT($mysql_cv_void_sighandler) -if test $mysql_cv_void_sighandler = yes; then +if test "$mysql_cv_void_sighandler" = "yes"; then AC_DEFINE(VOID_SIGHANDLER) fi ]) @@ -593,7 +600,7 @@ then AC_CACHE_CHECK([for working alloca.h], ac_cv_header_alloca_h, [AC_TRY_LINK([#include <alloca.h>], [char *p = alloca(2 * sizeof(int));], ac_cv_header_alloca_h=yes, ac_cv_header_alloca_h=no)]) - if test $ac_cv_header_alloca_h = yes + if test "$ac_cv_header_alloca_h" = "yes" then AC_DEFINE(HAVE_ALLOCA) fi @@ -617,11 +624,11 @@ then #endif ], [char *p = (char *) alloca(1);], ac_cv_func_alloca_works=yes, ac_cv_func_alloca_works=no)]) - if test $ac_cv_func_alloca_works = yes; then + if test "$ac_cv_func_alloca_works" = "yes"; then AC_DEFINE(HAVE_ALLOCA) fi - if test $ac_cv_func_alloca_works = no; then + if test "$ac_cv_func_alloca_works" = "no"; then # The SVR3 libPW and SVR4 libucb both contain incompatible functions # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, @@ -637,7 +644,7 @@ then wenotbecray #endif ], ac_cv_os_cray=yes, ac_cv_os_cray=no)]) - if test $ac_cv_os_cray = yes; then + if test "$ac_cv_os_cray" = "yes"; then for ac_func in _getb67 GETB67 getb67; do AC_CHECK_FUNC($ac_func, [AC_DEFINE_UNQUOTED(CRAY_STACKSEG_END, $ac_func) break]) @@ -742,26 +749,43 @@ AC_DEFUN(MYSQL_CHECK_VIO, [ ]) AC_DEFUN(MYSQL_FIND_OPENSSL, [ - for d in /usr/ssl/include /usr/local/ssl/include /usr/include \ + incs="$1" + libs="$2" + case "$incs---$libs" in + ---) + for d in /usr/ssl/include /usr/local/ssl/include /usr/include \ /usr/include/ssl /opt/ssl/include /opt/openssl/include \ /usr/local/ssl/include /usr/local/include ; do - if test -f $d/openssl/ssl.h ; then - OPENSSL_INCLUDE=-I$d - fi - done + if test -f $d/openssl/ssl.h ; then + OPENSSL_INCLUDE=-I$d + fi + done - for d in /usr/ssl/lib /usr/local/ssl/lib /usr/lib/openssl \ -/usr/lib /opt/ssl/lib /opt/openssl/lib /usr/local/lib/ ; do - if test -f $d/libssl.a ; then - OPENSSL_LIB=$d - fi - done + for d in /usr/ssl/lib /usr/local/ssl/lib /usr/lib/openssl \ +/usr/lib /usr/lib64 /opt/ssl/lib /opt/openssl/lib /usr/local/lib/ ; do + if test -f $d/libssl.a ; then + OPENSSL_LIB=$d + fi + done + ;; + ---* | *---) + AC_MSG_ERROR([if either 'includes' or 'libs' is specified, both must be specified]) + ;; + * ) + if test -f $incs/openssl/ssl.h ; then + OPENSSL_INCLUDE=-I$incs + fi + if test -f $libs/libssl.a ; then + OPENSSL_LIB=$libs + fi + ;; + esac # On RedHat 9 we need kerberos to compile openssl for d in /usr/kerberos/include do if test -f $d/krb5.h ; then - OPENSSL_INCLUDE="$OPENSSL_INCLUDE -I$d" + OPENSSL_KERBEROS_INCLUDE="$d" fi done @@ -770,7 +794,7 @@ AC_DEFUN(MYSQL_FIND_OPENSSL, [ echo "Could not find an installation of OpenSSL" if test -n "$OPENSSL_LIB" ; then if test "$IS_LINUX" = "true"; then - echo "Looks like you've forgotted to install OpenSSL development RPM" + echo "Looks like you've forgotten to install OpenSSL development RPM" fi fi exit 1 @@ -785,11 +809,23 @@ AC_MSG_CHECKING(for OpenSSL) [openssl="$withval"], [openssl=no]) - openssl_libs="" - openssl_includes="" + AC_ARG_WITH([openssl-includes], + [ + --with-openssl-includes=DIR + Find OpenSSL headers in DIR], + [openssl_includes="$withval"], + [openssl_includes=""]) + + AC_ARG_WITH([openssl-libs], + [ + --with-openssl-libs=DIR + Find OpenSSL libraries in DIR], + [openssl_libs="$withval"], + [openssl_libs=""]) + if test "$openssl" = "yes" then - MYSQL_FIND_OPENSSL + MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs]) #force VIO use vio_dir="vio" vio_libs="../vio/libvio.la" @@ -798,10 +834,15 @@ AC_MSG_CHECKING(for OpenSSL) openssl_libs="-L$OPENSSL_LIB -lssl -lcrypto" # Don't set openssl_includes to /usr/include as this gives us a lot of # compiler warnings when using gcc 3.x + openssl_includes="" if test "$OPENSSL_INCLUDE" != "-I/usr/include" then openssl_includes="$OPENSSL_INCLUDE" fi + if test "$OPENSSL_KERBEROS_INCLUDE" + then + openssl_includes="$openssl_includes -I$OPENSSL_KERBEROS_INCLUDE" + fi AC_DEFINE(HAVE_OPENSSL) # openssl-devel-0.9.6 requires dlopen() and we can't link staticly @@ -811,7 +852,7 @@ AC_MSG_CHECKING(for OpenSSL) case "$CLIENT_EXTRA_LDFLAGS $MYSQLD_EXTRA_LDFLAGS" in *-all-static*) using_static="yes" ;; esac - if test $using_static = "yes" + if test "$using_static" = "yes" then echo "You can't use the --all-static link option when using openssl." exit 1 diff --git a/client/get_password.c b/client/get_password.c index f187c113644..1b7b4e65a9f 100644 --- a/client/get_password.c +++ b/client/get_password.c @@ -70,7 +70,7 @@ char *get_tty_password(char *opt_message) char *pos=to,*end=to+sizeof(to)-1; int i=0; DBUG_ENTER("get_tty_password"); - fprintf(stderr,opt_message ? opt_message : "Enter password: "); + _cputs(opt_message ? opt_message : "Enter password: "); for (;;) { char tmp; diff --git a/client/mysql.cc b/client/mysql.cc index ed0c1bf102b..0b6485172e4 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2645,7 +2645,8 @@ com_status(String *buffer __attribute__((unused)), (void) mysql_fetch_row(result); // Read eof } #ifdef HAVE_OPENSSL - if (mysql.net.vio->ssl_ && SSL_get_cipher(mysql.net.vio->ssl_)) + if (mysql.net.vio && mysql.net.vio->ssl_ && + SSL_get_cipher(mysql.net.vio->ssl_)) tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n", SSL_get_cipher(mysql.net.vio->ssl_)); else @@ -2924,12 +2925,11 @@ static void mysql_end_timer(ulong start_time,char *buff) static const char* construct_prompt() { - //erase the old prompt - processed_prompt.free(); - //get the date struct - time_t lclock = time(NULL); + processed_prompt.free(); // Erase the old prompt + time_t lclock = time(NULL); // Get the date struct struct tm *t = localtime(&lclock); - //parse thru the settings for the prompt + + /* parse thru the settings for the prompt */ for (char *c = current_prompt; *c ; *c++) { if (*c != PROMPT_CHAR) @@ -2938,8 +2938,7 @@ static const char* construct_prompt() { switch (*++c) { case '\0': - //stop it from going beyond if ends with % - c--; + c--; // stop it from going beyond if ends with % break; case 'c': add_int_to_prompt(++prompt_counter); diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 0ef0cb9b8c1..9fdda0a3853 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 MySQL AB +/* Copyright (C) 2001-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 @@ -51,21 +51,19 @@ static bool short_form = 0; static ulonglong offset = 0; static const char* host = "localhost"; static int port = MYSQL_PORT; +static const char* sock= MYSQL_UNIX_ADDR; static const char* user = "test"; static const char* pass = ""; static ulonglong position = 0; static bool use_remote = 0; static short binlog_flags = 0; static MYSQL* mysql = NULL; -static const char* table = 0; - static const char* dirname_for_local_load= 0; static void dump_local_log_entries(const char* logname); static void dump_remote_log_entries(const char* logname); static void dump_log_entries(const char* logname); static void dump_remote_file(NET* net, const char* fname); -static void dump_remote_table(NET* net, const char* db, const char* table); static void die(const char* fmt, ...); static MYSQL* safe_connect(); @@ -224,8 +222,9 @@ static struct my_option my_long_options[] = {"short-form", 's', "Just show the queries, no extra info.", (gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"table", 't', "Get raw table dump using COM_TABLE_DUMB.", (gptr*) &table, - (gptr*) &table, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"socket", 'S', "Socket file to use for connection.", + (gptr*) &sock, (gptr*) &sock, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, + 0, 0}, {"user", 'u', "Connect to the remote server as username.", (gptr*) &user, (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -369,7 +368,7 @@ static MYSQL* safe_connect() if(!local_mysql) die("Failed on mysql_init"); - if (!mysql_real_connect(local_mysql, host, user, pass, 0, port, 0, 0)) + if (!mysql_real_connect(local_mysql, host, user, pass, 0, port, sock, 0)) die("failed on connect: %s", mysql_error(local_mysql)); return local_mysql; @@ -383,35 +382,6 @@ static void dump_log_entries(const char* logname) dump_local_log_entries(logname); } -static void dump_remote_table(NET* net, const char* db, const char* table) -{ - char buf[1024]; - char * p = buf; - uint table_len = (uint) strlen(table); - uint db_len = (uint) strlen(db); - if (table_len + db_len > sizeof(buf) - 2) - die("Buffer overrun"); - - *p++ = db_len; - memcpy(p, db, db_len); - p += db_len; - *p++ = table_len; - memcpy(p, table, table_len); - - if (simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1)) - die("Error sending the table dump command"); - - for (;;) - { - uint packet_len = my_net_read(net); - if (packet_len == 0) break; // end of file - if (packet_len == packet_error) - die("Error reading packet in table dump"); - my_fwrite(result_file, (byte*)net->read_pos, packet_len, MYF(MY_WME)); - fflush(result_file); - } -} - static int check_master_version(MYSQL* mysql) { MYSQL_RES* res = 0; @@ -491,7 +461,7 @@ static void dump_remote_log_entries(const char* logname) len = net_safe_read(mysql); if (len == packet_error) die("Error reading packet from server: %s", mysql_error(mysql)); - if (len == 1 && net->read_pos[0] == 254) + if (len < 8 && net->read_pos[0] == 254) break; // end of data DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n", len, net->read_pos[5])); @@ -527,8 +497,8 @@ static int check_header(IO_CACHE* file) if (buf[4] == START_EVENT) { uint event_len; - event_len = uint4korr(buf + 4); - old_format = (event_len < LOG_EVENT_HEADER_LEN + START_HEADER_LEN); + event_len = uint4korr(buf + EVENT_LEN_OFFSET); + old_format = (event_len < (LOG_EVENT_HEADER_LEN + START_HEADER_LEN)); } } my_b_seek(file, pos); @@ -673,7 +643,7 @@ int main(int argc, char** argv) MY_INIT(argv[0]); parse_args(&argc, (char***)&argv); - if (!argc && !table) + if (!argc) { usage(); return -1; @@ -696,22 +666,8 @@ int main(int argc, char** argv) else load_processor.init_by_cur_dir(); - if (table) - { - if (!use_remote) - die("You must specify connection parameter to get table dump"); - char* db = (char*) table; - char* tbl = (char*) strchr(table, '.'); - if (!tbl) - die("You must use database.table syntax to specify the table"); - *tbl++ = 0; - dump_remote_table(&mysql->net, db, tbl); - } - else - { - while (--argc >= 0) - dump_log_entries(*(argv++)); - } + while (--argc >= 0) + dump_log_entries(*(argv++)); if (tmpdir.list) free_tmpdir(&tmpdir); if (result_file != stdout) diff --git a/client/mysqltest.c b/client/mysqltest.c index 26e72560eff..a3b5facae9c 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1014,7 +1014,8 @@ int do_sync_with_master2(const char* p) if (!(row = mysql_fetch_row(res))) die("line %u: empty result in %s", start_lineno, query_buf); if (!row[0]) - die("Error on slave while syncing with master"); + die("line %u: could not sync with master ('%s' returned NULL)", + start_lineno, query_buf); mysql_free_result(res); last_result=0; if (rpl_parse) diff --git a/configure.in b/configure.in index 63b33e391b2..783e3af5c61 100644 --- a/configure.in +++ b/configure.in @@ -755,7 +755,7 @@ AC_CHECK_LIB(crypt, crypt) AC_CHECK_FUNC(crypt, AC_DEFINE(HAVE_CRYPT)) # For sem_xxx functions on Solaris 2.6 -AC_CHECK_FUNC(sem_init, , AC_CHECK_LIB(posix4)) +AC_CHECK_FUNC(sem_init, , AC_CHECK_LIB(posix4, sem_init)) # For compress in zlib MYSQL_CHECK_ZLIB_WITH_COMPRESS($with_named_zlib) @@ -1280,12 +1280,12 @@ then AC_MSG_ERROR([On SCO UNIX MySQL must be compiled with gcc. See the Installation chapter in the Reference Manual.]); fi AC_MSG_RESULT("yes") - # Hack for SCO UnixWare 7.1 + # Hack for SCO UnixWare 7.1.x # elif test "$with_named_thread" = "no" then AC_MSG_RESULT("no") - AC_MSG_CHECKING("SCO UnixWare 7.1 native threads") + AC_MSG_CHECKING("SCO UnixWare 7.1.x native threads") if expr "$SYSTEM_TYPE" : ".*sco.*" > /dev/null then if test -f /usr/lib/libthread.so -o -f /usr/lib/libthreadT.so @@ -1308,11 +1308,11 @@ then AC_MSG_CHECKING("for gcc") if expr "$CC" : ".*gcc.*" then - CC="$CC -pthread -DUNIXWARE_7"; - CXX="$CXX -pthread -DUNIXWARE_7"; + CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; else - CC="$CC -Kthread -DUNIXWARE_7"; - CXX="$CXX -Kthread -DUNIXWARE_7"; + CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; fi else { echo "configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; @@ -1348,10 +1348,11 @@ then AC_MSG_CHECKING("for gcc") if expr "$CC" : ".*gcc.*" then - { echo "configure: error: On SCO UnixWare7 MySQL must be compiled with cc. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; + CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; else - CC="$CC -Kthread -DUNIXWARE_7"; - CXX="$CXX -Kthread -DUNIXWARE_7"; + CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; fi AC_MSG_RESULT("yes") else @@ -1383,7 +1384,8 @@ then AC_MSG_CHECKING("for gcc") if expr "$CC" : ".*gcc.*" then - { echo "configure: error: On OpenUNIX8 and UnixWare7 MySQL must be compiled with cc. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; + CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; else CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; diff --git a/extra/perror.c b/extra/perror.c index 1e47364bc5e..d05fa2492de 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -111,7 +111,7 @@ static void usage(void) { print_version(); puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"); - printf("Print a description for a system error code or a error code from\na MyISAM/ISAM/BDB table handler.\n"); + printf("Print a description for a system error code or an error code from\na MyISAM/ISAM/BDB table handler.\n"); printf("If you want to get the error for a negative error code, you should use\n-- before the first error code to tell perror that there was no more options.\n\n"); printf("Usage: %s [OPTIONS] [ERRORCODE [ERRORCODE...]]\n",my_progname); my_print_help(my_long_options); diff --git a/include/config-win.h b/include/config-win.h index c4e9588666e..6b40a0f2ed3 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -253,7 +253,6 @@ inline double ulonglong2double(ulonglong value) #define HAVE_PERROR #define HAVE_VFPRINT -#define HAVE_CHSIZE /* System has chsize() function */ #define HAVE_RENAME /* Have rename() as function */ #define HAVE_BINARY_STREAMS /* Have "b" flag in streams */ #define HAVE_LONG_JMP /* Have long jump function */ diff --git a/include/my_base.h b/include/my_base.h index 8c5496cc2e0..972a02e65cd 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -257,7 +257,8 @@ enum ha_base_keytype { #define HA_ERR_CANNOT_ADD_FOREIGN 150 /* Cannot add a foreign key constr. */ #define HA_ERR_NO_REFERENCED_ROW 151 /* Cannot add a child row */ #define HA_ERR_ROW_IS_REFERENCED 152 /* Cannot delete a parent row */ -#define HA_ERR_NON_UNIQUE_BLOCK_SIZE 153 /* Non unique key block size */ +#define HA_ERR_NO_SAVEPOINT 153 /* No savepoint with that name */ +#define HA_ERR_NON_UNIQUE_BLOCK_SIZE 154 /* Non unique key block size */ /* Other constants */ diff --git a/include/my_global.h b/include/my_global.h index 9de8e310d79..98f666548a5 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -43,6 +43,10 @@ #define HAVE_ERRNO_AS_DEFINE #endif /* __CYGWIN__ */ +#if defined(i386) && !defined(__i386__) +#define __i386__ +#endif + /* Macros to make switching between C and C++ mode easier */ #ifdef __cplusplus #define C_MODE_START extern "C" { @@ -283,7 +287,9 @@ C_MODE_END #endif #ifdef HAVE_ATOMIC_ADD #define __SMP__ +#ifndef CONFIG_SMP #define CONFIG_SMP +#endif #include <asm/atomic.h> #endif #include <errno.h> /* Recommended by debian */ @@ -660,7 +666,6 @@ typedef long my_ptrdiff_t; typedef long long my_ptrdiff_t; #endif - #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) /* Size to make adressable obj. */ @@ -920,8 +925,11 @@ typedef union { double v; long m[2]; } doubleget_union; -#define doubleget(V,M) { ((doubleget_union *)&V)->m[0] = *((long*) M); \ - ((doubleget_union *)&V)->m[1] = *(((long*) M)+1); } +#define doubleget(V,M) \ +{ doubleget_union _tmp; \ + _tmp.m[0] = *((long*)(M)); \ + _tmp.m[1] = *(((long*) (M))+1); \ + (V) = _tmp.v; } #define doublestore(T,V) { *((long *) T) = ((doubleget_union *)&V)->m[0]; \ *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; } #define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); } diff --git a/include/my_sys.h b/include/my_sys.h index e4125a2e7e6..688e8bfc9e3 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -135,7 +135,7 @@ extern int NEAR my_errno; /* Last error in mysys */ #define QUICK_SAFEMALLOC sf_malloc_quick=1 #define NORMAL_SAFEMALLOC sf_malloc_quick=0 extern uint sf_malloc_prehunc,sf_malloc_endhunc,sf_malloc_quick; -extern ulonglong safemalloc_mem_limit; +extern ulonglong sf_malloc_mem_limit; #define CALLER_INFO_PROTO , const char *sFile, uint uLine #define CALLER_INFO , __FILE__, __LINE__ @@ -240,7 +240,7 @@ extern int NEAR my_umask, /* Default creation mask */ NEAR my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ NEAR my_dont_interrupt; /* call remember_intr when set */ extern my_bool NEAR mysys_uses_curses, my_use_symdir; -extern long lCurMemory,lMaxMemory; /* from safemalloc */ +extern ulong sf_malloc_cur_memory, sf_malloc_max_memory; extern ulong my_default_record_cache_size; extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io, diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 17ededfbb52..d2240b7a28e 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -253,39 +253,40 @@ #define ER_CANT_USE_OPTION_HERE 1234 #define ER_NOT_SUPPORTED_YET 1235 #define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 -#define ER_WRONG_FK_DEF 1237 -#define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1238 -#define ER_CARDINALITY_COL 1239 -#define ER_SUBSELECT_NO_1_ROW 1240 -#define ER_UNKNOWN_STMT_HANDLER 1241 -#define ER_CORRUPT_HELP_DB 1242 -#define ER_CYCLIC_REFERENCE 1243 -#define ER_AUTO_CONVERT 1244 -#define ER_ILLEGAL_REFERENCE 1245 -#define ER_DERIVED_MUST_HAVE_ALIAS 1246 -#define ER_SELECT_REDUCED 1247 -#define ER_TABLENAME_NOT_ALLOWED_HERE 1248 -#define ER_NOT_SUPPORTED_AUTH_MODE 1249 -#define ER_SPATIAL_CANT_HAVE_NULL 1250 -#define ER_COLLATION_CHARSET_MISMATCH 1251 -#define ER_SLAVE_WAS_RUNNING 1252 -#define ER_SLAVE_WAS_NOT_RUNNING 1253 -#define ER_TOO_BIG_FOR_UNCOMPRESS 1254 -#define ER_ZLIB_Z_MEM_ERROR 1255 -#define ER_ZLIB_Z_BUF_ERROR 1256 -#define ER_ZLIB_Z_DATA_ERROR 1257 -#define ER_CUT_VALUE_GROUP_CONCAT 1258 -#define ER_WARN_TOO_FEW_RECORDS 1259 -#define ER_WARN_TOO_MANY_RECORDS 1260 -#define ER_WARN_NULL_TO_NOTNULL 1261 -#define ER_WARN_DATA_OUT_OF_RANGE 1262 -#define ER_WARN_DATA_TRUNCATED 1263 -#define ER_WARN_USING_OTHER_HANDLER 1264 -#define ER_CANT_AGGREGATE_2COLLATIONS 1265 -#define ER_DROP_USER 1266 -#define ER_REVOKE_GRANTS 1267 -#define ER_CANT_AGGREGATE_3COLLATIONS 1268 -#define ER_CANT_AGGREGATE_NCOLLATIONS 1269 -#define ER_VARIABLE_IS_NOT_STRUCT 1270 -#define ER_UNKNOWN_COLLATION 1271 -#define ER_ERROR_MESSAGES 272 +#define ER_SLAVE_IGNORED_TABLE 1237 +#define ER_WRONG_FK_DEF 1238 +#define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1239 +#define ER_CARDINALITY_COL 1240 +#define ER_SUBSELECT_NO_1_ROW 1241 +#define ER_UNKNOWN_STMT_HANDLER 1242 +#define ER_CORRUPT_HELP_DB 1243 +#define ER_CYCLIC_REFERENCE 1244 +#define ER_AUTO_CONVERT 1245 +#define ER_ILLEGAL_REFERENCE 1246 +#define ER_DERIVED_MUST_HAVE_ALIAS 1247 +#define ER_SELECT_REDUCED 1248 +#define ER_TABLENAME_NOT_ALLOWED_HERE 1249 +#define ER_NOT_SUPPORTED_AUTH_MODE 1250 +#define ER_SPATIAL_CANT_HAVE_NULL 1251 +#define ER_COLLATION_CHARSET_MISMATCH 1252 +#define ER_SLAVE_WAS_RUNNING 1253 +#define ER_SLAVE_WAS_NOT_RUNNING 1254 +#define ER_TOO_BIG_FOR_UNCOMPRESS 1255 +#define ER_ZLIB_Z_MEM_ERROR 1256 +#define ER_ZLIB_Z_BUF_ERROR 1257 +#define ER_ZLIB_Z_DATA_ERROR 1258 +#define ER_CUT_VALUE_GROUP_CONCAT 1259 +#define ER_WARN_TOO_FEW_RECORDS 1260 +#define ER_WARN_TOO_MANY_RECORDS 1261 +#define ER_WARN_NULL_TO_NOTNULL 1262 +#define ER_WARN_DATA_OUT_OF_RANGE 1263 +#define ER_WARN_DATA_TRUNCATED 1264 +#define ER_WARN_USING_OTHER_HANDLER 1265 +#define ER_CANT_AGGREGATE_2COLLATIONS 1266 +#define ER_DROP_USER 1267 +#define ER_REVOKE_GRANTS 1268 +#define ER_CANT_AGGREGATE_3COLLATIONS 1269 +#define ER_CANT_AGGREGATE_NCOLLATIONS 1270 +#define ER_VARIABLE_IS_NOT_STRUCT 1271 +#define ER_UNKNOWN_COLLATION 1272 +#define ER_ERROR_MESSAGES 273 diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c index 51c164b7cef..d8a0959e47f 100644 --- a/innobase/btr/btr0btr.c +++ b/innobase/btr/btr0btr.c @@ -822,9 +822,16 @@ btr_page_reorganize_low( { page_t* new_page; ulint log_mode; + ulint data_size1; + ulint data_size2; + ulint max_ins_size1; + ulint max_ins_size2; ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); + data_size1 = page_get_data_size(page); + max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1); + /* Write the log record */ mlog_write_initial_log_record(page, MLOG_PAGE_REORGANIZE, mtr); @@ -859,6 +866,19 @@ btr_page_reorganize_low( lock_move_reorganize_page(page, new_page); } + data_size2 = page_get_data_size(page); + max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1); + + if (data_size1 != data_size2 || max_ins_size1 != max_ins_size2) { + buf_page_print(page); + buf_page_print(new_page); + fprintf(stderr, +"InnoDB: Error: page old data size %lu new data size %lu\n" +"InnoDB: Error: page old max ins size %lu new max ins size %lu\n" +"InnoDB: Make a detailed bug report and send it to mysql@lists.mysql.com\n", + data_size1, data_size2, max_ins_size1, max_ins_size2); + } + buf_frame_free(new_page); /* Restore logging mode */ @@ -1945,11 +1965,20 @@ btr_compress( btr_page_reorganize(merge_page, mtr); + max_ins_size = page_get_max_insert_size(merge_page, n_recs); + ut_ad(page_validate(merge_page, cursor->index)); ut_ad(page_get_max_insert_size(merge_page, n_recs) == max_ins_size_reorg); } + if (data_size > max_ins_size) { + + /* Add fault tolerance, though this should never happen */ + + return; + } + btr_search_drop_page_hash_index(page); /* Remove the page from the level list */ diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c index 69952c842ce..f6b4a2964f5 100644 --- a/innobase/btr/btr0cur.c +++ b/innobase/btr/btr0cur.c @@ -1110,6 +1110,10 @@ btr_cur_pessimistic_insert( if (big_rec_vec == NULL) { + if (n_extents > 0) { + fil_space_release_free_extents(index->space, + n_extents); + } return(DB_TOO_BIG_RECORD); } } @@ -1367,7 +1371,8 @@ btr_cur_update_sec_rec_in_place( } /***************************************************************** -Updates a record when the update causes no size changes in its fields. */ +Updates a record when the update causes no size changes in its fields. +We assume here that the ordering fields of the record do not change. */ ulint btr_cur_update_in_place( @@ -1458,7 +1463,8 @@ btr_cur_update_in_place( Tries to update a record on a page in an index tree. It is assumed that mtr holds an x-latch on the page. The operation does not succeed if there is too little space on the page or if the update would result in too empty a page, -so that tree compression is recommended. */ +so that tree compression is recommended. We assume here that the ordering +fields of the record do not change. */ ulint btr_cur_optimistic_update( @@ -1510,10 +1516,11 @@ btr_cur_optimistic_update( ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); - if (!row_upd_changes_field_size(rec, index, update)) { + if (!row_upd_changes_field_size_or_external(rec, index, update)) { - /* The simplest and most common case: the update does not - change the size of any field */ + /* The simplest and the most common case: the update does not + change the size of any field and none of the updated fields is + externally stored in rec or update */ return(btr_cur_update_in_place(flags, cursor, update, cmpl_info, thr, mtr)); @@ -1542,7 +1549,7 @@ btr_cur_optimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); - row_upd_clust_index_replace_new_col_vals(new_entry, update); + row_upd_index_replace_new_col_vals(new_entry, index, update, NULL); old_rec_size = rec_get_size(rec); new_rec_size = rec_get_converted_size(new_entry); @@ -1672,54 +1679,13 @@ btr_cur_pess_upd_restore_supremum( lock_rec_reset_and_inherit_gap_locks(page_get_supremum_rec(prev_page), rec); } - -/*************************************************************** -Replaces and copies the data in the new column values stored in the -update vector to the clustered index entry given. */ -static -void -btr_cur_copy_new_col_vals( -/*======================*/ - dtuple_t* entry, /* in/out: index entry where replaced */ - upd_t* update, /* in: update vector */ - mem_heap_t* heap) /* in: heap where data is copied */ -{ - upd_field_t* upd_field; - dfield_t* dfield; - dfield_t* new_val; - ulint field_no; - byte* data; - ulint i; - - dtuple_set_info_bits(entry, update->info_bits); - - for (i = 0; i < upd_get_n_fields(update); i++) { - - upd_field = upd_get_nth_field(update, i); - - field_no = upd_field->field_no; - - dfield = dtuple_get_nth_field(entry, field_no); - - new_val = &(upd_field->new_val); - - if (new_val->len == UNIV_SQL_NULL) { - data = NULL; - } else { - data = mem_heap_alloc(heap, new_val->len); - - ut_memcpy(data, new_val->data, new_val->len); - } - - dfield_set_data(dfield, data, new_val->len); - } -} /***************************************************************** Performs an update of a record on a page of a tree. It is assumed that mtr holds an x-latch on the tree and on the cursor page. If the update is made on the leaf level, to avoid deadlocks, mtr must also -own x-latches to brothers of page, if those brothers exist. */ +own x-latches to brothers of page, if those brothers exist. We assume +here that the ordering fields of the record do not change. */ ulint btr_cur_pessimistic_update( @@ -1816,7 +1782,7 @@ btr_cur_pessimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); - btr_cur_copy_new_col_vals(new_entry, update, heap); + row_upd_index_replace_new_col_vals(new_entry, index, update, heap); if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, @@ -1825,21 +1791,6 @@ btr_cur_pessimistic_update( trx->id); } - page_cursor = btr_cur_get_page_cur(cursor); - - /* Store state of explicit locks on rec on the page infimum record, - before deleting rec. The page infimum acts as a dummy carrier of the - locks, taking care also of lock releases, before we can move the locks - back on the actual record. There is a special case: if we are - inserting on the root page and the insert causes a call of - btr_root_raise_and_insert. Therefore we cannot in the lock system - delete the lock structs set on the root page even if the root - page carries just node pointers. */ - - lock_rec_store_on_page_infimum(rec); - - btr_search_update_hash_on_delete(cursor); - if (flags & BTR_NO_UNDO_LOG_FLAG) { /* We are in a transaction rollback undoing a row update: we must free possible externally stored fields @@ -1860,10 +1811,6 @@ btr_cur_pessimistic_update( ext_vect = mem_heap_alloc(heap, sizeof(ulint) * rec_get_n_fields(rec)); n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, update); - page_cur_delete_rec(page_cursor, mtr); - - page_cur_move_to_prev(page_cursor); - if ((rec_get_converted_size(new_entry) >= page_get_free_space_of_empty() / 2) || (rec_get_converted_size(new_entry) >= REC_MAX_DATA_SIZE)) { @@ -1874,10 +1821,31 @@ btr_cur_pessimistic_update( mem_heap_free(heap); + err = DB_TOO_BIG_RECORD; + goto return_after_reservations; } } + page_cursor = btr_cur_get_page_cur(cursor); + + /* Store state of explicit locks on rec on the page infimum record, + before deleting rec. The page infimum acts as a dummy carrier of the + locks, taking care also of lock releases, before we can move the locks + back on the actual record. There is a special case: if we are + inserting on the root page and the insert causes a call of + btr_root_raise_and_insert. Therefore we cannot in the lock system + delete the lock structs set on the root page even if the root + page carries just node pointers. */ + + lock_rec_store_on_page_infimum(rec); + + btr_search_update_hash_on_delete(cursor); + + page_cur_delete_rec(page_cursor, mtr); + + page_cur_move_to_prev(page_cursor); + rec = btr_cur_insert_if_possible(cursor, new_entry, &dummy_reorganized, mtr); ut_a(rec || optim_err != DB_UNDERFLOW); @@ -3372,8 +3340,8 @@ btr_free_externally_stored_field( page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO); - offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET); - + offset = mach_read_from_4(data + local_len + + BTR_EXTERN_OFFSET); extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4); diff --git a/innobase/btr/btr0pcur.c b/innobase/btr/btr0pcur.c index 13efacb9da3..39e70d91be8 100644 --- a/innobase/btr/btr0pcur.c +++ b/innobase/btr/btr0pcur.c @@ -381,6 +381,8 @@ btr_pcur_move_to_next_page( btr_leaf_page_release(page, cursor->latch_mode, mtr); page_cur_set_before_first(next_page, btr_pcur_get_page_cur(cursor)); + + page_check_dir(next_page); } /************************************************************* diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 1cdddaf6cb4..9d920c7c0d8 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -34,6 +34,7 @@ Created 11/5/1995 Heikki Tuuri #include "ibuf0ibuf.h" #include "dict0dict.h" #include "log0recv.h" +#include "log0log.h" #include "trx0undo.h" #include "srv0srv.h" @@ -231,12 +232,12 @@ ibool buf_debug_prints = FALSE; /* If this is set TRUE, /************************************************************************ Calculates a page checksum which is stored to the page when it is written -to a file. Note that we must be careful to calculate the same value -on 32-bit and 64-bit architectures. */ +to a file. Note that we must be careful to calculate the same value on +32-bit and 64-bit architectures. */ ulint -buf_calc_page_checksum( -/*===================*/ +buf_calc_page_new_checksum( +/*=======================*/ /* out: checksum */ byte* page) /* in: buffer page */ { @@ -244,12 +245,39 @@ buf_calc_page_checksum( /* Since the fields FIL_PAGE_FILE_FLUSH_LSN and ..._ARCH_LOG_NO are written outside the buffer pool to the first pages of data - files, we have to skip them in page checksum calculation */ + files, we have to skip them in the page checksum calculation. + We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the + checksum is stored, and also the last 8 bytes of page because + there we store the old formula checksum. */ + + checksum = ut_fold_binary(page + FIL_PAGE_OFFSET, + FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET) + + ut_fold_binary(page + FIL_PAGE_DATA, + UNIV_PAGE_SIZE - FIL_PAGE_DATA + - FIL_PAGE_END_LSN_OLD_CHKSUM); + checksum = checksum & 0xFFFFFFFF; + + return(checksum); +} + +/************************************************************************ +In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only +looked at the first few bytes of the page. This calculates that old +checksum. +NOTE: we must first store the new formula checksum to +FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum +because this takes that field as an input! */ + +ulint +buf_calc_page_old_checksum( +/*=======================*/ + /* out: checksum */ + byte* page) /* in: buffer page */ +{ + ulint checksum; checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN); - + ut_fold_binary(page + FIL_PAGE_DATA, - UNIV_PAGE_SIZE - FIL_PAGE_DATA - - FIL_PAGE_END_LSN); + checksum = checksum & 0xFFFFFFFF; return(checksum); @@ -265,27 +293,69 @@ buf_page_is_corrupted( byte* read_buf) /* in: a database page */ { ulint checksum; + ulint old_checksum; + ulint checksum_field; + ulint old_checksum_field; + dulint current_lsn; - checksum = buf_calc_page_checksum(read_buf); + if (mach_read_from_4(read_buf + FIL_PAGE_LSN + 4) + != mach_read_from_4(read_buf + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) { - /* Note that InnoDB initializes empty pages to zero, and - early versions of InnoDB did not store page checksum to - the 4 most significant bytes of the page lsn field at the - end of a page: */ + /* Stored log sequence numbers at the start and the end + of page do not match */ + + return(TRUE); + } + +#ifndef UNIV_HOTBACKUP + if (recv_lsn_checks_on && log_peek_lsn(¤t_lsn)) { + if (ut_dulint_cmp(current_lsn, + mach_read_from_8(read_buf + FIL_PAGE_LSN)) + < 0) { + ut_print_timestamp(stderr); + + fprintf(stderr, +" InnoDB: Error: page %lu log sequence number %lu %lu\n" +"InnoDB: is in the future! Current system log sequence number %lu %lu.\n" +"InnoDB: Your database may be corrupt.\n", + mach_read_from_4(read_buf + FIL_PAGE_OFFSET), + ut_dulint_get_high( + mach_read_from_8(read_buf + FIL_PAGE_LSN)), + ut_dulint_get_low( + mach_read_from_8(read_buf + FIL_PAGE_LSN)), + ut_dulint_get_high(current_lsn), + ut_dulint_get_low(current_lsn)); + } + } +#endif + old_checksum = buf_calc_page_old_checksum(read_buf); + + old_checksum_field = mach_read_from_4(read_buf + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM); + + /* There are 2 valid formulas for old_checksum_field: + 1. Very old versions of InnoDB only stored 8 byte lsn to the start + and the end of the page. + 2. Newer InnoDB versions store the old formula checksum there. */ - if ((mach_read_from_4(read_buf + FIL_PAGE_LSN + 4) - != mach_read_from_4(read_buf + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN + 4)) - || (checksum != mach_read_from_4(read_buf - + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN) - && mach_read_from_4(read_buf + FIL_PAGE_LSN) - != mach_read_from_4(read_buf - + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN))) { + if (old_checksum_field != mach_read_from_4(read_buf + FIL_PAGE_LSN) + && old_checksum_field != old_checksum) { + return(TRUE); } + checksum = buf_calc_page_new_checksum(read_buf); + checksum_field = mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM); + + /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id + (always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */ + + if (checksum_field != 0 && checksum_field != checksum) { + + return(TRUE); + } + return(FALSE); } @@ -299,6 +369,7 @@ buf_page_print( { dict_index_t* index; ulint checksum; + ulint old_checksum; char* buf; buf = mem_alloc(4 * UNIV_PAGE_SIZE); @@ -313,19 +384,23 @@ buf_page_print( mem_free(buf); - checksum = buf_calc_page_checksum(read_buf); + checksum = buf_calc_page_new_checksum(read_buf); + old_checksum = buf_calc_page_old_checksum(read_buf); ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Page checksum %lu stored checksum %lu\n", - checksum, mach_read_from_4(read_buf - + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN)); + fprintf(stderr, +" InnoDB: Page checksum %lu, prior-to-4.0.14-form checksum %lu\n" +"InnoDB: stored checksum %lu, prior-to-4.0.14-form stored checksum %lu\n", + checksum, old_checksum, + mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM), + mach_read_from_4(read_buf + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM)); fprintf(stderr, "InnoDB: Page lsn %lu %lu, low 4 bytes of lsn at page end %lu\n", mach_read_from_4(read_buf + FIL_PAGE_LSN), mach_read_from_4(read_buf + FIL_PAGE_LSN + 4), mach_read_from_4(read_buf + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN + 4)); + - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)); if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT) { fprintf(stderr, diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index 47ac9c6b041..5102674a8df 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -361,21 +361,29 @@ buf_flush_init_for_writing( ulint space, /* in: space id */ ulint page_no) /* in: page number */ { - /* Write the newest modification lsn to the page */ - mach_write_to_8(page + FIL_PAGE_LSN, newest_lsn); + UT_NOT_USED(space); - mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN, newest_lsn); + /* Write the newest modification lsn to the page header and trailer */ + mach_write_to_8(page + FIL_PAGE_LSN, newest_lsn); - /* Write to the page the space id and page number */ + mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, + newest_lsn); + /* Write the page number */ - mach_write_to_4(page + FIL_PAGE_SPACE, space); mach_write_to_4(page + FIL_PAGE_OFFSET, page_no); + /* Store the new formula checksum */ + + mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, + buf_calc_page_new_checksum(page)); + /* We overwrite the first 4 bytes of the end lsn field to store - a page checksum */ + the old formula checksum. Since it depends also on the field + FIL_PAGE_SPACE_OR_CHKSUM, it has to be calculated after storing the + new formula checksum. */ - mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN, - buf_calc_page_checksum(page)); + mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, + buf_calc_page_old_checksum(page)); } /************************************************************************ diff --git a/innobase/data/data0data.c b/innobase/data/data0data.c index 8ab5acb4da7..f2f94cc47ce 100644 --- a/innobase/data/data0data.c +++ b/innobase/data/data0data.c @@ -584,8 +584,7 @@ dtuple_convert_big_rec( * sizeof(big_rec_field_t)); /* Decide which fields to shorten: the algorithm is to look for - the longest field which does not occur in the ordering part - of any index on the table */ + the longest field whose type is DATA_BLOB */ n_fields = 0; @@ -610,12 +609,9 @@ dtuple_convert_big_rec( } } - /* Skip over fields which are ordering in some index */ - - if (!is_externally_stored && - dict_field_get_col( - dict_index_get_nth_field(index, i)) - ->ord_part == 0) { + if (!is_externally_stored + && dict_index_get_nth_type(index, i)->mtype + == DATA_BLOB) { dfield = dtuple_get_nth_field(entry, i); @@ -629,9 +625,13 @@ dtuple_convert_big_rec( } } - if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10 - + REC_1BYTE_OFFS_LIMIT) { + /* We do not store externally fields which are smaller than + DICT_MAX_COL_PREFIX_LEN */ + + ut_a(DICT_MAX_COL_PREFIX_LEN > REC_1BYTE_OFFS_LIMIT); + if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10 + + DICT_MAX_COL_PREFIX_LEN) { /* Cannot shorten more */ mem_heap_free(heap); @@ -644,13 +644,19 @@ dtuple_convert_big_rec( drop below 128 which is the limit for the 2-byte offset storage format in a physical record. This we accomplish by storing 128 bytes of data in entry - itself, and only the remaining part to big rec vec. */ + itself, and only the remaining part to big rec vec. + + We store the first bytes locally to the record. Then + we can calculate all ordering fields in all indexes + from locally stored data. */ dfield = dtuple_get_nth_field(entry, longest_i); vector->fields[n_fields].field_no = longest_i; + ut_a(dfield->len > DICT_MAX_COL_PREFIX_LEN); + vector->fields[n_fields].len = dfield->len - - REC_1BYTE_OFFS_LIMIT; + - DICT_MAX_COL_PREFIX_LEN; vector->fields[n_fields].data = mem_heap_alloc(heap, vector->fields[n_fields].len); diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c index 5d0ddf3e887..df430f06bcb 100644 --- a/innobase/data/data0type.c +++ b/innobase/data/data0type.c @@ -85,8 +85,6 @@ dtype_print( printf("DATA_MIX_ID"); } else if (prtype == DATA_ENGLISH) { printf("DATA_ENGLISH"); - } else if (prtype == DATA_FINNISH) { - printf("DATA_FINNISH"); } else { printf("prtype %lu", mtype); } diff --git a/innobase/dict/dict0boot.c b/innobase/dict/dict0boot.c index 374c567c3ca..0bf2ace3324 100644 --- a/innobase/dict/dict0boot.c +++ b/innobase/dict/dict0boot.c @@ -276,7 +276,7 @@ dict_boot(void) DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 1); - dict_mem_index_add_field(index, (char *) "NAME", 0); + dict_mem_index_add_field(index, (char *) "NAME", 0, 0); index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_TABLES, MLOG_4BYTES, &mtr); @@ -287,7 +287,7 @@ dict_boot(void) index = dict_mem_index_create((char *) "SYS_TABLES", (char *) "ID_IND", DICT_HDR_SPACE, DICT_UNIQUE, 1); - dict_mem_index_add_field(index, (char *) "ID", 0); + dict_mem_index_add_field(index, (char *) "ID", 0, 0); index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_TABLE_IDS, MLOG_4BYTES, &mtr); @@ -313,8 +313,8 @@ dict_boot(void) (char *) "CLUST_IND", DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 2); - dict_mem_index_add_field(index, (char *) "TABLE_ID", 0); - dict_mem_index_add_field(index, (char *) "POS", 0); + dict_mem_index_add_field(index, (char *) "TABLE_ID", 0, 0); + dict_mem_index_add_field(index, (char *) "POS", 0, 0); index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_COLUMNS, MLOG_4BYTES, &mtr); @@ -343,8 +343,8 @@ dict_boot(void) (char *) "CLUST_IND", DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 2); - dict_mem_index_add_field(index, (char *) "TABLE_ID", 0); - dict_mem_index_add_field(index, (char *) "ID", 0); + dict_mem_index_add_field(index, (char *) "TABLE_ID", 0, 0); + dict_mem_index_add_field(index, (char *) "ID", 0, 0); index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_INDEXES, MLOG_4BYTES, &mtr); @@ -365,8 +365,8 @@ dict_boot(void) (char *) "CLUST_IND", DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 2); - dict_mem_index_add_field(index, (char *) "INDEX_ID", 0); - dict_mem_index_add_field(index, (char *) "POS", 0); + dict_mem_index_add_field(index, (char *) "INDEX_ID", 0, 0); + dict_mem_index_add_field(index, (char *) "POS", 0, 0); index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_FIELDS, MLOG_4BYTES, &mtr); diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index 3619ac02f4d..9139e589a0a 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -337,7 +337,7 @@ dict_create_index_for_cluster_step( for (i = 0; i < table->n_cols; i++) { col = dict_table_get_nth_col(table, i); - dict_mem_index_add_field(index, col->name, 0); + dict_mem_index_add_field(index, col->name, 0, 0); } (node->cluster)->index = index; @@ -450,9 +450,17 @@ dict_create_sys_fields_tuple( dict_field_t* field; dfield_t* dfield; byte* ptr; + ibool index_contains_column_prefix_field = FALSE; + ulint j; ut_ad(index && heap); + for (j = 0; j < index->n_fields; j++) { + if (dict_index_get_nth_field(index, j)->prefix_len > 0) { + index_contains_column_prefix_field = TRUE; + } + } + field = dict_index_get_nth_field(index, i); sys_fields = dict_sys->sys_fields; @@ -466,11 +474,25 @@ dict_create_sys_fields_tuple( mach_write_to_8(ptr, index->id); dfield_set_data(dfield, ptr, 8); - /* 1: POS ----------------------------*/ + /* 1: POS + PREFIX LENGTH ----------------------------*/ + dfield = dtuple_get_nth_field(entry, 1); ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, i); + + if (index_contains_column_prefix_field) { + /* If there are column prefix fields in the index, then + we store the number of the field to the 2 HIGH bytes + and the prefix length to the 2 low bytes, */ + + mach_write_to_4(ptr, (i << 16) + field->prefix_len); + } else { + /* Else we store the number of the field to the 2 LOW bytes. + This is to keep the storage format compatible with + InnoDB versions < 4.0.14. */ + + mach_write_to_4(ptr, i); + } dfield_set_data(dfield, ptr, 4); /* 4: COL_NAME -------------------------*/ diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index c11a5f76d94..924fa3ecf95 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -88,15 +88,6 @@ dict_index_remove_from_cache( dict_table_t* table, /* in: table */ dict_index_t* index); /* in, own: index */ /*********************************************************************** -Adds a column to index. */ -UNIV_INLINE -void -dict_index_add_col( -/*===============*/ - dict_index_t* index, /* in: index */ - dict_col_t* col, /* in: column */ - ulint order); /* in: order criterion */ -/*********************************************************************** Copies fields contained in index2 to index1. */ static void @@ -482,8 +473,9 @@ dict_index_get_nth_col_pos( ut_ad(index); ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + col = dict_table_get_nth_col(index->table, n); + if (index->type & DICT_CLUSTERED) { - col = dict_table_get_nth_col(index->table, n); return(col->clust_pos); } @@ -492,9 +484,8 @@ dict_index_get_nth_col_pos( for (pos = 0; pos < n_fields; pos++) { field = dict_index_get_nth_field(index, pos); - col = field->col; - if (dict_col_get_no(col) == n) { + if (col == field->col && field->prefix_len == 0) { return(pos); } @@ -502,7 +493,86 @@ dict_index_get_nth_col_pos( return(ULINT_UNDEFINED); } + +/************************************************************************ +Returns TRUE if the index contains a column or a prefix of that column. */ + +ibool +dict_index_contains_col_or_prefix( +/*==============================*/ + /* out: TRUE if contains the column or its + prefix */ + dict_index_t* index, /* in: index */ + ulint n) /* in: column number */ +{ + dict_field_t* field; + dict_col_t* col; + ulint pos; + ulint n_fields; + + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + + if (index->type & DICT_CLUSTERED) { + + return(TRUE); + } + + col = dict_table_get_nth_col(index->table, n); + + n_fields = dict_index_get_n_fields(index); + + for (pos = 0; pos < n_fields; pos++) { + field = dict_index_get_nth_field(index, pos); + + if (col == field->col) { + + return(TRUE); + } + } + + return(FALSE); +} + +/************************************************************************ +Looks for a matching field in an index. The column and the prefix len have +to be the same. */ + +ulint +dict_index_get_nth_field_pos( +/*=========================*/ + /* out: position in internal representation + of the index; if not contained, returns + ULINT_UNDEFINED */ + dict_index_t* index, /* in: index from which to search */ + dict_index_t* index2, /* in: index */ + ulint n) /* in: field number in index2 */ +{ + dict_field_t* field; + dict_field_t* field2; + ulint n_fields; + ulint pos; + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + + field2 = dict_index_get_nth_field(index2, n); + + n_fields = dict_index_get_n_fields(index); + + for (pos = 0; pos < n_fields; pos++) { + field = dict_index_get_nth_field(index, pos); + + if (field->col == field2->col + && field->prefix_len == field2->prefix_len) { + + return(pos); + } + } + + return(ULINT_UNDEFINED); +} + /************************************************************************** Returns a table object, based on table id, and memoryfixes it. */ @@ -622,8 +692,7 @@ dict_table_get( } /************************************************************************** -Returns a table object and increments MySQL open handle count on the table. -*/ +Returns a table object and increments MySQL open handle count on the table. */ dict_table_t* dict_table_get_and_increment_handle_count( @@ -732,11 +801,12 @@ dict_table_add_to_cache( } /* Add table to hash table of tables */ - HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, table); + HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, + table); /* Add table to hash table of tables based on table id */ HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold, - table); + table); /* Add table to LRU list of tables */ UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table); @@ -828,7 +898,7 @@ dict_table_rename_in_cache( /* Remove table from the hash tables of tables */ HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, - ut_fold_string(table->name), table); + ut_fold_string(table->name), table); name_buf = mem_heap_alloc(table->heap, ut_strlen(new_name) + 1); @@ -837,7 +907,8 @@ dict_table_rename_in_cache( table->name = name_buf; /* Add table to hash table of tables */ - HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, table); + HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, + table); dict_sys->size += (mem_heap_get_size(table->heap) - old_size); @@ -1128,7 +1199,6 @@ dict_index_add_to_cache( ulint n_ord; ibool success; ulint i; - ulint j; ut_ad(index); ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1158,28 +1228,6 @@ dict_index_add_to_cache( return(FALSE); } - - /* Check that the same column does not appear twice in the index. - InnoDB assumes this in its algorithms, e.g., update of an index - entry */ - - for (i = 0; i < dict_index_get_n_fields(index); i++) { - - for (j = 0; j < i; j++) { - if (dict_index_get_nth_field(index, j)->col - == dict_index_get_nth_field(index, i)->col) { - - ut_print_timestamp(stderr); - - fprintf(stderr, -" InnoDB: Error: column %s appears twice in index %s of table %s\n" -"InnoDB: This is not allowed in InnoDB.\n" -"InnoDB: UPDATE can cause such an index to become corrupt in InnoDB.\n", - dict_index_get_nth_field(index, i)->col->name, - index->name, table->name); - } - } - } /* Build the cache internal representation of the index, containing also the added system fields */ @@ -1223,8 +1271,8 @@ dict_index_add_to_cache( cluster = dict_table_get_low(table->cluster_name); - tree = dict_index_get_tree(UT_LIST_GET_FIRST(cluster->indexes)); - + tree = dict_index_get_tree( + UT_LIST_GET_FIRST(cluster->indexes)); new_index->tree = tree; new_index->page_no = tree->page; } else { @@ -1352,13 +1400,14 @@ UNIV_INLINE void dict_index_add_col( /*===============*/ - dict_index_t* index, /* in: index */ - dict_col_t* col, /* in: column */ - ulint order) /* in: order criterion */ + dict_index_t* index, /* in: index */ + dict_col_t* col, /* in: column */ + ulint order, /* in: order criterion */ + ulint prefix_len) /* in: column prefix length */ { dict_field_t* field; - dict_mem_index_add_field(index, col->name, order); + dict_mem_index_add_field(index, col->name, order, prefix_len); field = dict_index_get_nth_field(index, index->n_def - 1); @@ -1384,7 +1433,8 @@ dict_index_copy( for (i = start; i < end; i++) { field = dict_index_get_nth_field(index2, i); - dict_index_add_col(index1, field->col, field->order); + dict_index_add_col(index1, field->col, field->order, + field->prefix_len); } } @@ -1487,7 +1537,7 @@ dict_index_build_internal_clust( /* Add the mix id column */ dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_MIX_ID), 0); + dict_table_get_sys_col(table, DATA_MIX_ID), 0, 0); /* Copy the rest of fields */ dict_index_copy(new_index, index, table->mix_len, @@ -1525,14 +1575,15 @@ dict_index_build_internal_clust( if (!(index->type & DICT_UNIQUE)) { dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_ROW_ID), 0); + dict_table_get_sys_col(table, DATA_ROW_ID), 0, 0); trx_id_pos++; } dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_TRX_ID), 0); + dict_table_get_sys_col(table, DATA_TRX_ID), 0, 0); + dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_ROLL_PTR), 0); + dict_table_get_sys_col(table, DATA_ROLL_PTR), 0, 0); for (i = 0; i < trx_id_pos; i++) { @@ -1561,7 +1612,14 @@ dict_index_build_internal_clust( for (i = 0; i < new_index->n_def; i++) { field = dict_index_get_nth_field(new_index, i); - (field->col)->aux = 0; + + /* If there is only a prefix of the column in the index + field, do not mark the column as contained in the index */ + + if (field->prefix_len == 0) { + + field->col->aux = 0; + } } /* Add to new_index non-system columns of table not yet included @@ -1572,7 +1630,7 @@ dict_index_build_internal_clust( ut_ad(col->type.mtype != DATA_SYS); if (col->aux == ULINT_UNDEFINED) { - dict_index_add_col(new_index, col, 0); + dict_index_add_col(new_index, col, 0, 0); } } @@ -1584,7 +1642,11 @@ dict_index_build_internal_clust( for (i = 0; i < new_index->n_def; i++) { field = dict_index_get_nth_field(new_index, i); - (field->col)->clust_pos = i; + + if (field->prefix_len == 0) { + + field->col->clust_pos = i; + } } new_index->cached = TRUE; @@ -1646,25 +1708,33 @@ dict_index_build_internal_non_clust( for (i = 0; i < clust_index->n_uniq; i++) { field = dict_index_get_nth_field(clust_index, i); - (field->col)->aux = ULINT_UNDEFINED; + field->col->aux = ULINT_UNDEFINED; } /* Mark with 0 table columns already contained in new_index */ for (i = 0; i < new_index->n_def; i++) { field = dict_index_get_nth_field(new_index, i); - (field->col)->aux = 0; + + /* If there is only a prefix of the column in the index + field, do not mark the column as contained in the index */ + + if (field->prefix_len == 0) { + + field->col->aux = 0; + } } - /* Add to new_index columns necessary to determine the clustered + /* Add to new_index the columns necessary to determine the clustered index entry uniquely */ for (i = 0; i < clust_index->n_uniq; i++) { field = dict_index_get_nth_field(clust_index, i); - if ((field->col)->aux == ULINT_UNDEFINED) { - dict_index_add_col(new_index, field->col, 0); + if (field->col->aux == ULINT_UNDEFINED) { + dict_index_add_col(new_index, field->col, 0, + field->prefix_len); } } @@ -1787,6 +1857,14 @@ dict_foreign_find_index( for (i = 0; i < n_cols; i++) { col_name = dict_index_get_nth_field(index, i) ->col->name; + if (dict_index_get_nth_field(index, i) + ->prefix_len != 0) { + /* We do not accept column prefix + indexes here */ + + break; + } + if (ut_strlen(columns[i]) != ut_strlen(col_name) || 0 != ut_cmp_in_lower_case(columns[i], @@ -2327,9 +2405,12 @@ dict_strip_comments( ptr = str; for (;;) { +scan_more: if (*sptr == '\0') { *ptr = '\0'; + ut_a(ptr <= str + strlen(sql_string)); + return(str); } @@ -2343,7 +2424,7 @@ dict_strip_comments( || *sptr == (char)0x0D || *sptr == '\0') { - break; + goto scan_more; } sptr++; @@ -2357,12 +2438,12 @@ dict_strip_comments( sptr += 2; - break; + goto scan_more; } if (*sptr == '\0') { - break; + goto scan_more; } sptr++; @@ -3776,6 +3857,10 @@ dict_field_print_low( ut_ad(mutex_own(&(dict_sys->mutex))); printf(" %s", field->name); + + if (field->prefix_len != 0) { + printf("(%lu)", field->prefix_len); + } } /************************************************************************** diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 999eb55bb20..d5c51a43747 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -301,6 +301,8 @@ dict_load_fields( dtuple_t* tuple; dfield_t* dfield; char* col_name; + ulint pos_and_prefix_len; + ulint prefix_len; rec_t* rec; byte* field; ulint len; @@ -345,8 +347,28 @@ dict_load_fields( ut_a(ut_memcmp(buf, field, len) == 0); field = rec_get_nth_field(rec, 1, &len); - ut_ad(len == 4); - ut_a(i == mach_read_from_4(field)); + ut_a(len == 4); + + /* The next field stores the field position in the index + and a possible column prefix length if the index field + does not contain the whole column. The storage format is + like this: if there is at least one prefix field in the index, + then the HIGH 2 bytes contain the field number (== i) and the + low 2 bytes the prefix length for the field. Otherwise the + field number (== i) is contained in the 2 LOW bytes. */ + + pos_and_prefix_len = mach_read_from_4(field); + + ut_a((pos_and_prefix_len & 0xFFFF) == i + || (pos_and_prefix_len & 0xFFFF0000) == (i << 16)); + + if ((i == 0 && pos_and_prefix_len > 0) + || (pos_and_prefix_len & 0xFFFF0000) > 0) { + + prefix_len = pos_and_prefix_len & 0xFFFF; + } else { + prefix_len = 0; + } ut_a(0 == ut_strcmp((char*) "COL_NAME", dict_field_get_col( @@ -359,7 +381,7 @@ dict_load_fields( ut_memcpy(col_name, field, len); col_name[len] = '\0'; - dict_mem_index_add_field(index, col_name, 0); + dict_mem_index_add_field(index, col_name, 0, prefix_len); btr_pcur_move_to_next_user_rec(&pcur, &mtr); } diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c index e5918c6aeb6..56efc0a0117 100644 --- a/innobase/dict/dict0mem.c +++ b/innobase/dict/dict0mem.c @@ -266,10 +266,13 @@ by the column name may be released only after publishing the index. */ void dict_mem_index_add_field( /*=====================*/ - dict_index_t* index, /* in: index */ - char* name, /* in: column name */ - ulint order) /* in: order criterion; 0 means an ascending - order */ + dict_index_t* index, /* in: index */ + char* name, /* in: column name */ + ulint order, /* in: order criterion; 0 means an + ascending order */ + ulint prefix_len) /* in: 0 or the column prefix length + in a MySQL index like + INDEX (textcol(25)) */ { dict_field_t* field; @@ -282,6 +285,8 @@ dict_mem_index_add_field( field->name = name; field->order = order; + + field->prefix_len = prefix_len; } /************************************************************************** diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 98980f6c337..f55df90846c 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -632,7 +632,7 @@ fil_space_create( /* Spaces with an odd id number are reserved to replicate spaces used in log debugging */ - ut_a((purpose == FIL_LOG) || (id % 2 == 0)); + ut_anp((purpose == FIL_LOG) || (id % 2 == 0)); #endif mutex_enter(&(system->mutex)); @@ -831,6 +831,34 @@ fil_space_release_free_extents( mutex_exit(&(system->mutex)); } +/*********************************************************************** +Gets the number of reserved extents. If the database is silent, this number +should be zero. */ + +ulint +fil_space_get_n_reserved_extents( +/*=============================*/ + ulint id) /* in: space id */ +{ + fil_space_t* space; + fil_system_t* system = fil_system; + ulint n; + + ut_ad(system); + + mutex_enter(&(system->mutex)); + + HASH_SEARCH(hash, system->spaces, id, space, space->id == id); + + ut_a(space); + + n = space->n_reserved_extents; + + mutex_exit(&(system->mutex)); + + return(n); +} + /************************************************************************ Prepares a file node for i/o. Opens the file if it is closed. Updates the pending i/o's field in the node and the system appropriately. Takes the node @@ -1202,8 +1230,8 @@ loop: /* Do aio */ - ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0); + ut_anp(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_anp((len % OS_FILE_LOG_BLOCK_SIZE) == 0); /* Queue the aio request */ ret = os_aio(type, mode | wake_later, node->name, node->handle, buf, diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index ee48288b875..20bf4972f64 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -778,7 +778,7 @@ fsp_init_file_page_low( page[i] = 0xFF; } #endif - mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN, + mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, ut_dulint_zero); mach_write_to_8(page + FIL_PAGE_LSN, ut_dulint_zero); } @@ -2709,10 +2709,52 @@ fseg_free_page_low( return; } +/* + fprintf(stderr, +"InnoDB: InnoDB is freeing space %lu page %lu,\n" +"InnoDB: which belongs to descr seg %lu %lu\n" +"InnoDB: segment %lu %lu.\n", + space, page, + ut_dulint_get_high( + mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), + ut_dulint_get_low( + mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), + ut_dulint_get_high( + mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr)), + ut_dulint_get_low( + mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr))); +*/ /* If we get here, the page is in some extent of the segment */ - ut_a(0 == ut_dulint_cmp( + if (0 != ut_dulint_cmp( mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr), - mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr))); + mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr))) { + + ut_sprintf_buf(errbuf, descr, 40); + fprintf(stderr, +"InnoDB: Dump of the tablespace extent descriptor: %s\n", errbuf); + ut_sprintf_buf(errbuf, seg_inode, 40); + fprintf(stderr, +"InnoDB: Dump of the segment inode: %s\n", errbuf); + + fprintf(stderr, +"InnoDB: Serious error: InnoDB is trying to free space %lu page %lu,\n" +"InnoDB: which does not belong to segment %lu %lu but belongs\n" +"InnoDB: to segment %lu %lu.\n", + space, page, + ut_dulint_get_high( + mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), + ut_dulint_get_low( + mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), + ut_dulint_get_high( + mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr)), + ut_dulint_get_low( + mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr))); + + fprintf(stderr, +"InnoDB: If the InnoDB recovery crashes here, see section 6.1\n" +"InnoDB: of http://www.innodb.com/ibman.html about forcing recovery.\n"); + ut_a(0); + } not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr); @@ -2875,7 +2917,7 @@ fseg_free_step( freed yet */ ut_a(descr); - ut_a(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header) + ut_anp(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header) % FSP_EXTENT_SIZE, mtr) == FALSE); inode = fseg_inode_get(header, mtr); diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c index b847798586d..eb28e15215d 100644 --- a/innobase/ha/ha0ha.c +++ b/innobase/ha/ha0ha.c @@ -293,11 +293,13 @@ ha_print_info( hash_table_t* table) /* in: hash table */ { hash_cell_t* cell; -/* ha_node_t* node; */ -/* ulint nodes = 0; */ +/* + ha_node_t* node; + ulint len = 0; + ulint max_len = 0; + ulint nodes = 0; +*/ ulint cells = 0; -/* ulint len = 0; */ -/* ulint max_len = 0; */ ulint n_bufs; ulint i; diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c index 187afa17047..c07756ab308 100644 --- a/innobase/ibuf/ibuf0ibuf.c +++ b/innobase/ibuf/ibuf0ibuf.c @@ -170,7 +170,7 @@ dropped! So, there seems to be no problem. */ /********************************************************************** Validates the ibuf data structures when the caller owns ibuf_mutex. */ -static + ibool ibuf_validate_low(void); /*===================*/ @@ -484,8 +484,8 @@ ibuf_data_init_for_space( index = dict_mem_index_create(buf, (char *) "CLUST_IND", space, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,2); - dict_mem_index_add_field(index, (char *) "PAGE_NO", 0); - dict_mem_index_add_field(index, (char *) "TYPES", 0); + dict_mem_index_add_field(index, (char *) "PAGE_NO", 0, 0); + dict_mem_index_add_field(index, (char *) "TYPES", 0, 0); index->page_no = FSP_IBUF_TREE_ROOT_PAGE_NO; @@ -2727,7 +2727,7 @@ reset_bit: /********************************************************************** Validates the ibuf data structures when the caller owns ibuf_mutex. */ -static + ibool ibuf_validate_low(void) /*===================*/ diff --git a/innobase/include/btr0cur.h b/innobase/include/btr0cur.h index 1d17c0e952d..506877333c3 100644 --- a/innobase/include/btr0cur.h +++ b/innobase/include/btr0cur.h @@ -690,7 +690,13 @@ and sleep this many microseconds in between */ #define BTR_CUR_RETRY_DELETE_N_TIMES 100 #define BTR_CUR_RETRY_SLEEP_TIME 50000 -/* The reference in a field of which data is stored on a different page */ +/* The reference in a field for which data is stored on a different page. +The reference is at the end of the 'locally' stored part of the field. +'Locally' means storage in the index record. +We store locally a long enough prefix of each column so that we can determine +the ordering parts of each index record without looking into the externally +stored part. */ + /*--------------------------------------*/ #define BTR_EXTERN_SPACE_ID 0 /* space id where stored */ #define BTR_EXTERN_PAGE_NO 4 /* page no where stored */ diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index b613d60ebf7..d2ee1a440c7 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -388,11 +388,24 @@ to a file. Note that we must be careful to calculate the same value on 32-bit and 64-bit architectures. */ ulint -buf_calc_page_checksum( -/*===================*/ +buf_calc_page_new_checksum( +/*=======================*/ /* out: checksum */ byte* page); /* in: buffer page */ /************************************************************************ +In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only +looked at the first few bytes of the page. This calculates that old +checksum. +NOTE: we must first store the new formula checksum to +FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum +because this takes that field as an input! */ + +ulint +buf_calc_page_old_checksum( +/*=======================*/ + /* out: checksum */ + byte* page); /* in: buffer page */ +/************************************************************************ Checks if a page is corrupt. */ ibool diff --git a/innobase/include/data0data.h b/innobase/include/data0data.h index e0fb06e5018..889d148d3fe 100644 --- a/innobase/include/data0data.h +++ b/innobase/include/data0data.h @@ -453,8 +453,6 @@ struct dfield_struct{ void* data; /* pointer to data */ ulint len; /* data length; UNIV_SQL_NULL if SQL null; */ dtype_t type; /* type of data */ - ulint col_no; /* when building index entries, the column - number can be stored here */ }; struct dtuple_struct { diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h index b53a70a8909..4da686bf2e1 100644 --- a/innobase/include/data0type.h +++ b/innobase/include/data0type.h @@ -18,14 +18,16 @@ typedef struct dtype_struct dtype_t; data type */ extern dtype_t* dtype_binary; -/* Data main types of SQL data; NOTE! character data types requiring -collation transformation must have the smallest codes! All codes must be -less than 256! */ +/* Data main types of SQL data */ #define DATA_VARCHAR 1 /* character varying */ #define DATA_CHAR 2 /* fixed length character */ #define DATA_FIXBINARY 3 /* binary string of fixed length */ #define DATA_BINARY 4 /* binary string */ -#define DATA_BLOB 5 /* binary large object */ +#define DATA_BLOB 5 /* binary large object, or a TEXT type; if + prtype & DATA_NONLATIN1 != 0 the data must + be compared by MySQL as a whole field; if + prtype & DATA_BINARY_TYPE == 0, then this is + actually a TEXT column */ #define DATA_INT 6 /* integer: can be any size 1 - 8 bytes */ #define DATA_SYS_CHILD 7 /* address of the child page in node pointer */ #define DATA_SYS 8 /* system column */ @@ -34,35 +36,55 @@ binary strings */ #define DATA_FLOAT 9 #define DATA_DOUBLE 10 #define DATA_DECIMAL 11 /* decimal number stored as an ASCII string */ -#define DATA_VARMYSQL 12 /* data types for which comparisons must be */ -#define DATA_MYSQL 13 /* made by MySQL */ -#define DATA_ERROR 111 /* error value */ -#define DATA_MTYPE_MAX 255 +#define DATA_VARMYSQL 12 /* non-latin1 varying length char */ +#define DATA_MYSQL 13 /* non-latin1 fixed length char */ +#define DATA_MTYPE_MAX 63 /* dtype_store_for_order_and_null_size() + requires the values are <= 63 */ /*-------------------------------------------*/ -/* Precise data types for system columns; NOTE: the values must run -from 0 up in the order given! All codes must be less than 256! */ +/* In the lowest byte in the precise type we store the MySQL type code +(not applicable for system columns). */ + +#define DATA_ENGLISH 4 /* English language character string: this + is a relic from pre-MySQL time and only used + for InnoDB's own system tables */ +#define DATA_ERROR 111 /* another relic from pre-MySQL time */ + +#define DATA_MYSQL_TYPE_MASK 255 /* AND with this mask to extract the MySQL + type from the precise type */ + +/* Precise data types for system columns and the length of those columns; +NOTE: the values must run from 0 up in the order given! All codes must +be less than 256 */ #define DATA_ROW_ID 0 /* row id: a dulint */ #define DATA_ROW_ID_LEN 6 /* stored length for row id */ + #define DATA_TRX_ID 1 /* transaction id: 6 bytes */ #define DATA_TRX_ID_LEN 6 + #define DATA_ROLL_PTR 2 /* rollback data pointer: 7 bytes */ #define DATA_ROLL_PTR_LEN 7 + #define DATA_MIX_ID 3 /* mixed index label: a dulint, stored in a row in a compressed form */ #define DATA_MIX_ID_LEN 9 /* maximum stored length for mix id (in a compressed dulint form) */ #define DATA_N_SYS_COLS 4 /* number of system columns defined above */ +/*-------------------------------------------*/ +/* Flags ORed to the precise data type */ #define DATA_NOT_NULL 256 /* this is ORed to the precise type when the column is declared as NOT NULL */ #define DATA_UNSIGNED 512 /* this id ORed to the precise type when we have an unsigned integer type */ +#define DATA_BINARY_TYPE 1024 /* if the data type is a binary character + string, this is ORed to the precise type: + this only holds for tables created with + >= MySQL-4.0.14 */ +#define DATA_NONLATIN1 2048 /* if the data type is a DATA_BLOB (actually + TEXT) of a non-latin1 type, this is ORed to + the precise type: this only holds for tables + created with >= MySQL-4.0.14 */ /*-------------------------------------------*/ -/* Precise types of a char or varchar data. All codes must be less than 256! */ -#define DATA_ENGLISH 4 /* English language character string */ -#define DATA_FINNISH 5 /* Finnish */ -#define DATA_PRTYPE_MAX 255 - /* This many bytes we need to store the type information affecting the alphabetical order for a single field and decide the storage size of an SQL null*/ @@ -123,7 +145,7 @@ dtype_get_pad_char( /*===============*/ /* out: padding character code, or ULINT_UNDEFINED if no padding specified */ - dtype_t* type); /* in: typeumn */ + dtype_t* type); /* in: type */ /*************************************************************************** Returns the size of a fixed size data type, 0 if not a fixed size type. */ UNIV_INLINE @@ -150,24 +172,24 @@ dtype_is_fixed_size( /* out: TRUE if fixed size */ dtype_t* type); /* in: type */ /************************************************************************** -Stores to a type the information which determines its alphabetical -ordering. */ +Stores for a type the information which determines its alphabetical ordering +and the storage size of an SQL NULL value. */ UNIV_INLINE void dtype_store_for_order_and_null_size( /*================================*/ byte* buf, /* in: buffer for DATA_ORDER_NULL_TYPE_BUF_SIZE - bytes */ + bytes where we store the info */ dtype_t* type); /* in: type struct */ /************************************************************************** -Reads of a type the stored information which determines its alphabetical -ordering. */ +Reads to a type the stored information which determines its alphabetical +ordering and the storage size of an SQL NULL value. */ UNIV_INLINE void dtype_read_for_order_and_null_size( /*===============================*/ dtype_t* type, /* in: type struct */ - byte* buf); /* in: buffer for type order info */ + byte* buf); /* in: buffer for the stored order info */ /************************************************************************* Validates a data type structure. */ diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic index d82d976d076..ddd0b0ae8cc 100644 --- a/innobase/include/data0type.ic +++ b/innobase/include/data0type.ic @@ -110,7 +110,9 @@ dtype_get_pad_char( if (type->mtype == DATA_CHAR || type->mtype == DATA_VARCHAR || type->mtype == DATA_BINARY - || type->mtype == DATA_FIXBINARY) { + || type->mtype == DATA_FIXBINARY + || type->mtype == DATA_MYSQL + || type->mtype == DATA_VARMYSQL) { /* Space is the padding character for all char and binary strings */ @@ -124,39 +126,56 @@ dtype_get_pad_char( } /************************************************************************** -Stores to a type the information which determines its alphabetical -ordering. */ +Stores for a type the information which determines its alphabetical ordering +and the storage size of an SQL NULL value. */ UNIV_INLINE void dtype_store_for_order_and_null_size( /*================================*/ byte* buf, /* in: buffer for DATA_ORDER_NULL_TYPE_BUF_SIZE - bytes */ + bytes where we store the info */ dtype_t* type) /* in: type struct */ { ut_ad(4 == DATA_ORDER_NULL_TYPE_BUF_SIZE); buf[0] = (byte)(type->mtype & 0xFF); + + if (type->prtype & DATA_BINARY_TYPE) { + buf[0] = buf[0] | 128; + } + + if (type->prtype & DATA_NONLATIN1) { + buf[0] = buf[0] | 64; + } + buf[1] = (byte)(type->prtype & 0xFF); mach_write_to_2(buf + 2, type->len & 0xFFFF); } /************************************************************************** -Reads of a type the stored information which determines its alphabetical -ordering. */ +Reads to a type the stored information which determines its alphabetical +ordering and the storage size of an SQL NULL value. */ UNIV_INLINE void dtype_read_for_order_and_null_size( /*===============================*/ dtype_t* type, /* in: type struct */ - byte* buf) /* in: buffer for type order info */ + byte* buf) /* in: buffer for stored type order info */ { ut_ad(4 == DATA_ORDER_NULL_TYPE_BUF_SIZE); - type->mtype = buf[0]; + type->mtype = buf[0] & 63; type->prtype = buf[1]; + if (buf[0] & 128) { + type->prtype = type->prtype | DATA_BINARY_TYPE; + } + + if (buf[0] & 64) { + type->prtype = type->prtype | DATA_NONLATIN1; + } + type->len = mach_read_from_2(buf + 2); } diff --git a/innobase/include/db0err.h b/innobase/include/db0err.h index ab7d0caa35c..854b9794c00 100644 --- a/innobase/include/db0err.h +++ b/innobase/include/db0err.h @@ -44,8 +44,10 @@ Created 5/24/1996 Heikki Tuuri #define DB_CORRUPTION 39 /* data structure corruption noticed */ #define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index where same column appears twice */ -#define DB_CANNOT_DROP_CONSTRAINT 40 /* dropping a foreign key constraint +#define DB_CANNOT_DROP_CONSTRAINT 41 /* dropping a foreign key constraint from a table failed */ +#define DB_NO_SAVEPOINT 42 /* no savepoint exists with the given + name */ /* The following are partial failure codes */ #define DB_FAIL 1000 diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index 97486a7c2f6..b5ec5381db2 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -569,6 +569,29 @@ dict_index_get_nth_col_pos( dict_index_t* index, /* in: index */ ulint n); /* in: column number */ /************************************************************************ +Returns TRUE if the index contains a column or a prefix of that column. */ + +ibool +dict_index_contains_col_or_prefix( +/*==============================*/ + /* out: TRUE if contains the column or its + 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. */ + +ulint +dict_index_get_nth_field_pos( +/*=========================*/ + /* out: position in internal representation + of the index; if not contained, returns + ULINT_UNDEFINED */ + dict_index_t* index, /* in: index from which to search */ + dict_index_t* index2, /* in: index */ + ulint n); /* in: field number in index2 */ +/************************************************************************ Looks for column n position in the clustered index. */ ulint diff --git a/innobase/include/dict0dict.ic b/innobase/include/dict0dict.ic index 71ea67117a7..c5982c162a7 100644 --- a/innobase/include/dict0dict.ic +++ b/innobase/include/dict0dict.ic @@ -203,7 +203,6 @@ dict_index_get_n_fields( { ut_ad(index); ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - ut_ad(index->cached); return(index->n_fields); } diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index 0798541cfe0..03dc913a7c9 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -111,10 +111,13 @@ by the column name may be released only after publishing the index. */ void dict_mem_index_add_field( /*=====================*/ - dict_index_t* index, /* in: index */ - char* name, /* in: column name */ - ulint order); /* in: order criterion; 0 means an ascending - order */ + dict_index_t* index, /* in: index */ + char* name, /* in: column name */ + ulint order, /* in: order criterion; 0 means an + ascending order */ + ulint prefix_len); /* in: 0 or the column prefix length + in a MySQL index like + INDEX (textcol(25)) */ /************************************************************************** Frees an index memory object. */ @@ -158,12 +161,18 @@ struct dict_col_struct{ in some of the functions below */ }; +#define DICT_MAX_COL_PREFIX_LEN 512 + /* Data structure for a field in an index */ struct dict_field_struct{ - dict_col_t* col; /* pointer to the table column */ - char* name; /* name of the column */ - ulint order; /* flags for ordering this field: - DICT_DESCEND, ... */ + dict_col_t* col; /* pointer to the table column */ + char* name; /* name of the column */ + ulint order; /* flags for ordering this field: + DICT_DESCEND, ... */ + ulint prefix_len; /* 0 or the length of the column + prefix in a MySQL index of type, e.g., + INDEX (textcol(25)); must be smaller + than DICT_MAX_COL_PREFIX_LEN */ }; /* Data structure for an index tree */ diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h index 23ef0304b2d..ad3149f0b36 100644 --- a/innobase/include/fil0fil.h +++ b/innobase/include/fil0fil.h @@ -43,7 +43,10 @@ struct fil_addr_struct{ extern fil_addr_t fil_addr_null; /* The byte offsets on a file page for various variables */ -#define FIL_PAGE_SPACE 0 /* space id the page belongs to */ +#define FIL_PAGE_SPACE_OR_CHKSUM 0 /* in < MySQL-4.0.14 space id the + page belongs to (== 0) but in later + versions the 'new' checksum of the + page */ #define FIL_PAGE_OFFSET 4 /* page offset inside space */ #define FIL_PAGE_PREV 8 /* if there is a 'natural' predecessor of the page, its offset */ @@ -64,7 +67,7 @@ extern fil_addr_t fil_addr_null; #define FIL_PAGE_DATA 38 /* start of the data on the page */ /* File page trailer */ -#define FIL_PAGE_END_LSN 8 /* the low 4 bytes of this are used +#define FIL_PAGE_END_LSN_OLD_CHKSUM 8 /* the low 4 bytes of this are used to store the page checksum, the last 4 bytes should be identical to the last 4 bytes of FIL_PAGE_LSN */ @@ -383,6 +386,14 @@ fil_space_release_free_extents( /*===========================*/ ulint id, /* in: space id */ ulint n_reserved); /* in: how many one reserved */ +/*********************************************************************** +Gets the number of reserved extents. If the database is silent, this number +should be zero. */ + +ulint +fil_space_get_n_reserved_extents( +/*=============================*/ + ulint id); /* in: space id */ typedef struct fil_space_struct fil_space_t; diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h index d3b3d55d015..5608ba020b7 100644 --- a/innobase/include/lock0lock.h +++ b/innobase/include/lock0lock.h @@ -450,6 +450,18 @@ lock_rec_get_mutex_for_addr( ulint space, /* in: space id */ ulint page_no);/* in: page number */ /************************************************************************* +Checks that a transaction id is sensible, i.e., not in the future. */ + +ibool +lock_check_trx_id_sanity( +/*=====================*/ + /* out: TRUE if ok */ + dulint trx_id, /* in: trx id */ + rec_t* rec, /* in: user record */ + dict_index_t* index, /* in: clustered index */ + ibool has_kernel_mutex);/* in: TRUE if the caller owns the + kernel mutex */ +/************************************************************************* Validates the lock queue on a single record. */ ibool diff --git a/innobase/include/log0log.h b/innobase/include/log0log.h index 4e1404b15fe..24ec28a56e6 100644 --- a/innobase/include/log0log.h +++ b/innobase/include/log0log.h @@ -173,6 +173,12 @@ log_write_up_to( /* in: TRUE if we want the written log also to be flushed to disk */ /******************************************************************** +Does a syncronous flush of the log buffer to disk. */ + +void +log_buffer_flush_to_disk(void); +/*==========================*/ +/******************************************************************** Advances the smallest lsn for which there are unflushed dirty blocks in the buffer pool and also may make a new checkpoint. NOTE: this function may only be called if the calling thread owns no synchronization objects! */ @@ -507,6 +513,15 @@ log_print( /*======*/ char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ +/********************************************************** +Peeks the current lsn. */ + +ibool +log_peek_lsn( +/*=========*/ + /* out: TRUE if success, FALSE if could not get the + log system mutex */ + dulint* lsn); /* out: if returns TRUE, current lsn is here */ /************************************************************************** Refreshes the statistics used to print per-second averages. */ @@ -779,6 +794,11 @@ struct log_struct{ called */ /* Fields involved in checkpoints */ + ulint log_group_capacity; /* capacity of the log group; if + the checkpoint age exceeds this, it is + a serious error because it is possible + we will then overwrite log and spoil + crash recovery */ ulint max_modified_age_async; /* when this recommended value for lsn - buf_pool_get_oldest_modification() diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h index bef42cfec1c..7b27ee34541 100644 --- a/innobase/include/log0recv.h +++ b/innobase/include/log0recv.h @@ -333,6 +333,8 @@ extern ibool recv_recovery_on; extern ibool recv_no_ibuf_operations; extern ibool recv_needed_recovery; +extern ibool recv_lsn_checks_on; + extern ibool recv_is_making_a_backup; extern ulint recv_max_parsed_page_no; diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index 86f27a2d3eb..5c52f0e92bf 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -146,6 +146,21 @@ os_file_create_simple( ulint access_type,/* in: OS_FILE_READ_ONLY or OS_FILE_READ_WRITE */ ibool* success);/* out: TRUE if succeed, FALSE if error */ /******************************************************************** +A simple function to open or create a file. */ + +os_file_t +os_file_create_simple_no_error_handling( +/*====================================*/ + /* out, own: handle to the file, not defined if error, + error number can be retrieved with os_get_last_error */ + char* name, /* in: name of the file or path as a null-terminated + string */ + ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened + (if does not exist, error), or OS_FILE_CREATE if a new + file is created (if exists, error) */ + ulint access_type,/* in: OS_FILE_READ_ONLY or OS_FILE_READ_WRITE */ + ibool* success);/* out: TRUE if succeed, FALSE if error */ +/******************************************************************** Opens an existing file or creates a new. */ os_file_t @@ -160,7 +175,11 @@ os_file_create( file is created (if exists, error), OS_FILE_OVERWRITE if a new file is created or an old overwritten */ ulint purpose,/* in: OS_FILE_AIO, if asynchronous, non-buffered i/o - is desired, OS_FILE_NORMAL, if any normal file */ + is desired, OS_FILE_NORMAL, if any normal file; + NOTE that it also depends on type, os_aio_.. and srv_.. + variables whether we really use async i/o or + unbuffered i/o: look in the function source code for + the exact rules */ ulint type, /* in: OS_DATA_FILE or OS_LOG_FILE */ ibool* success);/* out: TRUE if succeed, FALSE if error */ /*************************************************************************** @@ -173,6 +192,14 @@ os_file_close( /* out: TRUE if success */ os_file_t file); /* in, own: handle to a file */ /*************************************************************************** +Closes a file handle. */ + +ibool +os_file_close_no_error_handling( +/*============================*/ + /* out: TRUE if success */ + os_file_t file); /* in, own: handle to a file */ +/*************************************************************************** Gets a file size. */ ibool diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index 634507467f9..e1cf263216e 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -36,8 +36,12 @@ typedef os_event_struct_t* os_event_t; struct os_event_struct { os_fast_mutex_t os_mutex; /* this mutex protects the next fields */ - ibool is_set; /* this is TRUE if the next mutex is - not reserved */ + ibool is_set; /* this is TRUE when the event is + in the signaled state, i.e., a thread + does not stop if it tries to wait for + this event */ + ib_longlong signal_count; /* this is incremented each time + the event becomes signaled */ pthread_cond_t cond_var; /* condition variable is used in waiting for the event */ UT_LIST_NODE_T(os_event_struct_t) os_event_list; diff --git a/innobase/include/page0page.h b/innobase/include/page0page.h index b5e33af5bc0..04f771c3abd 100644 --- a/innobase/include/page0page.h +++ b/innobase/include/page0page.h @@ -666,6 +666,15 @@ page_rec_validate( /* out: TRUE if ok */ rec_t* rec); /* in: record on the page */ /******************************************************************* +Checks that the first directory slot points to the infimum record and +the last to the supremum. This function is intended to track if the +bug fixed in 4.0.14 has caused corruption to users' databases. */ + +void +page_check_dir( +/*===========*/ + page_t* page); /* in: index page */ +/******************************************************************* This function checks the consistency of an index page when we do not know the index. This is also resilient so that this should never crash even if the page is total garbage. */ diff --git a/innobase/include/rem0cmp.h b/innobase/include/rem0cmp.h index 6f2a99fc8c2..712e263350e 100644 --- a/innobase/include/rem0cmp.h +++ b/innobase/include/rem0cmp.h @@ -42,6 +42,22 @@ cmp_data_data( buffer) */ ulint len2); /* in: data field length or UNIV_SQL_NULL */ /***************************************************************** +This function is used to compare two data fields for which we know the +data type. */ + +int +cmp_data_data_slow( +/*===============*/ + /* out: 1, 0, -1, if data1 is greater, equal, + less than data2, respectively */ + dtype_t* cur_type,/* in: data type of the fields */ + byte* data1, /* in: data field (== a pointer to a memory + buffer) */ + ulint len1, /* in: data field length or UNIV_SQL_NULL */ + byte* data2, /* in: data field (== a pointer to a memory + buffer) */ + ulint len2); /* in: data field length or UNIV_SQL_NULL */ +/***************************************************************** This function is used to compare two dfields where at least the first has its data type field set. */ UNIV_INLINE diff --git a/innobase/include/row0mysql.ic b/innobase/include/row0mysql.ic index e9d493da8b5..4ecd66e06ec 100644 --- a/innobase/include/row0mysql.ic +++ b/innobase/include/row0mysql.ic @@ -58,7 +58,8 @@ row_mysql_store_col_in_innobase_format( /*===================================*/ dfield_t* dfield, /* in/out: dfield */ byte* buf, /* in/out: buffer for the converted - value */ + value; this must be at least col_len + long! */ byte* mysql_data, /* in: MySQL column value, not SQL NULL; NOTE that dfield may also get a pointer to mysql_data, @@ -96,7 +97,6 @@ row_mysql_store_col_in_innobase_format( while (col_len > 0 && ptr[col_len - 1] == ' ') { col_len--; } - } else if (type == DATA_BLOB) { ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len); } diff --git a/innobase/include/row0row.h b/innobase/include/row0row.h index 09a79e19fd7..d1befbbbad3 100644 --- a/innobase/include/row0row.h +++ b/innobase/include/row0row.h @@ -86,9 +86,10 @@ dtuple_t* row_build( /*======*/ /* out, own: row built; see the NOTE below! */ - ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS: - the former copies also the data fields to - heap as the latter only places pointers to + ulint type, /* in: ROW_COPY_POINTERS, ROW_COPY_DATA, or + ROW_COPY_ALSO_EXTERNALS, + the two last copy also the data fields to + heap as the first only places pointers to data fields on the index page, and thus is more efficient */ dict_index_t* index, /* in: clustered index */ diff --git a/innobase/include/row0sel.h b/innobase/include/row0sel.h index cfc30852b87..a35d588ad08 100644 --- a/innobase/include/row0sel.h +++ b/innobase/include/row0sel.h @@ -87,9 +87,11 @@ row_printf_step( /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ /******************************************************************** -Converts a key value stored in MySQL format to an Innobase dtuple. -The last field of the key value may be just a prefix of a fixed length -field: hence the parameter key_len. */ +Converts a key value stored in MySQL format to an Innobase dtuple. The last +field of the key value may be just a prefix of a fixed length field: hence +the parameter key_len. But currently we do not allow search keys where the +last field is only a prefix of the full key field len and print a warning if +such appears. */ void row_sel_convert_mysql_key_to_innobase( @@ -100,6 +102,7 @@ row_sel_convert_mysql_key_to_innobase( to index! */ byte* buf, /* in: buffer to use in field conversions */ + ulint buf_len, /* in: buffer length */ dict_index_t* index, /* in: index of the key value */ byte* key_ptr, /* in: MySQL key value */ ulint key_len); /* in: MySQL key value length */ diff --git a/innobase/include/row0upd.h b/innobase/include/row0upd.h index 273ec6074eb..473c55c7ef9 100644 --- a/innobase/include/row0upd.h +++ b/innobase/include/row0upd.h @@ -114,13 +114,15 @@ row_upd_index_write_log( closed within this function */ mtr_t* mtr); /* in: mtr into whose log to write */ /*************************************************************** -Returns TRUE if row update changes size of some field in index. */ +Returns TRUE if row update changes size of some field in index or if some +field to be updated is stored externally in rec or update. */ ibool -row_upd_changes_field_size( -/*=======================*/ +row_upd_changes_field_size_or_external( +/*===================================*/ /* out: TRUE if the update changes the size of - some field in index */ + some field in index or the field is external + in rec or update */ rec_t* rec, /* in: record in clustered index */ dict_index_t* index, /* in: clustered index */ upd_t* update);/* in: update vector */ @@ -175,16 +177,10 @@ row_upd_index_replace_new_col_vals( dtuple_t* entry, /* in/out: index entry where replaced */ dict_index_t* index, /* in: index; NOTE that may also be a non-clustered index */ - upd_t* update); /* in: update vector */ -/*************************************************************** -Replaces the new column values stored in the update vector to the -clustered index entry given. */ - -void -row_upd_clust_index_replace_new_col_vals( -/*=====================================*/ - dtuple_t* entry, /* in/out: index entry where replaced */ - upd_t* update); /* in: update vector */ + upd_t* update, /* in: update vector */ + mem_heap_t* heap); /* in: memory heap to which we allocate and + copy the new values, set this as NULL if you + do not want allocation */ /*************************************************************** Checks if an update vector changes an ordering field of an index record. This function is fast if the update vector is short or the number of ordering @@ -358,9 +354,9 @@ struct upd_node_struct{ externally in the clustered index record of row */ ulint n_ext_vec;/* number of fields in ext_vec */ - mem_heap_t* heap; /* memory heap used as auxiliary storage for - row; this must be emptied after a successful - update if node->row != NULL */ + mem_heap_t* heap; /* memory heap used as auxiliary storage; + this must be emptied after a successful + update */ /*----------------------*/ sym_node_t* table_sym;/* table node in symbol table */ que_node_t* col_assign_list; diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 8fd0fc2dd6d..87643e87a68 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -156,6 +156,7 @@ extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, /* Array of English strings describing the current state of an i/o handler thread */ extern char* srv_io_thread_op_info[]; +extern char* srv_io_thread_function[]; typedef struct srv_sys_struct srv_sys_t; @@ -170,6 +171,7 @@ what these mean */ #define SRV_UNIX_O_DSYNC 2 #define SRV_UNIX_LITTLESYNC 3 #define SRV_UNIX_NOSYNC 4 +#define SRV_UNIX_O_DIRECT 5 /* Alternatives for file i/o in Windows */ #define SRV_WIN_IO_NORMAL 1 diff --git a/innobase/include/trx0roll.h b/innobase/include/trx0roll.h index 820af4cd014..0d7126c9c57 100644 --- a/innobase/include/trx0roll.h +++ b/innobase/include/trx0roll.h @@ -177,6 +177,55 @@ trx_general_rollback_for_mysql( ibool partial,/* in: TRUE if partial rollback requested */ trx_savept_t* savept);/* in: pointer to savepoint undo number, if partial rollback requested */ +/*********************************************************************** +Rolls back a transaction back to a named savepoint. Modifications after the +savepoint are undone but InnoDB does NOT release the corresponding locks +which are stored in memory. If a lock is 'implicit', that is, a new inserted +row holds a lock where the lock information is carried by the trx id stored in +the row, these locks are naturally released in the rollback. Savepoints which +were set after this savepoint are deleted. */ + +ulint +trx_rollback_to_savepoint_for_mysql( +/*================================*/ + /* out: if no savepoint + of the name found then + DB_NO_SAVEPOINT, + otherwise DB_SUCCESS */ + trx_t* trx, /* in: transaction handle */ + char* savepoint_name, /* in: savepoint name */ + ib_longlong* mysql_binlog_cache_pos);/* out: the MySQL binlog cache + position corresponding to this + savepoint; MySQL needs this + information to remove the + binlog entries of the queries + executed after the savepoint */ +/*********************************************************************** +Creates a named savepoint. If the transaction is not yet started, starts it. +If there is already a savepoint of the same name, this call erases that old +savepoint and replaces it with a new. Savepoints are deleted in a transaction +commit or rollback. */ + +ulint +trx_savepoint_for_mysql( +/*====================*/ + /* out: always DB_SUCCESS */ + trx_t* trx, /* in: transaction handle */ + char* savepoint_name, /* in: savepoint name */ + ib_longlong binlog_cache_pos); /* in: MySQL binlog cache + position corresponding to this + connection at the time of the + savepoint */ +/*********************************************************************** +Frees savepoint structs. */ + +void +trx_roll_savepoints_free( +/*=====================*/ + trx_t* trx, /* in: transaction handle */ + trx_named_savept_t* savep); /* in: free all savepoints > this one; + if this is NULL, free all savepoints + of trx */ extern sess_t* trx_dummy_sess; @@ -207,6 +256,21 @@ struct roll_node_struct{ case of a partial rollback */ }; +/* A savepoint set with SQL's "SAVEPOINT savepoint_id" command */ +struct trx_named_savept_struct{ + char* name; /* savepoint name */ + trx_savept_t savept; /* the undo number corresponding to + the savepoint */ + ib_longlong mysql_binlog_cache_pos; + /* the MySQL binlog cache position + corresponding to this savepoint, not + defined if the MySQL binlogging is not + enabled */ + UT_LIST_NODE_T(trx_named_savept_t) + trx_savepoints; /* the list of savepoints of a + transaction */ +}; + /* Rollback node states */ #define ROLL_NODE_SEND 1 #define ROLL_NODE_WAIT 2 diff --git a/innobase/include/trx0sys.ic b/innobase/include/trx0sys.ic index ada2d8cb19c..343e6d7c2fa 100644 --- a/innobase/include/trx0sys.ic +++ b/innobase/include/trx0sys.ic @@ -296,6 +296,16 @@ trx_is_active( return(FALSE); } + if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) { + + /* There must be corruption: we return TRUE because this + function is only called by lock_clust_rec_some_has_impl() + and row_vers_impl_x_locked_off_kernel() and they have + diagnostic prints in this case */ + + return(TRUE); + } + trx = trx_get_on_id(trx_id); if (trx && (trx->conc_state == TRX_ACTIVE)) { diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 39229923375..6b08b674db8 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -381,7 +381,8 @@ struct trx_struct{ replication slave, we have here the master binlog name up to which replication has processed; otherwise - this is a pointer to a null character */ + this is a pointer to a null + character */ ib_longlong mysql_master_log_pos; /* if the database server is a MySQL replication slave, this is the @@ -501,6 +502,10 @@ struct trx_struct{ mem_heap_t* read_view_heap; /* memory heap for the read view */ read_view_t* read_view; /* consistent read view or NULL */ /*------------------------------*/ + UT_LIST_BASE_NODE_T(trx_named_savept_t) + trx_savepoints; /* savepoints set with SAVEPOINT ..., + oldest first */ + /*------------------------------*/ mutex_t undo_mutex; /* mutex protecting the fields in this section (down to undo_no_arr), EXCEPT last_sql_stat_start, which can be diff --git a/innobase/include/trx0types.h b/innobase/include/trx0types.h index b8befe7172f..2965eb4451f 100644 --- a/innobase/include/trx0types.h +++ b/innobase/include/trx0types.h @@ -24,6 +24,7 @@ typedef struct trx_undo_inf_struct trx_undo_inf_t; typedef struct trx_purge_struct trx_purge_t; typedef struct roll_node_struct roll_node_t; typedef struct commit_node_struct commit_node_t; +typedef struct trx_named_savept_struct trx_named_savept_t; /* Transaction savepoint */ typedef struct trx_savept_struct trx_savept_t; diff --git a/innobase/include/ut0dbg.h b/innobase/include/ut0dbg.h index e99dc8c09d6..802557099fc 100644 --- a/innobase/include/ut0dbg.h +++ b/innobase/include/ut0dbg.h @@ -50,6 +50,37 @@ extern ulint* ut_dbg_null_ptr; }\ } +/* This can be used if there are % characters in the assertion formula: +if we try to printf the formula gcc would complain of illegal print +format characters */ +#define ut_anp(EXPR)\ +{\ + ulint dbg_i;\ +\ + if (!((ulint)(EXPR) + ut_dbg_zero)) {\ + ut_print_timestamp(stderr);\ + fprintf(stderr,\ + " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\ + (ulint)__LINE__);\ + fprintf(stderr,\ + "\nInnoDB: We intentionally generate a memory trap.\n");\ + fprintf(stderr,\ + "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\ + ut_dbg_stop_threads = TRUE;\ + dbg_i = *(ut_dbg_null_ptr);\ + if (dbg_i) {\ + ut_dbg_null_ptr = NULL;\ + }\ + }\ + if (ut_dbg_stop_threads) {\ + fprintf(stderr,\ + "InnoDB: Thread %lu stopped in file %s line %lu\n",\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ + os_thread_sleep(1000000000);\ + }\ +} + #define ut_error {\ ulint dbg_i;\ ut_print_timestamp(stderr);\ diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h index d3d04d58596..ba6905a8618 100644 --- a/innobase/include/ut0mem.h +++ b/innobase/include/ut0mem.h @@ -67,7 +67,7 @@ ut_free( /*====*/ void* ptr); /* in, own: memory block */ /************************************************************************** -Frees all allocated memory not freed yet. */ +Frees in shutdown all allocated memory not freed yet. */ void ut_free_all_mem(void); diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 74dc4aea515..af589cd9441 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -83,10 +83,6 @@ x-lock also has an explicit non-gap record x-lock. Therefore, as locks are released, we can grant locks to waiting lock requests purely by looking at the explicit lock requests in the queue. -RULE 2: Granted non-gap locks on a record are always ahead in the queue -------- -of waiting non-gap locks on a record. - RULE 3: Different transactions cannot have conflicting granted non-gap locks ------- on a record at the same time. However, they can have conflicting granted gap @@ -356,7 +352,7 @@ lock_mutex_enter_kernel(void) } /************************************************************************* -Releses the kernel mutex. This function is used in this module to allow +Releases the kernel mutex. This function is used in this module to allow monitoring the contention degree on the kernel mutex caused by the lock operations. */ UNIV_INLINE @@ -515,6 +511,53 @@ lock_rec_mutex_own_all(void) #endif /************************************************************************* +Checks that a transaction id is sensible, i.e., not in the future. */ + +ibool +lock_check_trx_id_sanity( +/*=====================*/ + /* out: TRUE if ok */ + dulint trx_id, /* in: trx id */ + rec_t* rec, /* in: user record */ + dict_index_t* index, /* in: clustered index */ + ibool has_kernel_mutex)/* in: TRUE if the caller owns the + kernel mutex */ +{ + char err_buf[500]; + ibool is_ok = TRUE; + + if (!has_kernel_mutex) { + mutex_enter(&kernel_mutex); + } + + /* A sanity check: the trx_id in rec must be smaller than the global + trx id counter */ + + if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) { + rec_sprintf(err_buf, 400, rec); + ut_print_timestamp(stderr); + fprintf(stderr, +"InnoDB: Error: transaction id associated with record\n%s\n" +"InnoDB: in table %s index %s\n" +"InnoDB: is %lu %lu which is higher than the global trx id counter %lu %lu!\n" +"InnoDB: The table is corrupt. You have to do dump + drop + reimport.\n", + err_buf, index->table_name, index->name, + ut_dulint_get_high(trx_id), + ut_dulint_get_low(trx_id), + ut_dulint_get_high(trx_sys->max_trx_id), + ut_dulint_get_low(trx_sys->max_trx_id)); + + is_ok = FALSE; + } + + if (!has_kernel_mutex) { + mutex_exit(&kernel_mutex); + } + + return(is_ok); +} + +/************************************************************************* Checks that a record is seen in a consistent read. */ ibool @@ -532,6 +575,10 @@ lock_clust_rec_cons_read_sees( ut_ad(index->type & DICT_CLUSTERED); ut_ad(page_rec_is_user_rec(rec)); + /* NOTE that we call this function while holding the search + system latch. To obey the latching order we must NOT reserve the + kernel mutex here! */ + trx_id = row_get_rec_trx_id(rec, index); if (read_view_sees_trx_id(view, trx_id)) { @@ -562,10 +609,16 @@ lock_sec_rec_cons_read_sees( read_view_t* view) /* in: consistent read view */ { dulint max_trx_id; - + + UT_NOT_USED(index); + ut_ad(!(index->type & DICT_CLUSTERED)); ut_ad(page_rec_is_user_rec(rec)); + /* NOTE that we might call this function while holding the search + system latch. To obey the latching order we must NOT reserve the + kernel mutex here! */ + if (recv_recovery_is_on()) { return(FALSE); @@ -1569,6 +1622,15 @@ lock_sec_rec_some_has_impl_off_kernel( /* Ok, in this case it is possible that some transaction has an implicit x-lock. We have to look in the clustered index. */ + if (!lock_check_trx_id_sanity(page_get_max_trx_id(page), rec, index, + TRUE)) { + buf_page_print(page); + + /* The page is corrupt: try to avoid a crash by returning + NULL */ + return(NULL); + } + return(row_vers_impl_x_locked_off_kernel(rec, index)); } @@ -2565,7 +2627,7 @@ lock_move_rec_list_start( ulint heap_no; ulint type_mode; - ut_ad(new_page); + ut_a(new_page); lock_mutex_enter_kernel(); @@ -3028,7 +3090,7 @@ lock_deadlock_recursive( we return LOCK_VICTIM_IS_START */ { lock_t* lock; - ulint bit_no; + ulint bit_no = ULINT_UNDEFINED; trx_t* lock_trx; char* err_buf; ulint ret; @@ -3067,6 +3129,7 @@ lock_deadlock_recursive( lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock); } else { ut_ad(lock_get_type(lock) == LOCK_REC); + ut_a(bit_no != ULINT_UNDEFINED); lock = lock_rec_get_prev(lock, bit_no); } @@ -4205,7 +4268,6 @@ lock_rec_queue_validate( { trx_t* impl_trx; lock_t* lock; - ibool is_waiting; ut_a(rec); @@ -4266,8 +4328,6 @@ lock_rec_queue_validate( } } - is_waiting = FALSE; - lock = lock_rec_get_first(rec); while (lock) { @@ -4280,8 +4340,6 @@ lock_rec_queue_validate( } if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { - - ut_a(!is_waiting); if (lock_get_mode(lock) == LOCK_S) { ut_a(!lock_rec_other_has_expl_req(LOCK_X, @@ -4293,7 +4351,6 @@ lock_rec_queue_validate( } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { - is_waiting = TRUE; ut_a(lock_rec_has_to_wait_in_queue(lock)); } diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 6892e6fc6c1..b0140ef767b 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -33,6 +33,11 @@ log_t* log_sys = NULL; ibool log_do_write = TRUE; ibool log_debug_writes = FALSE; +/* These control how often we print warnings if the last checkpoint is too +old */ +ibool log_has_printed_chkp_warning = FALSE; +time_t log_last_warning_time; + /* Pointer to this variable is used as the i/o-message when we do i/o to an archive */ byte log_archive_io; @@ -178,7 +183,8 @@ loop: /* Not enough free space, do a syncronous flush of the log buffer */ - log_write_up_to(ut_dulint_max, LOG_WAIT_ALL_GROUPS, TRUE); + + log_buffer_flush_to_disk(); count++; @@ -298,6 +304,7 @@ log_close(void) dulint oldest_lsn; dulint lsn; log_t* log = log_sys; + ulint checkpoint_age; ut_ad(mutex_own(&(log->mutex))); @@ -321,8 +328,34 @@ log_close(void) log->check_flush_or_checkpoint = TRUE; } - if (ut_dulint_minus(lsn, log->last_checkpoint_lsn) - <= log->max_modified_age_async) { + checkpoint_age = ut_dulint_minus(lsn, log->last_checkpoint_lsn); + + if (checkpoint_age >= log->log_group_capacity) { + /* TODO: split btr_store_big_rec_extern_fields() into small + steps so that we can release all latches in the middle, and + call log_free_check() to ensure we never write over log written + after the latest checkpoint. In principle, we should split all + big_rec operations, but other operations are smaller. */ + + if (!log_has_printed_chkp_warning + || difftime(time(NULL), log_last_warning_time) > 15) { + + log_has_printed_chkp_warning = TRUE; + log_last_warning_time = time(NULL); + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: ERROR: the age of the last checkpoint is %lu,\n" +"InnoDB: which exceeds the log group capacity %lu.\n" +"InnoDB: If you are using big BLOB or TEXT rows, you must set the\n" +"InnoDB: combined size of log files at least 10 times bigger than the\n" +"InnoDB: largest such row.\n", + checkpoint_age, log->log_group_capacity); + } + } + + if (checkpoint_age <= log->max_modified_age_async) { + goto function_exit; } @@ -331,8 +364,7 @@ log_close(void) if (ut_dulint_is_zero(oldest_lsn) || (ut_dulint_minus(lsn, oldest_lsn) > log->max_modified_age_async) - || (ut_dulint_minus(lsn, log->last_checkpoint_lsn) - > log->max_checkpoint_age_async)) { + || checkpoint_age > log->max_checkpoint_age_async) { log->check_flush_or_checkpoint = TRUE; } @@ -375,7 +407,7 @@ log_pad_current_log_block(void) log_close(); log_release(); - ut_ad((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) + ut_anp((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) == LOG_BLOCK_HDR_SIZE); } @@ -468,7 +500,7 @@ log_group_calc_lsn_offset( offset = (gr_lsn_size_offset + difference) % group_size; - ut_a(offset <= 0xFFFFFFFF); + ut_a(offset < (((ib_longlong) 1) << 32)); /* offset must be < 4 GB */ /* printf("Offset is %lu gr_lsn_offset is %lu difference is %lu\n", (ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference); @@ -550,7 +582,6 @@ log_calc_max_ages(void) the database server */ { log_group_t* group; - ulint n_threads; ulint margin; ulint free; ibool success = TRUE; @@ -560,8 +591,6 @@ log_calc_max_ages(void) ut_ad(!mutex_own(&(log_sys->mutex))); - n_threads = srv_get_n_threads(); - mutex_enter(&(log_sys->mutex)); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -589,12 +618,15 @@ log_calc_max_ages(void) group = UT_LIST_GET_NEXT(log_groups, group); } + /* Add extra safety */ + smallest_capacity = smallest_capacity - smallest_capacity / 10; + /* For each OS thread we must reserve so much free space in the smallest log group that it can accommodate the log entries produced by single query steps: running out of free log space is a serious system error which requires rebooting the database. */ - free = LOG_CHECKPOINT_FREE_PER_THREAD * n_threads + free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency) + LOG_CHECKPOINT_EXTRA_FREE; if (free >= smallest_capacity / 2) { success = FALSE; @@ -606,6 +638,10 @@ log_calc_max_ages(void) margin = ut_min(margin, log_sys->adm_checkpoint_interval); + margin = margin - margin / 10; /* Add still some extra safety */ + + log_sys->log_group_capacity = smallest_capacity; + log_sys->max_modified_age_async = margin - margin / LOG_POOL_PREFLUSH_RATIO_ASYNC; log_sys->max_modified_age_sync = margin @@ -625,7 +661,7 @@ failure: if (!success) { fprintf(stderr, - "Error: log file group too small for the number of threads\n"); +"InnoDB: Error: log file group too small for innodb_thread_concurrency\n"); } return(success); @@ -1070,8 +1106,8 @@ log_group_write_buf( ulint i; ut_ad(mutex_own(&(log_sys->mutex))); - ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_anp(len % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_anp(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); if (new_data_offset == 0) { write_header = TRUE; @@ -1365,6 +1401,24 @@ do_waits: } /******************************************************************** +Does a syncronous flush of the log buffer to disk. */ + +void +log_buffer_flush_to_disk(void) +/*==========================*/ +{ + dulint lsn; + + mutex_enter(&(log_sys->mutex)); + + lsn = log_sys->lsn; + + mutex_exit(&(log_sys->mutex)); + + log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, TRUE); +} + +/******************************************************************** Tries to establish a big enough margin of free space in the log buffer, such that a new log entry can be catenated without an immediate need for a flush. */ static @@ -1374,6 +1428,7 @@ log_flush_margin(void) { ibool do_flush = FALSE; log_t* log = log_sys; + dulint lsn; mutex_enter(&(log->mutex)); @@ -1384,13 +1439,14 @@ log_flush_margin(void) free space */ } else { do_flush = TRUE; + lsn = log->lsn; } } mutex_exit(&(log->mutex)); if (do_flush) { - log_write_up_to(ut_dulint_max, LOG_NO_WAIT, FALSE); + log_write_up_to(lsn, LOG_NO_WAIT, FALSE); } } @@ -2123,11 +2179,11 @@ log_group_archive( start_lsn = log_sys->archived_lsn; - ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_anp(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); end_lsn = log_sys->next_archived_lsn; - ut_ad(ut_dulint_get_low(end_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_anp(ut_dulint_get_low(end_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); buf = log_sys->archive_buf; @@ -2234,7 +2290,7 @@ loop: group->next_archived_file_no = group->archived_file_no + n_files; group->next_archived_offset = next_offset % group->file_size; - ut_ad(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_anp(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0); } /********************************************************* @@ -2429,8 +2485,8 @@ loop: start_lsn = log_sys->archived_lsn; if (calc_new_limit) { - ut_ad(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE == 0); - + ut_anp(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE + == 0); limit_lsn = ut_dulint_add(start_lsn, log_sys->archive_buf_size); @@ -2916,6 +2972,7 @@ loop: mutex_enter(&kernel_mutex); + /* Check that there are no longer transactions */ if (trx_n_mysql_transactions > 0 || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { @@ -2924,6 +2981,8 @@ loop: goto loop; } + /* Check that the master thread is suspended */ + if (srv_n_threads_active[SRV_MASTER] != 0) { mutex_exit(&kernel_mutex); @@ -2952,7 +3011,6 @@ loop: } log_archive_all(); - log_make_checkpoint_at(ut_dulint_max, TRUE); mutex_enter(&(log_sys->mutex)); @@ -2961,8 +3019,9 @@ loop: if (ut_dulint_cmp(lsn, log_sys->last_checkpoint_lsn) != 0 || (srv_log_archive_on - && ut_dulint_cmp(lsn, - ut_dulint_add(log_sys->archived_lsn, LOG_BLOCK_HDR_SIZE)) != 0)) { + && ut_dulint_cmp(lsn, + ut_dulint_add(log_sys->archived_lsn, LOG_BLOCK_HDR_SIZE)) + != 0)) { mutex_exit(&(log_sys->mutex)); @@ -2981,10 +3040,22 @@ loop: mutex_exit(&(log_sys->mutex)); + mutex_enter(&kernel_mutex); + /* Check that the master thread has stayed suspended */ + if (srv_n_threads_active[SRV_MASTER] != 0) { + fprintf(stderr, +"InnoDB: Warning: the master thread woke up during shutdown\n"); + + mutex_exit(&kernel_mutex); + + goto loop; + } + mutex_exit(&kernel_mutex); + fil_flush_file_spaces(FIL_TABLESPACE); fil_flush_file_spaces(FIL_LOG); - /* The following fil_write_... will pass the buffer pool: therefore + /* The next fil_write_... will pass the buffer pool: therefore it is essential that the buffer pool has been completely flushed to disk! */ @@ -2993,12 +3064,14 @@ loop: goto loop; } + /* The lock timeout thread should now have exited */ + if (srv_lock_timeout_and_monitor_active) { goto loop; } - /* We now suspend also the InnoDB error monitor thread */ + /* We now let also the InnoDB error monitor thread to exit */ srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE; @@ -3008,6 +3081,7 @@ loop: } /* Make some checks that the server really is quiet */ + ut_a(srv_n_threads_active[SRV_MASTER] == 0); ut_a(buf_all_freed()); ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn)); @@ -3016,6 +3090,7 @@ loop: fil_flush_file_spaces(FIL_TABLESPACE); /* Make some checks that the server really is quiet */ + ut_a(srv_n_threads_active[SRV_MASTER] == 0); ut_a(buf_all_freed()); ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn)); } @@ -3072,6 +3147,28 @@ log_check_log_recs( } /********************************************************** +Peeks the current lsn. */ + +ibool +log_peek_lsn( +/*=========*/ + /* out: TRUE if success, FALSE if could not get the + log system mutex */ + dulint* lsn) /* out: if returns TRUE, current lsn is here */ +{ + if (0 == mutex_enter_nowait(&(log_sys->mutex), (char*)__FILE__, + __LINE__)) { + *lsn = log_sys->lsn; + + mutex_exit(&(log_sys->mutex)); + + return(TRUE); + } + + return(FALSE); +} + +/********************************************************** Prints info of the log. */ void diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 4efe4e7b23d..ce90683ae7f 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -46,6 +46,8 @@ ibool recv_recovery_from_backup_on = FALSE; ibool recv_needed_recovery = FALSE; +ibool recv_lsn_checks_on = FALSE; + /* If the following is TRUE, the buffer pool file pages must be invalidated after recovery and no ibuf operations are allowed; this becomes TRUE if the log record hash table becomes too full, and log records must be merged @@ -71,6 +73,12 @@ ulint recv_previous_parsed_rec_is_multi = 0; ulint recv_max_parsed_page_no = 0; +/* The maximum lsn we see for a page during the recovery process. If this +is bigger than the lsn we are able to scan up to, that is an indication that +the recovery failed and the database may be corrupt. */ + +dulint recv_max_page_lsn; + /* This many frames must be left free in the buffer pool when we scan the log and store the scanned log records in the buffer pool: we will use these free frames to read in pages when we start applying the @@ -140,6 +148,8 @@ recv_sys_init( OS_FILE_LOG_BLOCK_SIZE); recv_sys->found_corrupt_log = FALSE; + recv_max_page_lsn = ut_dulint_zero; + mutex_exit(&(recv_sys->mutex)); } @@ -981,7 +991,7 @@ recv_recover_page( ulint space, /* in: space id */ ulint page_no) /* in: page number */ { - buf_block_t* block; + buf_block_t* block = NULL; recv_addr_t* recv_addr; recv_t* recv; byte* buf; @@ -1093,7 +1103,7 @@ recv_recover_page( page_lsn = page_newest_lsn; mach_write_to_8(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN, ut_dulint_zero); + - FIL_PAGE_END_LSN_OLD_CHKSUM, ut_dulint_zero); mach_write_to_8(page + FIL_PAGE_LSN, ut_dulint_zero); } @@ -1115,7 +1125,7 @@ recv_recover_page( recv_parse_or_apply_log_rec_body(recv->type, buf, buf + recv->len, page, &mtr); mach_write_to_8(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN, + - FIL_PAGE_END_LSN_OLD_CHKSUM, ut_dulint_add(recv->start_lsn, recv->len)); mach_write_to_8(page + FIL_PAGE_LSN, @@ -1132,6 +1142,10 @@ recv_recover_page( mutex_enter(&(recv_sys->mutex)); + if (ut_dulint_cmp(recv_max_page_lsn, page_lsn) < 0) { + recv_max_page_lsn = page_lsn; + } + recv_addr->state = RECV_PROCESSED; ut_a(recv_sys->n_addrs); @@ -1140,6 +1154,8 @@ recv_recover_page( mutex_exit(&(recv_sys->mutex)); if (!recover_backup && modification_to_page) { + ut_a(block); + buf_flush_recv_note_modification(block, start_lsn, end_lsn); } @@ -1347,6 +1363,7 @@ loop: mutex_exit(&(recv_sys->mutex)); } +#ifdef UNIV_HOTBACKUP /*********************************************************************** Applies log records in the hash table to a backup. */ @@ -1528,8 +1545,8 @@ recv_check_identical( for (i = 0; i < len; i++) { if (str1[i] != str2[i]) { - fprintf(stderr, "Strings do not match at offset %lu\n", i); - + fprintf(stderr, + "Strings do not match at offset %lu\n", i); ut_print_buf(str1 + i, 16); fprintf(stderr, "\n"); ut_print_buf(str2 + i, 16); @@ -1662,6 +1679,7 @@ recv_compare_spaces_low( recv_compare_spaces(space1, space2, n_pages); } +#endif /*********************************************************************** Tries to parse a single log record and returns its length. */ @@ -2196,9 +2214,12 @@ recv_scan_log_recs( while (log_block < buf + len && !finished) { no = log_block_get_hdr_no(log_block); +/* + fprintf(stderr, "Log block header no %lu\n", no); - /* fprintf(stderr, "Log block header no %lu\n", no); */ - + fprintf(stderr, "Scanned lsn no %lu\n", + log_block_convert_lsn_to_no(scanned_lsn)); +*/ if (no != log_block_convert_lsn_to_no(scanned_lsn) || !log_block_checksum_is_ok_or_old_format(log_block)) { @@ -2590,7 +2611,6 @@ recv_recovery_from_checkpoint_start( recv_group_scan_log_recs(group, &contiguous_lsn, &group_scanned_lsn); - group->scanned_lsn = group_scanned_lsn; if (ut_dulint_cmp(old_scanned_lsn, group_scanned_lsn) < 0) { @@ -2607,6 +2627,31 @@ recv_recovery_from_checkpoint_start( group = UT_LIST_GET_NEXT(log_groups, group); } + /* We currently have only one log group */ + if (ut_dulint_cmp(group_scanned_lsn, checkpoint_lsn) < 0) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: ERROR: We were only able to scan the log up to\n" +"InnoDB: %lu %lu, but a checkpoint was at %lu %lu.\n" +"InnoDB: It is possible that the database is now corrupt!\n", + ut_dulint_get_high(group_scanned_lsn), + ut_dulint_get_low(group_scanned_lsn), + ut_dulint_get_high(checkpoint_lsn), + ut_dulint_get_low(checkpoint_lsn)); + } + + if (ut_dulint_cmp(group_scanned_lsn, recv_max_page_lsn) < 0) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: ERROR: We were only able to scan the log up to %lu %lu\n" +"InnoDB: but a database page a had an lsn %lu %lu. It is possible that the\n" +"InnoDB: database is now corrupt!\n", + ut_dulint_get_high(group_scanned_lsn), + ut_dulint_get_low(group_scanned_lsn), + ut_dulint_get_high(recv_max_page_lsn), + ut_dulint_get_low(recv_max_page_lsn)); + } + if (ut_dulint_cmp(recv_sys->recovered_lsn, checkpoint_lsn) < 0) { mutex_exit(&(log_sys->mutex)); @@ -2660,6 +2705,8 @@ recv_recovery_from_checkpoint_start( sync_order_checks_on = FALSE; + recv_lsn_checks_on = TRUE; + /* The database is now ready to start almost normal processing of user transactions: transaction rollbacks and the application of the log records in the hash table can be run in background. */ diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 382e505b63f..b004a8c4df7 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -99,6 +99,12 @@ mem_pool_t* mem_comm_pool = NULL; ulint mem_out_of_mem_err_msg_count = 0; +/* We use this counter to check that the mem pool mutex does not leak; +this is to track a strange assertion failure reported at +mysql@lists.mysql.com */ + +ulint mem_n_threads_inside = 0; + /************************************************************************ Reserves the mem pool mutex. */ @@ -328,6 +334,9 @@ mem_area_alloc( n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE)); mutex_enter(&(pool->mutex)); + mem_n_threads_inside++; + + ut_a(mem_n_threads_inside == 1); area = UT_LIST_GET_FIRST(pool->free_list[n]); @@ -338,6 +347,7 @@ mem_area_alloc( /* Out of memory in memory pool: we try to allocate from the operating system with the regular malloc: */ + mem_n_threads_inside--; mutex_exit(&(pool->mutex)); return(ut_malloc(size)); @@ -353,6 +363,16 @@ mem_area_alloc( n); mem_analyze_corruption((byte*)area); + + /* Try to analyze a strange assertion failure reported at + mysql@lists.mysql.com where the free bit IS 1 in the + hex dump above */ + + if (mem_area_get_free(area)) { + fprintf(stderr, +"InnoDB: Probably a race condition because now the area is marked free!\n"); + } + ut_a(0); } @@ -374,6 +394,7 @@ mem_area_alloc( pool->reserved += mem_area_get_size(area); + mem_n_threads_inside--; mutex_exit(&(pool->mutex)); ut_ad(mem_pool_validate(pool)); @@ -495,6 +516,9 @@ mem_area_free( n = ut_2_log(size); mutex_enter(&(pool->mutex)); + mem_n_threads_inside++; + + ut_a(mem_n_threads_inside == 1); if (buddy && mem_area_get_free(buddy) && (size == mem_area_get_size(buddy))) { @@ -518,6 +542,7 @@ mem_area_free( pool->reserved += ut_2_exp(n); + mem_n_threads_inside--; mutex_exit(&(pool->mutex)); mem_area_free(new_ptr, pool); @@ -533,6 +558,7 @@ mem_area_free( pool->reserved -= size; } + mem_n_threads_inside--; mutex_exit(&(pool->mutex)); ut_ad(mem_pool_validate(pool)); @@ -577,7 +603,7 @@ mem_pool_validate( } } - ut_a(free + pool->reserved == pool->size + ut_anp(free + pool->reserved == pool->size - (pool->size % MEM_AREA_MIN_SIZE)); mutex_exit(&(pool->mutex)); diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index e401503c4e3..e31fd1d9efe 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -60,6 +60,7 @@ struct os_aio_slot_struct{ ulint pos; /* index of the slot in the aio array */ ibool reserved; /* TRUE if this slot is reserved */ + time_t reservation_time;/* time when reserved */ ulint len; /* length of the block to read or write */ byte* buf; /* buffer used in i/o */ @@ -147,6 +148,12 @@ time_t os_last_printout; ibool os_has_said_disk_full = FALSE; +/* The mutex protecting the following counts of pending pread and pwrite +operations */ +os_mutex_t os_file_count_mutex; +ulint os_file_n_pending_preads = 0; +ulint os_file_n_pending_pwrites = 0; + /*************************************************************************** Gets the operating system version. Currently works only on Windows. */ @@ -204,9 +211,9 @@ os_file_get_last_error(void) if (err != ERROR_DISK_FULL && err != ERROR_FILE_EXISTS) { ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Operating system error number %li in a file operation.\n" + " InnoDB: Operating system error number %lu in a file operation.\n" "InnoDB: See http://www.innodb.com/ibman.html for installation help.\n", - (long) err); + err); if (err == ERROR_PATH_NOT_FOUND) { fprintf(stderr, @@ -248,9 +255,9 @@ os_file_get_last_error(void) ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Operating system error number %li in a file operation.\n" + " InnoDB: Operating system error number %lu in a file operation.\n" "InnoDB: See http://www.innodb.com/ibman.html for installation help.\n", - (long) err); + err); if (err == ENOENT) { fprintf(stderr, @@ -344,7 +351,8 @@ os_file_handle_error( fprintf(stderr, "InnoDB: File name %s\n", name); } - fprintf(stderr, "InnoDB: System call %s.\n", operation); + fprintf(stderr, "InnoDB: File operation call: '%s'.\n", + operation); fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fflush(stderr); @@ -364,6 +372,8 @@ os_io_init_simple(void) { ulint i; + os_file_count_mutex = os_mutex_create(NULL); + for (i = 0; i < OS_FILE_N_SEEK_MUTEXES; i++) { os_file_seek_mutexes[i] = os_mutex_create(NULL); } @@ -415,9 +425,8 @@ try_again: file = CreateFile(name, access, - FILE_SHARE_READ | FILE_SHARE_WRITE, - /* file can be read and written - also by other processes */ + FILE_SHARE_READ,/* file can be read also by other + processes */ NULL, /* default security attributes */ create_flag, attributes, @@ -481,6 +490,101 @@ try_again: return(file); #endif } + +/******************************************************************** +A simple function to open or create a file. */ + +os_file_t +os_file_create_simple_no_error_handling( +/*====================================*/ + /* out, own: handle to the file, not defined if error, + error number can be retrieved with os_get_last_error */ + char* name, /* in: name of the file or path as a null-terminated + string */ + ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened + (if does not exist, error), or OS_FILE_CREATE if a new + file is created (if exists, error) */ + ulint access_type,/* in: OS_FILE_READ_ONLY or OS_FILE_READ_WRITE */ + ibool* success)/* out: TRUE if succeed, FALSE if error */ +{ +#ifdef __WIN__ + os_file_t file; + DWORD create_flag; + DWORD access; + DWORD attributes = 0; + + ut_a(name); + + if (create_mode == OS_FILE_OPEN) { + create_flag = OPEN_EXISTING; + } else if (create_mode == OS_FILE_CREATE) { + create_flag = CREATE_NEW; + } else { + create_flag = 0; + ut_error; + } + + if (access_type == OS_FILE_READ_ONLY) { + access = GENERIC_READ; + } else if (access_type == OS_FILE_READ_WRITE) { + access = GENERIC_READ | GENERIC_WRITE; + } else { + access = 0; + ut_error; + } + + file = CreateFile(name, + access, + FILE_SHARE_READ,/* file can be read also by other + processes */ + NULL, /* default security attributes */ + create_flag, + attributes, + NULL); /* no template file */ + + if (file == INVALID_HANDLE_VALUE) { + *success = FALSE; + } else { + *success = TRUE; + } + + return(file); +#else + os_file_t file; + int create_flag; + + ut_a(name); + + if (create_mode == OS_FILE_OPEN) { + if (access_type == OS_FILE_READ_ONLY) { + create_flag = O_RDONLY; + } else { + create_flag = O_RDWR; + } + } else if (create_mode == OS_FILE_CREATE) { + create_flag = O_RDWR | O_CREAT | O_EXCL; + } else { + create_flag = 0; + ut_error; + } + + if (create_mode == OS_FILE_CREATE) { + file = open(name, create_flag, S_IRUSR | S_IWUSR + | S_IRGRP | S_IWGRP); + } else { + file = open(name, create_flag); + } + + if (file == -1) { + *success = FALSE; + } else { + *success = TRUE; + } + + return(file); +#endif +} + /******************************************************************** Opens an existing file or creates a new. */ @@ -496,7 +600,11 @@ os_file_create( file is created (if exists, error), OS_FILE_OVERWRITE if a new is created or an old overwritten */ ulint purpose,/* in: OS_FILE_AIO, if asynchronous, non-buffered i/o - is desired, OS_FILE_NORMAL, if any normal file */ + is desired, OS_FILE_NORMAL, if any normal file; + NOTE that it also depends on type, os_aio_.. and srv_.. + variables whether we really use async i/o or + unbuffered i/o: look in the function source code for + the exact rules */ ulint type, /* in: OS_DATA_FILE or OS_LOG_FILE */ ibool* success)/* out: TRUE if succeed, FALSE if error */ { @@ -521,8 +629,8 @@ try_again: } if (purpose == OS_FILE_AIO) { - /* use asynchronous (overlapped) io and no buffering - of writes in the OS */ + /* If specified, use asynchronous (overlapped) io and no + buffering of writes in the OS */ attributes = 0; #ifdef WIN_ASYNC_IO if (os_aio_use_native_aio) { @@ -530,17 +638,13 @@ try_again: } #endif #ifdef UNIV_NON_BUFFERED_IO - if (type == OS_LOG_FILE) { + if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { /* Do not use unbuffered i/o to log files because - to allow group commit to work when MySQL binlogging - is used we must separate log file write and log - file flush to disk. */ - } else { - if (srv_win_file_flush_method == - SRV_WIN_IO_UNBUFFERED) { - attributes = attributes - | FILE_FLAG_NO_BUFFERING; - } + value 2 denotes that we do not flush the log at every + commit, but only once per second */ + } else if (srv_win_file_flush_method == + SRV_WIN_IO_UNBUFFERED) { + attributes = attributes | FILE_FLAG_NO_BUFFERING; } #endif } else if (purpose == OS_FILE_NORMAL) { @@ -550,12 +654,9 @@ try_again: /* Do not use unbuffered i/o to log files because value 2 denotes that we do not flush the log at every commit, but only once per second */ - } else { - if (srv_win_file_flush_method == - SRV_WIN_IO_UNBUFFERED) { - attributes = attributes - | FILE_FLAG_NO_BUFFERING; - } + } else if (srv_win_file_flush_method == + SRV_WIN_IO_UNBUFFERED) { + attributes = attributes | FILE_FLAG_NO_BUFFERING; } #endif } else { @@ -566,9 +667,14 @@ try_again: file = CreateFile(name, GENERIC_READ | GENERIC_WRITE, /* read and write access */ - FILE_SHARE_READ | FILE_SHARE_WRITE, - /* file can be read and written - also by other processes */ + FILE_SHARE_READ,/* File can be read also by other + processes; we must give the read + permission because of ibbackup. We do + not give the write permission to + others because if one would succeed to + start 2 instances of mysqld on the + SAME files, that could cause severe + database corruption! */ NULL, /* default security attributes */ create_flag, attributes, @@ -592,30 +698,70 @@ try_again: os_file_t file; int create_flag; ibool retry; + const char* mode_str = NULL; + const char* type_str = NULL; + const char* purpose_str = NULL; try_again: ut_a(name); if (create_mode == OS_FILE_OPEN) { + mode_str = "OPEN"; + create_flag = O_RDWR; } else if (create_mode == OS_FILE_CREATE) { + mode_str = "CREATE"; + create_flag = O_RDWR | O_CREAT | O_EXCL; } else if (create_mode == OS_FILE_OVERWRITE) { + mode_str = "OVERWRITE"; + create_flag = O_RDWR | O_CREAT | O_TRUNC; } else { create_flag = 0; ut_error; } - UT_NOT_USED(purpose); + if (type == OS_LOG_FILE) { + type_str = "LOG"; + } else if (type == OS_DATA_FILE) { + type_str = "DATA"; + } else { + ut_a(0); + } + + if (purpose == OS_FILE_AIO) { + purpose_str = "AIO"; + } else if (purpose == OS_FILE_NORMAL) { + purpose_str = "NORMAL"; + } else { + ut_a(0); + } +/* printf("Opening file %s, mode %s, type %s, purpose %s\n", + name, mode_str, type_str, purpose_str); */ #ifdef O_SYNC - if ((!srv_use_doublewrite_buf || type != OS_DATA_FILE) + /* We let O_SYNC only affect log files; note that we map O_DSYNC to + O_SYNC because the datasync options seemed to corrupt files in 2001 + in both Linux and Solaris */ + if (type == OS_LOG_FILE && srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) { +/* printf("Using O_SYNC for file %s\n", name); */ + create_flag = create_flag | O_SYNC; } #endif +#ifdef O_DIRECT + /* We let O_DIRECT only affect data files */ + if (type != OS_LOG_FILE + && srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) { + +/* printf("Using O_DIRECT for file %s\n", name); */ + + create_flag = create_flag | O_DIRECT; + } +#endif if (create_mode == OS_FILE_CREATE) { file = open(name, create_flag, os_innodb_umask); } else { @@ -677,6 +823,41 @@ os_file_close( } /*************************************************************************** +Closes a file handle. */ + +ibool +os_file_close_no_error_handling( +/*============================*/ + /* out: TRUE if success */ + os_file_t file) /* in, own: handle to a file */ +{ +#ifdef __WIN__ + BOOL ret; + + ut_a(file); + + ret = CloseHandle(file); + + if (ret) { + return(TRUE); + } + + return(FALSE); +#else + int ret; + + ret = close(file); + + if (ret == -1) { + + return(FALSE); + } + + return(TRUE); +#endif +} + +/*************************************************************************** Gets a file size. */ ibool @@ -849,6 +1030,7 @@ os_file_flush( #ifdef HAVE_FDATASYNC ret = fdatasync(file); #else +/* printf("Flushing to file %lu\n", (ulint)file); */ ret = fsync(file); #endif os_n_fsyncs++; @@ -896,6 +1078,7 @@ os_file_pread( offset */ { off_t offs; + ssize_t n_bytes; ut_a((offset & 0xFFFFFFFF) == offset); @@ -917,7 +1100,17 @@ os_file_pread( os_n_file_reads++; #ifdef HAVE_PREAD - return(pread(file, buf, n, offs)); + os_mutex_enter(os_file_count_mutex); + os_file_n_pending_preads++; + os_mutex_exit(os_file_count_mutex); + + n_bytes = pread(file, buf, n, offs); + + os_mutex_enter(os_file_count_mutex); + os_file_n_pending_preads--; + os_mutex_exit(os_file_count_mutex); + + return(n_bytes); #else { ssize_t ret; @@ -982,8 +1175,16 @@ os_file_pwrite( os_n_file_writes++; #ifdef HAVE_PWRITE + os_mutex_enter(os_file_count_mutex); + os_file_n_pending_pwrites++; + os_mutex_exit(os_file_count_mutex); + ret = pwrite(file, buf, n, offs); + os_mutex_enter(os_file_count_mutex); + os_file_n_pending_pwrites--; + os_mutex_exit(os_file_count_mutex); + if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC && !os_do_not_call_flush_at_each_write) { @@ -1157,6 +1358,7 @@ os_file_write( DWORD high; ulint i; ulint n_retries = 0; + ulint err; ut_a((offset & 0xFFFFFFFF) == offset); @@ -1224,18 +1426,27 @@ retry: if (!os_has_said_disk_full) { + err = (ulint)GetLastError(); + ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Error: Write to file %s failed at offset %lu %lu.\n" "InnoDB: %lu bytes should have been written, only %lu were written.\n" "InnoDB: Operating system error number %lu.\n" -"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n" -"InnoDB: what the error number means.\n" "InnoDB: Check that your OS and file system support files of this size.\n" "InnoDB: Check also that the disk is not full or a disk quota exceeded.\n", name, offset_high, offset, n, (ulint)len, - (ulint)GetLastError()); + err); + + if (strerror((int)err) != NULL) { + fprintf(stderr, +"InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err)); + } + + fprintf(stderr, +"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n" +"InnoDB: about operating system error numbers.\n"); os_has_said_disk_full = TRUE; } @@ -1259,12 +1470,19 @@ retry: " InnoDB: Error: Write to file %s failed at offset %lu %lu.\n" "InnoDB: %lu bytes should have been written, only %ld were written.\n" "InnoDB: Operating system error number %lu.\n" -"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n" -"InnoDB: what the error number means or use the perror program of MySQL.\n" "InnoDB: Check that your OS and file system support files of this size.\n" "InnoDB: Check also that the disk is not full or a disk quota exceeded.\n", name, offset_high, offset, n, (long int)ret, (ulint)errno); + if (strerror(errno) != NULL) { + fprintf(stderr, +"InnoDB: Error number %lu means '%s'.\n", (ulint)errno, strerror(errno)); + } + + fprintf(stderr, +"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n" +"InnoDB: about operating system error numbers.\n"); + os_has_said_disk_full = TRUE; } @@ -1372,19 +1590,35 @@ os_aio_init( os_io_init_simple(); + for (i = 0; i < n_segments; i++) { + srv_io_thread_op_info[i] = (char*)"not started yet"; + } + n_per_seg = n / n_segments; n_write_segs = (n_segments - 2) / 2; n_read_segs = n_segments - 2 - n_write_segs; /* printf("Array n per seg %lu\n", n_per_seg); */ + os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1); + + srv_io_thread_function[0] = (char*)"insert buffer thread"; + + os_aio_log_array = os_aio_array_create(n_per_seg, 1); + + srv_io_thread_function[1] = (char*)"log thread"; + os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg, n_read_segs); + for (i = 2; i < 2 + n_read_segs; i++) { + srv_io_thread_function[i] = (char*)"read thread"; + } + os_aio_write_array = os_aio_array_create(n_write_segs * n_per_seg, n_write_segs); - os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1); - - os_aio_log_array = os_aio_array_create(n_per_seg, 1); + for (i = 2 + n_read_segs; i < n_segments; i++) { + srv_io_thread_function[i] = (char*)"write thread"; + } os_aio_sync_array = os_aio_array_create(n_slots_sync, 1); @@ -1677,6 +1911,7 @@ loop: } slot->reserved = TRUE; + slot->reservation_time = time(NULL); slot->message1 = message1; slot->message2 = message2; slot->file = file; @@ -2249,6 +2484,8 @@ os_aio_simulated_handle( ulint total_len; ulint offs; ulint lowest_offset; + ulint biggest_age; + ulint age; byte* combined_buf; byte* combined_buf2; ibool ret; @@ -2301,22 +2538,55 @@ restart: n_consecutive = 0; - /* Look for an i/o request at the lowest offset in the array - (we ignore the high 32 bits of the offset in these heuristics) */ + /* If there are at least 2 seconds old requests, then pick the oldest + one to prevent starvation. If several requests have the same age, + then pick the one at the lowest offset. */ + biggest_age = 0; lowest_offset = ULINT_MAX; - + for (i = 0; i < n; i++) { slot = os_aio_array_get_nth_slot(array, i + segment * n); - if (slot->reserved && slot->offset < lowest_offset) { + if (slot->reserved) { + age = (ulint)difftime(time(NULL), + slot->reservation_time); - /* Found an i/o request */ - consecutive_ios[0] = slot; + if ((age >= 2 && age > biggest_age) + || (age >= 2 && age == biggest_age + && slot->offset < lowest_offset)) { - n_consecutive = 1; + /* Found an i/o request */ + consecutive_ios[0] = slot; - lowest_offset = slot->offset; + n_consecutive = 1; + + biggest_age = age; + lowest_offset = slot->offset; + } + } + } + + if (n_consecutive == 0) { + /* There were no old requests. Look for an i/o request at the + lowest offset in the array (we ignore the high 32 bits of the + offset in these heuristics) */ + + lowest_offset = ULINT_MAX; + + for (i = 0; i < n; i++) { + slot = os_aio_array_get_nth_slot(array, + i + segment * n); + + if (slot->reserved && slot->offset < lowest_offset) { + + /* Found an i/o request */ + consecutive_ios[0] = slot; + + n_consecutive = 1; + + lowest_offset = slot->offset; + } } } @@ -2422,7 +2692,7 @@ consecutive_loop: + FIL_PAGE_LSN + 4) != mach_read_from_4(combined_buf + len2 + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN + 4)) { + - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: ERROR: The page to be written seems corrupt!\n"); @@ -2583,14 +2853,15 @@ os_aio_print( double avg_bytes_read; ulint i; - if (buf_end - buf < 1000) { + if (buf_end - buf < 1200) { return; } for (i = 0; i < srv_n_file_io_threads; i++) { - buf += sprintf(buf, "I/O thread %lu state: %s\n", i, - srv_io_thread_op_info[i]); + buf += sprintf(buf, "I/O thread %lu state: %s (%s)\n", i, + srv_io_thread_op_info[i], + srv_io_thread_function[i]); } buf += sprintf(buf, "Pending normal aio reads:"); @@ -2665,6 +2936,12 @@ loop: "%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n", os_n_file_reads, os_n_file_writes, os_n_fsyncs); + if (os_file_n_pending_preads != 0 || os_file_n_pending_pwrites != 0) { + buf += sprintf(buf, + "%lu pending preads, %lu pending pwrites\n", + os_file_n_pending_preads, os_file_n_pending_pwrites); + } + if (os_n_file_reads == os_n_file_reads_old) { avg_bytes_read = 0.0; } else { diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index bf5fc57bf57..827d68501db 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -143,6 +143,7 @@ os_event_create( ut_a(0 == pthread_cond_init(&(event->cond_var), NULL)); #endif event->is_set = FALSE; + event->signal_count = 0; #endif /* __WIN__ */ /* Put to the list of events */ @@ -218,6 +219,7 @@ os_event_set( /* Do nothing */ } else { event->is_set = TRUE; + event->signal_count += 1; ut_a(0 == pthread_cond_broadcast(&(event->cond_var))); } @@ -310,9 +312,15 @@ os_event_wait( os_thread_exit(NULL); } #else + ib_longlong old_signal_count; + os_fast_mutex_lock(&(event->os_mutex)); + + old_signal_count = event->signal_count; loop: - if (event->is_set == TRUE) { + if (event->is_set == TRUE + || event->signal_count != old_signal_count) { + os_fast_mutex_unlock(&(event->os_mutex)); if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { @@ -326,8 +334,9 @@ loop: pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); - /* Solaris manual said that spurious wakeups may occur: we have - to check the 'is_set' variable again */ + /* Solaris manual said that spurious wakeups may occur: we have to + check if the event really has been signaled after we came here to + wait */ goto loop; #endif diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 9af98760ad1..1252cc5e4b7 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -187,8 +187,8 @@ os_thread_exit( is cast as a DWORD */ { #ifdef UNIV_DEBUG_THREAD_CREATION - printf("A thread exits.\n"); - printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); + printf("Thread exits, id %lu\n", + os_thread_pf(os_thread_get_curr_id())); #endif os_mutex_enter(os_sync_mutex); os_thread_count--; diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c index d3a40668c4b..7e2fc19c00f 100644 --- a/innobase/page/page0cur.c +++ b/innobase/page/page0cur.c @@ -14,6 +14,7 @@ Created 10/4/1994 Heikki Tuuri #include "rem0cmp.h" #include "mtr0log.h" #include "log0recv.h" +#include "rem0cmp.h" ulint page_cur_short_succ = 0; @@ -218,6 +219,8 @@ page_cur_search_with_match( || (mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE) || (mode == PAGE_CUR_LE_OR_EXTENDS) || (mode == PAGE_CUR_DBG)); + page_check_dir(page); + #ifdef PAGE_CUR_ADAPT if ((page_header_get_field(page, PAGE_LEVEL) == 0) && (mode == PAGE_CUR_LE) @@ -595,6 +598,7 @@ page_cur_parse_insert_rec( rec_t* cursor_rec; byte buf1[1024]; byte* buf; + byte* ptr2 = ptr; ulint info_bits = 0; /* remove warning */ page_cur_t cursor; @@ -697,7 +701,20 @@ page_cur_parse_insert_rec( /* Build the inserted record to buf */ - ut_a(mismatch_index < UNIV_PAGE_SIZE); + if (mismatch_index >= UNIV_PAGE_SIZE) { + printf("Is short %lu, info_bits %lu, offset %lu, o_offset %lu\n" + "mismatch index %lu, end_seg_len %lu\n" + "parsed len %lu\n", + is_short, info_bits, offset, origin_offset, + mismatch_index, end_seg_len, (ulint)(ptr - ptr2)); + + printf("Dump of 300 bytes of log:\n"); + ut_print_buf(ptr2, 300); + + buf_page_print(page); + + ut_a(0); + } ut_memcpy(buf, rec_get_start(cursor_rec), mismatch_index); ut_memcpy(buf + mismatch_index, ptr, end_seg_len); diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c index 7d240bdd5b0..e087941a970 100644 --- a/innobase/page/page0page.c +++ b/innobase/page/page0page.c @@ -353,7 +353,7 @@ page_create( infimum_rec = rec_convert_dtuple_to_rec(heap_top, tuple); - ut_ad(infimum_rec == page + PAGE_INFIMUM); + ut_a(infimum_rec == page + PAGE_INFIMUM); rec_set_n_owned(infimum_rec, 1); rec_set_heap_no(infimum_rec, 0); @@ -370,7 +370,7 @@ page_create( supremum_rec = rec_convert_dtuple_to_rec(heap_top, tuple); - ut_ad(supremum_rec == page + PAGE_SUPREMUM); + ut_a(supremum_rec == page + PAGE_SUPREMUM); rec_set_n_owned(supremum_rec, 1); rec_set_heap_no(supremum_rec, 1); @@ -389,6 +389,8 @@ page_create( page_header_set_ptr(page, PAGE_FREE, NULL); page_header_set_field(page, PAGE_GARBAGE, 0); page_header_set_ptr(page, PAGE_LAST_INSERT, NULL); + page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION); + page_header_set_field(page, PAGE_N_DIRECTION, 0); page_header_set_field(page, PAGE_N_RECS, 0); page_set_max_trx_id(page, ut_dulint_zero); @@ -402,17 +404,22 @@ page_create( slot = page_dir_get_nth_slot(page, 1); page_dir_slot_set_rec(slot, supremum_rec); - /* Set next pointers in infimum and supremum */ + /* Set the next pointers in infimum and supremum */ rec_set_next_offs(infimum_rec, (ulint)(supremum_rec - page)); rec_set_next_offs(supremum_rec, 0); +#ifdef notdefined + /* Disable the use of page_template: there is a race condition here: + while one thread is creating page_template, another one can start + using it before the memcpy completes! */ + if (page_template == NULL) { page_template = mem_alloc(UNIV_PAGE_SIZE); ut_memcpy(page_template, page, UNIV_PAGE_SIZE); } - +#endif return(page); } @@ -439,6 +446,8 @@ page_copy_rec_list_end_no_locks( page_cur_move_to_next(&cur1); } + ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == PAGE_INFIMUM); + page_cur_set_before_first(new_page, &cur2); /* Copy records from the original page to the new page */ @@ -446,8 +455,22 @@ page_copy_rec_list_end_no_locks( sup = page_get_supremum_rec(page); while (sup != page_cur_get_rec(&cur1)) { - ut_a( - page_cur_rec_insert(&cur2, page_cur_get_rec(&cur1), mtr)); + if (!page_cur_rec_insert(&cur2, + page_cur_get_rec(&cur1), mtr)) { + /* Track an assertion failure reported on the mailing + list on June 18th, 2003 */ + + buf_page_print(new_page); + buf_page_print(page); + ut_print_timestamp(stderr); + + fprintf(stderr, +"InnoDB: rec offset %lu, cur1 offset %lu, cur2 offset %lu\n", + (ulint)(rec - page), + (ulint)(page_cur_get_rec(&cur1) - page), + (ulint)(page_cur_get_rec(&cur2) - new_page)); + ut_a(0); + } page_cur_move_to_next(&cur1); page_cur_move_to_next(&cur2); @@ -1315,6 +1338,37 @@ page_rec_validate( return(TRUE); } + +/******************************************************************* +Checks that the first directory slot points to the infimum record and +the last to the supremum. This function is intended to track if the +bug fixed in 4.0.14 has caused corruption to users' databases. */ + +void +page_check_dir( +/*===========*/ + page_t* page) /* in: index page */ +{ + ulint n_slots; + + n_slots = page_dir_get_n_slots(page); + + if (page_dir_slot_get_rec(page_dir_get_nth_slot(page, 0)) + != page_get_infimum_rec(page)) { + + fprintf(stderr, +"InnoDB: Page directory corruption: supremum not pointed to\n"); + buf_page_print(page); + } + + if (page_dir_slot_get_rec(page_dir_get_nth_slot(page, n_slots - 1)) + != page_get_supremum_rec(page)) { + + fprintf(stderr, +"InnoDB: Page directory corruption: supremum not pointed to\n"); + buf_page_print(page); + } +} /******************************************************************* This function checks the consistency of an index page when we do not @@ -1598,7 +1652,8 @@ page_validate( "InnoDB: previous record %s\n", err_buf); rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); + fprintf(stderr, + "InnoDB: record %s\n", err_buf); goto func_exit; } diff --git a/innobase/pars/pars0opt.c b/innobase/pars/pars0opt.c index 91083e6fa16..4faf83b47a3 100644 --- a/innobase/pars/pars0opt.c +++ b/innobase/pars/pars0opt.c @@ -1058,7 +1058,6 @@ opt_clust_access( dfield_t* dfield; mem_heap_t* heap; ulint n_fields; - ulint col_no; ulint pos; ulint i; @@ -1093,8 +1092,7 @@ opt_clust_access( plan->clust_map = mem_heap_alloc(heap, n_fields * sizeof(ulint)); for (i = 0; i < n_fields; i++) { - col_no = dict_index_get_nth_col_no(clust_index, i); - pos = dict_index_get_nth_col_pos(index, col_no); + pos = dict_index_get_nth_field_pos(index, clust_index, i); *(plan->clust_map + i) = pos; @@ -1109,7 +1107,8 @@ opt_clust_access( dfield = dtuple_get_nth_field(plan->clust_ref, table->mix_len); - dfield_set_data(dfield, mem_heap_alloc(heap, table->mix_id_len), + dfield_set_data(dfield, mem_heap_alloc(heap, + table->mix_id_len), table->mix_id_len); ut_memcpy(dfield_get_data(dfield), table->mix_id_buf, table->mix_id_len); diff --git a/innobase/pars/pars0pars.c b/innobase/pars/pars0pars.c index 664f498ef3e..3e43b6ae262 100644 --- a/innobase/pars/pars0pars.c +++ b/innobase/pars/pars0pars.c @@ -244,13 +244,11 @@ pars_resolve_func_data_type( /* Inherit the data type from the first argument (which must not be the SQL null literal whose type is DATA_ERROR) */ - ut_a(dtype_get_mtype(que_node_get_data_type(arg)) - != DATA_ERROR); dtype_copy(que_node_get_data_type(node), que_node_get_data_type(arg)); - ut_a(dtype_get_mtype(que_node_get_data_type(node)) == DATA_INT); - + ut_a(dtype_get_mtype(que_node_get_data_type(node)) + == DATA_INT); } else if (func == PARS_COUNT_TOKEN) { ut_a(arg); dtype_set(que_node_get_data_type(node), DATA_INT, 0, 4, 0); @@ -1596,7 +1594,7 @@ pars_create_index( column = column_list; while (column) { - dict_mem_index_add_field(index, column->name, 0); + dict_mem_index_add_field(index, column->name, 0, 0); column->resolved = TRUE; column->token_type = SYM_COLUMN; diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c index e9740d7ea78..2e18e68ec43 100644 --- a/innobase/rem/rem0cmp.c +++ b/innobase/rem/rem0cmp.c @@ -38,7 +38,7 @@ Used in debug checking of cmp_dtuple_... . This function is used to compare a data tuple to a physical record. If dtuple has n fields then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. */ -static + int cmp_debug_dtuple_rec_with_match( /*============================*/ @@ -50,9 +50,10 @@ cmp_debug_dtuple_rec_with_match( dtuple in some of the common fields, or which has an equal number or more fields than dtuple */ - ulint* matched_fields);/* in/out: number of already completely - matched fields; when function returns, - contains the value for current comparison */ + ulint* matched_fields);/* in/out: number of already + completely matched fields; when function + returns, contains the value for current + comparison */ /***************************************************************** This function is used to compare two data fields for which the data type is such that we must use MySQL code to compare them. The prototype here @@ -79,17 +80,12 @@ UNIV_INLINE ulint cmp_collate( /*========*/ - /* out: collation order position */ - dtype_t* type __attribute__((unused)) , /* in: type */ - ulint code) /* in: code of a character stored in database - record */ -{ - ut_ad((type->mtype == DATA_CHAR) || (type->mtype == DATA_VARCHAR)); - + /* out: collation order position */ + ulint code) /* in: code of a character stored in database record */ +{ return((ulint) srv_latin1_ordering[code]); } - /***************************************************************** Returns TRUE if two types are equal for comparison purposes. */ @@ -118,7 +114,8 @@ cmp_types_are_equal( if (type1->mtype == DATA_INT && (type1->prtype & DATA_UNSIGNED) - != (type2->prtype & DATA_UNSIGNED)) { + != (type2->prtype & DATA_UNSIGNED)) { + /* The storage format of an unsigned integer is different from a signed integer: in a signed integer we OR 0x8000... to the value of positive integers. */ @@ -131,12 +128,17 @@ cmp_types_are_equal( return(FALSE); } + if (type1->mtype == DATA_BLOB && (type1->prtype & DATA_BINARY_TYPE) + != (type2->prtype & DATA_BINARY_TYPE)) { + return(FALSE); + } + return(TRUE); } /***************************************************************** -Innobase uses this function is to compare two data fields for which the -data type is such that we must compare whole fields. */ +Innobase uses this function to compare two data fields for which the data type +is such that we must compare whole fields or call MySQL to do the comparison */ static int cmp_whole_field( @@ -239,8 +241,34 @@ cmp_whole_field( return(0); case DATA_VARMYSQL: case DATA_MYSQL: + case DATA_BLOB: + if (data_type == DATA_BLOB + && 0 != (type->prtype & DATA_BINARY_TYPE)) { + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: comparing a binary BLOB with a character set sensitive\n" +"InnoDB: comparison!\n"); + } + + /* MySQL does not pad the ends of strings with spaces in a + comparison. That would cause a foreign key check to fail for + non-latin1 character sets if we have different length columns. + To prevent that we remove trailing spaces here before doing + the comparison. NOTE that if we in the future map more MySQL + types to DATA_MYSQL or DATA_VARMYSQL, we have to change this + code. */ + + while (a_length > 0 && a[a_length - 1] == ' ') { + a_length--; + } + + while (b_length > 0 && b[b_length - 1] == ' ') { + b_length--; + } + return(innobase_mysql_cmp( - (int)(type->prtype & ~DATA_NOT_NULL), + (int)(type->prtype & DATA_MYSQL_TYPE_MASK), a, a_length, b, b_length)); default: fprintf(stderr, @@ -291,7 +319,10 @@ cmp_data_data_slow( return(1); } - if (cur_type->mtype >= DATA_FLOAT) { + if (cur_type->mtype >= DATA_FLOAT + || (cur_type->mtype == DATA_BLOB + && (cur_type->prtype & DATA_NONLATIN1))) { + return(cmp_whole_field(cur_type, data1, len1, data2, len2)); } @@ -334,9 +365,12 @@ cmp_data_data_slow( goto next_byte; } - if (cur_type->mtype <= DATA_CHAR) { - data1_byte = cmp_collate(cur_type, data1_byte); - data2_byte = cmp_collate(cur_type, data2_byte); + if (cur_type->mtype <= DATA_CHAR + || (cur_type->mtype == DATA_BLOB + && 0 == (cur_type->prtype & DATA_BINARY_TYPE))) { + + data1_byte = cmp_collate(data1_byte); + data2_byte = cmp_collate(data2_byte); } if (data1_byte > data2_byte) { @@ -487,7 +521,9 @@ cmp_dtuple_rec_with_match( } } - if (cur_type->mtype >= DATA_FLOAT) { + if (cur_type->mtype >= DATA_FLOAT + || (cur_type->mtype == DATA_BLOB + && (cur_type->prtype & DATA_NONLATIN1))) { ret = cmp_whole_field(cur_type, dfield_get_data(dtuple_field), dtuple_f_len, @@ -547,10 +583,13 @@ cmp_dtuple_rec_with_match( goto next_byte; } - if (cur_type->mtype <= DATA_CHAR) { - rec_byte = cmp_collate(cur_type, rec_byte); - dtuple_byte = cmp_collate(cur_type, - dtuple_byte); + if (cur_type->mtype <= DATA_CHAR + || (cur_type->mtype == DATA_BLOB + && 0 == + (cur_type->prtype & DATA_BINARY_TYPE))) { + + rec_byte = cmp_collate(rec_byte); + dtuple_byte = cmp_collate(dtuple_byte); } if (dtuple_byte > rec_byte) { @@ -583,8 +622,8 @@ order_resolved: matched_fields)); ut_ad(*matched_fields == cur_field); /* In the debug version, the above cmp_debug_... sets - *matched_fields to a value */ - *matched_fields = cur_field; + *matched_fields to a value */ + *matched_fields = cur_field; *matched_bytes = cur_bytes; return(ret); @@ -804,7 +843,10 @@ cmp_rec_rec_with_match( } } - if (cur_type->mtype >= DATA_FLOAT) { + if (cur_type->mtype >= DATA_FLOAT + || (cur_type->mtype == DATA_BLOB + && (cur_type->prtype & DATA_NONLATIN1))) { + ret = cmp_whole_field(cur_type, rec1_b_ptr, rec1_f_len, rec2_b_ptr, rec2_f_len); @@ -861,9 +903,13 @@ cmp_rec_rec_with_match( goto next_byte; } - if (cur_type->mtype <= DATA_CHAR) { - rec1_byte = cmp_collate(cur_type, rec1_byte); - rec2_byte = cmp_collate(cur_type, rec2_byte); + if (cur_type->mtype <= DATA_CHAR + || (cur_type->mtype == DATA_BLOB + && 0 == + (cur_type->prtype & DATA_BINARY_TYPE))) { + + rec1_byte = cmp_collate(rec1_byte); + rec2_byte = cmp_collate(rec2_byte); } if (rec1_byte < rec2_byte) { @@ -906,7 +952,7 @@ This function is used to compare a data tuple to a physical record. If dtuple has n fields then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If encounters an externally stored field, returns 0. */ -static + int cmp_debug_dtuple_rec_with_match( /*============================*/ @@ -918,9 +964,10 @@ cmp_debug_dtuple_rec_with_match( dtuple in some of the common fields, or which has an equal number or more fields than dtuple */ - ulint* matched_fields) /* in/out: number of already completely - matched fields; when function returns, - contains the value for current comparison */ + ulint* matched_fields) /* in/out: number of already + completely matched fields; when function + returns, contains the value for current + comparison */ { dtype_t* cur_type; /* pointer to type of the current field in dtuple */ diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index e96c08a715b..e02859bc851 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -217,8 +217,8 @@ ins_node_set_new_row( } /*********************************************************************** -Does an insert operation by updating a delete marked existing record -in the index. This situation can occur if the delete marked record is +Does an insert operation by updating a delete-marked existing record +in the index. This situation can occur if the delete-marked record is kept in the index for consistent reads. */ static ulint @@ -240,9 +240,9 @@ row_ins_sec_index_entry_by_modify( ut_ad((cursor->index->type & DICT_CLUSTERED) == 0); ut_ad(rec_get_deleted_flag(rec)); - /* We know that in the ordering entry and rec are identified. - But in their binary form there may be differences if there - are char fields in them. Therefore we have to calculate the + /* We know that in the alphabetical ordering, entry and rec are + identical. But in their binary form there may be differences if + there are char fields in them. Therefore we have to calculate the difference and do an update-in-place if necessary. */ heap = mem_heap_create(1024); @@ -305,8 +305,8 @@ row_ins_clust_index_entry_by_modify( /* Try optimistic updating of the record, keeping changes within the page */ - err = btr_cur_optimistic_update(0, cursor, update, 0, thr, mtr); - + err = btr_cur_optimistic_update(0, cursor, update, 0, thr, + mtr); if (err == DB_OVERFLOW || err == DB_UNDERFLOW) { err = DB_FAIL; } @@ -364,11 +364,17 @@ row_ins_cascade_calc_update_vec( /* out: number of fields in the calculated update vector; the value can also be 0 if no foreign key - fields changed */ + fields changed; the returned value + is ULINT_UNDEFINED if the column + type in the child table is too short + to fit the new value in the parent + table: that means the update fails */ upd_node_t* node, /* in: update node of the parent table */ - dict_foreign_t* foreign) /* in: foreign key constraint whose + dict_foreign_t* foreign, /* in: foreign key constraint whose type is != 0 */ + mem_heap_t* heap) /* in: memory heap to use as + temporary storage */ { upd_node_t* cascade = node->cascade_node; dict_table_t* table = foreign->foreign_table; @@ -381,14 +387,16 @@ row_ins_cascade_calc_update_vec( upd_field_t* parent_ufield; ulint n_fields_updated; ulint parent_field_no; + dtype_t* type; ulint i; ulint j; ut_a(node && foreign && cascade && table && index); /* Calculate the appropriate update vector which will set the fields - in the child index record to the same value as the referenced index - record will get in the update. */ + in the child index record to the same value (possibly padded with + spaces if the column is a fixed length CHAR or FIXBINARY column) as + the referenced index record will get in the update. */ parent_table = node->table; ut_a(parent_table == foreign->referenced_table); @@ -424,7 +432,56 @@ row_ins_cascade_calc_update_vec( dict_table_get_nth_col_pos(table, dict_index_get_nth_col_no(index, i)); ufield->exp = NULL; + ufield->new_val = parent_ufield->new_val; + + type = dict_index_get_nth_type(index, i); + + /* Do not allow a NOT NULL column to be + updated as NULL */ + + if (ufield->new_val.len == UNIV_SQL_NULL + && (type->prtype & DATA_NOT_NULL)) { + + return(ULINT_UNDEFINED); + } + + /* If the new value would not fit in the + column, do not allow the update */ + + if (ufield->new_val.len != UNIV_SQL_NULL + && ufield->new_val.len + > dtype_get_len(type)) { + + return(ULINT_UNDEFINED); + } + + /* If the parent column type has a different + length than the child column type, we may + need to pad with spaces the new value of the + child column */ + + if (dtype_is_fixed_size(type) + && ufield->new_val.len != UNIV_SQL_NULL + && ufield->new_val.len + < dtype_get_fixed_size(type)) { + + ufield->new_val.data = + mem_heap_alloc(heap, + dtype_get_fixed_size(type)); + ufield->new_val.len = + dtype_get_fixed_size(type); + ut_a(dtype_get_pad_char(type) + != ULINT_UNDEFINED); + + memset(ufield->new_val.data, + (byte)dtype_get_pad_char(type), + dtype_get_fixed_size(type)); + ut_memcpy(ufield->new_val.data, + parent_ufield->new_val.data, + parent_ufield->new_val.len); + } + ufield->extern_storage = FALSE; n_fields_updated++; @@ -570,9 +627,11 @@ row_ins_foreign_check_on_constraint( dict_index_t* clust_index; dtuple_t* ref; mem_heap_t* tmp_heap; + mem_heap_t* upd_vec_heap = NULL; rec_t* rec; rec_t* clust_rec; upd_t* update; + ulint n_to_update; ulint err; ulint i; char* ptr; @@ -597,8 +656,10 @@ row_ins_foreign_check_on_constraint( *ptr = '\0'; /* We call a function in ha_innodb.cc */ +#ifndef UNIV_HOTBACKUP innobase_invalidate_query_cache(thr_get_trx(thr), table_name_buf, ut_strlen(table->name) + 1); +#endif node = thr->run_node; if (node->is_delete && 0 == (foreign->type & @@ -730,27 +791,30 @@ row_ins_foreign_check_on_constraint( mem_heap_free(tmp_heap); clust_rec = btr_pcur_get_rec(cascade->pcur); - } - if (!page_rec_is_user_rec(clust_rec)) { - fprintf(stderr, + if (!page_rec_is_user_rec(clust_rec) + || btr_pcur_get_low_match(cascade->pcur) + < dict_index_get_n_unique(clust_index)) { + + fprintf(stderr, "InnoDB: error in cascade of a foreign key op\n" "InnoDB: index %s table %s\n", index->name, index->table->name); - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); + rec_sprintf(err_buf, 900, rec); + fprintf(stderr, "InnoDB: record %s\n", err_buf); - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clustered record %s\n", err_buf); - - fprintf(stderr, + rec_sprintf(err_buf, 900, clust_rec); + fprintf(stderr, "InnoDB: clustered record %s\n", + err_buf); + fprintf(stderr, "InnoDB: Make a detailed bug report and send it\n"); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); - err = DB_SUCCESS; + err = DB_SUCCESS; - goto nonstandard_exit_func; + goto nonstandard_exit_func; + } } /* Set an X-lock on the row to delete or update in the child table */ @@ -828,7 +892,21 @@ row_ins_foreign_check_on_constraint( /* Build the appropriate update vector which sets changing foreign->n_fields first fields in rec to new values */ - row_ins_cascade_calc_update_vec(node, foreign); + upd_vec_heap = mem_heap_create(256); + + n_to_update = row_ins_cascade_calc_update_vec(node, foreign, + upd_vec_heap); + if (n_to_update == ULINT_UNDEFINED) { + err = DB_ROW_IS_REFERENCED; + + row_ins_foreign_report_err( +(char*)"Trying a cascaded update where the updated value in the child\n" +"table would not fit in the length of the column, or the value would\n" +"be NULL and the column is declared as not NULL in the child table,", + thr, foreign, btr_pcur_get_rec(pcur), entry); + + goto nonstandard_exit_func; + } if (cascade->update->n_fields == 0) { @@ -867,10 +945,18 @@ row_ins_foreign_check_on_constraint( btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr); + if (upd_vec_heap) { + mem_heap_free(upd_vec_heap); + } + return(err); nonstandard_exit_func: + if (upd_vec_heap) { + mem_heap_free(upd_vec_heap); + } + btr_pcur_store_position(pcur, mtr); mtr_commit(mtr); @@ -1275,6 +1361,11 @@ row_ins_unique_report_err( dtuple_t* entry, /* in: index entry to insert in the index */ dict_index_t* index) /* in: index */ { + UT_NOT_USED(thr); + UT_NOT_USED(rec); + UT_NOT_USED(entry); + UT_NOT_USED(index); + #ifdef notdefined /* Disable reporting to test if the slowdown of REPLACE in 4.0.13 was caused by this! */ @@ -1816,7 +1907,7 @@ row_ins_index_entry( /* Try first optimistic descent to the B-tree */ err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry, - ext_vec, n_ext_vec, thr); + ext_vec, n_ext_vec, thr); if (err != DB_FAIL) { return(err); @@ -1832,13 +1923,15 @@ row_ins_index_entry( /*************************************************************** Sets the values of the dtuple fields in entry from the values of appropriate columns in row. */ -UNIV_INLINE +static void row_ins_index_entry_set_vals( /*=========================*/ + dict_index_t* index, /* in: index */ dtuple_t* entry, /* in: index entry to make */ dtuple_t* row) /* in: row */ { + dict_field_t* ind_field; dfield_t* field; dfield_t* row_field; ulint n_fields; @@ -1850,11 +1943,21 @@ row_ins_index_entry_set_vals( for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(entry, i); + ind_field = dict_index_get_nth_field(index, i); + + row_field = dtuple_get_nth_field(row, ind_field->col->ind); - row_field = dtuple_get_nth_field(row, field->col_no); + /* Check column prefix indexes */ + if (ind_field->prefix_len > 0 + && dfield_get_len(row_field) != UNIV_SQL_NULL + && dfield_get_len(row_field) > ind_field->prefix_len) { + + field->len = ind_field->prefix_len; + } else { + field->len = row_field->len; + } field->data = row_field->data; - field->len = row_field->len; } } @@ -1873,7 +1976,7 @@ row_ins_index_entry_step( ut_ad(dtuple_check_typed(node->row)); - row_ins_index_entry_set_vals(node->entry, node->row); + row_ins_index_entry_set_vals(node->index, node->entry, node->row); ut_ad(dtuple_check_typed(node->entry)); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 6d1f6f6e40e..35305b037c6 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -89,9 +89,6 @@ row_mysql_store_blob_ref( also to set the NULL bit in the MySQL record header! */ { - ulint sum = 0; - ulint i; - /* MySQL might assume the field is set to zero except the length and the pointer fields */ @@ -106,22 +103,6 @@ row_mysql_store_blob_ref( ut_a(col_len - 8 > 2 || len < 256 * 256); ut_a(col_len - 8 > 3 || len < 256 * 256 * 256); - /* We try to track an elusive bug which probably was fixed - May 9, 2002, but better be sure: we probe the data buffer - to make sure it is in valid allocated memory */ - - for (i = 0; i < len; i++) { - - sum += (ulint)(data + i); - } - - /* The variable below is identically false, we just fool the - compiler to not optimize away our loop */ - if (row_mysql_identically_false) { - - printf("Sum %lu\n", sum); - } - mach_write_to_n_little_endian(dest, col_len - 8, len); ut_memcpy(dest + col_len - 8, (byte*)&data, sizeof(byte*)); @@ -539,6 +520,7 @@ row_get_prebuilt_insert_row( ins_node_t* node; dtuple_t* row; dict_table_t* table = prebuilt->table; + ulint i; ut_ad(prebuilt && table && prebuilt->trx); @@ -562,6 +544,14 @@ row_get_prebuilt_insert_row( dict_table_copy_types(row, table); + /* We init the value of every field to the SQL NULL to avoid + a debug assertion from failing */ + + for (i = 0; i < dtuple_get_n_fields(row); i++) { + + dtuple_get_nth_field(row, i)->len = UNIV_SQL_NULL; + } + ins_node_set_new_row(node, row); prebuilt->ins_graph = @@ -965,7 +955,8 @@ row_update_for_mysql( if (prebuilt->pcur->btr_cur.index == clust_index) { btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur); } else { - btr_pcur_copy_stored_position(node->pcur, prebuilt->clust_pcur); + btr_pcur_copy_stored_position(node->pcur, + prebuilt->clust_pcur); } ut_a(node->pcur->rel_pos == BTR_PCUR_ON); @@ -1490,8 +1481,7 @@ row_create_index_for_mysql( ulint namelen; ulint keywordlen; ulint err; - ulint i; - ulint j; + ulint i, j; ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1499,23 +1489,9 @@ row_create_index_for_mysql( trx->op_info = (char *) "creating index"; - trx_start_if_not_started(trx); - - namelen = ut_strlen(index->table_name); - - keywordlen = ut_strlen("_recover_innodb_tmp_table"); - - if (namelen >= keywordlen - && 0 == ut_memcmp( - index->table_name + namelen - keywordlen, - (char*)"_recover_innodb_tmp_table", keywordlen)) { - - return(DB_SUCCESS); - } - /* Check that the same column does not appear twice in the index. - InnoDB assumes this in its algorithms, e.g., update of an index - entry */ + Starting from 4.0.14 InnoDB should be able to cope with that, but + safer not to allow them. */ for (i = 0; i < dict_index_get_n_fields(index); i++) { for (j = 0; j < i; j++) { @@ -1538,6 +1514,20 @@ row_create_index_for_mysql( } } + trx_start_if_not_started(trx); + + namelen = ut_strlen(index->table_name); + + keywordlen = ut_strlen("_recover_innodb_tmp_table"); + + if (namelen >= keywordlen + && 0 == ut_memcmp( + index->table_name + namelen - keywordlen, + (char*)"_recover_innodb_tmp_table", keywordlen)) { + + return(DB_SUCCESS); + } + heap = mem_heap_create(512); trx->dict_operation = TRUE; @@ -1555,6 +1545,7 @@ row_create_index_for_mysql( que_graph_free((que_t*) que_node_get_parent(thr)); error_handling: + if (err != DB_SUCCESS) { /* We have special error handling here */ @@ -1677,7 +1668,7 @@ row_drop_table_for_mysql_in_background( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); trx_commit_for_mysql(trx); @@ -1959,7 +1950,8 @@ row_drop_table_for_mysql( " found := 0;\n" " ELSE" " DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n" - " DELETE FROM SYS_INDEXES WHERE ID = index_id;\n" + " DELETE FROM SYS_INDEXES WHERE ID = index_id\n" + " AND TABLE_ID = table_id;\n" " END IF;\n" "END LOOP;\n" "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n" @@ -2554,7 +2546,7 @@ loop: prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); - ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT); + ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT); goto loop; } diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c index 40a775143f4..6c0c6c04cd5 100644 --- a/innobase/row/row0row.c +++ b/innobase/row/row0row.c @@ -136,7 +136,14 @@ row_build_index_entry( dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col)); dfield_copy(dfield, dfield2); - dfield->col_no = dict_col_get_no(col); + + /* If a column prefix index, take only the prefix */ + if (ind_field->prefix_len > 0 + && dfield_get_len(dfield2) != UNIV_SQL_NULL + && dfield_get_len(dfield2) > ind_field->prefix_len) { + + dfield_set_len(dfield, ind_field->prefix_len); + } } ut_ad(dtuple_check_typed(entry)); @@ -146,8 +153,7 @@ row_build_index_entry( /*********************************************************************** An inverse function to dict_row_build_index_entry. Builds a row from a -record in a clustered index. NOTE that externally stored (often big) -fields are always copied to heap. */ +record in a clustered index. */ dtuple_t* row_build( @@ -172,6 +178,7 @@ row_build( { dtuple_t* row; dict_table_t* table; + dict_field_t* ind_field; dict_col_t* col; dfield_t* dfield; ulint n_fields; @@ -204,19 +211,24 @@ row_build( dict_table_copy_types(row, table); for (i = 0; i < n_fields; i++) { + ind_field = dict_index_get_nth_field(index, i); - col = dict_field_get_col(dict_index_get_nth_field(index, i)); - dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); - field = rec_get_nth_field(rec, i, &len); + if (ind_field->prefix_len == 0) { - if (type == ROW_COPY_ALSO_EXTERNALS - && rec_get_nth_field_extern_bit(rec, i)) { + col = dict_field_get_col(ind_field); + dfield = dtuple_get_nth_field(row, + dict_col_get_no(col)); + field = rec_get_nth_field(rec, i, &len); - field = btr_rec_copy_externally_stored_field(rec, - i, &len, heap); - } + if (type == ROW_COPY_ALSO_EXTERNALS + && rec_get_nth_field_extern_bit(rec, i)) { - dfield_set_data(dfield, field, len); + field = btr_rec_copy_externally_stored_field( + rec, i, &len, heap); + } + + dfield_set_data(dfield, field, len); + } } ut_ad(dtuple_check_typed(row)); @@ -371,7 +383,6 @@ row_build_row_ref( dict_table_t* table; dict_index_t* clust_index; dfield_t* dfield; - dict_col_t* col; dtuple_t* ref; byte* field; ulint len; @@ -403,24 +414,13 @@ row_build_row_ref( for (i = 0; i < ref_len; i++) { dfield = dtuple_get_nth_field(ref, i); - col = dict_field_get_col( - dict_index_get_nth_field(clust_index, i)); - pos = dict_index_get_nth_col_pos(index, dict_col_get_no(col)); + pos = dict_index_get_nth_field_pos(index, clust_index, i); - if (pos != ULINT_UNDEFINED) { - field = rec_get_nth_field(rec, pos, &len); + ut_a(pos != ULINT_UNDEFINED); + + field = rec_get_nth_field(rec, pos, &len); - dfield_set_data(dfield, field, len); - } else { - ut_ad(table->type == DICT_TABLE_CLUSTER_MEMBER); - ut_ad(i == table->mix_len); - - dfield_set_data(dfield, - mem_heap_alloc(heap, table->mix_id_len), - table->mix_id_len); - ut_memcpy(dfield_get_data(dfield), table->mix_id_buf, - table->mix_id_len); - } + dfield_set_data(dfield, field, len); } ut_ad(dtuple_check_typed(ref)); @@ -448,7 +448,6 @@ row_build_row_ref_in_tuple( dict_table_t* table; dict_index_t* clust_index; dfield_t* dfield; - dict_col_t* col; byte* field; ulint len; ulint ref_len; @@ -483,19 +482,13 @@ row_build_row_ref_in_tuple( for (i = 0; i < ref_len; i++) { dfield = dtuple_get_nth_field(ref, i); - col = dict_field_get_col( - dict_index_get_nth_field(clust_index, i)); - pos = dict_index_get_nth_col_pos(index, dict_col_get_no(col)); + pos = dict_index_get_nth_field_pos(index, clust_index, i); - if (pos != ULINT_UNDEFINED) { - field = rec_get_nth_field(rec, pos, &len); + ut_a(pos != ULINT_UNDEFINED); + + field = rec_get_nth_field(rec, pos, &len); - dfield_set_data(dfield, field, len); - } else { - ut_ad(table->type == DICT_TABLE_CLUSTER_MEMBER); - ut_ad(i == table->mix_len); - ut_a(0); - } + dfield_set_data(dfield, field, len); } ut_ad(dtuple_check_typed(ref)); @@ -517,6 +510,7 @@ row_build_row_ref_from_row( directly into data of this row */ { dict_index_t* clust_index; + dict_field_t* field; dfield_t* dfield; dfield_t* dfield2; dict_col_t* col; @@ -533,13 +527,21 @@ row_build_row_ref_from_row( for (i = 0; i < ref_len; i++) { dfield = dtuple_get_nth_field(ref, i); - - col = dict_field_get_col( - dict_index_get_nth_field(clust_index, i)); - + + field = dict_index_get_nth_field(clust_index, i); + + col = dict_field_get_col(field); + dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col)); dfield_copy(dfield, dfield2); + + if (field->prefix_len > 0 + && dfield->len != UNIV_SQL_NULL + && dfield->len > field->prefix_len) { + + dfield->len = field->prefix_len; + } } ut_ad(dtuple_check_typed(ref)); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 97a69f76eaa..81bbf5053c0 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -65,41 +65,50 @@ row_sel_sec_rec_is_for_clust_rec( rec_t* sec_rec, /* in: secondary index record */ dict_index_t* sec_index, /* in: secondary index */ rec_t* clust_rec, /* in: clustered index record */ - dict_index_t* clust_index __attribute__((unused))) - /* in: clustered index */ + dict_index_t* clust_index) /* in: clustered index */ { - dict_col_t* col; - byte* sec_field; - ulint sec_len; - byte* clust_field; - ulint clust_len; - ulint n; - ulint i; + dict_field_t* ifield; + dict_col_t* col; + byte* sec_field; + ulint sec_len; + byte* clust_field; + ulint clust_len; + ulint n; + ulint i; - n = dict_index_get_n_ordering_defined_by_user(sec_index); + UT_NOT_USED(clust_index); - for (i = 0; i < n; i++) { - col = dict_field_get_col( - dict_index_get_nth_field(sec_index, i)); + n = dict_index_get_n_ordering_defined_by_user(sec_index); - clust_field = rec_get_nth_field(clust_rec, - dict_col_get_clust_pos(col), - &clust_len); - sec_field = rec_get_nth_field(sec_rec, i, &sec_len); + for (i = 0; i < n; i++) { + ifield = dict_index_get_nth_field(sec_index, i); + col = dict_field_get_col(ifield); + + clust_field = rec_get_nth_field(clust_rec, + dict_col_get_clust_pos(col), + &clust_len); + sec_field = rec_get_nth_field(sec_rec, i, &sec_len); - if (sec_len != clust_len) { + if (ifield->prefix_len > 0 + && clust_len != UNIV_SQL_NULL + && clust_len > ifield->prefix_len) { - return(FALSE); + clust_len = ifield->prefix_len; } - if (0 != cmp_data_data(dict_col_get_type(col), - clust_field, clust_len, - sec_field, sec_len)) { - return(FALSE); - } - } + if (sec_len != clust_len) { - return(TRUE); + return(FALSE); + } + + if (0 != cmp_data_data(dict_col_get_type(col), + clust_field, clust_len, + sec_field, sec_len)) { + return(FALSE); + } + } + + return(TRUE); } /************************************************************************* @@ -600,13 +609,35 @@ row_sel_get_clust_rec( clust_rec = btr_pcur_get_rec(&(plan->clust_pcur)); - ut_ad(page_rec_is_user_rec(clust_rec)); + /* Note: only if the search ends up on a non-infimum record is the + low_match value the real match to the search tuple */ + + if (!page_rec_is_user_rec(clust_rec) + || btr_pcur_get_low_match(&(plan->clust_pcur)) + < dict_index_get_n_unique(index)) { + + ut_a(rec_get_deleted_flag(rec)); + ut_a(node->read_view); + + /* In a rare case it is possible that no clust rec is found + for a delete-marked secondary index record: if in row0umod.c + in row_undo_mod_remove_clust_low() we have already removed + the clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case we know that the + clustered index record did not exist in the read view of + trx. */ + + clust_rec = NULL; + + goto func_exit; + } if (!node->read_view) { /* Try to place a lock on the index record */ err = lock_clust_rec_read_check_and_lock(0, clust_rec, index, - node->row_lock_mode, LOCK_ORDINARY, thr); + node->row_lock_mode, LOCK_ORDINARY, thr); if (err != DB_SUCCESS) { return(err); @@ -656,13 +687,14 @@ row_sel_get_clust_rec( *out_rec = clust_rec; return(DB_SUCCESS); - } + } } /* Fetch the columns needed in test conditions */ row_sel_fetch_columns(index, clust_rec, UT_LIST_GET_FIRST(plan->columns)); +func_exit: *out_rec = clust_rec; return(DB_SUCCESS); @@ -1244,6 +1276,8 @@ rec_loop: /* PHASE 3: Get previous version in a consistent read */ + cons_read_requires_clust_rec = FALSE; + if (consistent_read) { /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ @@ -1850,9 +1884,11 @@ row_printf_step( } /******************************************************************** -Converts a key value stored in MySQL format to an Innobase dtuple. -The last field of the key value may be just a prefix of a fixed length -field: hence the parameter key_len. */ +Converts a key value stored in MySQL format to an Innobase dtuple. The last +field of the key value may be just a prefix of a fixed length field: hence +the parameter key_len. But currently we do not allow search keys where the +last field is only a prefix of the full key field len and print a warning if +such appears. */ void row_sel_convert_mysql_key_to_innobase( @@ -1863,17 +1899,24 @@ row_sel_convert_mysql_key_to_innobase( to index! */ byte* buf, /* in: buffer to use in field conversions */ + ulint buf_len, /* in: buffer length */ dict_index_t* index, /* in: index of the key value */ byte* key_ptr, /* in: MySQL key value */ ulint key_len) /* in: MySQL key value length */ { + byte* original_buf = buf; + dict_field_t* field; dfield_t* dfield; - ulint offset; - ulint len; + ulint data_offset; + ulint data_len; + ulint data_field_len; + ibool is_null; byte* key_end; ulint n_fields = 0; + ulint type; - UT_NOT_USED(index); + /* For documentation of the key value storage format in MySQL, see + ha_innobase::store_key_val_for_row() in ha_innodb.cc. */ key_end = key_ptr + key_len; @@ -1882,11 +1925,14 @@ row_sel_convert_mysql_key_to_innobase( dtuple_set_n_fields(tuple, ULINT_MAX); dfield = dtuple_get_nth_field(tuple, 0); + field = dict_index_get_nth_field(index, 0); if (dfield_get_type(dfield)->mtype == DATA_SYS) { - /* A special case: we are looking for a position in a - generated clustered index: the first and the only - ordering column is ROW_ID */ + /* A special case: we are looking for a position in the + generated clustered index which InnoDB automatically added + to a table with no primary key: the first and the only + ordering column is ROW_ID which InnoDB stored to the key_ptr + buffer. */ ut_a(key_len == DATA_ROW_ID_LEN); @@ -1897,70 +1943,114 @@ row_sel_convert_mysql_key_to_innobase( return; } - while (key_ptr < key_end) { - offset = 0; - len = dfield_get_type(dfield)->len; + while (key_ptr < key_end) { - n_fields++; + ut_a(dict_col_get_type(field->col)->mtype + == dfield_get_type(dfield)->mtype); + + data_offset = 0; + is_null = FALSE; if (!(dfield_get_type(dfield)->prtype & DATA_NOT_NULL)) { /* The first byte in the field tells if this is an SQL NULL value */ - offset = 1; + data_offset = 1; - if (*key_ptr != 0) { + if (*key_ptr != 0) { dfield_set_data(dfield, NULL, UNIV_SQL_NULL); - goto next_part; + is_null = TRUE; } } - row_mysql_store_col_in_innobase_format( - dfield, buf, key_ptr + offset, len, - dfield_get_type(dfield)->mtype, + type = dfield_get_type(dfield)->mtype; + + /* Calculate data length and data field total length */ + + if (type == DATA_BLOB) { + /* The key field is a column prefix of a BLOB or + TEXT type column */ + + ut_a(field->prefix_len > 0); + + /* MySQL stores the actual data length to the first 2 + bytes after the optional SQL NULL marker byte. The + storage format is little-endian. */ + + /* There are no key fields > 255 bytes currently in + MySQL */ + if (key_ptr[data_offset + 1] != 0) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: BLOB or TEXT prefix > 255 bytes in query to table %s\n", + index->table_name); + } + + data_len = key_ptr[data_offset]; + data_field_len = data_offset + 2 + field->prefix_len; + data_offset += 2; + + type = DATA_CHAR; /* now that we know the length, we + store the column value like it would + be a fixed char field */ + } else if (field->prefix_len > 0) { + data_len = field->prefix_len; + data_field_len = data_offset + data_len; + } else { + data_len = dfield_get_type(dfield)->len; + data_field_len = data_offset + data_len; + } + + /* Storing may use at most data_len bytes of buf */ + + if (!is_null) { + row_mysql_store_col_in_innobase_format( + dfield, buf, key_ptr + data_offset, + data_len, type, dfield_get_type(dfield)->prtype & DATA_UNSIGNED); - next_part: - key_ptr += (offset + len); + buf += data_len; + } + + key_ptr += data_field_len; if (key_ptr > key_end) { - /* The last field in key was not a complete - field but a prefix of it. + /* The last field in key was not a complete key field + but a prefix of it. - Print a warning about this! HA_READ_PREFIX_LAST - does not currently work in InnoDB with partial-field - key value prefixes. Since MySQL currently uses a - padding trick to calculate LIKE 'abc%' type queries - there should never be partial-field prefixes - in searches. */ + Print a warning about this! HA_READ_PREFIX_LAST does + not currently work in InnoDB with partial-field key + value prefixes. Since MySQL currently uses a padding + trick to calculate LIKE 'abc%' type queries there + should never be partial-field prefixes in searches. */ ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Warning: using a partial-field key prefix in search\n"); - ut_ad(dfield_get_len(dfield) != UNIV_SQL_NULL); - - dfield_set_data(dfield, buf, - len - (ulint)(key_ptr - key_end)); + if (!is_null) { + dfield->len -= (ulint)(key_ptr - key_end); + } } - buf += len; - + n_fields++; + field++; dfield++; } - /* We set the length of tuple to n_fields: we assume that - the memory area allocated for it is big enough (usually - bigger than n_fields). */ + ut_a(buf <= original_buf + buf_len); + + /* We set the length of tuple to n_fields: we assume that the memory + area allocated for it is big enough (usually bigger than n_fields). */ dtuple_set_n_fields(tuple, n_fields); } /****************************************************************** Stores the row id to the prebuilt struct. */ -UNIV_INLINE +static void row_sel_store_row_id_to_prebuilt( /*=============================*/ @@ -1970,11 +2060,22 @@ row_sel_store_row_id_to_prebuilt( { byte* data; ulint len; + char err_buf[1000]; data = rec_get_nth_field(index_rec, dict_index_get_sys_col_pos(index, DATA_ROW_ID), &len); - ut_a(len == DATA_ROW_ID_LEN); + if (len != DATA_ROW_ID_LEN) { + rec_sprintf(err_buf, 900, index_rec); + + fprintf(stderr, +"InnoDB: Error: Row id field is wrong length %lu in table %s index %s\n" +"InnoDB: Field number %lu, record:\n%s\n", + len, index->table_name, index->name, + dict_index_get_sys_col_pos(index, DATA_ROW_ID), + err_buf); + ut_a(0); + } ut_memcpy(prebuilt->row_id, data, len); } @@ -2210,7 +2311,10 @@ row_sel_get_clust_rec_for_mysql( /* out: DB_SUCCESS or error code */ row_prebuilt_t* prebuilt,/* in: prebuilt struct in the handle */ dict_index_t* sec_index,/* in: secondary index where rec resides */ - rec_t* rec, /* in: record in a non-clustered index */ + rec_t* rec, /* in: record in a non-clustered index; if + this is a locking read, then rec is not + allowed to be delete-marked, and that would + not make sense either */ que_thr_t* thr, /* in: query thread */ rec_t** out_rec,/* out: clustered record or an old version of it, NULL if the old version did not exist @@ -2226,7 +2330,7 @@ row_sel_get_clust_rec_for_mysql( ulint err; trx_t* trx; char err_buf[1000]; - + *out_rec = NULL; row_build_row_ref_in_tuple(prebuilt->clust_ref, sec_index, rec); @@ -2239,26 +2343,47 @@ row_sel_get_clust_rec_for_mysql( clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur); - if (!page_rec_is_user_rec(clust_rec)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: error clustered record for sec rec not found\n" - "InnoDB: index %s table %s\n", sec_index->name, - sec_index->table->name); + /* Note: only if the search ends up on a non-infimum record is the + low_match value the real match to the search tuple */ - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: sec index record %s\n", err_buf); + if (!page_rec_is_user_rec(clust_rec) + || btr_pcur_get_low_match(prebuilt->clust_pcur) + < dict_index_get_n_unique(clust_index)) { + + /* In a rare case it is possible that no clust rec is found + for a delete-marked secondary index record: if in row0umod.c + in row_undo_mod_remove_clust_low() we have already removed + the clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case we know that the + clustered index record did not exist in the read view of + trx. */ - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clust index record %s\n", err_buf); + if (!rec_get_deleted_flag(rec) + || prebuilt->select_lock_type != LOCK_NONE) { - trx = thr_get_trx(thr); - trx_print(err_buf, trx); + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: error clustered record for sec rec not found\n" + "InnoDB: index %s table %s\n", sec_index->name, + sec_index->table->name); - fprintf(stderr, - "%s\nInnoDB: Make a detailed bug report and send it\n", - err_buf); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + rec_sprintf(err_buf, 900, rec); + fprintf(stderr, + "InnoDB: sec index record %s\n", err_buf); + + rec_sprintf(err_buf, 900, clust_rec); + fprintf(stderr, + "InnoDB: clust index record %s\n", err_buf); + + trx = thr_get_trx(thr); + trx_print(err_buf, trx); + + fprintf(stderr, + "%s\nInnoDB: Make a detailed bug report and send it\n", + err_buf); + fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + } clust_rec = NULL; @@ -2936,8 +3061,6 @@ rec_loop: /*-------------------------------------------------------------*/ /* PHASE 4: Look for matching records in a loop */ - cons_read_requires_clust_rec = FALSE; - rec = btr_pcur_get_rec(pcur); /* printf("Using index %s cnt %lu ", index->name, cnt); @@ -3044,7 +3167,7 @@ rec_loop: if (prebuilt->select_lock_type != LOCK_NONE && set_also_gap_locks) { - /* Try to place a lock on the index record */ + /* Try to place a lock on the index record */ err = sel_set_rec_lock(rec, index, prebuilt->select_lock_type, @@ -3092,6 +3215,8 @@ rec_loop: /* We are ready to look at a possible new index entry in the result set: the cursor is now placed on a user record */ + cons_read_requires_clust_rec = FALSE; + if (prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a lock on the index record; note that delete marked records are a special case in a unique search. If there @@ -3117,8 +3242,6 @@ rec_loop: /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ - cons_read_requires_clust_rec = FALSE; - if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) { /* Do nothing: we let a non-locking SELECT read the @@ -3162,7 +3285,7 @@ rec_loop: if (rec_get_deleted_flag(rec) && !cons_read_requires_clust_rec) { - /* The record is delete marked: we can skip it if this is + /* The record is delete-marked: we can skip it if this is not a consistent read which might see an earlier version of a non-clustered index record */ @@ -3275,7 +3398,7 @@ got_row: goto normal_return; next_rec: - /*-------------------------------------------------------------*/ + /*-------------------------------------------------------------*/ /* PHASE 5: Move the cursor to the next index record */ if (mtr_has_extra_clust_latch) { diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c index b84e55ca643..b22e494f891 100644 --- a/innobase/row/row0umod.c +++ b/innobase/row/row0umod.c @@ -428,7 +428,8 @@ row_undo_mod_del_unmark_sec( found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur, &mtr); if (!found) { - fprintf(stderr, "InnoDB: error in sec index entry del undo in\n" + fprintf(stderr, + "InnoDB: error in sec index entry del undo in\n" "InnoDB: index %s table %s\n", index->name, index->table->name); dtuple_sprintf(err_buf, 900, entry); @@ -570,7 +571,7 @@ row_undo_mod_upd_exist_sec( the row */ row_upd_index_replace_new_col_vals(entry, index, - node->update); + node->update, NULL); row_undo_mod_del_unmark_sec(node, thr, index, entry); } diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 5fce1c1861b..db68479509d 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -72,8 +72,9 @@ searched delete is obviously to keep the x-latch for several steps of query graph execution. */ /*************************************************************** -Checks if an update vector changes some of the first fields of an index -record. */ +Checks if an update vector changes some of the first ordering fields of an +index record. This is only used in foreign key checks and we can assume +that index does not contain column prefixes. */ static ibool row_upd_changes_first_fields( @@ -234,7 +235,8 @@ row_upd_check_references_constraints( if (err != DB_SUCCESS) { if (got_s_lock) { - row_mysql_unfreeze_data_dictionary(trx); + row_mysql_unfreeze_data_dictionary( + trx); } mem_heap_free(heap); @@ -350,14 +352,15 @@ row_upd_index_entry_sys_field( } /*************************************************************** -Returns TRUE if row update changes size of some field in index -or if some field to be updated is stored externally in rec or update. */ +Returns TRUE if row update changes size of some field in index or if some +field to be updated is stored externally in rec or update. */ ibool -row_upd_changes_field_size( -/*=======================*/ +row_upd_changes_field_size_or_external( +/*===================================*/ /* out: TRUE if the update changes the size of - some field in index */ + some field in index or the field is external + in rec or update */ rec_t* rec, /* in: record in clustered index */ dict_index_t* index, /* in: clustered index */ upd_t* update) /* in: update vector */ @@ -820,69 +823,55 @@ void row_upd_index_replace_new_col_vals( /*===============================*/ dtuple_t* entry, /* in/out: index entry where replaced */ - dict_index_t* index, /* in: index; NOTE that may also be a + dict_index_t* index, /* in: index; NOTE that this may also be a non-clustered index */ - upd_t* update) /* in: update vector */ + upd_t* update, /* in: update vector */ + mem_heap_t* heap) /* in: memory heap to which we allocate and + copy the new values, set this as NULL if you + do not want allocation */ { + dict_field_t* field; upd_field_t* upd_field; dfield_t* dfield; dfield_t* new_val; - ulint field_no; - dict_index_t* clust_index; + ulint j; ulint i; ut_ad(index); - clust_index = dict_table_get_first_index(index->table); - dtuple_set_info_bits(entry, update->info_bits); - for (i = 0; i < upd_get_n_fields(update); i++) { - - upd_field = upd_get_nth_field(update, i); - - field_no = dict_index_get_nth_col_pos(index, - dict_index_get_nth_col_no(clust_index, - upd_field->field_no)); - if (field_no != ULINT_UNDEFINED) { - dfield = dtuple_get_nth_field(entry, field_no); + for (j = 0; j < dict_index_get_n_fields(index); j++) { - new_val = &(upd_field->new_val); + field = dict_index_get_nth_field(index, j); - dfield_set_data(dfield, new_val->data, new_val->len); - } - } -} - -/*************************************************************** -Replaces the new column values stored in the update vector to the -clustered index entry given. */ - -void -row_upd_clust_index_replace_new_col_vals( -/*=====================================*/ - dtuple_t* entry, /* in/out: index entry where replaced */ - upd_t* update) /* in: update vector */ -{ - upd_field_t* upd_field; - dfield_t* dfield; - dfield_t* new_val; - ulint field_no; - ulint i; + for (i = 0; i < upd_get_n_fields(update); i++) { - dtuple_set_info_bits(entry, update->info_bits); + upd_field = upd_get_nth_field(update, i); - for (i = 0; i < upd_get_n_fields(update); i++) { + if (upd_field->field_no == field->col->clust_pos) { - upd_field = upd_get_nth_field(update, i); + dfield = dtuple_get_nth_field(entry, j); - field_no = upd_field->field_no; + new_val = &(upd_field->new_val); - dfield = dtuple_get_nth_field(entry, field_no); + dfield_set_data(dfield, new_val->data, + new_val->len); + if (heap && new_val->len != UNIV_SQL_NULL) { + dfield->data = mem_heap_alloc(heap, + new_val->len); + ut_memcpy(dfield->data, new_val->data, + new_val->len); + } - new_val = &(upd_field->new_val); + if (field->prefix_len > 0 + && new_val->len != UNIV_SQL_NULL + && new_val->len > field->prefix_len) { - dfield_set_data(dfield, new_val->data, new_val->len); + dfield->len = field->prefix_len; + } + } + } } } @@ -931,9 +920,15 @@ row_upd_changes_ord_field_binary( upd_field = upd_get_nth_field(update, j); + /* Note that if the index field is a column prefix + then it may be that row does not contain an externally + stored part of the column value, and we cannot compare + the datas */ + if (col_pos == upd_field->field_no - && (row == NULL - || !dfield_datas_are_binary_equal( + && (row == NULL + || ind_field->prefix_len > 0 + || !dfield_datas_are_binary_equal( dtuple_get_nth_field(row, col_no), &(upd_field->new_val)))) { return(TRUE); @@ -978,8 +973,9 @@ row_upd_changes_some_index_ord_field_binary( } /*************************************************************** -Checks if an update vector changes some of the first fields of an index -record. */ +Checks if an update vector changes some of the first ordering fields of an +index record. This is only used in foreign key checks and we can assume +that index does not contain column prefixes. */ static ibool row_upd_changes_first_fields( @@ -1013,9 +1009,10 @@ row_upd_changes_first_fields( upd_field = upd_get_nth_field(update, j); if (col_pos == upd_field->field_no - && cmp_dfield_dfield( + && (ind_field->prefix_len > 0 + || 0 != cmp_dfield_dfield( dtuple_get_nth_field(entry, i), - &(upd_field->new_val))) { + &(upd_field->new_val)))) { return(TRUE); } } @@ -1204,7 +1201,7 @@ close_cur: } /* Build a new index entry */ - row_upd_index_replace_new_col_vals(entry, index, node->update); + row_upd_index_replace_new_col_vals(entry, index, node->update, NULL); /* Insert new index entry */ err = row_ins_index_entry(index, entry, NULL, 0, thr); @@ -1317,12 +1314,12 @@ row_upd_clust_rec_by_insert( entry = row_build_index_entry(node->row, index, heap); - row_upd_clust_index_replace_new_col_vals(entry, node->update); + row_upd_index_replace_new_col_vals(entry, index, node->update, NULL); row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id); /* If we return from a lock wait, for example, we may have - extern fields marked as not-owned in entry (marked if the + extern fields marked as not-owned in entry (marked in the if-branch above). We must unmark them. */ btr_cur_unmark_dtuple_extern_fields(entry, node->ext_vec, @@ -1702,9 +1699,9 @@ function_exit: /* Do some cleanup */ if (node->row != NULL) { - mem_heap_empty(node->heap); node->row = NULL; node->n_ext_vec = 0; + mem_heap_empty(node->heap); } node->state = UPD_NODE_UPDATE_CLUSTERED; diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c index cd8b18e5e12..d4a463d8a96 100644 --- a/innobase/row/row0vers.c +++ b/innobase/row/row0vers.c @@ -27,6 +27,7 @@ Created 2/6/1997 Heikki Tuuri #include "row0upd.h" #include "rem0cmp.h" #include "read0read.h" +#include "lock0lock.h" /********************************************************************* Finds out if an active transaction has inserted or modified a secondary @@ -58,7 +59,6 @@ row_vers_impl_x_locked_off_kernel( ibool rec_del; ulint err; mtr_t mtr; - char err_buf[1000]; ut_ad(mutex_own(&kernel_mutex)); ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); @@ -76,22 +76,20 @@ row_vers_impl_x_locked_off_kernel( clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); if (!clust_rec) { - rec_sprintf(err_buf, 900, rec); - - ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: cannot find the clustered index record\n" -"InnoDB: for a secondary index record in table %s index %s.\n" -"InnoDB: Secondary index record %s.\n" -"InnoDB: The table is probably corrupt. Please run CHECK TABLE on it.\n" -"InnoDB: You can try to repair the table by dump + drop + reimport.\n" -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com.\n", - index->table_name, index->name, err_buf); - mutex_enter(&kernel_mutex); - mtr_commit(&mtr); - - /* We assume there is no lock on the record, though this - is not certain because the table is apparently corrupt */ + /* In a rare case it is possible that no clust rec is found + for a secondary index record: if in row0umod.c + row_undo_mod_remove_clust_low() we have already removed the + clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case there cannot be + any implicit lock on the secondary index record, because + an active transaction which has modified the secondary index + record has also modified the clustered index record. And in + a rollback we always undo the modifications to secondary index + records before the clustered index record. */ + + mutex_enter(&kernel_mutex); + mtr_commit(&mtr); return(NULL); } @@ -111,6 +109,14 @@ row_vers_impl_x_locked_off_kernel( return(NULL); } + if (!lock_check_trx_id_sanity(trx_id, clust_rec, clust_index, TRUE)) { + /* Corruption noticed: try to avoid a crash by returning */ + + mtr_commit(&mtr); + + return(NULL); + } + /* We look up if some earlier version of the clustered index record would require rec to be in a different state (delete marked or unmarked, or not existing). If there is such a version, then rec was @@ -177,7 +183,8 @@ row_vers_impl_x_locked_off_kernel( /* If we get here, we know that the trx_id transaction is still active and it has modified prev_version. Let us check - if prev_version would require rec to be in a different state. */ + if prev_version would require rec to be in a different + state. */ vers_del = rec_get_deleted_flag(prev_version); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 90331157289..a886cbee22a 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -298,6 +298,7 @@ ulint srv_test_n_mutexes = ULINT_MAX; i/o handler thread */ char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS]; +char* srv_io_thread_function[SRV_MAX_N_IO_THREADS]; time_t srv_last_monitor_time; @@ -1750,7 +1751,7 @@ srv_conc_enter_innodb( trx_t* trx) /* in: transaction object associated with the thread */ { - ibool has_slept = FALSE; + ibool has_slept = FALSE; srv_conc_slot_t* slot; ulint i; char err_buf[1000]; @@ -1769,9 +1770,9 @@ srv_conc_enter_innodb( return; } -retry: - os_fast_mutex_lock(&srv_conc_mutex); + os_fast_mutex_lock(&srv_conc_mutex); +retry: if (trx->declared_to_be_inside_innodb) { ut_print_timestamp(stderr); @@ -1780,6 +1781,9 @@ retry: fprintf(stderr, " InnoDB: Error: trying to declare trx to enter InnoDB, but\n" "InnoDB: it already is declared.\n%s\n", err_buf); + os_fast_mutex_unlock(&srv_conc_mutex); + + return; } if (srv_conc_n_threads < (lint)srv_thread_concurrency) { @@ -1793,21 +1797,31 @@ retry: return; } - /* If the transaction is not holding resources, let it sleep - for 100 milliseconds, and try again then */ - + /* If the transaction is not holding resources, let it sleep for 50 + milliseconds, and try again then */ + if (!has_slept && !trx->has_search_latch && NULL == UT_LIST_GET_FIRST(trx->trx_locks)) { - has_slept = TRUE; /* We let is sleep only once to avoid - starvation */ + has_slept = TRUE; /* We let is sleep only once to avoid + starvation */ + + srv_conc_n_waiting_threads++; + + os_fast_mutex_unlock(&srv_conc_mutex); + + trx->op_info = (char*)"sleeping before joining InnoDB queue"; + + os_thread_sleep(50000); - os_fast_mutex_unlock(&srv_conc_mutex); + trx->op_info = (char*)""; - os_thread_sleep(100000); + os_fast_mutex_lock(&srv_conc_mutex); + + srv_conc_n_waiting_threads--; goto retry; - } + } /* Too many threads inside: put the current thread to a queue */ @@ -2131,7 +2145,8 @@ srv_suspend_mysql_thread( os_event_t event; double wait_time; trx_t* trx; - ibool had_dict_lock = FALSE; + ibool had_dict_lock = FALSE; + ibool was_declared_inside_innodb = FALSE; ut_ad(!mutex_own(&kernel_mutex)); @@ -2179,11 +2194,16 @@ srv_suspend_mysql_thread( mutex_exit(&kernel_mutex); - /* We must declare this OS thread to exit InnoDB, since a possible - other thread holding a lock which this thread waits for must be - allowed to enter, sooner or later */ + if (trx->declared_to_be_inside_innodb) { + + was_declared_inside_innodb = TRUE; + + /* We must declare this OS thread to exit InnoDB, since a + possible other thread holding a lock which this thread waits + for must be allowed to enter, sooner or later */ - srv_conc_force_exit_innodb(thr_get_trx(thr)); + srv_conc_force_exit_innodb(trx); + } /* Release possible foreign key check latch */ if (trx->dict_operation_lock_mode == RW_S_LATCH) { @@ -2204,9 +2224,12 @@ srv_suspend_mysql_thread( row_mysql_freeze_data_dictionary(trx); } - /* Return back inside InnoDB */ + if (was_declared_inside_innodb) { + + /* Return back inside InnoDB */ - srv_conc_force_enter_innodb(thr_get_trx(thr)); + srv_conc_force_enter_innodb(trx); + } mutex_enter(&kernel_mutex); @@ -2302,6 +2325,7 @@ srv_sprintf_innodb_monitor( char* buf_end = buf + len - 2000; double time_elapsed; time_t current_time; + ulint n_reserved; mutex_enter(&srv_innodb_monitor_mutex); @@ -2429,12 +2453,21 @@ srv_sprintf_innodb_monitor( "ROW OPERATIONS\n" "--------------\n"); buf += sprintf(buf, - "%ld queries inside InnoDB, %ld queries in queue\n", + "%ld queries inside InnoDB, %lu queries in queue\n", srv_conc_n_threads, srv_conc_n_waiting_threads); + + n_reserved = fil_space_get_n_reserved_extents(0); + if (n_reserved > 0) { + buf += sprintf(buf, + "%lu tablespace extents now reserved for B-tree split operations\n", + n_reserved); + } + #ifdef UNIV_LINUX buf += sprintf(buf, - "Main thread process no %lu, state: %s\n", + "Main thread process no. %lu, id %lu, state: %s\n", srv_main_thread_process_no, + srv_main_thread_id, srv_main_thread_op_info); #else buf += sprintf(buf, @@ -2498,8 +2531,8 @@ srv_lock_timeout_and_monitor_thread( ulint i; #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Lock timeout thread starts\n"); - printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); + printf("Lock timeout thread starts, id %lu\n", + os_thread_pf(os_thread_get_curr_id())); #endif UT_NOT_USED(arg); srv_last_monitor_time = time(NULL); @@ -2671,8 +2704,8 @@ srv_error_monitor_thread( UT_NOT_USED(arg); #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Error monitor thread starts\n"); - printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); + printf("Error monitor thread starts, id %lu\n", + os_thread_pf(os_thread_get_curr_id())); #endif loop: srv_error_monitor_active = TRUE; @@ -2794,8 +2827,8 @@ srv_master_thread( UT_NOT_USED(arg); #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Master thread starts\n"); - printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); + printf("Master thread starts, id %lu\n", + os_thread_pf(os_thread_get_curr_id())); #endif srv_main_thread_process_no = os_proc_get_number(); srv_main_thread_id = os_thread_pf(os_thread_get_curr_id()); @@ -2868,7 +2901,7 @@ loop: at transaction commit */ srv_main_thread_op_info = (char*)"flushing log"; - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); /* If there were less than 5 i/os during the one second sleep, we assume that there is free @@ -2884,10 +2917,9 @@ loop: (char*)"doing insert buffer merge"; ibuf_contract_for_n_pages(TRUE, 5); - srv_main_thread_op_info = - (char*)"flushing log"; - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, - TRUE); + srv_main_thread_op_info = (char*)"flushing log"; + + log_buffer_flush_to_disk(); } if (buf_get_modified_ratio_pct() > @@ -2937,7 +2969,7 @@ loop: buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); srv_main_thread_op_info = (char*) "flushing log"; - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); } /* We run a batch of insert buffer merge every 10 seconds, @@ -2947,7 +2979,7 @@ loop: ibuf_contract_for_n_pages(TRUE, 5); srv_main_thread_op_info = (char*)"flushing log"; - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); /* We run a full purge every 10 seconds, even if the server were active */ @@ -2971,8 +3003,7 @@ loop: if (difftime(current_time, last_flush_time) > 1) { srv_main_thread_op_info = (char*) "flushing log"; - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, - TRUE); + log_buffer_flush_to_disk(); last_flush_time = current_time; } } @@ -3043,10 +3074,29 @@ background_loop: srv_main_thread_op_info = (char*)"purging"; - if (srv_fast_shutdown && srv_shutdown_state > 0) { - n_pages_purged = 0; - } else { - n_pages_purged = trx_purge(); + /* Run a full purge */ + + n_pages_purged = 1; + + last_flush_time = time(NULL); + + while (n_pages_purged) { + if (srv_fast_shutdown && srv_shutdown_state > 0) { + + break; + } + + srv_main_thread_op_info = (char*)"purging"; + n_pages_purged = trx_purge(); + + current_time = time(NULL); + + if (difftime(current_time, last_flush_time) > 1) { + srv_main_thread_op_info = (char*) "flushing log"; + + log_buffer_flush_to_disk(); + last_flush_time = current_time; + } } srv_main_thread_op_info = (char*)"reserving kernel mutex"; @@ -3092,6 +3142,10 @@ flush_loop: (char*) "waiting for buffer pool flush to end"; buf_flush_wait_batch_end(BUF_FLUSH_LIST); + srv_main_thread_op_info = (char*) "flushing log"; + + log_buffer_flush_to_disk(); + srv_main_thread_op_info = (char*)"making checkpoint"; log_checkpoint(TRUE, FALSE); diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index ad985d8282d..f0ff1167f4d 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -415,8 +415,8 @@ io_handler_thread( segment = *((ulint*)arg); #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Io handler thread %lu starts\n", segment); - printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); + printf("Io handler thread %lu starts, id %lu\n", segment, + os_thread_pf(os_thread_get_curr_id())); #endif for (i = 0;; i++) { fil_aio_wait(segment); @@ -1073,6 +1073,10 @@ innobase_start_or_create_for_mysql(void) srv_unix_file_flush_method = SRV_UNIX_O_DSYNC; } else if (0 == ut_strcmp(srv_file_flush_method_str, + (char*)"O_DIRECT")) { + srv_unix_file_flush_method = SRV_UNIX_O_DIRECT; + + } else if (0 == ut_strcmp(srv_file_flush_method_str, (char*)"littlesync")) { srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC; @@ -1531,7 +1535,9 @@ innobase_shutdown_for_mysql(void) } /* 1. Flush buffer pool to disk, write the current lsn to - the tablespace header(s), and copy all log data to archive */ + the tablespace header(s), and copy all log data to archive. + The step 1 is the real InnoDB shutdown. The remaining steps + just free data structures after the shutdown. */ logs_empty_and_mark_files_at_shutdown(); diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 32615ce88ac..773b239189c 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -159,7 +159,7 @@ struct sync_thread_struct{ }; /* Number of slots reserved for each OS thread in the sync level array */ -#define SYNC_THREAD_N_LEVELS 10000 +#define SYNC_THREAD_N_LEVELS 250 struct sync_level_struct{ void* latch; /* pointer to a mutex or an rw-lock; NULL means that diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c index d58240d3c11..fa9c287b0ad 100644 --- a/innobase/trx/trx0purge.c +++ b/innobase/trx/trx0purge.c @@ -593,7 +593,7 @@ trx_purge_rseg_get_next_history_log( mutex_enter(&(rseg->mutex)); - ut_ad(rseg->last_page_no != FIL_NULL); + ut_a(rseg->last_page_no != FIL_NULL); purge_sys->purge_trx_no = ut_dulint_add(rseg->last_trx_no, 1); purge_sys->purge_undo_no = ut_dulint_zero; @@ -606,16 +606,9 @@ trx_purge_rseg_get_next_history_log( log_hdr = undo_page + rseg->last_offset; seg_hdr = undo_page + TRX_UNDO_SEG_HDR; - if ((mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0) - && (mach_read_from_2(seg_hdr + TRX_UNDO_STATE) - == TRX_UNDO_TO_PURGE)) { - - /* This is the last log header on this page and the log - segment cannot be reused: we may increment the number of - pages handled */ + /* Increase the purge page count by one for every handled log */ - purge_sys->n_pages_handled++; - } + purge_sys->n_pages_handled++; prev_log_addr = trx_purge_get_log_from_hist( flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c index 05e179e06a5..9453189d598 100644 --- a/innobase/trx/trx0rec.c +++ b/innobase/trx/trx0rec.c @@ -272,8 +272,8 @@ trx_undo_page_report_insert( mach_write_to_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE, ptr - undo_page); - /* Write the log entry to the REDO log of this change in the UNDO log */ - + /* Write the log entry to the REDO log of this change in the UNDO + log */ trx_undof_page_add_undo_rec_log(undo_page, first_free, ptr - undo_page, mtr); return(first_free); @@ -492,7 +492,8 @@ trx_undo_page_report_modify( /* Reserve 2 bytes for the pointer to the next undo log record */ ptr += 2; - /* Store first some general parameters to the undo log */ + /* Store first some general parameters to the undo log */ + if (update) { if (rec_get_deleted_flag(rec)) { type_cmpl = TRX_UNDO_UPD_DEL_REC; @@ -526,8 +527,7 @@ trx_undo_page_report_modify( /* Store the values of the system columns */ trx_id = dict_index_rec_get_sys_col(index, DATA_TRX_ID, rec); - roll_ptr = dict_index_rec_get_sys_col(index, DATA_ROLL_PTR, rec); - + roll_ptr = dict_index_rec_get_sys_col(index, DATA_ROLL_PTR, rec); len = mach_dulint_write_compressed(ptr, trx_id); ptr += len; @@ -632,7 +632,11 @@ trx_undo_page_report_modify( columns which occur as ordering fields in any index. This info is used in the purge of old versions where we use it to build and search the delete marked index records, to look if we can remove them from the - index tree. */ + index tree. Note that starting from 4.0.14 also externally stored + fields can be ordering in some index. But we always store at least + 384 first bytes locally to the clustered index record, which means + we can construct the column prefix fields in the index from the + stored data. */ if (!update || !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { @@ -1408,11 +1412,11 @@ trx_undo_prev_version_build( return(DB_ERROR); } - if (row_upd_changes_field_size(rec, index, update)) { - - entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); + if (row_upd_changes_field_size_or_external(rec, index, update)) { - row_upd_clust_index_replace_new_col_vals(entry, update); + entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, + heap); + row_upd_index_replace_new_col_vals(entry, index, update, heap); buf = mem_heap_alloc(heap, rec_get_converted_size(entry)); diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index a9f8c5ad22c..7d1b341221c 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -52,6 +52,11 @@ trx_general_rollback_for_mysql( que_thr_t* thr; roll_node_t* roll_node; + /* Tell Innobase server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + trx_start_if_not_started(trx); heap = mem_heap_create(512); @@ -89,6 +94,11 @@ trx_general_rollback_for_mysql( ut_a(trx->error_state == DB_SUCCESS); + /* Tell Innobase server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + return((int) trx->error_state); } @@ -110,20 +120,8 @@ trx_rollback_for_mysql( trx->op_info = (char *) "rollback"; - /* Tell Innobase server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - err = trx_general_rollback_for_mysql(trx, FALSE, NULL); - trx_mark_sql_stat_end(trx); - - /* Tell Innobase server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - trx->op_info = (char *) ""; return(err); @@ -147,26 +145,192 @@ trx_rollback_last_sql_stat_for_mysql( trx->op_info = (char *) "rollback of SQL statement"; - /* Tell Innobase server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - err = trx_general_rollback_for_mysql(trx, TRUE, &(trx->last_sql_stat_start)); + /* The following call should not be needed, but we play safe: */ trx_mark_sql_stat_end(trx); - /* Tell Innobase server that there might be work for - utility threads: */ + trx->op_info = (char *) ""; + + return(err); +} - srv_active_wake_master_thread(); +/*********************************************************************** +Frees savepoint structs. */ - trx->op_info = (char *) ""; +void +trx_roll_savepoints_free( +/*=====================*/ + trx_t* trx, /* in: transaction handle */ + trx_named_savept_t* savep) /* in: free all savepoints > this one; + if this is NULL, free all savepoints + of trx */ +{ + trx_named_savept_t* next_savep; + + if (savep == NULL) { + savep = UT_LIST_GET_FIRST(trx->trx_savepoints); + } else { + savep = UT_LIST_GET_NEXT(trx_savepoints, savep); + } + while (savep != NULL) { + next_savep = UT_LIST_GET_NEXT(trx_savepoints, savep); + + UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); + mem_free(savep->name); + mem_free(savep); + + savep = next_savep; + } +} + +/*********************************************************************** +Rolls back a transaction back to a named savepoint. Modifications after the +savepoint are undone but InnoDB does NOT release the corresponding locks +which are stored in memory. If a lock is 'implicit', that is, a new inserted +row holds a lock where the lock information is carried by the trx id stored in +the row, these locks are naturally released in the rollback. Savepoints which +were set after this savepoint are deleted. */ + +ulint +trx_rollback_to_savepoint_for_mysql( +/*================================*/ + /* out: if no savepoint + of the name found then + DB_NO_SAVEPOINT, + otherwise DB_SUCCESS */ + trx_t* trx, /* in: transaction handle */ + char* savepoint_name, /* in: savepoint name */ + ib_longlong* mysql_binlog_cache_pos) /* out: the MySQL binlog cache + position corresponding to this + savepoint; MySQL needs this + information to remove the + binlog entries of the queries + executed after the savepoint */ +{ + trx_named_savept_t* savep; + ulint err; + + savep = UT_LIST_GET_FIRST(trx->trx_savepoints); + + while (savep != NULL) { + if (0 == ut_strcmp(savep->name, savepoint_name)) { + /* Found */ + break; + } + savep = UT_LIST_GET_NEXT(trx_savepoints, savep); + } + + if (savep == NULL) { + + return(DB_NO_SAVEPOINT); + } + + if (trx->conc_state == TRX_NOT_STARTED) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: transaction has a savepoint %s though it is not started\n", + savep->name); + return(DB_ERROR); + } + + /* We can now free all savepoints strictly later than this one */ + + trx_roll_savepoints_free(trx, savep); + + *mysql_binlog_cache_pos = savep->mysql_binlog_cache_pos; + + trx->op_info = (char *) "rollback to a savepoint"; + + err = trx_general_rollback_for_mysql(trx, TRUE, &(savep->savept)); + + /* Store the current undo_no of the transaction so that we know where + to roll back if we have to roll back the next SQL statement: */ + + trx_mark_sql_stat_end(trx); + + trx->op_info = (char *) ""; + return(err); } /*********************************************************************** +Creates a named savepoint. If the transaction is not yet started, starts it. +If there is already a savepoint of the same name, this call erases that old +savepoint and replaces it with a new. Savepoints are deleted in a transaction +commit or rollback. */ + +ulint +trx_savepoint_for_mysql( +/*====================*/ + /* out: always DB_SUCCESS */ + trx_t* trx, /* in: transaction handle */ + char* savepoint_name, /* in: savepoint name */ + ib_longlong binlog_cache_pos) /* in: MySQL binlog cache + position corresponding to this + connection at the time of the + savepoint */ +{ + trx_named_savept_t* savep; + + ut_a(trx); + ut_a(savepoint_name); + + trx_start_if_not_started(trx); + + savep = UT_LIST_GET_FIRST(trx->trx_savepoints); + + while (savep != NULL) { + if (0 == ut_strcmp(savep->name, savepoint_name)) { + /* Found */ + break; + } + savep = UT_LIST_GET_NEXT(trx_savepoints, savep); + } + + if (savep) { + /* There is a savepoint with the same name: free that */ + + UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); + + mem_free(savep->name); + mem_free(savep); + } + + /* Create a new savepoint and add it as the last in the list */ + + savep = mem_alloc(sizeof(trx_named_savept_t)); + + savep->name = mem_alloc(1 + ut_strlen(savepoint_name)); + ut_memcpy(savep->name, savepoint_name, 1 + ut_strlen(savepoint_name)); + + savep->savept = trx_savept_take(trx); + + savep->mysql_binlog_cache_pos = binlog_cache_pos; + + UT_LIST_ADD_LAST(trx_savepoints, trx->trx_savepoints, savep); + + return(DB_SUCCESS); +} + +/*********************************************************************** +Returns a transaction savepoint taken at this point in time. */ + +trx_savept_t +trx_savept_take( +/*============*/ + /* out: savepoint */ + trx_t* trx) /* in: transaction */ +{ + trx_savept_t savept; + + savept.least_undo_no = trx->undo_no; + + return(savept); +} + +/*********************************************************************** Rollback or clean up transactions which have no user session. If the transaction already was committed, then we clean up a possible insert undo log. If the transaction was not yet committed, then we roll it back. */ @@ -325,22 +489,6 @@ loop: goto loop; } - -/*********************************************************************** -Returns a transaction savepoint taken at this point in time. */ - -trx_savept_t -trx_savept_take( -/*============*/ - /* out: savepoint */ - trx_t* trx) /* in: transaction */ -{ - trx_savept_t savept; - - savept.least_undo_no = trx->undo_no; - - return(savept); -} /*********************************************************************** Creates an undo number array. */ diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index b9e4a9fea4b..0c0dbab708c 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -321,8 +321,8 @@ trx_sys_doublewrite_restore_corrupt_pages(void) for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) { - space_id = mach_read_from_4(page + FIL_PAGE_SPACE); page_no = mach_read_from_4(page + FIL_PAGE_OFFSET); + space_id = 0; if (!fil_check_adress_in_tablespace(space_id, page_no)) { fprintf(stderr, diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 5753b5b338e..1ece349ec6c 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -86,6 +86,10 @@ trx_create( trx->start_time = time(NULL); trx->isolation_level = TRX_ISO_REPEATABLE_READ; + + trx->id = ut_dulint_zero; + trx->no = ut_dulint_max; + trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; @@ -135,6 +139,8 @@ trx_create( trx->lock_heap = mem_heap_create_in_buffer(256); UT_LIST_INIT(trx->trx_locks); + UT_LIST_INIT(trx->trx_savepoints); + trx->dict_operation_lock_mode = 0; trx->has_search_latch = FALSE; trx->search_latch_timeout = BTR_SEA_TIMEOUT; @@ -776,29 +782,53 @@ trx_commit_off_kernel( efficient here: call os_thread_yield here to allow also other trxs to come to commit! */ - /* We now flush the log, as the transaction made changes to - the database, making the transaction committed on disk. It is - enough that any one of the log groups gets written to disk. */ - /*-------------------------------------*/ - /* Most MySQL users run with srv_flush_.. set to 0: */ - - if (srv_flush_log_at_trx_commit != 0) { - if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC - && srv_flush_log_at_trx_commit != 2 - && !trx->flush_log_later) { - - /* Write the log to the log files AND flush - them to disk */ - - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); - } else { - /* Write the log but do not flush it to disk */ - - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); - } - } + /* Depending on the my.cnf options, we may now write the log + buffer to the log files, making the transaction durable if + the OS does not crash. We may also flush the log files to + disk, making the transaction durable also at an OS crash or a + power outage. + + The idea in InnoDB's group commit is that a group of + transactions gather behind a trx doing a physical disk write + to log files, and when that physical write has been completed, + one of those transactions does a write which commits the whole + group. Note that this group commit will only bring benefit if + there are > 2 users in the database. Then at least 2 users can + gather behind one doing the physical log write to disk. + + If we are calling trx_commit() under MySQL's binlog mutex, we + will delay possible log write and flush to a separate function + trx_commit_complete_for_mysql(), which is only called when the + thread has released the binlog mutex. This is to make the + group commit algorithm to work. Otherwise, the MySQL binlog + mutex would serialize all commits and prevent a group of + transactions from gathering. */ + + if (trx->flush_log_later) { + /* Do nothing yet */ + } else if (srv_flush_log_at_trx_commit == 0) { + /* Do nothing */ + } else if (srv_flush_log_at_trx_commit == 1) { + if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { + /* Write the log but do not flush it to disk */ + + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + } else { + /* Write the log to the log files AND flush + them to disk */ + + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + } + } else if (srv_flush_log_at_trx_commit == 2) { + + /* Write the log but do not flush it to disk */ + + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + } else { + ut_a(0); + } trx->commit_lsn = lsn; @@ -807,6 +837,9 @@ trx_commit_off_kernel( mutex_enter(&kernel_mutex); } + /* Free savepoints */ + trx_roll_savepoints_free(trx, NULL); + trx->conc_state = TRX_NOT_STARTED; trx->rseg = NULL; trx->undo_no = ut_dulint_zero; @@ -1492,21 +1525,37 @@ trx_commit_complete_for_mysql( /* out: 0 or error number */ trx_t* trx) /* in: trx handle */ { - ut_a(trx); + dulint lsn = trx->commit_lsn; + + ut_a(trx); + + trx->op_info = (char*)"flushing log"; - if (srv_flush_log_at_trx_commit == 1 - && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { - - trx->op_info = (char *) "flushing log"; + if (srv_flush_log_at_trx_commit == 0) { + /* Do nothing */ + } else if (srv_flush_log_at_trx_commit == 1) { + if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { + /* Write the log but do not flush it to disk */ - /* Flush the log files to disk */ + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + } else { + /* Write the log to the log files AND flush them to + disk */ - log_write_up_to(trx->commit_lsn, LOG_WAIT_ONE_GROUP, TRUE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + } + } else if (srv_flush_log_at_trx_commit == 2) { - trx->op_info = (char *) ""; - } + /* Write the log but do not flush it to disk */ - return(0); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + } else { + ut_a(0); + } + + trx->op_info = (char*)""; + + return(0); } /************************************************************************** @@ -1575,6 +1624,13 @@ trx_print( } buf += sprintf(buf, "\n"); + + if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) { + + buf += sprintf(buf, "mysql tables in use %lu, locked %lu\n", + trx->n_mysql_tables_in_use, + trx->mysql_n_tables_locked); + } start_of_line = buf; diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index 2609b8f5241..ebead6424c8 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -201,7 +201,7 @@ ut_free( } /************************************************************************** -Frees all allocated memory not freed yet. */ +Frees in shutdown all allocated memory not freed yet. */ void ut_free_all_mem(void) @@ -209,7 +209,7 @@ ut_free_all_mem(void) { ut_mem_block_t* block; - os_fast_mutex_lock(&ut_list_mutex); + os_fast_mutex_free(&ut_list_mutex); while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) { @@ -222,11 +222,11 @@ ut_free_all_mem(void) free(block); } - os_fast_mutex_unlock(&ut_list_mutex); - - ut_a(ut_total_allocated_memory == 0); - - os_fast_mutex_free(&ut_list_mutex); + if (ut_total_allocated_memory != 0) { + fprintf(stderr, +"InnoDB: Warning: after shutdown total allocated memory is %lu\n", + ut_total_allocated_memory); + } } /************************************************************************** diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c index c503cda54b9..4ca113f40ad 100644 --- a/innobase/ut/ut0ut.c +++ b/innobase/ut/ut0ut.c @@ -54,6 +54,8 @@ ut_get_high32( ulint a) /* in: ulint */ { #if SIZEOF_LONG == 4 + UT_NOT_USED(a); + return 0; #else return(a >> 32); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index d75f217585d..57613b68448 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -47,8 +47,12 @@ #include <sys/select.h> #endif #endif +#ifdef HAVE_POLL +#include <sys/poll.h> +#endif +#endif /* !defined(MSDOS) && !defined(__WIN__) */ #ifdef HAVE_SYS_UN_H -# include <sys/un.h> +#include <sys/un.h> #endif #if defined(THREAD) && !defined(__WIN__) #include <my_pthread.h> /* because of signal() */ diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 6d7b71c61be..aaa31908360 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -247,7 +247,7 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) opt_bin_logname=my_strdup(tmp,MYF(MY_WME)); } open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin", - opt_binlog_index_name, LOG_BIN); + opt_binlog_index_name, LOG_BIN, 0, 0, max_binlog_size); using_update_log=1; } diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index c59d140da85..2fbd6490cfd 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -353,7 +353,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=0; + ftb->lastpos=HA_POS_ERROR; bzero(& ftb->no_dupes, sizeof(TREE)); init_alloc_root(&ftb->mem_root, 1024, 1024); @@ -569,7 +569,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) if (!ftb->queue.elements) return 0; - if (ftb->state != INDEX_SEARCH && docid < ftb->lastpos) + if (ftb->state != INDEX_SEARCH && docid <= ftb->lastpos) { FTB_EXPR *x; uint i; diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 019222fdf22..60053674647 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -881,7 +881,8 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) if (_mi_rec_unpack(info,record,info->rec_buff,block_info.rec_len) == MY_FILE_ERROR) { - mi_check_print_error(param,"Found wrong record at %s", llstr(start_recpos,llbuff)); + mi_check_print_error(param,"Found wrong record at %s", + llstr(start_recpos,llbuff)); got_error=1; } else @@ -3698,10 +3699,13 @@ int update_state_info(MI_CHECK *param, MI_INFO *info,uint update) uint i, key_parts= mi_uint2korr(share->state.header.key_parts); share->state.rec_per_key_rows=info->state->records; share->state.changed&= ~STATE_NOT_ANALYZED; - for (i=0; i<key_parts; i++) + if (info->state->records) { - if (!(share->state.rec_per_key_part[i]=param->rec_per_key_part[i])) - share->state.changed|= STATE_NOT_ANALYZED; + for (i=0; i<key_parts; i++) + { + if (!(share->state.rec_per_key_part[i]=param->rec_per_key_part[i])) + share->state.changed|= STATE_NOT_ANALYZED; + } } } if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME | UPDATE_AUTO_INC)) @@ -3748,6 +3752,7 @@ err: void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, my_bool repair_only) { + byte *record; if (!info->s->base.auto_key || !(((ulonglong) 1 << (info->s->base.auto_key-1) & info->s->state.key_map))) @@ -3761,13 +3766,24 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, if (!(param->testflag & T_SILENT) && !(param->testflag & T_REP)) printf("Updating MyISAM file: %s\n", param->isam_file_name); - /* We have to use keyread here as a normal read uses info->rec_buff */ + /* + We have to use an allocated buffer instead of info->rec_buff as + _mi_put_key_in_record() may use info->rec_buff + */ + if (!(record= (byte*) my_malloc((uint) info->s->base.pack_reclength, + MYF(0)))) + { + mi_check_print_error(param,"Not enough memory for extra record"); + return; + } + mi_extra(info,HA_EXTRA_KEYREAD,0); - if (mi_rlast(info,info->rec_buff, info->s->base.auto_key-1)) + if (mi_rlast(info, record, info->s->base.auto_key-1)) { if (my_errno != HA_ERR_END_OF_FILE) { mi_extra(info,HA_EXTRA_NO_KEYREAD,0); + my_free((char*) record, MYF(0)); mi_check_print_error(param,"%d when reading last record",my_errno); return; } @@ -3779,10 +3795,11 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, ulonglong auto_increment= (repair_only ? info->s->state.auto_increment : param->auto_increment_value); info->s->state.auto_increment=0; - update_auto_increment(info,info->rec_buff); + update_auto_increment(info, record); set_if_bigger(info->s->state.auto_increment,auto_increment); } mi_extra(info,HA_EXTRA_NO_KEYREAD,0); + my_free((char*) record, MYF(0)); update_state_info(param, info, UPDATE_AUTO_INC); return; } diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 4b71f3a867b..c86ca1c2e7b 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -273,6 +273,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) } break; case HA_EXTRA_FORCE_REOPEN: + pthread_mutex_lock(&THR_LOCK_myisam); + share->last_version= 0L; /* Impossible version */ + pthread_mutex_unlock(&THR_LOCK_myisam); + break; case HA_EXTRA_PREPARE_FOR_DELETE: pthread_mutex_lock(&THR_LOCK_myisam); share->last_version= 0L; /* Impossible version */ diff --git a/myisam/mi_info.c b/myisam/mi_info.c index 32767e73bb1..f4eace198f9 100644 --- a/myisam/mi_info.c +++ b/myisam/mi_info.c @@ -80,15 +80,17 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag) (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? 0L : share->base.pack_reclength); x->sortkey= -1; /* No clustering */ - /* The following should be included even if we are not compiling with - USE_RAID as the client must be able to request it! */ x->rec_per_key = share->state.rec_per_key_part; - x->raid_type= share->base.raid_type; - x->raid_chunks= share->base.raid_chunks; - x->raid_chunksize= share->base.raid_chunksize; x->key_map = share->state.key_map; x->data_file_name = share->data_file_name; x->index_file_name = share->index_file_name; + /* + The following should be included even if we are not compiling with + USE_RAID as the client must be able to request it! + */ + x->raid_type= share->base.raid_type; + x->raid_chunks= share->base.raid_chunks; + x->raid_chunksize= share->base.raid_chunksize; } if ((flag & HA_STATUS_TIME) && !my_fstat(info->dfile,&state,MYF(0))) x->update_time=state.st_mtime; diff --git a/myisam/mi_key.c b/myisam/mi_key.c index a375a415103..93e3b9621f3 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -273,7 +273,7 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, byte *blob_ptr; DBUG_ENTER("_mi_put_key_in_record"); - if (info->blobs && info->s->keyinfo[keynr].flag & HA_VAR_LENGTH_KEY) + if (info->s->base.blobs && info->s->keyinfo[keynr].flag & HA_VAR_LENGTH_KEY) { if (!(blob_ptr= mi_alloc_rec_buff(info, info->s->keyinfo[keynr].keylength, diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index cbde05d31f5..22772a3dd2e 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -39,6 +39,14 @@ int mi_lock_database(MI_INFO *info, int lock_type) if (share->options & HA_OPTION_READ_ONLY_DATA || info->lock_type == lock_type) DBUG_RETURN(0); + if (lock_type == F_EXTRA_LCK) + { + ++share->w_locks; + ++share->tot_locks; + info->lock_type= lock_type; + DBUG_RETURN(0); + } + flag=error=0; pthread_mutex_lock(&share->intern_lock); if (share->kfile >= 0) /* May only be false on windows */ diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index b7f8d561a5b..43ade35bfd5 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -172,7 +172,7 @@ static struct my_option my_long_options[] = "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"check-only-changed", 'C', - "Check only tables that have changed since last check.", + "Check only tables that have changed since last check. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"correct-checksum", OPT_CORRECT_CHECKSUM, "Correct checksum information for table.", @@ -194,7 +194,7 @@ static struct my_option my_long_options[] = "If used when checking a table, ensure that the table is 100 percent consistent, which will take a long time. If used when repairing a table, try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option with repair if you are not totally desperate.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"fast", 'F', - "Check only tables that haven't been closed properly.", + "Check only tables that haven't been closed properly. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Restart with -r if there are any errors in the table. States will be updated as with --update-state.", @@ -892,10 +892,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) param->error_printed=0; goto end2; } - share->w_locks++; /* Mark for writeinfo */ - share->tot_locks++; - info->lock_type= F_EXTRA_LCK; /* Simulate as locked */ - info->tmp_lock_type=lock_type; + mi_lock_database(info, F_EXTRA_LCK); datafile=info->dfile; if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX)) @@ -1071,8 +1068,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) VOID(lock_file(param, share->kfile,0L,F_UNLCK,"indexfile",filename)); info->update&= ~HA_STATE_CHANGED; } - share->w_locks--; - share->tot_locks--; + mi_lock_database(info, F_UNLCK); end2: if (mi_close(info)) { @@ -1426,6 +1422,12 @@ static int mi_sort_records(MI_CHECK *param, param->error_printed=0; DBUG_RETURN(-1); } + if (share->data_file_type == COMPRESSED_RECORD) + { + mi_check_print_error(param,"Can't sort read-only table '%s'", name); + param->error_printed=0; + DBUG_RETURN(-1); + } if (!(param->testflag & T_SILENT)) { printf("- Sorting records for MyISAM-table '%s'\n",name); diff --git a/myisammrg/myrg_def.h b/myisammrg/myrg_def.h index d56cf4aa8d8..00e7950bccf 100644 --- a/myisammrg/myrg_def.h +++ b/myisammrg/myrg_def.h @@ -29,3 +29,5 @@ extern pthread_mutex_t THR_LOCK_open; #endif int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag); +int _myrg_mi_read_record(MI_INFO *info, byte *buf); + diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index 7ff00270c68..5188669cad1 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -33,7 +33,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) { int save_errno,i,errpos; - uint files,dir_length,length,options, key_parts; + uint files,dir_length,length,key_parts; ulonglong file_offset; char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end; MYRG_INFO info,*m_info; @@ -110,13 +110,11 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) } errpos=2; - options= (uint) ~0; for (i=files ; i-- > 0 ; ) { uint j; m_info->open_tables[i].table=isam; m_info->options|=isam->s->options; - options&=isam->s->options; m_info->records+=isam->state->records; m_info->del+=isam->state->del; m_info->data_file_length+=isam->state->data_file_length; @@ -125,9 +123,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) if (i) isam=(MI_INFO*) (isam->open_list.next->data); } - /* Don't force readonly if not all tables are readonly */ - if (! (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA))) - m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA); + /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */ + m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA); /* Fix fileinfo for easyer debugging (actually set by rrnd) */ file_offset=0; diff --git a/myisammrg/myrg_queue.c b/myisammrg/myrg_queue.c index 08a248bdd64..dfb434d6397 100644 --- a/myisammrg/myrg_queue.c +++ b/myisammrg/myrg_queue.c @@ -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 */ -/* Read record based on a key */ - #include "myrg_def.h" static int queue_key_cmp(void *keyseg, byte *a, byte *b) @@ -55,3 +53,13 @@ int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag) } return error; } + +int _myrg_mi_read_record(MI_INFO *info, byte *buf) +{ + if (!(*info->read_record)(info,info->lastpos,buf)) + { + info->update|= HA_STATE_AKTIV; /* Record is read */ + return 0; + } + return my_errno; +} diff --git a/myisammrg/myrg_rfirst.c b/myisammrg/myrg_rfirst.c index 2ee9c015a84..9ba07686c47 100644 --- a/myisammrg/myrg_rfirst.c +++ b/myisammrg/myrg_rfirst.c @@ -45,5 +45,5 @@ int myrg_rfirst(MYRG_INFO *info, byte *buf, int inx) return HA_ERR_END_OF_FILE; mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table; - return mi_rrnd(mi,buf,mi->lastpos); + return _myrg_mi_read_record(mi,buf); } diff --git a/myisammrg/myrg_rkey.c b/myisammrg/myrg_rkey.c index c0cef5a4eca..a85ef6a3b5e 100644 --- a/myisammrg/myrg_rkey.c +++ b/myisammrg/myrg_rkey.c @@ -36,7 +36,7 @@ SerG */ -int myrg_rkey(MYRG_INFO *info,byte *record,int inx, const byte *key, +int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, uint key_len, enum ha_rkey_function search_flag) { byte *key_buff; @@ -83,5 +83,5 @@ int myrg_rkey(MYRG_INFO *info,byte *record,int inx, const byte *key, mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table; mi->once_flags|= RRND_PRESERVE_LASTINX; - return mi_rrnd(mi,record,mi->lastpos); + return _myrg_mi_read_record(mi,buf); } diff --git a/myisammrg/myrg_rlast.c b/myisammrg/myrg_rlast.c index e03a07c295a..96bb798bd4f 100644 --- a/myisammrg/myrg_rlast.c +++ b/myisammrg/myrg_rlast.c @@ -45,6 +45,6 @@ int myrg_rlast(MYRG_INFO *info, byte *buf, int inx) return HA_ERR_END_OF_FILE; mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table; - return mi_rrnd(mi,buf,mi->lastpos); + return _myrg_mi_read_record(mi,buf); } diff --git a/myisammrg/myrg_rnext.c b/myisammrg/myrg_rnext.c index 6d657b5926c..0929c63fc1d 100644 --- a/myisammrg/myrg_rnext.c +++ b/myisammrg/myrg_rnext.c @@ -49,5 +49,5 @@ int myrg_rnext(MYRG_INFO *info, byte *buf, int inx) /* now, mymerge's read_next is as simple as one queue_top */ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table; - return mi_rrnd(mi,buf,mi->lastpos); + return _myrg_mi_read_record(mi,buf); } diff --git a/myisammrg/myrg_rprev.c b/myisammrg/myrg_rprev.c index c21ca06dacd..797993e903d 100644 --- a/myisammrg/myrg_rprev.c +++ b/myisammrg/myrg_rprev.c @@ -49,5 +49,5 @@ int myrg_rprev(MYRG_INFO *info, byte *buf, int inx) /* now, mymerge's read_prev is as simple as one queue_top */ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table; - return mi_rrnd(mi,buf,mi->lastpos); + return _myrg_mi_read_record(mi,buf); } diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 137e99f48b3..8800055a3bb 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -323,11 +323,15 @@ while test $# -gt 0; do $ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --client-gdb option" fi DO_CLIENT_GDB=1 + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --gdb" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb" ;; --manual-gdb ) DO_GDB=1 MANUAL_GDB=1 USE_RUNNING_SERVER="" + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --gdb" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb" ;; --ddd ) if [ x$BINARY_DIST = x1 ] ; then @@ -335,6 +339,8 @@ while test $# -gt 0; do fi DO_DDD=1 USE_RUNNING_SERVER="" + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --gdb" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb" ;; --valgrind) VALGRIND="valgrind --alignment=8 --leak-check=yes --num-callers=16" @@ -567,7 +573,9 @@ error () { } error_is () { - $CAT < $TIMEFILE | $SED -e 's/.* At line \(.*\)\: \(.*\)/ \>\> Error at line \1: \2<\</' | $HEAD -1 + $ECHO "Errors are (from $TIMEFILE) :" + $CAT < $TIMEFILE + $ECHO "(the last line(s) may be the ones that caused the die() in mysqltest)" } prefix_to_8() { @@ -1068,6 +1076,16 @@ stop_slave () fi } +stop_slave_threads () +{ + eval "this_slave_running=\$SLAVE$1_RUNNING" + slave_ident="slave$1" + if [ x$this_slave_running = x1 ] + then + $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$slave_ident.sock stop-slave > /dev/null 2>&1 + fi +} + stop_master () { if [ x$MASTER_RUNNING = x1 ] @@ -1161,6 +1179,12 @@ run_testcase () return fi + # Stop all slave threads, so that we don't have useless reconnection attempts + # and error messages in case the slave and master servers restart. + stop_slave_threads + stop_slave_threads 1 + stop_slave_threads 2 + if [ -z "$USE_RUNNING_SERVER" ] ; then if [ -f $master_opt_file ] ; diff --git a/mysql-test/r/alias.result b/mysql-test/r/alias.result index 3954c2d0170..5ed10b58929 100644 --- a/mysql-test/r/alias.result +++ b/mysql-test/r/alias.result @@ -59,3 +59,15 @@ SELECT ELT(FIELD(kundentyp,'PP','PPA','PG','PGA','FK','FKA','FP','FPA','K','KA', Kundentyp kategorie Privat (Private Nutzung) Mobilfunk drop table t1; +CREATE TABLE t1 ( +AUFNR varchar(12) NOT NULL default '', +PLNFL varchar(6) NOT NULL default '', +VORNR varchar(4) NOT NULL default '', +xstatus_vor smallint(5) unsigned NOT NULL default '0', +); +INSERT INTO t1 VALUES ('40004712','000001','0010',9); +INSERT INTO t1 VALUES ('40004712','000001','0020',0); +UPDATE t1 SET t1.xstatus_vor = Greatest(t1.xstatus_vor,1) WHERE t1.aufnr = +"40004712" AND t1.plnfl = "000001" AND t1.vornr > "0010" ORDER BY t1.vornr +ASC LIMIT 1; +drop table t1; diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 7fa5a0f601f..9d3a0461f9f 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -320,3 +320,72 @@ select a,hex(a) from t1; a hex(a) ÔÅÓÔ D4C5D3D4 drop table t1; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User) +) TYPE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty'); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 3 NULL NULL BTREE +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; +CHECK TABLES t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User), +KEY (Host) +) TYPE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 2 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +ALTER TABLE t1 ENABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 2 NULL NULL BTREE +t1 1 Host 1 Host A 1 NULL NULL BTREE +UNLOCK TABLES; +CHECK TABLES t1; +Table Op Msg_type Msg_text +test.t1 check status OK +LOCK TABLES t1 WRITE; +ALTER TABLE t1 RENAME t2; +UNLOCK TABLES; +select * from t2; +Host User +localhost +localhost root +DROP TABLE t2; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User), +KEY (Host) +) TYPE=MyISAM; +LOCK TABLES t1 WRITE; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +DROP TABLE t1; diff --git a/mysql-test/r/convert.result b/mysql-test/r/convert.result new file mode 100644 index 00000000000..f8dad8c69ba --- /dev/null +++ b/mysql-test/r/convert.result @@ -0,0 +1,17 @@ +select @@convert_character_set; +@@convert_character_set + +select @@global.convert_character_set; +@@global.convert_character_set + +show variables like "%convert_character_set%"; +Variable_name Value +convert_character_set +SET CHARACTER SET cp1251_koi8; +select @@convert_character_set; +@@convert_character_set +cp1251_koi8 +SET CHARACTER SET DEFAULT; +select @@convert_character_set; +@@convert_character_set + diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 9a0eca52b84..2f907880cbe 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -310,3 +310,5 @@ t1 CREATE TABLE `t1` ( ) TYPE=MyISAM CHARSET=latin1 SET SESSION table_type=default; drop table t1; +create table t1 select x'4132'; +drop table t1; diff --git a/mysql-test/r/ctype_cp1251.result b/mysql-test/r/ctype_cp1251.result new file mode 100644 index 00000000000..a1f860e1f83 --- /dev/null +++ b/mysql-test/r/ctype_cp1251.result @@ -0,0 +1,24 @@ +drop table if exists t1; +create table t1 (a varchar(10) not null); +insert into t1 values ("a"),("ab"),("abc"); +select * from t1; +a +a +ab +abc +select a, left(a,1) as b from t1; +a b +a a +ab a +abc a +select a, left(a,1) as b from t1 group by a; +a b +a a +ab a +abc a +SELECT DISTINCT RIGHT(a,1) from t1; +RIGHT(a,1) +a +b +c +drop table t1; diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result index 7503c16a85e..7f116c1fc52 100644 --- a/mysql-test/r/ctype_latin1_de.result +++ b/mysql-test/r/ctype_latin1_de.result @@ -196,6 +196,9 @@ strcmp('ßa','ss') strcmp('ssa','ß') strcmp('sssb','sßa') strcmp('ß','s') select strcmp('u','öa'),strcmp('u','ö'); strcmp('u','öa') strcmp('u','ö') 1 1 +select strcmp('sä', 'ßa'), strcmp('aä', 'äx'); +strcmp('sä', 'ßa') strcmp('aä', 'äx') +-1 -1 create table t1 (a varchar(10), key(a), fulltext (a)); insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test"); select * from t1 where a like "abc%"; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index c5841f28830..3c6769e797b 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -161,7 +161,7 @@ SELECT DISTINCT UserId FROM t1 WHERE UserId=22; UserId drop table t1; CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned); -INSERT INTO t1 VALUES (1,1),(2,1); +INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1); CREATE TABLE t2 (a int(10) unsigned not null, key (A)); INSERT INTO t2 VALUES (1),(2); CREATE TABLE t3 (a int(10) unsigned, key(A), b text); @@ -189,7 +189,7 @@ insert into t4 select * from t3; insert into t3 select * from t4; explain select distinct t1.a from t1,t3 where t1.a=t3.a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index; Using temporary +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 4 Using index; Using temporary 1 SIMPLE t3 ref a a 5 test.t1.a 10 Using where; Using index; Distinct select distinct t1.a from t1,t3 where t1.a=t3.a; a @@ -200,16 +200,16 @@ select distinct 1 from t1,t3 where t1.a=t3.a; 1 explain SELECT distinct t1.a from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index explain SELECT distinct t1.a from t1 order by a desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index explain SELECT t1.a from t1 group by a order by a desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index explain SELECT distinct t1.a from t1 order by a desc limit 1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index explain SELECT distinct a from t3 order by a desc limit 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 index NULL a 5 NULL 204 Using index @@ -418,3 +418,12 @@ SELECT DISTINCT t1.a, t2.b FROM t1, t2 WHERE t1.a=1 ORDER BY t2.c; a b 1 4 DROP TABLE t1,t2; +CREATE table t1 ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL default '', PRIMARY KEY (`id`)) TYPE=MyISAM AUTO_INCREMENT=3 ; +INSERT INTO t1 VALUES (1, 'aaaaa'); +INSERT INTO t1 VALUES (3, 'aaaaa'); +INSERT INTO t1 VALUES (2, 'eeeeeee'); +select distinct left(name,1) as name from t1; +name +a +e +drop table t1; diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index 9555ea452ca..6029cc90d1d 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -25,7 +25,6 @@ n drop database if exists mysqltest; create database mysqltest; drop database mysqltest; -drop database if exists mysqltest; Warnings: Note 1008 Can't drop database 'mysqltest'; database doesn't exist flush tables with read lock; diff --git a/mysql-test/r/fulltext_left_join.result b/mysql-test/r/fulltext_left_join.result index abc63358dbe..6875a517718 100644 --- a/mysql-test/r/fulltext_left_join.result +++ b/mysql-test/r/fulltext_left_join.result @@ -31,3 +31,14 @@ match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE) 1 0 drop table t1, t2; +create table t1 (venue_id int(11) default null, venue_text varchar(255) default null, dt datetime default null) type=myisam; +insert into t1 (venue_id, venue_text, dt) values (1, 'a1', '2003-05-23 19:30:00'),(null, 'a2', '2003-05-23 19:30:00'); +create table t2 (name varchar(255) not null default '', entity_id int(11) not null auto_increment, primary key (entity_id), fulltext key name (name)) type=myisam; +insert into t2 (name, entity_id) values ('aberdeen town hall', 1), ('glasgow royal concert hall', 2), ('queen\'s hall, edinburgh', 3); +select * from t1 left join t2 on venue_id = entity_id where match(name) against('aberdeen' in boolean mode) and dt = '2003-05-23 19:30:00'; +venue_id venue_text dt name entity_id +1 a1 2003-05-23 19:30:00 aberdeen town hall 1 +select * from t1 left join t2 on venue_id = entity_id where match(name) against('aberdeen') and dt = '2003-05-23 19:30:00'; +venue_id venue_text dt name entity_id +1 a1 2003-05-23 19:30:00 aberdeen town hall 1 +drop table t1,t2; diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 8d05adcc1ba..d51bea020ed 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -13,3 +13,6 @@ NULL 255.255.1.255 0.0.1.255 select length(format('nan', 2)) > 0; length(format('nan', 2)) > 0 1 +select concat("$",format(2500,2)); +concat("$",format(2500,2)) +$2,500.00 diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result index ab72e42eca9..86608e7c247 100644 --- a/mysql-test/r/func_set.result +++ b/mysql-test/r/func_set.result @@ -25,6 +25,9 @@ find_in_set("","a,b,c") find_in_set("","a,b,c,") find_in_set("",",a,b,c") select find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc"); find_in_set("abc","abc") find_in_set("ab","abc") find_in_set("abcd","abc") 1 0 0 +select interval(null, 1, 10, 100); +interval(null, 1, 10, 100) +-1 drop table if exists t1,t2; create table t1 (id int(10) not null unique); create table t2 (id int(10) not null primary key, diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 929ab0535d8..06f63b525cd 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -558,3 +558,26 @@ select * from t7 where concat(s1 collate latin1_general_ci,s1 collate latin1_swedish_ci) = 'AA'; ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_swedish_ci,EXPLICIT) for operation 'concat' drop table t7; +CREATE TABLE t1 ( +wid int(10) unsigned NOT NULL auto_increment, +data_podp date default NULL, +status_wnio enum('nowy','podp','real','arch') NOT NULL default 'nowy', +PRIMARY KEY(wid), +); +INSERT INTO t1 VALUES (8,NULL,'real'); +INSERT INTO t1 VALUES (9,NULL,'nowy'); +SELECT elt(status_wnio,data_podp) FROM t1 GROUP BY wid; +elt(status_wnio,data_podp) +NULL +NULL +DROP TABLE t1; +CREATE TABLE t1 ( +title text +) TYPE=MyISAM; +INSERT INTO t1 VALUES ('Congress reconvenes in September to debate welfare and adult education'); +INSERT INTO t1 VALUES ('House passes the CAREERS bill'); +SELECT CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) from t1; +CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) +NULL +</a>.......................... +DROP TABLE t1; diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index be0e3144fd6..9ae7b0c3ef1 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -109,6 +109,11 @@ select _koi8r'a' COLLATE koi8r_general_ci LIKE _koi8r'A' COLLATE koi8r_bin; ERROR HY000: Illegal mix of collations (koi8r_general_ci,EXPLICIT) and (koi8r_bin,EXPLICIT) for operation 'like' select _koi8r'a' LIKE _latin1'A'; ERROR HY000: Illegal mix of collations (koi8r_general_ci,COERCIBLE) and (latin1_swedish_ci,COERCIBLE) for operation 'like' +create table t1 (a int); +insert t1 values (1); +select * from t1 where 1 xor 1; +a +drop table t1; select 5 between 0 and 10 between 0 and 1,(5 between 0 and 10) between 0 and 1; 5 between 0 and 10 between 0 and 1 (5 between 0 and 10) between 0 and 1 0 1 diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 38fe97a79a6..e6673ace227 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -334,6 +334,9 @@ insert into t1 values ('2001-01-12 12:23:40'); select ctime, hour(ctime) from t1; ctime hour(ctime) 2001-01-12 12:23:40 12 +select ctime from t1 where extract(MONTH FROM ctime) = 1 AND extract(YEAR FROM ctime) = 2001; +ctime +2001-01-12 12:23:40 drop table t1; create table t1 (id int); create table t2 (id int, date date); diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 6b33f6a7536..09c2b2042b3 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -66,41 +66,46 @@ GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TE revoke all privileges on mysqltest.* from mysqltest_1@localhost; delete from mysql.user where user='mysqltest_1'; flush privileges; -grant usage on test.* to user@localhost with grant option; -show grants for user@localhost; -Grants for user@localhost -GRANT USAGE ON *.* TO 'user'@'localhost' -GRANT USAGE ON `test`.* TO 'user'@'localhost' WITH GRANT OPTION -grant ALL PRIVILEGES on *.* to drop_user2@localhost with GRANT OPTION; -show grants for drop_user2@localhost; -Grants for drop_user2@localhost -GRANT ALL PRIVILEGES ON *.* TO 'drop_user2'@'localhost' WITH GRANT OPTION -revoke all privileges, grant from drop_user2@localhost; -drop user drop_user2@localhost; -grant ALL PRIVILEGES on *.* to drop_user@localhost with GRANT OPTION; -grant ALL PRIVILEGES on test.* to drop_user@localhost with GRANT OPTION; -grant select(a) on test.t1 to drop_user@localhost; -show grants for drop_user@localhost; -Grants for drop_user@localhost -GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION -GRANT ALL PRIVILEGES ON `test`.* TO 'drop_user'@'localhost' WITH GRANT OPTION -GRANT SELECT (a) ON `test`.`t1` TO 'drop_user'@'localhost' -revoke all privileges, grant from drop_user@localhost; -show grants for drop_user@localhost; -Grants for drop_user@localhost -GRANT USAGE ON *.* TO 'drop_user'@'localhost' -drop user drop_user@localhost; -revoke all privileges, grant from drop_user@localhost; -ERROR HY000: Can't revoke all privileges, grant for one or more of the requested users -grant select(a) on test.t1 to drop_user1@localhost; -grant select on test.t1 to drop_user2@localhost; -grant select on test.* to drop_user3@localhost; -grant select on *.* to drop_user4@localhost; -drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, -drop_user4@localhost; -ERROR HY000: Can't drop one or more of the requested users -revoke all privileges, grant from drop_user1@localhost, drop_user2@localhost, -drop_user3@localhost, drop_user4@localhost; -drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, -drop_user4@localhost; +grant usage on test.* to mysqltest_1@localhost with grant option; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT USAGE ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +GRANT USAGE ON `test`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; +create table t1 (a int); +GRANT select,update,insert on t1 to mysqltest_1@localhost; +GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, SELECT (a), INSERT, INSERT (a), UPDATE, UPDATE (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +table_priv column_priv +Select,Insert,Update Select,Insert,Update,References +REVOKE select (a), update on t1 from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, INSERT (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +REVOKE insert,insert (a) on t1 from mysqltest_1@localhost; +GRANT references on t1 to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, REFERENCES, REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +table_priv column_priv +Select,References References +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; drop table t1; +GRANT FILE on mysqltest.* to mysqltest_1@localhost; +Wrong usage of DB GRANT and GLOBAL PRIVILEGES diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result index 3edaa003b60..f49db67a9f7 100644 --- a/mysql-test/r/grant_cache.result +++ b/mysql-test/r/grant_cache.result @@ -1,4 +1,5 @@ drop table if exists test.t1,mysqltest.t1,mysqltest.t2; +drop database if exists mysqltest; reset query cache; flush status; create database if not exists mysqltest; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 23f82532d06..de0407a8907 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -593,11 +593,11 @@ a b explain select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary; Using filesort -1 SIMPLE t2 ALL a NULL NULL NULL 4 Using where +1 SIMPLE t2 ALL a NULL NULL NULL 3 Using where explain select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b ORDER BY NULL; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary -1 SIMPLE t2 ALL a NULL NULL NULL 4 Using where +1 SIMPLE t2 ALL a NULL NULL NULL 3 Using where drop table t1,t2; create table t1 (a int, b int); insert into t1 values (1, 4),(10, 40),(1, 4),(10, 43),(1, 4),(10, 41),(1, 4),(10, 43),(1, 4); diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 4e0153006f8..bf68057a9aa 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -167,3 +167,30 @@ handler t1 read first; a 6 drop table t1; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6); +delete from t1 limit 2; +handler t1 open; +handler t1 read first; +a +3 +handler t1 read first limit 1,1; +a +4 +handler t1 read first limit 2,2; +a +5 +6 +delete from t1 limit 3; +handler t1 read first; +a +6 +drop table t1; +create table t1(a int, index(a)); +insert into t1 values (1), (2), (3); +handler t1 open; +handler t1 read a=(W); +Unknown column 'W' in 'field list' +handler t1 read a=(a); +Wrong arguments to HANDLER ... READ +drop table t1; diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index 7d929f50801..4f73cfb6d72 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -172,7 +172,7 @@ Warning 1263 Data truncated for column 'new_col' at row 4 Warning 1263 Data truncated for column 'new_col' at row 5 explain select * from t1 where btn="a"; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL btn NULL NULL NULL 14 Using where +1 SIMPLE t1 ALL btn NULL NULL NULL 11 Using where explain select * from t1 where btn="a" and new_col="a"; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref btn btn 11 const,const 10 Using where @@ -203,6 +203,20 @@ a b INSERT INTO t1 VALUES (1,3); ERROR 23000: Duplicate entry '3' for key 1 DROP TABLE t1; +CREATE TABLE t1 ( +a int default NULL, +key a (a) +) TYPE=HEAP; +INSERT INTO t1 VALUES (10), (10), (10); +EXPLAIN SELECT * FROM t1 WHERE a=10; +table type possible_keys key key_len ref rows Extra +t1 ref a a 5 const 10 Using where +SELECT * FROM t1 WHERE a=10; +a +10 +10 +10 +DROP TABLE t1; CREATE TABLE t1 (a int not null, primary key(a)) type=heap; INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); DELETE from t1 where a < 100; diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index ebd34dd7668..59c598265c0 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -58,6 +58,16 @@ skr 2 test 1 test 2 drop table t1; +create table t1 (id int NOT NULL DEFAULT 8); +insert into t1 values(NULL); +Column 'id' cannot be null +insert into t1 values (1), (NULL), (2); +select * from t1; +id +1 +0 +2 +drop table t1; drop database if exists test_$1; create database test_$1; use test_$1; diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 04c3bc9027d..d5b9b9a2117 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -76,3 +76,518 @@ show binlog events; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 drop table t1, t2; +drop table if exists t1, t2; +create table t1 (a int not null); +create table t2 (a int not null); +insert into t1 values (1); +insert into t1 values (a+2); +insert into t1 values (a+3); +insert into t1 values (4),(a+5); +insert into t1 select * from t1; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +insert into t1 select * from t1 as t2; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +insert into t2 select * from t1 as t2; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +insert into t1 select t2.a from t1,t2; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +insert into t1 select * from t1,t1; +Not unique table/alias: 't1' +drop table t1,t2; +create table t1 (a int not null primary key, b char(10)); +create table t2 (a int not null, b char(10)); +insert into t1 values (1,"t1:1"),(3,"t1:3"); +insert into t2 values (2,"t2:2"), (3,"t2:3"); +insert into t1 select * from t2; +Duplicate entry '3' for key 1 +select * from t1; +a b +1 t1:1 +3 t1:3 +2 t2:2 +replace into t1 select * from t2; +select * from t1; +a b +1 t1:1 +3 t2:3 +2 t2:2 +drop table t1,t2; +CREATE TABLE t1 ( USID INTEGER UNSIGNED, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User CHAR(32) NOT NULL DEFAULT '<UNKNOWN>', NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL); +CREATE TABLE t2 ( USID INTEGER UNSIGNED AUTO_INCREMENT, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User TEXT NOT NULL, NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL, INDEX(USID,ServerID,NASAddr,SessionID), INDEX(AssignedAddr)); +INSERT INTO t1 VALUES (39,42,'Access-Granted','46','491721000045',2130706433,17690,NULL,NULL,'Localnet','491721000045','49172200000',754974766,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2003-07-18 00:11:21',NULL,NULL,20030718001121); +INSERT INTO t2 SELECT USID, ServerID, State, SessionID, User, NASAddr, NASPort, NASPortType, ConnectSpeed, CarrierType, CallingStationID, CalledStationID, AssignedAddr, SessionTime, PacketsIn, OctetsIn, PacketsOut, OctetsOut, TerminateCause, UnauthTime, AccessRequestTime, AcctStartTime, AcctLastTime, LastModification from t1 LIMIT 1; +drop table t1,t2; diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 05dac389ada..24b272a1985 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -104,9 +104,7 @@ KEY category (category,county,state) INSERT INTO t2 VALUES (3,2,11,12,5400,7800); INSERT INTO t2 VALUES (4,2,25,12,6500,11200); INSERT INTO t2 VALUES (5,1,37,6,10000,12000); -select a.id, b.category as catid, b.state as stateid, b.county as -countyid from t1 a, t2 b where (a.token = -'a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id); +select a.id, b.category as catid, b.state as stateid, b.county as countyid from t1 a, t2 b ignore index (primary) where (a.token ='a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id); id catid stateid countyid 27 2 12 11 28 2 12 11 diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 9e494fc88c2..b7d3f94cb33 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -657,3 +657,11 @@ i i i 1 NULL NULL 2 2 2 drop table t1,t2,t3; +create table t1 (f1 integer,f2 integer,f3 integer); +create table t2 (f2 integer,f4 integer); +create table t3 (f3 integer,f5 integer); +select * from t1 +left outer join t2 using (f2) +left outer join t3 using (f3); +Unknown column 'test.t2.f3' in 'on clause' +drop table t1,t2,t3; diff --git a/mysql-test/r/key_diff.result b/mysql-test/r/key_diff.result index 8097186bde1..c3f4f743967 100644 --- a/mysql-test/r/key_diff.result +++ b/mysql-test/r/key_diff.result @@ -36,7 +36,7 @@ a a a a explain select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL a NULL NULL NULL 5 -1 SIMPLE t2 ALL b NULL NULL NULL 5 Using where +1 SIMPLE t2 ALL b NULL NULL NULL 4 Using where select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B order by binary t1.a,t2.a; a b a b A B a a diff --git a/mysql-test/r/lock_tables_lost_commit.result b/mysql-test/r/lock_tables_lost_commit.result new file mode 100644 index 00000000000..ccf56793f45 --- /dev/null +++ b/mysql-test/r/lock_tables_lost_commit.result @@ -0,0 +1,8 @@ +drop table if exists t1; +create table t1(a int) type=innodb; +lock tables t1 write; +insert into t1 values(10); +select * from t1; +a +10 +drop table t1; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 507ceb8951c..9a99d1c64fb 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -610,3 +610,17 @@ AND file_code = '0000000115' LIMIT 1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const PRIMARY,files PRIMARY 33 const,const 1 DROP TABLE t2, t1; +create table t1 (x int, y int, index xy(x, y)); +create table t2 (x int, y int, index xy(x, y)); +create table t3 (x int, y int, index xy(x, y)) type=merge union=(t1,t2); +insert into t1 values(1, 2); +insert into t2 values(1, 3); +select * from t3 where x = 1 and y < 5 order by y; +x y +1 2 +1 3 +select * from t3 where x = 1 and y < 5 order by y desc; +x y +1 3 +1 2 +drop table t1,t2,t3; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index fd9ff2c90cf..59af9b3e7f3 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -361,12 +361,12 @@ t1 1 c_2 1 c A 5 NULL NULL YES BTREE t1 1 c_2 2 a A 5 NULL NULL BTREE explain select * from t1,t2 where t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL a NULL NULL NULL 5 1 SIMPLE t2 ALL a NULL NULL NULL 2 Using where +1 SIMPLE t1 ALL a NULL NULL NULL 4 explain select * from t1,t2 force index(a) where t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL a NULL NULL NULL 2 -1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where +1 SIMPLE t1 ALL a NULL NULL NULL 4 Using where explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL a NULL NULL NULL 2 @@ -377,8 +377,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref b b 5 test.t2.b 1 Using where explain select * from t1,t2 force index(c) where t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL a NULL NULL NULL 5 1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where +1 SIMPLE t1 ALL a NULL NULL NULL 4 explain select * from t1 where a=0 or a=2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 1e940351a4a..5470b9387e3 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -306,17 +306,17 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 9 NULL 8 Using where; Using index explain select * from t1 where a = 2 and b >0 order by a desc,b desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 9 NULL 5 Using where; Using index +1 SIMPLE t1 range a a 9 NULL 4 Using where; Using index explain select * from t1 where a = 2 and b is null order by a desc,b desc; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref a a 9 const,const 1 Using where; Using index; Using filesort explain select * from t1 where a = 2 and (b is null or b > 0) order by a desc,b desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 9 NULL 6 Using where; Using index +1 SIMPLE t1 range a a 9 NULL 5 Using where; Using index explain select * from t1 where a = 2 and b > 0 order by a desc,b desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 9 NULL 5 Using where; Using index +1 SIMPLE t1 range a a 9 NULL 4 Using where; Using index explain select * from t1 where a = 2 and b < 2 order by a desc,b desc; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 9 NULL 2 Using where; Using index diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 68ddb5a377b..420281b7ef2 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -2,8 +2,8 @@ flush query cache; flush query cache; reset query cache; flush status; +drop table if exists t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t00,mysqltest.t1; drop database if exists mysqltest; -drop table if exists t1,t2,t3,t11,t21, mysqltest.t1; create table t1 (a int not null); insert into t1 values (1),(2),(3); select * from t1; @@ -358,7 +358,7 @@ show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 drop table t1,t2; -create database if not exists mysqltest; +create database mysqltest; create table mysqltest.t1 (i int not null auto_increment, a int, primary key (i)); insert into mysqltest.t1 (a) values (1); select * from mysqltest.t1 where i is null; @@ -709,3 +709,536 @@ Variable_name Value Qcache_queries_in_cache 2 SET OPTION SQL_SELECT_LIMIT=DEFAULT; drop table t1; +flush status; +create table t0(a int); +create table t1(a int); +create table t2(a int); +create table t3(a int); +create table t4(a int); +create table t5(a int); +create table t6(a int); +create table t7(a int); +create table t8(a int); +create table t9(a int); +create table t10(a int); +create table t11(a int); +create table t12(a int); +create table t13(a int); +create table t14(a int); +create table t15(a int); +create table t16(a int); +create table t17(a int); +create table t18(a int); +create table t19(a int); +create table t20(a int); +create table t21(a int); +create table t22(a int); +create table t23(a int); +create table t24(a int); +create table t25(a int); +create table t26(a int); +create table t27(a int); +create table t28(a int); +create table t29(a int); +create table t30(a int); +create table t31(a int); +create table t32(a int); +create table t33(a int); +create table t34(a int); +create table t35(a int); +create table t36(a int); +create table t37(a int); +create table t38(a int); +create table t39(a int); +create table t40(a int); +create table t41(a int); +create table t42(a int); +create table t43(a int); +create table t44(a int); +create table t45(a int); +create table t46(a int); +create table t47(a int); +create table t48(a int); +create table t49(a int); +create table t50(a int); +create table t51(a int); +create table t52(a int); +create table t53(a int); +create table t54(a int); +create table t55(a int); +create table t56(a int); +create table t57(a int); +create table t58(a int); +create table t59(a int); +create table t60(a int); +create table t61(a int); +create table t62(a int); +create table t63(a int); +create table t64(a int); +create table t65(a int); +create table t66(a int); +create table t67(a int); +create table t68(a int); +create table t69(a int); +create table t70(a int); +create table t71(a int); +create table t72(a int); +create table t73(a int); +create table t74(a int); +create table t75(a int); +create table t76(a int); +create table t77(a int); +create table t78(a int); +create table t79(a int); +create table t80(a int); +create table t81(a int); +create table t82(a int); +create table t83(a int); +create table t84(a int); +create table t85(a int); +create table t86(a int); +create table t87(a int); +create table t88(a int); +create table t89(a int); +create table t90(a int); +create table t91(a int); +create table t92(a int); +create table t93(a int); +create table t94(a int); +create table t95(a int); +create table t96(a int); +create table t97(a int); +create table t98(a int); +create table t99(a int); +create table t100(a int); +create table t101(a int); +create table t102(a int); +create table t103(a int); +create table t104(a int); +create table t105(a int); +create table t106(a int); +create table t107(a int); +create table t108(a int); +create table t109(a int); +create table t110(a int); +create table t111(a int); +create table t112(a int); +create table t113(a int); +create table t114(a int); +create table t115(a int); +create table t116(a int); +create table t117(a int); +create table t118(a int); +create table t119(a int); +create table t120(a int); +create table t121(a int); +create table t122(a int); +create table t123(a int); +create table t124(a int); +create table t125(a int); +create table t126(a int); +create table t127(a int); +create table t128(a int); +create table t129(a int); +create table t130(a int); +create table t131(a int); +create table t132(a int); +create table t133(a int); +create table t134(a int); +create table t135(a int); +create table t136(a int); +create table t137(a int); +create table t138(a int); +create table t139(a int); +create table t140(a int); +create table t141(a int); +create table t142(a int); +create table t143(a int); +create table t144(a int); +create table t145(a int); +create table t146(a int); +create table t147(a int); +create table t148(a int); +create table t149(a int); +create table t150(a int); +create table t151(a int); +create table t152(a int); +create table t153(a int); +create table t154(a int); +create table t155(a int); +create table t156(a int); +create table t157(a int); +create table t158(a int); +create table t159(a int); +create table t160(a int); +create table t161(a int); +create table t162(a int); +create table t163(a int); +create table t164(a int); +create table t165(a int); +create table t166(a int); +create table t167(a int); +create table t168(a int); +create table t169(a int); +create table t170(a int); +create table t171(a int); +create table t172(a int); +create table t173(a int); +create table t174(a int); +create table t175(a int); +create table t176(a int); +create table t177(a int); +create table t178(a int); +create table t179(a int); +create table t180(a int); +create table t181(a int); +create table t182(a int); +create table t183(a int); +create table t184(a int); +create table t185(a int); +create table t186(a int); +create table t187(a int); +create table t188(a int); +create table t189(a int); +create table t190(a int); +create table t191(a int); +create table t192(a int); +create table t193(a int); +create table t194(a int); +create table t195(a int); +create table t196(a int); +create table t197(a int); +create table t198(a int); +create table t199(a int); +create table t200(a int); +create table t201(a int); +create table t202(a int); +create table t203(a int); +create table t204(a int); +create table t205(a int); +create table t206(a int); +create table t207(a int); +create table t208(a int); +create table t209(a int); +create table t210(a int); +create table t211(a int); +create table t212(a int); +create table t213(a int); +create table t214(a int); +create table t215(a int); +create table t216(a int); +create table t217(a int); +create table t218(a int); +create table t219(a int); +create table t220(a int); +create table t221(a int); +create table t222(a int); +create table t223(a int); +create table t224(a int); +create table t225(a int); +create table t226(a int); +create table t227(a int); +create table t228(a int); +create table t229(a int); +create table t230(a int); +create table t231(a int); +create table t232(a int); +create table t233(a int); +create table t234(a int); +create table t235(a int); +create table t236(a int); +create table t237(a int); +create table t238(a int); +create table t239(a int); +create table t240(a int); +create table t241(a int); +create table t242(a int); +create table t243(a int); +create table t244(a int); +create table t245(a int); +create table t246(a int); +create table t247(a int); +create table t248(a int); +create table t249(a int); +create table t250(a int); +create table t251(a int); +create table t252(a int); +create table t253(a int); +create table t254(a int); +create table t255(a int); +create table t256(a int); +create table t00 (a int) type=MERGE UNION=(t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256) INSERT_METHOD=FIRST; +insert into t0 values (1),(2); +insert into t1 values (1),(2); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +insert into t4 values (1),(2); +insert into t5 values (1),(2); +insert into t6 values (1),(2); +insert into t7 values (1),(2); +insert into t8 values (1),(2); +insert into t9 values (1),(2); +insert into t10 values (1),(2); +insert into t11 values (1),(2); +insert into t12 values (1),(2); +insert into t13 values (1),(2); +insert into t14 values (1),(2); +insert into t15 values (1),(2); +insert into t16 values (1),(2); +insert into t17 values (1),(2); +insert into t18 values (1),(2); +insert into t19 values (1),(2); +insert into t20 values (1),(2); +insert into t21 values (1),(2); +insert into t22 values (1),(2); +insert into t23 values (1),(2); +insert into t24 values (1),(2); +insert into t25 values (1),(2); +insert into t26 values (1),(2); +insert into t27 values (1),(2); +insert into t28 values (1),(2); +insert into t29 values (1),(2); +insert into t30 values (1),(2); +insert into t31 values (1),(2); +insert into t32 values (1),(2); +insert into t33 values (1),(2); +insert into t34 values (1),(2); +insert into t35 values (1),(2); +insert into t36 values (1),(2); +insert into t37 values (1),(2); +insert into t38 values (1),(2); +insert into t39 values (1),(2); +insert into t40 values (1),(2); +insert into t41 values (1),(2); +insert into t42 values (1),(2); +insert into t43 values (1),(2); +insert into t44 values (1),(2); +insert into t45 values (1),(2); +insert into t46 values (1),(2); +insert into t47 values (1),(2); +insert into t48 values (1),(2); +insert into t49 values (1),(2); +insert into t50 values (1),(2); +insert into t51 values (1),(2); +insert into t52 values (1),(2); +insert into t53 values (1),(2); +insert into t54 values (1),(2); +insert into t55 values (1),(2); +insert into t56 values (1),(2); +insert into t57 values (1),(2); +insert into t58 values (1),(2); +insert into t59 values (1),(2); +insert into t60 values (1),(2); +insert into t61 values (1),(2); +insert into t62 values (1),(2); +insert into t63 values (1),(2); +insert into t64 values (1),(2); +insert into t65 values (1),(2); +insert into t66 values (1),(2); +insert into t67 values (1),(2); +insert into t68 values (1),(2); +insert into t69 values (1),(2); +insert into t70 values (1),(2); +insert into t71 values (1),(2); +insert into t72 values (1),(2); +insert into t73 values (1),(2); +insert into t74 values (1),(2); +insert into t75 values (1),(2); +insert into t76 values (1),(2); +insert into t77 values (1),(2); +insert into t78 values (1),(2); +insert into t79 values (1),(2); +insert into t80 values (1),(2); +insert into t81 values (1),(2); +insert into t82 values (1),(2); +insert into t83 values (1),(2); +insert into t84 values (1),(2); +insert into t85 values (1),(2); +insert into t86 values (1),(2); +insert into t87 values (1),(2); +insert into t88 values (1),(2); +insert into t89 values (1),(2); +insert into t90 values (1),(2); +insert into t91 values (1),(2); +insert into t92 values (1),(2); +insert into t93 values (1),(2); +insert into t94 values (1),(2); +insert into t95 values (1),(2); +insert into t96 values (1),(2); +insert into t97 values (1),(2); +insert into t98 values (1),(2); +insert into t99 values (1),(2); +insert into t100 values (1),(2); +insert into t101 values (1),(2); +insert into t102 values (1),(2); +insert into t103 values (1),(2); +insert into t104 values (1),(2); +insert into t105 values (1),(2); +insert into t106 values (1),(2); +insert into t107 values (1),(2); +insert into t108 values (1),(2); +insert into t109 values (1),(2); +insert into t110 values (1),(2); +insert into t111 values (1),(2); +insert into t112 values (1),(2); +insert into t113 values (1),(2); +insert into t114 values (1),(2); +insert into t115 values (1),(2); +insert into t116 values (1),(2); +insert into t117 values (1),(2); +insert into t118 values (1),(2); +insert into t119 values (1),(2); +insert into t120 values (1),(2); +insert into t121 values (1),(2); +insert into t122 values (1),(2); +insert into t123 values (1),(2); +insert into t124 values (1),(2); +insert into t125 values (1),(2); +insert into t126 values (1),(2); +insert into t127 values (1),(2); +insert into t128 values (1),(2); +insert into t129 values (1),(2); +insert into t130 values (1),(2); +insert into t131 values (1),(2); +insert into t132 values (1),(2); +insert into t133 values (1),(2); +insert into t134 values (1),(2); +insert into t135 values (1),(2); +insert into t136 values (1),(2); +insert into t137 values (1),(2); +insert into t138 values (1),(2); +insert into t139 values (1),(2); +insert into t140 values (1),(2); +insert into t141 values (1),(2); +insert into t142 values (1),(2); +insert into t143 values (1),(2); +insert into t144 values (1),(2); +insert into t145 values (1),(2); +insert into t146 values (1),(2); +insert into t147 values (1),(2); +insert into t148 values (1),(2); +insert into t149 values (1),(2); +insert into t150 values (1),(2); +insert into t151 values (1),(2); +insert into t152 values (1),(2); +insert into t153 values (1),(2); +insert into t154 values (1),(2); +insert into t155 values (1),(2); +insert into t156 values (1),(2); +insert into t157 values (1),(2); +insert into t158 values (1),(2); +insert into t159 values (1),(2); +insert into t160 values (1),(2); +insert into t161 values (1),(2); +insert into t162 values (1),(2); +insert into t163 values (1),(2); +insert into t164 values (1),(2); +insert into t165 values (1),(2); +insert into t166 values (1),(2); +insert into t167 values (1),(2); +insert into t168 values (1),(2); +insert into t169 values (1),(2); +insert into t170 values (1),(2); +insert into t171 values (1),(2); +insert into t172 values (1),(2); +insert into t173 values (1),(2); +insert into t174 values (1),(2); +insert into t175 values (1),(2); +insert into t176 values (1),(2); +insert into t177 values (1),(2); +insert into t178 values (1),(2); +insert into t179 values (1),(2); +insert into t180 values (1),(2); +insert into t181 values (1),(2); +insert into t182 values (1),(2); +insert into t183 values (1),(2); +insert into t184 values (1),(2); +insert into t185 values (1),(2); +insert into t186 values (1),(2); +insert into t187 values (1),(2); +insert into t188 values (1),(2); +insert into t189 values (1),(2); +insert into t190 values (1),(2); +insert into t191 values (1),(2); +insert into t192 values (1),(2); +insert into t193 values (1),(2); +insert into t194 values (1),(2); +insert into t195 values (1),(2); +insert into t196 values (1),(2); +insert into t197 values (1),(2); +insert into t198 values (1),(2); +insert into t199 values (1),(2); +insert into t200 values (1),(2); +insert into t201 values (1),(2); +insert into t202 values (1),(2); +insert into t203 values (1),(2); +insert into t204 values (1),(2); +insert into t205 values (1),(2); +insert into t206 values (1),(2); +insert into t207 values (1),(2); +insert into t208 values (1),(2); +insert into t209 values (1),(2); +insert into t210 values (1),(2); +insert into t211 values (1),(2); +insert into t212 values (1),(2); +insert into t213 values (1),(2); +insert into t214 values (1),(2); +insert into t215 values (1),(2); +insert into t216 values (1),(2); +insert into t217 values (1),(2); +insert into t218 values (1),(2); +insert into t219 values (1),(2); +insert into t220 values (1),(2); +insert into t221 values (1),(2); +insert into t222 values (1),(2); +insert into t223 values (1),(2); +insert into t224 values (1),(2); +insert into t225 values (1),(2); +insert into t226 values (1),(2); +insert into t227 values (1),(2); +insert into t228 values (1),(2); +insert into t229 values (1),(2); +insert into t230 values (1),(2); +insert into t231 values (1),(2); +insert into t232 values (1),(2); +insert into t233 values (1),(2); +insert into t234 values (1),(2); +insert into t235 values (1),(2); +insert into t236 values (1),(2); +insert into t237 values (1),(2); +insert into t238 values (1),(2); +insert into t239 values (1),(2); +insert into t240 values (1),(2); +insert into t241 values (1),(2); +insert into t242 values (1),(2); +insert into t243 values (1),(2); +insert into t244 values (1),(2); +insert into t245 values (1),(2); +insert into t246 values (1),(2); +insert into t247 values (1),(2); +insert into t248 values (1),(2); +insert into t249 values (1),(2); +insert into t250 values (1),(2); +insert into t251 values (1),(2); +insert into t252 values (1),(2); +insert into t253 values (1),(2); +insert into t254 values (1),(2); +insert into t255 values (1),(2); +insert into t256 values (1),(2); +select count(*) from t00; +count(*) +514 +select count(*) from t00; +count(*) +514 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +delete from t256; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +drop table t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t00; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 86a93398a9f..247221a92f3 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -5,7 +5,24 @@ type int(11) DEFAULT '0' NOT NULL, event_id int(11) DEFAULT '0' NOT NULL, PRIMARY KEY (event_date,type,event_id) ); -INSERT INTO t1 VALUES ('1999-07-10',100100,24),('1999-07-11',100100,25),('1999-07-13',100600,0),('1999-07-13',100600,4),('1999-07-13',100600,26),('1999-07-14',100600,10),('1999-07-15',100600,16),('1999-07-15',100800,45),('1999-07-15',101000,47),('1999-07-16',100800,46),('1999-07-20',100600,5),('1999-07-20',100600,27),('1999-07-21',100600,11),('1999-07-22',100600,17),('1999-07-23',100100,39),('1999-07-24',100100,39),('1999-07-24',100500,40),('1999-07-25',100100,39),('1999-07-27',100600,1),('1999-07-27',100600,6),('1999-07-27',100600,28),('1999-07-28',100600,12),('1999-07-29',100500,41),('1999-07-29',100600,18),('1999-07-30',100500,41),('1999-07-31',100500,41),('1999-08-01',100700,34),('1999-08-03',100600,7),('1999-08-03',100600,29),('1999-08-04',100600,13),('1999-08-05',100500,42),('1999-08-05',100600,19),('1999-08-06',100500,42),('1999-08-07',100500,42),('1999-08-08',100500,42),('1999-08-10',100600,2),('1999-08-10',100600,9),('1999-08-10',100600,30),('1999-08-11',100600,14),('1999-08-12',100600,20),('1999-08-17',100500,8),('1999-08-17',100600,31),('1999-08-18',100600,15),('1999-08-19',100600,22),('1999-08-24',100600,3),('1999-08-24',100600,32),('1999-08-27',100500,43),('1999-08-31',100600,33),('1999-09-17',100100,37),('1999-09-18',100100,37),('1999-09-19',100100,37),('2000-12-18',100700,38); +INSERT INTO t1 VALUES ('1999-07-10',100100,24), ('1999-07-11',100100,25), +('1999-07-13',100600,0), ('1999-07-13',100600,4), ('1999-07-13',100600,26), +('1999-07-14',100600,10), ('1999-07-15',100600,16), ('1999-07-15',100800,45), +('1999-07-15',101000,47), ('1999-07-16',100800,46), ('1999-07-20',100600,5), +('1999-07-20',100600,27), ('1999-07-21',100600,11), ('1999-07-22',100600,17), +('1999-07-23',100100,39), ('1999-07-24',100100,39), ('1999-07-24',100500,40), +('1999-07-25',100100,39), ('1999-07-27',100600,1), ('1999-07-27',100600,6), +('1999-07-27',100600,28), ('1999-07-28',100600,12), ('1999-07-29',100500,41), +('1999-07-29',100600,18), ('1999-07-30',100500,41), ('1999-07-31',100500,41), +('1999-08-01',100700,34), ('1999-08-03',100600,7), ('1999-08-03',100600,29), +('1999-08-04',100600,13), ('1999-08-05',100500,42), ('1999-08-05',100600,19), +('1999-08-06',100500,42), ('1999-08-07',100500,42), ('1999-08-08',100500,42), +('1999-08-10',100600,2), ('1999-08-10',100600,9), ('1999-08-10',100600,30), +('1999-08-11',100600,14), ('1999-08-12',100600,20), ('1999-08-17',100500,8), +('1999-08-17',100600,31), ('1999-08-18',100600,15), ('1999-08-19',100600,22), +('1999-08-24',100600,3), ('1999-08-24',100600,32), ('1999-08-27',100500,43), +('1999-08-31',100600,33), ('1999-09-17',100100,37), ('1999-09-18',100100,37), +('1999-09-19',100100,37), ('2000-12-18',100700,38); select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; event_date type event_id 1999-07-10 100100 24 @@ -35,35 +52,21 @@ CLOSED tinyint(4) DEFAULT '0' NOT NULL, ISS_DATE date DEFAULT '0000-00-00' NOT NULL, PRIMARY KEY (PAPER_ID,YEAR,ISSUE) ); -INSERT INTO t1 VALUES (3,1999,34,0,'1999-07-12'); -INSERT INTO t1 VALUES (1,1999,111,0,'1999-03-23'); -INSERT INTO t1 VALUES (1,1999,222,0,'1999-03-23'); -INSERT INTO t1 VALUES (3,1999,33,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,32,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,31,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,30,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,29,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,28,0,'1999-07-12'); -INSERT INTO t1 VALUES (1,1999,40,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,41,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,42,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,46,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,47,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,48,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,49,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,50,0,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,51,0,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,200,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,52,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,53,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,54,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,55,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,56,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,57,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,58,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,59,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,60,0,'1999-07-01'); -INSERT INTO t1 VALUES (3,1999,35,0,'1999-07-12'); +INSERT INTO t1 VALUES (3,1999,34,0,'1999-07-12'), (1,1999,111,0,'1999-03-23'), +(1,1999,222,0,'1999-03-23'), (3,1999,33,0,'1999-07-12'), +(3,1999,32,0,'1999-07-12'), (3,1999,31,0,'1999-07-12'), +(3,1999,30,0,'1999-07-12'), (3,1999,29,0,'1999-07-12'), +(3,1999,28,0,'1999-07-12'), (1,1999,40,1,'1999-05-01'), +(1,1999,41,1,'1999-05-01'), (1,1999,42,1,'1999-05-01'), +(1,1999,46,1,'1999-05-01'), (1,1999,47,1,'1999-05-01'), +(1,1999,48,1,'1999-05-01'), (1,1999,49,1,'1999-05-01'), +(1,1999,50,0,'1999-05-01'), (1,1999,51,0,'1999-05-01'), +(1,1999,200,0,'1999-06-28'), (1,1999,52,0,'1999-06-28'), +(1,1999,53,0,'1999-06-28'), (1,1999,54,0,'1999-06-28'), +(1,1999,55,0,'1999-06-28'), (1,1999,56,0,'1999-07-01'), +(1,1999,57,0,'1999-07-01'), (1,1999,58,0,'1999-07-01'), +(1,1999,59,0,'1999-07-01'), (1,1999,60,0,'1999-07-01'), +(3,1999,35,0,'1999-07-12'); select YEAR,ISSUE from t1 where PAPER_ID=3 and (YEAR>1999 or (YEAR=1999 and ISSUE>28)) order by YEAR,ISSUE; YEAR ISSUE 1999 29 @@ -88,7 +91,12 @@ PRIMARY KEY (id), KEY parent_id (parent_id), KEY level (level) ); -INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2); +INSERT INTO t1 VALUES (1,0,0), (3,1,1), (4,1,1), (8,2,2), (9,2,2), (17,3,2), +(22,4,2), (24,4,2), (28,5,2), (29,5,2), (30,5,2), (31,6,2), (32,6,2), (33,6,2), +(203,7,2), (202,7,2), (20,3,2), (157,0,0), (193,5,2), (40,7,2), (2,1,1), +(15,2,2), (6,1,1), (34,6,2), (35,6,2), (16,3,2), (7,1,1), (36,7,2), (18,3,2), +(26,5,2), (27,5,2), (183,4,2), (38,7,2), (25,5,2), (37,7,2), (21,4,2), +(19,3,2), (5,1,1), (179,5,2); SELECT * FROM t1 WHERE level = 1 AND parent_id = 1; id parent_id level 3 1 1 @@ -207,3 +215,14 @@ select count(*) from t1 where art = 'J'; count(*) 213 drop table t1; +create table t1 ( id1 int not null, id2 int not null, idnull int null, c char(20), primary key (id1,id2)); +insert into t1 values (0,1,NULL,"aaa"), (1,1,NULL,"aaa"), (2,1,NULL,"aaa"), +(3,1,NULL,"aaa"), (4,1,NULL,"aaa"), (5,1,NULL,"aaa"), +(6,1,NULL,"aaa"), (7,1,NULL,"aaa"), (8,1,NULL,"aaa"), +(9,1,NULL,"aaa"), (10,1,NULL,"aaa"), (11,1,NULL,"aaa"), +(12,1,NULL,"aaa"), (13,1,NULL,"aaa"), (14,1,NULL,"aaa"), +(15,1,NULL,"aaa"), (16,1,NULL,"aaa"), (17,1,NULL,"aaa"), +(18,1,NULL,"aaa"), (19,1,NULL,"aaa"), (20,1,NULL,"aaa"); +select a.id1, b.idnull from t1 as a, t1 as b where a.id2=1 and a.id1=1 and b.id1=a.idnull order by b.id2 desc limit 1; +id1 idnull +drop table t1; diff --git a/mysql-test/r/rpl000018.result b/mysql-test/r/rpl000018.result index 7211d440524..b71f6492b97 100644 --- a/mysql-test/r/rpl000018.result +++ b/mysql-test/r/rpl000018.result @@ -1,3 +1,4 @@ +reset master; reset slave; start slave; show binary logs; diff --git a/mysql-test/r/rpl_do_grant.result b/mysql-test/r/rpl_do_grant.result new file mode 100644 index 00000000000..fec935ae7ac --- /dev/null +++ b/mysql-test/r/rpl_do_grant.result @@ -0,0 +1,26 @@ +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; +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +grant select on *.* to rpl_do_grant@localhost; +grant drop on test.* to rpl_do_grant@localhost; +show grants for rpl_do_grant@localhost; +Grants for rpl_do_grant@localhost +GRANT SELECT ON *.* TO 'rpl_do_grant'@'localhost' +GRANT DROP ON `test`.* TO 'rpl_do_grant'@'localhost' +set password for rpl_do_grant@localhost=password("does it work?"); +select password<>'' from mysql.user where user='rpl_do_grant'; +password<>'' +1 +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +flush privileges; diff --git a/mysql-test/r/rpl_error_ignored_table.result b/mysql-test/r/rpl_error_ignored_table.result new file mode 100644 index 00000000000..e1486220542 --- /dev/null +++ b/mysql-test/r/rpl_error_ignored_table.result @@ -0,0 +1,15 @@ +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 primary key); +insert into t1 values (1),(1); +Duplicate entry '1' for key 1 +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 213 slave-relay-bin.002 254 master-bin.001 Yes Yes 0 0 213 254 +show tables like 't1'; +Tables_in_test (t1) +drop table t1; diff --git a/mysql-test/r/rpl_flush_log_loop.result b/mysql-test/r/rpl_flush_log_loop.result index 954ab107123..a1709647f19 100644 --- a/mysql-test/r/rpl_flush_log_loop.result +++ b/mysql-test/r/rpl_flush_log_loop.result @@ -14,4 +14,4 @@ start slave; flush logs; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root SLAVE_PORT 60 slave-bin.000001 79 relay-log.000001 122 slave-bin.000001 Yes Yes 0 0 79 122 +127.0.0.1 root SLAVE_PORT 60 slave-bin.000001 79 relay-log.000002 4 slave-bin.000001 Yes Yes 0 0 79 4 diff --git a/mysql-test/r/rpl_ignore_grant.result b/mysql-test/r/rpl_ignore_grant.result new file mode 100644 index 00000000000..6cd7d5b4c00 --- /dev/null +++ b/mysql-test/r/rpl_ignore_grant.result @@ -0,0 +1,37 @@ +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; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +grant select on *.* to rpl_ignore_grant@localhost; +grant drop on test.* to rpl_ignore_grant@localhost; +show grants for rpl_ignore_grant@localhost; +Grants for rpl_ignore_grant@localhost +GRANT SELECT ON *.* TO 'rpl_ignore_grant'@'localhost' +GRANT DROP ON `test`.* TO 'rpl_ignore_grant'@'localhost' +show grants for rpl_ignore_grant@localhost; +There is no such grant defined for user 'rpl_ignore_grant' on host 'localhost' +select count(*) from mysql.user where user='rpl_ignore_grant'; +count(*) +0 +select count(*) from mysql.db where user='rpl_ignore_grant'; +count(*) +0 +grant select on *.* to rpl_ignore_grant@localhost; +set password for rpl_ignore_grant@localhost=password("does it work?"); +select password<>'' from mysql.user where user='rpl_ignore_grant'; +password<>'' +0 +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index 3d7a2a0dd75..cf70e196921 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -20,8 +20,8 @@ b c 1 4 drop table t1; drop table t2; -create table t1(a int auto_increment, key(a)); -create table t2(b int auto_increment, c int, key(b)); +create table t1(a int auto_increment, key(a)) type=innodb; +create table t2(b int auto_increment, c int, key(b), foreign key(b) references t1(a)) type=innodb; SET FOREIGN_KEY_CHECKS=0; insert into t1 values (10); insert into t1 values (null),(null),(null); diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index ec9011d573f..fb3921eb677 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -24,3 +24,30 @@ drop table t2; drop table t3; create table t1(a int, b int, unique(b)); insert into t1 values(1,10); +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +set global sql_slave_skip_counter=1; +start slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 1311 slave-relay-bin.002 1352 master-bin.001 Yes Yes 0 0 1311 1352 +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +stop slave; +change master to master_user='test'; +change master to master_user='root'; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 1442 slave-relay-bin.001 4 master-bin.001 No No 0 0 1442 4 +set global sql_slave_skip_counter=1; +start slave; +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +stop slave; +reset slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 diff --git a/mysql-test/r/rpl_master_pos_wait.result b/mysql-test/r/rpl_master_pos_wait.result index 801ffad6975..bbd125a98d6 100644 --- a/mysql-test/r/rpl_master_pos_wait.result +++ b/mysql-test/r/rpl_master_pos_wait.result @@ -4,6 +4,10 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -select master_pos_wait('master-bin.999999',0,10); -master_pos_wait('master-bin.999999',0,10) +select master_pos_wait('master-bin.999999',0,2); +master_pos_wait('master-bin.999999',0,2) -1 + select master_pos_wait('master-bin.999999',0); +stop slave sql_thread; +master_pos_wait('master-bin.999999',0) +NULL diff --git a/mysql-test/r/rpl_max_relay_size.result b/mysql-test/r/rpl_max_relay_size.result new file mode 100644 index 00000000000..1fa3fcd1adb --- /dev/null +++ b/mysql-test/r/rpl_max_relay_size.result @@ -0,0 +1,61 @@ +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; +stop slave; +create table t1 (a int); +drop table t1; +reset slave; +set global max_binlog_size=8192; +set global max_relay_log_size=8192-1; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +4096 +start slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.014 1221 master-bin.001 Yes Yes 0 0 50477 1221 +stop slave; +reset slave; +set global max_relay_log_size=(5*4096); +select @@global.max_relay_log_size; +@@global.max_relay_log_size +20480 +start slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.004 9457 master-bin.001 Yes Yes 0 0 50477 9457 +stop slave; +reset slave; +set global max_relay_log_size=0; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +0 +start slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.008 1283 master-bin.001 Yes Yes 0 0 50477 1283 +stop slave; +reset slave; +flush logs; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 +reset slave; +start slave; +flush logs; +create table t1 (a int); +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 50535 slave-relay-bin.009 62 master-bin.001 Yes Yes 0 0 50535 62 +flush logs; +drop table t1; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 50583 slave-relay-bin.010 52 master-bin.001 Yes Yes 0 0 50583 52 +flush logs; +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.002 4 diff --git a/mysql-test/r/rpl_relayspace.result b/mysql-test/r/rpl_relayspace.result index 610419980b5..1f2a739d3e3 100644 --- a/mysql-test/r/rpl_relayspace.result +++ b/mysql-test/r/rpl_relayspace.result @@ -6,8 +6,14 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; stop slave; create table t1 (a int); +drop table t1; +create table t1 (a int); +drop table t1; +reset slave; +start slave io_thread; +stop slave io_thread; reset slave; start slave; -select master_pos_wait('master-bin.001',5000,45)=-1; -master_pos_wait('master-bin.001',5000,45)=-1 +select master_pos_wait('master-bin.001',200,6)=-1; +master_pos_wait('master-bin.001',200,6)=-1 0 diff --git a/mysql-test/r/rpl_reset_slave.result b/mysql-test/r/rpl_reset_slave.result new file mode 100644 index 00000000000..c1bc1e8e483 --- /dev/null +++ b/mysql-test/r/rpl_reset_slave.result @@ -0,0 +1,22 @@ +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; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 +stop slave; +change master to master_user='test'; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 test MASTER_PORT 1 master-bin.001 79 slave-relay-bin.001 4 master-bin.001 No No 0 0 79 4 +reset slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 +start slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index 753edebea60..57b48827e33 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -5,7 +5,7 @@ ERROR HY000: Could not initialize master info structure, check permisions on mas start slave; ERROR HY000: Could not initialize master info structure, check permisions on master.info change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; -Could not initialize master info +Could not initialize master info structure, check permisions on master.info reset slave; change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; reset master; @@ -73,17 +73,15 @@ show binary logs; Log_name master-bin.000003 master-bin.000004 -master-bin.000005 -master-bin.000006 show master status; File Position Binlog_do_db Binlog_ignore_db -master-bin.000006 838 +master-bin.000004 2886 select * from t4; a testing temporary tables part 2 show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 60 master-bin.000006 838 slave-relay-bin.000001 8067 master-bin.000006 Yes Yes 0 0 838 8067 +127.0.0.1 root MASTER_PORT 60 master-bin.000006 838 slave-relay-bin.000001 8067 master-bin.000004 Yes Yes 0 0 2886 8067 lock tables t3 read; select count(*) from t3 where n >= 4; count(*) diff --git a/mysql-test/r/sel000100.result b/mysql-test/r/sel000100.result index f9234815a2b..3ffa4004b84 100644 --- a/mysql-test/r/sel000100.result +++ b/mysql-test/r/sel000100.result @@ -26,3 +26,13 @@ ORDER BY link; key_link_id link NULL NULL drop table t1,t2; +CREATE TABLE t1 ( +html varchar(5) default NULL, +rin int(11) default '0', +out int(11) default '0' +) TYPE=MyISAM; +INSERT INTO t1 VALUES ('1',1,0); +SELECT DISTINCT html,SUM(out)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; +html prod +1 0.00 +drop table t1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index fbce0e9290a..e83bbc2fc8c 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2568,21 +2568,51 @@ fld1 fld1 250503 250505 250504 250505 250505 250505 +insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; companynr companyname +99 NULL +select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; +count(*) +1199 explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where; Not exists explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 -1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Not exists +1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where; Not exists select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; companynr companynr 37 36 41 40 -explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; +delete from t2 where fld1=999999; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; +table type possible_keys key key_len ref rows Extra +t2 ALL NULL NULL NULL NULL 1199 Using where +t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; +table type possible_keys key key_len ref rows Extra +t2 ALL NULL NULL NULL NULL 1199 Using where +t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; +table type possible_keys key key_len ref rows Extra +t2 ALL NULL NULL NULL NULL 1199 Using where +t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; +table type possible_keys key key_len ref rows Extra +t4 ALL NULL NULL NULL NULL 12 +t2 ALL NULL NULL NULL NULL 1199 Using where +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; +table type possible_keys key key_len ref rows Extra +t4 ALL PRIMARY NULL NULL NULL 12 +t2 ALL NULL NULL NULL NULL 1199 Using where +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; +table type possible_keys key key_len ref rows Extra +t4 ALL NULL NULL NULL NULL 12 +t2 ALL NULL NULL NULL NULL 1199 Using where +plain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using temporary 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using where; Using index @@ -3487,3 +3517,23 @@ aa id t2_id id 5 8303 2520 2520 6 8304 2521 2521 drop table t1,t2; +create table t1 (id1 int NOT NULL); +create table t2 (id2 int NOT NULL); +create table t3 (id3 int NOT NULL); +create table t4 (id4 int NOT NULL, id44 int NOT NULL, KEY (id4)); +insert into t1 values (1); +insert into t1 values (2); +insert into t2 values (1); +insert into t4 values (1,1); +explain select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; +table type possible_keys key key_len ref rows Extra +t3 system NULL NULL NULL NULL 0 const row not found +t1 ALL NULL NULL NULL NULL 2 +t2 ALL NULL NULL NULL NULL 1 +t4 ALL id4 NULL NULL NULL 1 Using where +select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; +id1 id2 id3 id4 id44 +1 1 NULL NULL NULL +drop table t1,t2,t3,t4; diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index 0f2a781d073..dfb12eacd9c 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -13,7 +13,7 @@ a b 1 test 2 test2 update t1 set b="a" where a=1; -select 1 from t1,t1 as t2,t1 as t3,t1 as t4; +select 1 from t1,t1 as t2,t1 as t3; 1 1 1 @@ -35,18 +35,19 @@ update t1 set b="a" limit 1; update t1 set b="a" where b="b" limit 2; delete from t1 where b="test" limit 1; delete from t1 where a+0=1 limit 2; +alter table t1 add key b (b); SET MAX_JOIN_SIZE=2; SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; @@MAX_JOIN_SIZE @@SQL_BIG_SELECTS 2 0 insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); -SELECT * from t1; +SELECT * from t1 order by a; ERROR 42000: The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok SET SQL_BIG_SELECTS=1; -SELECT * from t1; +SELECT * from t1 order by a; a b -3 a 2 test2 +3 a 4 a 5 a SET MAX_JOIN_SIZE=2; @@ -55,9 +56,26 @@ ERROR 42000: The SELECT would examine more rows than MAX_JOIN_SIZE. Check your W SET MAX_JOIN_SIZE=DEFAULT; SELECT * from t1; a b -3 a 2 test2 +3 a 4 a 5 a +SELECT @@MAX_SEEKS_FOR_KEY; +@@max_seeks_for_key +4294967295 +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +explain select * from t1,t1 as t2 where t1.b=t2.b; +table type possible_keys key key_len ref rows Extra +t1 ALL b NULL NULL NULL 21 +t2 ALL b NULL NULL NULL 16 Using where +set MAX_SEEKS_FOR_KEY=1; +explain select * from t1,t1 as t2 where t1.b=t2.b; +table type possible_keys key key_len ref rows Extra +t1 ALL b NULL NULL NULL 21 +t2 ref b b 21 t1.b 6 Using where +SET MAX_SEEKS_FOR_KEY=DEFAULT; drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result index f12b98ba041..216fb4d6124 100644 --- a/mysql-test/r/symlink.result +++ b/mysql-test/r/symlink.result @@ -1,4 +1,5 @@ drop table if exists t1,t2,t7,t8,t9; +drop database if exists mysqltest; create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)); create table t2 (a int not null auto_increment, b char(16) not null, primary key (a)); insert into t1 (b) values ("test"),("test1"),("test2"),("test3"); @@ -51,11 +52,11 @@ Got one of the listed errors Got one of the listed errors Got one of the listed errors Got one of the listed errors -alter table t9 rename test_mysqltest.t9; -select count(*) from test_mysqltest.t9; +alter table t9 rename mysqltest.t9; +select count(*) from mysqltest.t9; count(*) 16724 -show create table test_mysqltest.t9; +show create table mysqltest.t9; Table Create Table t9 CREATE TABLE `t9` ( `a` int(11) NOT NULL auto_increment, @@ -64,4 +65,4 @@ t9 CREATE TABLE `t9` ( `d` int(11) NOT NULL default '0', PRIMARY KEY (`a`) ) TYPE=MyISAM CHARSET=latin1 -drop database test_mysqltest; +drop database mysqltest; diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index cf6533eef67..cebd005c2c8 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -32,6 +32,8 @@ datum 2000-01-02 2000-01-03 2000-01-04 +SELECT * FROM t1 WHERE datum BETWEEN "2000-1-2" AND datum - INTERVAL 100 DAY; +datum DROP TABLE t1; CREATE TABLE t1 ( user_id char(10), diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 5a9a8699d06..95e64a2a70e 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -52,10 +52,17 @@ a 0000-00-00 00:00:00 drop table t1; create table t1 (id int, dt datetime); -insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00"); +insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00"),(4,"2003-09-15 01:20:30"); select * from t1 where dt='2001-08-14 00:00:00' and dt = if(id=1,'2001-08-14 00:00:00','1999-08-15'); id dt 1 2001-08-14 00:00:00 +create index dt on t1 (dt); +select * from t1 where dt > 20021020; +id dt +4 2003-09-15 01:20:30 +select * from t1 ignore index (dt) where dt > 20021020; +id dt +4 2003-09-15 01:20:30 drop table t1; CREATE TABLE `t1` ( `date` datetime NOT NULL default '0000-00-00 00:00:00', diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 6d8bd263546..c29859bd4d4 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -90,6 +90,13 @@ explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a l id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 2 UNION t2 ALL NULL NULL NULL NULL 4 Using filesort +select sql_calc_found_rows a,b from t1 union all select a,b from t2 limit 2; +a b +1 a +2 b +select found_rows(); +found_rows() +6 explain select a,b from t1 union all select a,b from t2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 @@ -269,6 +276,35 @@ uid rl g1 cid gg uid rl g1 cid gg 1 NULL V1 NULL 1 drop table t1,t2,t3,t4,t5,t6; +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); +create table t3 select a,b from t1 union select a,b from t2; +create table t4 (select a,b from t1) union (select a,b from t2) limit 2; +insert into t4 select a,b from t1 union select a,b from t2; +insert into t3 (select a,b from t1) union (select a,b from t2) limit 2; +select * from t3; +a b +1 a +2 b +3 c +4 d +5 f +6 e +1 a +2 b +select * from t4; +a b +1 a +2 b +1 a +2 b +3 c +4 d +5 f +6 e +drop table t1,t2,t3,t4; CREATE TABLE t1 ( id int(3) unsigned default '0') TYPE=MyISAM; INSERT INTO t1 (id) VALUES("1"); CREATE TABLE t2 ( id int(3) unsigned default '0', id_master int(5) default '0', text1 varchar(5) default NULL, text2 varchar(5) default NULL) TYPE=MyISAM; diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 3a53dbdded0..23253f60de9 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -30,3 +30,15 @@ explain select * from t1 where i=@vv1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref i i 4 const 1 Using where drop table t1,t2; +select @a:=10, @b:=1, @a > @b, @a < @b; +@a:=10 @b:=1 @a > @b @a < @b +10 1 1 0 +select @a:="10", @b:="1", @a > @b, @a < @b; +@a:="10" @b:="1" @a > @b @a < @b +10 1 1 0 +select @a:=10, @b:=2, @a > @b, @a < @b; +@a:=10 @b:=2 @a > @b @a < @b +10 2 1 0 +select @a:="10", @b:="2", @a > @b, @a < @b; +@a:="10" @b:="2" @a > @b @a < @b +10 2 0 1 diff --git a/mysql-test/t/alias.test b/mysql-test/t/alias.test index 64dd481d37d..e0fa10d56d5 100644 --- a/mysql-test/t/alias.test +++ b/mysql-test/t/alias.test @@ -65,3 +65,24 @@ INSERT INTO t1 VALUES (3359362,406,3359362,'Mustermann Musterfrau',7001,'2000-05 SELECT ELT(FIELD(kundentyp,'PP','PPA','PG','PGA','FK','FKA','FP','FPA','K','KA','V','VA',''), 'Privat (Private Nutzung)','Privat (Private Nutzung) Sitz im Ausland','Privat (geschaeftliche Nutzung)','Privat (geschaeftliche Nutzung) Sitz im Ausland','Firma (Kapitalgesellschaft)','Firma (Kapitalgesellschaft) Sitz im Ausland','Firma (Personengesellschaft)','Firma (Personengesellschaft) Sitz im Ausland','oeff. rechtl. Koerperschaft','oeff. rechtl. Koerperschaft Sitz im Ausland','Eingetragener Verein','Eingetragener Verein Sitz im Ausland','Typ unbekannt') AS Kundentyp ,kategorie FROM t1 WHERE hdl_nr < 2000000 AND kategorie IN ('Prepaid','Mobilfunk') AND st_klasse = 'Workflow' GROUP BY kundentyp ORDER BY kategorie; drop table t1; + +# +# test case for #570 +# + +CREATE TABLE t1 ( + AUFNR varchar(12) NOT NULL default '', + PLNFL varchar(6) NOT NULL default '', + VORNR varchar(4) NOT NULL default '', + xstatus_vor smallint(5) unsigned NOT NULL default '0', + +); + +INSERT INTO t1 VALUES ('40004712','000001','0010',9); +INSERT INTO t1 VALUES ('40004712','000001','0020',0); + +UPDATE t1 SET t1.xstatus_vor = Greatest(t1.xstatus_vor,1) WHERE t1.aufnr = +"40004712" AND t1.plnfl = "000001" AND t1.vornr > "0010" ORDER BY t1.vornr +ASC LIMIT 1; + +drop table t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 346ad8fe80e..06a5db13ea3 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -171,3 +171,65 @@ alter table t1 change a a char(10) character set koi8r; select a,hex(a) from t1; drop table t1; + +# +# Test ALTER TABLE ENABLE/DISABLE keys when things are locked +# + +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User) +) TYPE=MyISAM; + +ALTER TABLE t1 DISABLE KEYS; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty'); +SHOW INDEX FROM t1; +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; +CHECK TABLES t1; +DROP TABLE t1; + +# +# Test with two keys +# + +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User), + KEY (Host) +) TYPE=MyISAM; + +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''); +SHOW INDEX FROM t1; +ALTER TABLE t1 ENABLE KEYS; +SHOW INDEX FROM t1; +UNLOCK TABLES; +CHECK TABLES t1; + +# Test RENAME with LOCK TABLES +LOCK TABLES t1 WRITE; +ALTER TABLE t1 RENAME t2; +UNLOCK TABLES; +select * from t2; +DROP TABLE t2; + +# +# Test disable keys with locking +# +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User), + KEY (Host) +) TYPE=MyISAM; + +LOCK TABLES t1 WRITE; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/convert.test b/mysql-test/t/convert.test new file mode 100644 index 00000000000..f26ef3a8c72 --- /dev/null +++ b/mysql-test/t/convert.test @@ -0,0 +1,11 @@ +# Test of character set conversions + +# Test that SET DEFAULT works + +select @@convert_character_set; +select @@global.convert_character_set; +show variables like "%convert_character_set%"; +SET CHARACTER SET cp1251_koi8; +select @@convert_character_set; +SET CHARACTER SET DEFAULT; +select @@convert_character_set; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 9bc37a0864d..ebb3854309b 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -215,3 +215,10 @@ CREATE TABLE t1 (a int not null); show create table t1; SET SESSION table_type=default; drop table t1; + +# +# Bug # 801 +# + +create table t1 select x'4132'; +drop table t1; diff --git a/mysql-test/t/ctype_cp1251-master.opt b/mysql-test/t/ctype_cp1251-master.opt new file mode 100644 index 00000000000..af089d9f176 --- /dev/null +++ b/mysql-test/t/ctype_cp1251-master.opt @@ -0,0 +1,2 @@ +--default-character-set=cp1251 --new + diff --git a/mysql-test/t/ctype_cp1251.test b/mysql-test/t/ctype_cp1251.test new file mode 100644 index 00000000000..fffade35389 --- /dev/null +++ b/mysql-test/t/ctype_cp1251.test @@ -0,0 +1,17 @@ +# Test of charset cp1251 + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Test problem with LEFT() (Bug #514) +# + +create table t1 (a varchar(10) not null); +insert into t1 values ("a"),("ab"),("abc"); +select * from t1; +select a, left(a,1) as b from t1; +select a, left(a,1) as b from t1 group by a; +SELECT DISTINCT RIGHT(a,1) from t1; +drop table t1; diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test index 00ac128a478..afad89729b4 100644 --- a/mysql-test/t/ctype_latin1_de.test +++ b/mysql-test/t/ctype_latin1_de.test @@ -37,6 +37,10 @@ select strcmp('ßa','ss'),strcmp('ssa','ß'),strcmp('sssb','sßa'),strcmp('ß','s'); select strcmp('u','öa'),strcmp('u','ö'); # +# overlapping combo's +# +select strcmp('sä', 'ßa'), strcmp('aä', 'äx'); +# # Some other simple tests with the current character set # diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index 859c4042b1d..0563b432873 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -62,7 +62,7 @@ drop table t1; # CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned); -INSERT INTO t1 VALUES (1,1),(2,1); +INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1); CREATE TABLE t2 (a int(10) unsigned not null, key (A)); INSERT INTO t2 VALUES (1),(2); CREATE TABLE t3 (a int(10) unsigned, key(A), b text); @@ -274,3 +274,14 @@ CREATE TABLE t2 (a int primary key, b int, c int); INSERT t2 VALUES (3,4,5); SELECT DISTINCT t1.a, t2.b FROM t1, t2 WHERE t1.a=1 ORDER BY t2.c; DROP TABLE t1,t2; + +# +# Test of LEFT() with distinct +# + +CREATE table t1 ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL default '', PRIMARY KEY (`id`)) TYPE=MyISAM AUTO_INCREMENT=3 ; +INSERT INTO t1 VALUES (1, 'aaaaa'); +INSERT INTO t1 VALUES (3, 'aaaaa'); +INSERT INTO t1 VALUES (2, 'eeeeeee'); +select distinct left(name,1) as name from t1; +drop table t1; diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test index 307dd45654d..e624ded0102 100644 --- a/mysql-test/t/drop.test +++ b/mysql-test/t/drop.test @@ -29,7 +29,6 @@ create database mysqltest; drop database mysqltest; # test drop/create database and FLUSH TABLES WITH READ LOCK -drop database if exists mysqltest; flush tables with read lock; --error 1209,1223; create database mysqltest; diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index 44a821b63c2..9ee6b5d76b8 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -69,4 +69,3 @@ connection con2; insert into t1 values (345); select * from t1; drop table t1; - diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index d06e2dce0a1..8c6bb97edf1 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -14,7 +14,7 @@ INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'), ('Full-text search in MySQL', 'implements vector space model'); # nl search - + select * from t1 where MATCH(a,b) AGAINST ("collections"); select * from t1 where MATCH(a,b) AGAINST ("indexes"); select * from t1 where MATCH(a,b) AGAINST ("indexes collections"); @@ -23,6 +23,20 @@ select * from t1 where MATCH(a,b) AGAINST ("only"); # UNION of fulltext's select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes"); + +# add_ft_keys() tests + +explain select * from t1 where MATCH(a,b) AGAINST ("collections"); +explain select * from t1 where MATCH(a,b) AGAINST ("collections")>0; +explain select * from t1 where MATCH(a,b) AGAINST ("collections")>1; +explain select * from t1 where MATCH(a,b) AGAINST ("collections")>=0; +explain select * from t1 where MATCH(a,b) AGAINST ("collections")>=1; +explain select * from t1 where 0<MATCH(a,b) AGAINST ("collections"); +explain select * from t1 where 1<MATCH(a,b) AGAINST ("collections"); +explain select * from t1 where 0<=MATCH(a,b) AGAINST ("collections"); +explain select * from t1 where 1<=MATCH(a,b) AGAINST ("collections"); +explain select * from t1 where MATCH(a,b) AGAINST ("collections")>0 and a like '%ll%'; + # boolean search select * from t1 where MATCH(a,b) AGAINST("support -collections" IN BOOLEAN MODE); @@ -50,6 +64,10 @@ select * from t1 where MATCH a,b AGAINST ('"text i"' IN BOOLEAN MODE); select * from t1 where MATCH a AGAINST ("search" IN BOOLEAN MODE); select * from t1 where MATCH b AGAINST ("sear*" IN BOOLEAN MODE); +# UNION of fulltext's + +select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes"); + #update/delete with fulltext index delete from t1 where a like "MySQL%"; @@ -176,7 +194,7 @@ select * from t1 where match (a) against ('aaaa'); drop table t1; # -# bug 283 by jocelyn fournier <joc@presence-pc.com> +# bug #283 by jocelyn fournier <joc@presence-pc.com> # FULLTEXT index on a TEXT filed converted to a CHAR field doesn't work anymore # @@ -186,3 +204,17 @@ select ref_mag from t1 where match ref_mag against ('+test' in boolean mode); alter table t1 change ref_mag ref_mag char (255) not null; select ref_mag from t1 where match ref_mag against ('+test' in boolean mode); drop table t1; + +# +# bug #942: JOIN +# + +create table t1 (t1_id int(11) primary key, name varchar(32)); +insert into t1 values (1, 'data1'); +insert into t1 values (2, 'data2'); +create table t2 (t2_id int(11) primary key, t1_id int(11), name varchar(32)); +insert into t2 values (1, 1, 'xxfoo'); +insert into t2 values (2, 1, 'xxbar'); +insert into t2 values (3, 1, 'xxbuz'); +select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode); +drop table t1,t2; diff --git a/mysql-test/t/fulltext_left_join.test b/mysql-test/t/fulltext_left_join.test index 4fce8ee287e..855649923c4 100644 --- a/mysql-test/t/fulltext_left_join.test +++ b/mysql-test/t/fulltext_left_join.test @@ -31,3 +31,15 @@ select match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE) drop table t1, t2; +# +# Bug #484, reported by Stephen Brandon <stephen@brandonitconsulting.co.uk> +# + +create table t1 (venue_id int(11) default null, venue_text varchar(255) default null, dt datetime default null) type=myisam; +insert into t1 (venue_id, venue_text, dt) values (1, 'a1', '2003-05-23 19:30:00'),(null, 'a2', '2003-05-23 19:30:00'); +create table t2 (name varchar(255) not null default '', entity_id int(11) not null auto_increment, primary key (entity_id), fulltext key name (name)) type=myisam; +insert into t2 (name, entity_id) values ('aberdeen town hall', 1), ('glasgow royal concert hall', 2), ('queen\'s hall, edinburgh', 3); +select * from t1 left join t2 on venue_id = entity_id where match(name) against('aberdeen' in boolean mode) and dt = '2003-05-23 19:30:00'; +select * from t1 left join t2 on venue_id = entity_id where match(name) against('aberdeen') and dt = '2003-05-23 19:30:00'; +drop table t1,t2; + diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index be64c170fa1..d15c26279ec 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -12,3 +12,8 @@ select inet_ntoa(1099511627775),inet_ntoa(4294902271),inet_ntoa(511); # Test for core dump with nan # select length(format('nan', 2)) > 0; + +# +# Test for bug #628 +# +select concat("$",format(2500,2)); diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test index 60d67a77562..e462e0a96c3 100644 --- a/mysql-test/t/func_set.test +++ b/mysql-test/t/func_set.test @@ -33,3 +33,4 @@ insert into t2 values (1,1),(2,1),(3,1),(4,2); select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id; select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id; drop table t1,t2; +select interval(null, 1, 10, 100); diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 4c996121446..14267976104 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -315,3 +315,24 @@ create table t7 (s1 char); select * from t7 where concat(s1 collate latin1_general_ci,s1 collate latin1_swedish_ci) = 'AA'; drop table t7; + +CREATE TABLE t1 ( + wid int(10) unsigned NOT NULL auto_increment, + data_podp date default NULL, + status_wnio enum('nowy','podp','real','arch') NOT NULL default 'nowy', + PRIMARY KEY(wid), +); + +INSERT INTO t1 VALUES (8,NULL,'real'); +INSERT INTO t1 VALUES (9,NULL,'nowy'); +SELECT elt(status_wnio,data_podp) FROM t1 GROUP BY wid; +DROP TABLE t1; + +# +# test for #739 + +CREATE TABLE t1 (title text) TYPE=MyISAM; +INSERT INTO t1 VALUES ('Congress reconvenes in September to debate welfare and adult education'); +INSERT INTO t1 VALUES ('House passes the CAREERS bill'); +SELECT CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) from t1; +DROP TABLE t1; diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index 2834d5bd9c7..4f44ec8fef1 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -20,6 +20,11 @@ select 1 XOR 1, 1 XOR 0, 0 XOR 1, 0 XOR 0, NULL XOR 1, 1 XOR NULL, 0 XOR NULL; select 10 % 7, 10 mod 7, 10 div 3; select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2; +create table t1 (a int); +insert t1 values (1); +select * from t1 where 1 xor 1; +drop table t1; + # # Coercibility # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index af222b0b3cc..d09fd12edc2 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -129,6 +129,8 @@ select extract(MONTH FROM "2001-02-00"); create table t1 (ctime varchar(20)); insert into t1 values ('2001-01-12 12:23:40'); select ctime, hour(ctime) from t1; +# test bug 614 (multiple extracts in where) +select ctime from t1 where extract(MONTH FROM ctime) = 1 AND extract(YEAR FROM ctime) = 2001; drop table t1; # diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index dcddbc99efa..b1338b790fd 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -45,8 +45,37 @@ show grants for mysqltest_1@localhost; revoke all privileges on mysqltest.* from mysqltest_1@localhost; delete from mysql.user where user='mysqltest_1'; flush privileges; -grant usage on test.* to user@localhost with grant option; -show grants for user@localhost; +grant usage on test.* to mysqltest_1@localhost with grant option; +show grants for mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; + +# +# Test what happens when you have same table and colum level grants +# + +create table t1 (a int); +GRANT select,update,insert on t1 to mysqltest_1@localhost; +GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +REVOKE select (a), update on t1 from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +REVOKE insert,insert (a) on t1 from mysqltest_1@localhost; +GRANT references on t1 to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; +drop table t1; +--error 1221 +GRANT FILE on mysqltest.* to mysqltest_1@localhost; # # Test for 'drop user', 'revoke privileges, grant' diff --git a/mysql-test/t/grant_cache.test b/mysql-test/t/grant_cache.test index 2d704a770aa..9ba845d6baa 100644 --- a/mysql-test/t/grant_cache.test +++ b/mysql-test/t/grant_cache.test @@ -5,6 +5,7 @@ # --disable_warnings drop table if exists test.t1,mysqltest.t1,mysqltest.t2; +drop database if exists mysqltest; --enable_warnings reset query cache; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 15d2e954a95..09dd06c817c 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -99,3 +99,16 @@ handler t1 read first limit 2,2; delete from t1 limit 3; handler t1 read first; drop table t1; + +# +#test for #751 +# +create table t1(a int, index(a)); +insert into t1 values (1), (2), (3); +handler t1 open; +--error 1054 +handler t1 read a=(W); +--error 1210 +handler t1 read a=(a); +drop table t1; + diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index 22d9e57a574..c708ea2baf6 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -132,6 +132,15 @@ SELECT * FROM t1 WHERE b<=>NULL; INSERT INTO t1 VALUES (1,3); DROP TABLE t1; +CREATE TABLE t1 ( + a int default NULL, + key a (a) +) TYPE=HEAP; +INSERT INTO t1 VALUES (10), (10), (10); +EXPLAIN SELECT * FROM t1 WHERE a=10; +SELECT * FROM t1 WHERE a=10; +DROP TABLE t1; + # # Test when deleting all rows # diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 635a15baa41..5ca357efe90 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -6,6 +6,7 @@ --disable_warnings drop table if exists t1,t2,t3; +drop database if exists mysqltest; --enable_warnings create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=innodb; @@ -45,9 +46,12 @@ update ignore t1 set id=id+1; # This will change all rows select * from t1; update ignore t1 set id=1023 where id=1010; select * from t1 where parent_id=102; -# explain select level from t1 where level=1; -# explain select level,id from t1 where level=1; -# explain select level,id,parent_id from t1 where level=1; +--replace_column 9 # +explain select level from t1 where level=1; +--replace_column 9 # +explain select level,id from t1 where level=1; +--replace_column 9 # +explain select level,id,parent_id from t1 where level=1; select level,id from t1 where level=1; select level,id,parent_id from t1 where level=1; optimize table t1; @@ -90,6 +94,7 @@ select * from t1; create index skr on t1 (a); insert into t1 values (3,""), (4,"testing"); analyze table t1; +--replace_column 7 # show keys from t1; drop table t1; @@ -228,6 +233,7 @@ drop table t1; CREATE TABLE t1 (a int not null, b int not null,c int not null, key(a),primary key(a,b), unique(c),key(a),unique(b)); +--replace_column 7 # show index from t1; drop table t1; @@ -345,7 +351,8 @@ update ignore t1 set id=id+1; # This will change all rows select * from t1; update ignore t1 set id=1023 where id=1010; select * from t1 where parent_id=102; -# explain select level from t1 where level=1; +--replace_column 9 # +explain select level from t1 where level=1; select level,id from t1 where level=1; select level,id,parent_id from t1 where level=1; select level,id from t1 where level=1 order by id; @@ -402,6 +409,7 @@ create table t1 (a varchar(100) not null, primary key(a), b int not null) type=i insert into t1 values("hello",1),("world",2); select * from t1 order by b desc; optimize table t1; +--replace_column 7 # show keys from t1; drop table t1; @@ -447,6 +455,7 @@ DROP TABLE t1; create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h int, i int, j int, k int, l int, m int, n int, o int, p int, q int, r int, s int, t int, u int, v int, w int, x int, y int, z int, a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, b1 int, b2 int, b3 int, b4 int, b5 int, b6 int) type = innodb; insert into t1 values (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); +--replace_column 9 # explain select * from t1 where a > 0 and a < 50; drop table t1; @@ -573,13 +582,21 @@ drop table t1; create table t1 (a int not null, b int not null, c int not null, primary key (a),key(b)) type=innodb; insert into t1 values (3,3,3),(1,1,1),(2,2,2),(4,4,4); +--replace_column 9 # explain select * from t1 order by a; +--replace_column 9 # explain select * from t1 order by b; +--replace_column 9 # explain select * from t1 order by c; +--replace_column 9 # explain select a from t1 order by a; +--replace_column 9 # explain select b from t1 order by b; +--replace_column 9 # explain select a,b from t1 order by b; +--replace_column 9 # explain select a,b from t1; +--replace_column 9 # explain select a,b,c from t1; drop table t1; @@ -840,8 +857,10 @@ insert into t1 (a) select b from t2; insert into t2 (a) select b from t1; insert into t1 (a) select b from t2; select count(*) from t1; +--replace_column 9 # explain select * from t1 where c between 1 and 10000; update t1 set c=a; +--replace_column 9 # explain select * from t1 where c between 1 and 10000; drop table t1,t2; diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index bfa8aac7a1f..9cc0bf8c46c 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -54,6 +54,17 @@ select * from t1; drop table t1; # +#Test of behaviour with INSERT VALUES (NULL) +# + +create table t1 (id int NOT NULL DEFAULT 8); +-- error 1048 +insert into t1 values(NULL); +insert into t1 values (1), (NULL), (2); +select * from t1; +drop table t1; + +# # Test of mysqld crash with fully qualified column names # diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 5bd7b95f560..4ac5a69a508 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -69,9 +69,8 @@ INSERT INTO t1 (numeropost,icone,contenu,pseudo,date,signature,ip) SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM t2 WHERE numeropost=9 ORDER BY numreponse ASC; -DROP TABLE IF EXISTS t1,t2; +DROP TABLE t1,t2; -# Addendum by Guilhem: # Check if a partly-completed INSERT SELECT in a MyISAM table goes # into the binlog @@ -88,3 +87,51 @@ let $VERSION=`select version()`; --replace_result $VERSION VERSION show binlog events; drop table t1, t2; +drop table if exists t1, t2; + +# +# Test of insert ... select from same table +# + +create table t1 (a int not null); +create table t2 (a int not null); +insert into t1 values (1); +insert into t1 values (a+2); +insert into t1 values (a+3); +insert into t1 values (4),(a+5); +insert into t1 select * from t1; +select * from t1; +insert into t1 select * from t1 as t2; +select * from t1; +insert into t2 select * from t1 as t2; +select * from t1; +insert into t1 select t2.a from t1,t2; +select * from t1; +--error 1066 +insert into t1 select * from t1,t1; +drop table t1,t2; + +# +# test replace ... select +# + +create table t1 (a int not null primary key, b char(10)); +create table t2 (a int not null, b char(10)); +insert into t1 values (1,"t1:1"),(3,"t1:3"); +insert into t2 values (2,"t2:2"), (3,"t2:3"); +--error 1062 +insert into t1 select * from t2; +select * from t1; +replace into t1 select * from t2; +select * from t1; +drop table t1,t2; + +# +# Test that caused uninitialized memory access in auto_increment_key update +# + +CREATE TABLE t1 ( USID INTEGER UNSIGNED, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User CHAR(32) NOT NULL DEFAULT '<UNKNOWN>', NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL); +CREATE TABLE t2 ( USID INTEGER UNSIGNED AUTO_INCREMENT, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User TEXT NOT NULL, NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL, INDEX(USID,ServerID,NASAddr,SessionID), INDEX(AssignedAddr)); +INSERT INTO t1 VALUES (39,42,'Access-Granted','46','491721000045',2130706433,17690,NULL,NULL,'Localnet','491721000045','49172200000',754974766,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2003-07-18 00:11:21',NULL,NULL,20030718001121); +INSERT INTO t2 SELECT USID, ServerID, State, SessionID, User, NASAddr, NASPort, NASPortType, ConnectSpeed, CarrierType, CallingStationID, CalledStationID, AssignedAddr, SessionTime, PacketsIn, OctetsIn, PacketsOut, OctetsOut, TerminateCause, UnauthTime, AccessRequestTime, AcctStartTime, AcctLastTime, LastModification from t1 LIMIT 1; +drop table t1,t2; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 882aec1006a..e8977ae9b62 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -99,10 +99,7 @@ CREATE TABLE t2 ( INSERT INTO t2 VALUES (3,2,11,12,5400,7800); INSERT INTO t2 VALUES (4,2,25,12,6500,11200); INSERT INTO t2 VALUES (5,1,37,6,10000,12000); - -select a.id, b.category as catid, b.state as stateid, b.county as -countyid from t1 a, t2 b where (a.token = -'a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id); +select a.id, b.category as catid, b.state as stateid, b.county as countyid from t1 a, t2 b ignore index (primary) where (a.token ='a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id); select a.id, b.category as catid, b.state as stateid, b.county as countyid from t1 a, t2 b where (a.token = 'a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id) order by a.id; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index df7e5b1524d..a63defff540 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -426,3 +426,15 @@ insert into t2 values(2),(3); insert into t3 values(2),(4); select * from t1 natural left join t2 natural left join t3; drop table t1,t2,t3; + +# +# Test of USING +# +create table t1 (f1 integer,f2 integer,f3 integer); +create table t2 (f2 integer,f4 integer); +create table t3 (f3 integer,f5 integer); +--error 1054 +select * from t1 + left outer join t2 using (f2) + left outer join t3 using (f3); +drop table t1,t2,t3; diff --git a/mysql-test/t/lock_tables_lost_commit-master.opt b/mysql-test/t/lock_tables_lost_commit-master.opt new file mode 100644 index 00000000000..d357a51cb27 --- /dev/null +++ b/mysql-test/t/lock_tables_lost_commit-master.opt @@ -0,0 +1 @@ +--binlog-ignore-db=test innodb
\ No newline at end of file diff --git a/mysql-test/t/lock_tables_lost_commit.test b/mysql-test/t/lock_tables_lost_commit.test new file mode 100644 index 00000000000..a12ee7369cb --- /dev/null +++ b/mysql-test/t/lock_tables_lost_commit.test @@ -0,0 +1,18 @@ +# This is a test for bug 578 + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +connection con1; +drop table if exists t1; +create table t1(a int) type=innodb; +lock tables t1 write; +insert into t1 values(10); +disconnect con1; + +connection con2; +# The bug was that, because of the LOCK TABLES, the handler "forgot" to commit, +# and the other commit when we write to the binlog was not done because of +# binlog-ignore-db +select * from t1; +drop table t1; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 01ba8986474..c3bffa4f2fb 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -250,3 +250,16 @@ EXPLAIN SELECT * FROM t2 WHERE fileset_id = 2 AND file_code = '0000000115' LIMIT 1; DROP TABLE t2, t1; +# +# Test of ORDER BY DESC on key (Bug #515) +# + +create table t1 (x int, y int, index xy(x, y)); +create table t2 (x int, y int, index xy(x, y)); +create table t3 (x int, y int, index xy(x, y)) type=merge union=(t1,t2); +insert into t1 values(1, 2); +insert into t2 values(1, 3); +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; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 6261260115c..b784bcf5076 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -11,8 +11,8 @@ flush query cache; # This crashed in some versions reset query cache; flush status; --disable_warnings +drop table if exists t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t00,mysqltest.t1; drop database if exists mysqltest; -drop table if exists t1,t2,t3,t11,t21, mysqltest.t1; --enable_warnings # @@ -244,7 +244,7 @@ drop table t1,t2; # # noncachable ODBC work around (and prepare cache for drop database) # -create database if not exists mysqltest; +create database mysqltest; create table mysqltest.t1 (i int not null auto_increment, a int, primary key (i)); insert into mysqltest.t1 (a) values (1); select * from mysqltest.t1 where i is null; @@ -487,3 +487,531 @@ select * from t1; show status like "Qcache_queries_in_cache"; SET OPTION SQL_SELECT_LIMIT=DEFAULT; drop table t1; + +# +# more then 255 (257) merged tables test +# +flush status; +create table t0(a int); +create table t1(a int); +create table t2(a int); +create table t3(a int); +create table t4(a int); +create table t5(a int); +create table t6(a int); +create table t7(a int); +create table t8(a int); +create table t9(a int); +create table t10(a int); +create table t11(a int); +create table t12(a int); +create table t13(a int); +create table t14(a int); +create table t15(a int); +create table t16(a int); +create table t17(a int); +create table t18(a int); +create table t19(a int); +create table t20(a int); +create table t21(a int); +create table t22(a int); +create table t23(a int); +create table t24(a int); +create table t25(a int); +create table t26(a int); +create table t27(a int); +create table t28(a int); +create table t29(a int); +create table t30(a int); +create table t31(a int); +create table t32(a int); +create table t33(a int); +create table t34(a int); +create table t35(a int); +create table t36(a int); +create table t37(a int); +create table t38(a int); +create table t39(a int); +create table t40(a int); +create table t41(a int); +create table t42(a int); +create table t43(a int); +create table t44(a int); +create table t45(a int); +create table t46(a int); +create table t47(a int); +create table t48(a int); +create table t49(a int); +create table t50(a int); +create table t51(a int); +create table t52(a int); +create table t53(a int); +create table t54(a int); +create table t55(a int); +create table t56(a int); +create table t57(a int); +create table t58(a int); +create table t59(a int); +create table t60(a int); +create table t61(a int); +create table t62(a int); +create table t63(a int); +create table t64(a int); +create table t65(a int); +create table t66(a int); +create table t67(a int); +create table t68(a int); +create table t69(a int); +create table t70(a int); +create table t71(a int); +create table t72(a int); +create table t73(a int); +create table t74(a int); +create table t75(a int); +create table t76(a int); +create table t77(a int); +create table t78(a int); +create table t79(a int); +create table t80(a int); +create table t81(a int); +create table t82(a int); +create table t83(a int); +create table t84(a int); +create table t85(a int); +create table t86(a int); +create table t87(a int); +create table t88(a int); +create table t89(a int); +create table t90(a int); +create table t91(a int); +create table t92(a int); +create table t93(a int); +create table t94(a int); +create table t95(a int); +create table t96(a int); +create table t97(a int); +create table t98(a int); +create table t99(a int); +create table t100(a int); +create table t101(a int); +create table t102(a int); +create table t103(a int); +create table t104(a int); +create table t105(a int); +create table t106(a int); +create table t107(a int); +create table t108(a int); +create table t109(a int); +create table t110(a int); +create table t111(a int); +create table t112(a int); +create table t113(a int); +create table t114(a int); +create table t115(a int); +create table t116(a int); +create table t117(a int); +create table t118(a int); +create table t119(a int); +create table t120(a int); +create table t121(a int); +create table t122(a int); +create table t123(a int); +create table t124(a int); +create table t125(a int); +create table t126(a int); +create table t127(a int); +create table t128(a int); +create table t129(a int); +create table t130(a int); +create table t131(a int); +create table t132(a int); +create table t133(a int); +create table t134(a int); +create table t135(a int); +create table t136(a int); +create table t137(a int); +create table t138(a int); +create table t139(a int); +create table t140(a int); +create table t141(a int); +create table t142(a int); +create table t143(a int); +create table t144(a int); +create table t145(a int); +create table t146(a int); +create table t147(a int); +create table t148(a int); +create table t149(a int); +create table t150(a int); +create table t151(a int); +create table t152(a int); +create table t153(a int); +create table t154(a int); +create table t155(a int); +create table t156(a int); +create table t157(a int); +create table t158(a int); +create table t159(a int); +create table t160(a int); +create table t161(a int); +create table t162(a int); +create table t163(a int); +create table t164(a int); +create table t165(a int); +create table t166(a int); +create table t167(a int); +create table t168(a int); +create table t169(a int); +create table t170(a int); +create table t171(a int); +create table t172(a int); +create table t173(a int); +create table t174(a int); +create table t175(a int); +create table t176(a int); +create table t177(a int); +create table t178(a int); +create table t179(a int); +create table t180(a int); +create table t181(a int); +create table t182(a int); +create table t183(a int); +create table t184(a int); +create table t185(a int); +create table t186(a int); +create table t187(a int); +create table t188(a int); +create table t189(a int); +create table t190(a int); +create table t191(a int); +create table t192(a int); +create table t193(a int); +create table t194(a int); +create table t195(a int); +create table t196(a int); +create table t197(a int); +create table t198(a int); +create table t199(a int); +create table t200(a int); +create table t201(a int); +create table t202(a int); +create table t203(a int); +create table t204(a int); +create table t205(a int); +create table t206(a int); +create table t207(a int); +create table t208(a int); +create table t209(a int); +create table t210(a int); +create table t211(a int); +create table t212(a int); +create table t213(a int); +create table t214(a int); +create table t215(a int); +create table t216(a int); +create table t217(a int); +create table t218(a int); +create table t219(a int); +create table t220(a int); +create table t221(a int); +create table t222(a int); +create table t223(a int); +create table t224(a int); +create table t225(a int); +create table t226(a int); +create table t227(a int); +create table t228(a int); +create table t229(a int); +create table t230(a int); +create table t231(a int); +create table t232(a int); +create table t233(a int); +create table t234(a int); +create table t235(a int); +create table t236(a int); +create table t237(a int); +create table t238(a int); +create table t239(a int); +create table t240(a int); +create table t241(a int); +create table t242(a int); +create table t243(a int); +create table t244(a int); +create table t245(a int); +create table t246(a int); +create table t247(a int); +create table t248(a int); +create table t249(a int); +create table t250(a int); +create table t251(a int); +create table t252(a int); +create table t253(a int); +create table t254(a int); +create table t255(a int); +create table t256(a int); +create table t00 (a int) type=MERGE UNION=(t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256) INSERT_METHOD=FIRST; +insert into t0 values (1),(2); +insert into t1 values (1),(2); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +insert into t4 values (1),(2); +insert into t5 values (1),(2); +insert into t6 values (1),(2); +insert into t7 values (1),(2); +insert into t8 values (1),(2); +insert into t9 values (1),(2); +insert into t10 values (1),(2); +insert into t11 values (1),(2); +insert into t12 values (1),(2); +insert into t13 values (1),(2); +insert into t14 values (1),(2); +insert into t15 values (1),(2); +insert into t16 values (1),(2); +insert into t17 values (1),(2); +insert into t18 values (1),(2); +insert into t19 values (1),(2); +insert into t20 values (1),(2); +insert into t21 values (1),(2); +insert into t22 values (1),(2); +insert into t23 values (1),(2); +insert into t24 values (1),(2); +insert into t25 values (1),(2); +insert into t26 values (1),(2); +insert into t27 values (1),(2); +insert into t28 values (1),(2); +insert into t29 values (1),(2); +insert into t30 values (1),(2); +insert into t31 values (1),(2); +insert into t32 values (1),(2); +insert into t33 values (1),(2); +insert into t34 values (1),(2); +insert into t35 values (1),(2); +insert into t36 values (1),(2); +insert into t37 values (1),(2); +insert into t38 values (1),(2); +insert into t39 values (1),(2); +insert into t40 values (1),(2); +insert into t41 values (1),(2); +insert into t42 values (1),(2); +insert into t43 values (1),(2); +insert into t44 values (1),(2); +insert into t45 values (1),(2); +insert into t46 values (1),(2); +insert into t47 values (1),(2); +insert into t48 values (1),(2); +insert into t49 values (1),(2); +insert into t50 values (1),(2); +insert into t51 values (1),(2); +insert into t52 values (1),(2); +insert into t53 values (1),(2); +insert into t54 values (1),(2); +insert into t55 values (1),(2); +insert into t56 values (1),(2); +insert into t57 values (1),(2); +insert into t58 values (1),(2); +insert into t59 values (1),(2); +insert into t60 values (1),(2); +insert into t61 values (1),(2); +insert into t62 values (1),(2); +insert into t63 values (1),(2); +insert into t64 values (1),(2); +insert into t65 values (1),(2); +insert into t66 values (1),(2); +insert into t67 values (1),(2); +insert into t68 values (1),(2); +insert into t69 values (1),(2); +insert into t70 values (1),(2); +insert into t71 values (1),(2); +insert into t72 values (1),(2); +insert into t73 values (1),(2); +insert into t74 values (1),(2); +insert into t75 values (1),(2); +insert into t76 values (1),(2); +insert into t77 values (1),(2); +insert into t78 values (1),(2); +insert into t79 values (1),(2); +insert into t80 values (1),(2); +insert into t81 values (1),(2); +insert into t82 values (1),(2); +insert into t83 values (1),(2); +insert into t84 values (1),(2); +insert into t85 values (1),(2); +insert into t86 values (1),(2); +insert into t87 values (1),(2); +insert into t88 values (1),(2); +insert into t89 values (1),(2); +insert into t90 values (1),(2); +insert into t91 values (1),(2); +insert into t92 values (1),(2); +insert into t93 values (1),(2); +insert into t94 values (1),(2); +insert into t95 values (1),(2); +insert into t96 values (1),(2); +insert into t97 values (1),(2); +insert into t98 values (1),(2); +insert into t99 values (1),(2); +insert into t100 values (1),(2); +insert into t101 values (1),(2); +insert into t102 values (1),(2); +insert into t103 values (1),(2); +insert into t104 values (1),(2); +insert into t105 values (1),(2); +insert into t106 values (1),(2); +insert into t107 values (1),(2); +insert into t108 values (1),(2); +insert into t109 values (1),(2); +insert into t110 values (1),(2); +insert into t111 values (1),(2); +insert into t112 values (1),(2); +insert into t113 values (1),(2); +insert into t114 values (1),(2); +insert into t115 values (1),(2); +insert into t116 values (1),(2); +insert into t117 values (1),(2); +insert into t118 values (1),(2); +insert into t119 values (1),(2); +insert into t120 values (1),(2); +insert into t121 values (1),(2); +insert into t122 values (1),(2); +insert into t123 values (1),(2); +insert into t124 values (1),(2); +insert into t125 values (1),(2); +insert into t126 values (1),(2); +insert into t127 values (1),(2); +insert into t128 values (1),(2); +insert into t129 values (1),(2); +insert into t130 values (1),(2); +insert into t131 values (1),(2); +insert into t132 values (1),(2); +insert into t133 values (1),(2); +insert into t134 values (1),(2); +insert into t135 values (1),(2); +insert into t136 values (1),(2); +insert into t137 values (1),(2); +insert into t138 values (1),(2); +insert into t139 values (1),(2); +insert into t140 values (1),(2); +insert into t141 values (1),(2); +insert into t142 values (1),(2); +insert into t143 values (1),(2); +insert into t144 values (1),(2); +insert into t145 values (1),(2); +insert into t146 values (1),(2); +insert into t147 values (1),(2); +insert into t148 values (1),(2); +insert into t149 values (1),(2); +insert into t150 values (1),(2); +insert into t151 values (1),(2); +insert into t152 values (1),(2); +insert into t153 values (1),(2); +insert into t154 values (1),(2); +insert into t155 values (1),(2); +insert into t156 values (1),(2); +insert into t157 values (1),(2); +insert into t158 values (1),(2); +insert into t159 values (1),(2); +insert into t160 values (1),(2); +insert into t161 values (1),(2); +insert into t162 values (1),(2); +insert into t163 values (1),(2); +insert into t164 values (1),(2); +insert into t165 values (1),(2); +insert into t166 values (1),(2); +insert into t167 values (1),(2); +insert into t168 values (1),(2); +insert into t169 values (1),(2); +insert into t170 values (1),(2); +insert into t171 values (1),(2); +insert into t172 values (1),(2); +insert into t173 values (1),(2); +insert into t174 values (1),(2); +insert into t175 values (1),(2); +insert into t176 values (1),(2); +insert into t177 values (1),(2); +insert into t178 values (1),(2); +insert into t179 values (1),(2); +insert into t180 values (1),(2); +insert into t181 values (1),(2); +insert into t182 values (1),(2); +insert into t183 values (1),(2); +insert into t184 values (1),(2); +insert into t185 values (1),(2); +insert into t186 values (1),(2); +insert into t187 values (1),(2); +insert into t188 values (1),(2); +insert into t189 values (1),(2); +insert into t190 values (1),(2); +insert into t191 values (1),(2); +insert into t192 values (1),(2); +insert into t193 values (1),(2); +insert into t194 values (1),(2); +insert into t195 values (1),(2); +insert into t196 values (1),(2); +insert into t197 values (1),(2); +insert into t198 values (1),(2); +insert into t199 values (1),(2); +insert into t200 values (1),(2); +insert into t201 values (1),(2); +insert into t202 values (1),(2); +insert into t203 values (1),(2); +insert into t204 values (1),(2); +insert into t205 values (1),(2); +insert into t206 values (1),(2); +insert into t207 values (1),(2); +insert into t208 values (1),(2); +insert into t209 values (1),(2); +insert into t210 values (1),(2); +insert into t211 values (1),(2); +insert into t212 values (1),(2); +insert into t213 values (1),(2); +insert into t214 values (1),(2); +insert into t215 values (1),(2); +insert into t216 values (1),(2); +insert into t217 values (1),(2); +insert into t218 values (1),(2); +insert into t219 values (1),(2); +insert into t220 values (1),(2); +insert into t221 values (1),(2); +insert into t222 values (1),(2); +insert into t223 values (1),(2); +insert into t224 values (1),(2); +insert into t225 values (1),(2); +insert into t226 values (1),(2); +insert into t227 values (1),(2); +insert into t228 values (1),(2); +insert into t229 values (1),(2); +insert into t230 values (1),(2); +insert into t231 values (1),(2); +insert into t232 values (1),(2); +insert into t233 values (1),(2); +insert into t234 values (1),(2); +insert into t235 values (1),(2); +insert into t236 values (1),(2); +insert into t237 values (1),(2); +insert into t238 values (1),(2); +insert into t239 values (1),(2); +insert into t240 values (1),(2); +insert into t241 values (1),(2); +insert into t242 values (1),(2); +insert into t243 values (1),(2); +insert into t244 values (1),(2); +insert into t245 values (1),(2); +insert into t246 values (1),(2); +insert into t247 values (1),(2); +insert into t248 values (1),(2); +insert into t249 values (1),(2); +insert into t250 values (1),(2); +insert into t251 values (1),(2); +insert into t252 values (1),(2); +insert into t253 values (1),(2); +insert into t254 values (1),(2); +insert into t255 values (1),(2); +insert into t256 values (1),(2); +enable_result_log; +select count(*) from t00; +select count(*) from t00; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +delete from t256; +show status like "Qcache_queries_in_cache"; +drop table t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t00; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 31b3ced6cc6..8d341837acd 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1,5 +1,5 @@ # -# Problem med range optimizer +# Problem with range optimizer # --disable_warnings @@ -13,7 +13,24 @@ CREATE TABLE t1 ( PRIMARY KEY (event_date,type,event_id) ); -INSERT INTO t1 VALUES ('1999-07-10',100100,24),('1999-07-11',100100,25),('1999-07-13',100600,0),('1999-07-13',100600,4),('1999-07-13',100600,26),('1999-07-14',100600,10),('1999-07-15',100600,16),('1999-07-15',100800,45),('1999-07-15',101000,47),('1999-07-16',100800,46),('1999-07-20',100600,5),('1999-07-20',100600,27),('1999-07-21',100600,11),('1999-07-22',100600,17),('1999-07-23',100100,39),('1999-07-24',100100,39),('1999-07-24',100500,40),('1999-07-25',100100,39),('1999-07-27',100600,1),('1999-07-27',100600,6),('1999-07-27',100600,28),('1999-07-28',100600,12),('1999-07-29',100500,41),('1999-07-29',100600,18),('1999-07-30',100500,41),('1999-07-31',100500,41),('1999-08-01',100700,34),('1999-08-03',100600,7),('1999-08-03',100600,29),('1999-08-04',100600,13),('1999-08-05',100500,42),('1999-08-05',100600,19),('1999-08-06',100500,42),('1999-08-07',100500,42),('1999-08-08',100500,42),('1999-08-10',100600,2),('1999-08-10',100600,9),('1999-08-10',100600,30),('1999-08-11',100600,14),('1999-08-12',100600,20),('1999-08-17',100500,8),('1999-08-17',100600,31),('1999-08-18',100600,15),('1999-08-19',100600,22),('1999-08-24',100600,3),('1999-08-24',100600,32),('1999-08-27',100500,43),('1999-08-31',100600,33),('1999-09-17',100100,37),('1999-09-18',100100,37),('1999-09-19',100100,37),('2000-12-18',100700,38); +INSERT INTO t1 VALUES ('1999-07-10',100100,24), ('1999-07-11',100100,25), +('1999-07-13',100600,0), ('1999-07-13',100600,4), ('1999-07-13',100600,26), +('1999-07-14',100600,10), ('1999-07-15',100600,16), ('1999-07-15',100800,45), +('1999-07-15',101000,47), ('1999-07-16',100800,46), ('1999-07-20',100600,5), +('1999-07-20',100600,27), ('1999-07-21',100600,11), ('1999-07-22',100600,17), +('1999-07-23',100100,39), ('1999-07-24',100100,39), ('1999-07-24',100500,40), +('1999-07-25',100100,39), ('1999-07-27',100600,1), ('1999-07-27',100600,6), +('1999-07-27',100600,28), ('1999-07-28',100600,12), ('1999-07-29',100500,41), +('1999-07-29',100600,18), ('1999-07-30',100500,41), ('1999-07-31',100500,41), +('1999-08-01',100700,34), ('1999-08-03',100600,7), ('1999-08-03',100600,29), +('1999-08-04',100600,13), ('1999-08-05',100500,42), ('1999-08-05',100600,19), +('1999-08-06',100500,42), ('1999-08-07',100500,42), ('1999-08-08',100500,42), +('1999-08-10',100600,2), ('1999-08-10',100600,9), ('1999-08-10',100600,30), +('1999-08-11',100600,14), ('1999-08-12',100600,20), ('1999-08-17',100500,8), +('1999-08-17',100600,31), ('1999-08-18',100600,15), ('1999-08-19',100600,22), +('1999-08-24',100600,3), ('1999-08-24',100600,32), ('1999-08-27',100500,43), +('1999-08-31',100600,33), ('1999-09-17',100100,37), ('1999-09-18',100100,37), +('1999-09-19',100100,37), ('2000-12-18',100700,38); select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; explain select event_date,type,event_id from t1 WHERE type = 100601 and event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; @@ -28,35 +45,21 @@ CREATE TABLE t1 ( ISS_DATE date DEFAULT '0000-00-00' NOT NULL, PRIMARY KEY (PAPER_ID,YEAR,ISSUE) ); -INSERT INTO t1 VALUES (3,1999,34,0,'1999-07-12'); -INSERT INTO t1 VALUES (1,1999,111,0,'1999-03-23'); -INSERT INTO t1 VALUES (1,1999,222,0,'1999-03-23'); -INSERT INTO t1 VALUES (3,1999,33,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,32,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,31,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,30,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,29,0,'1999-07-12'); -INSERT INTO t1 VALUES (3,1999,28,0,'1999-07-12'); -INSERT INTO t1 VALUES (1,1999,40,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,41,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,42,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,46,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,47,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,48,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,49,1,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,50,0,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,51,0,'1999-05-01'); -INSERT INTO t1 VALUES (1,1999,200,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,52,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,53,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,54,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,55,0,'1999-06-28'); -INSERT INTO t1 VALUES (1,1999,56,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,57,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,58,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,59,0,'1999-07-01'); -INSERT INTO t1 VALUES (1,1999,60,0,'1999-07-01'); -INSERT INTO t1 VALUES (3,1999,35,0,'1999-07-12'); +INSERT INTO t1 VALUES (3,1999,34,0,'1999-07-12'), (1,1999,111,0,'1999-03-23'), + (1,1999,222,0,'1999-03-23'), (3,1999,33,0,'1999-07-12'), + (3,1999,32,0,'1999-07-12'), (3,1999,31,0,'1999-07-12'), + (3,1999,30,0,'1999-07-12'), (3,1999,29,0,'1999-07-12'), + (3,1999,28,0,'1999-07-12'), (1,1999,40,1,'1999-05-01'), + (1,1999,41,1,'1999-05-01'), (1,1999,42,1,'1999-05-01'), + (1,1999,46,1,'1999-05-01'), (1,1999,47,1,'1999-05-01'), + (1,1999,48,1,'1999-05-01'), (1,1999,49,1,'1999-05-01'), + (1,1999,50,0,'1999-05-01'), (1,1999,51,0,'1999-05-01'), + (1,1999,200,0,'1999-06-28'), (1,1999,52,0,'1999-06-28'), + (1,1999,53,0,'1999-06-28'), (1,1999,54,0,'1999-06-28'), + (1,1999,55,0,'1999-06-28'), (1,1999,56,0,'1999-07-01'), + (1,1999,57,0,'1999-07-01'), (1,1999,58,0,'1999-07-01'), + (1,1999,59,0,'1999-07-01'), (1,1999,60,0,'1999-07-01'), + (3,1999,35,0,'1999-07-12'); select YEAR,ISSUE from t1 where PAPER_ID=3 and (YEAR>1999 or (YEAR=1999 and ISSUE>28)) order by YEAR,ISSUE; check table t1; repair table t1; @@ -70,7 +73,12 @@ CREATE TABLE t1 ( KEY parent_id (parent_id), KEY level (level) ); -INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2); +INSERT INTO t1 VALUES (1,0,0), (3,1,1), (4,1,1), (8,2,2), (9,2,2), (17,3,2), +(22,4,2), (24,4,2), (28,5,2), (29,5,2), (30,5,2), (31,6,2), (32,6,2), (33,6,2), +(203,7,2), (202,7,2), (20,3,2), (157,0,0), (193,5,2), (40,7,2), (2,1,1), +(15,2,2), (6,1,1), (34,6,2), (35,6,2), (16,3,2), (7,1,1), (36,7,2), (18,3,2), +(26,5,2), (27,5,2), (183,4,2), (38,7,2), (25,5,2), (37,7,2), (21,4,2), +(19,3,2), (5,1,1), (179,5,2); SELECT * FROM t1 WHERE level = 1 AND parent_id = 1; # The following select returned 0 rows in 3.23.8 SELECT * FROM t1 WHERE level = 1 AND parent_id = 1 order by id; @@ -166,3 +174,15 @@ select count(*) from t1 where art = 'j' or art = 'J'; select count(*) from t1 where art = 'j'; select count(*) from t1 where art = 'J'; drop table t1; + +create table t1 ( id1 int not null, id2 int not null, idnull int null, c char(20), primary key (id1,id2)); +insert into t1 values (0,1,NULL,"aaa"), (1,1,NULL,"aaa"), (2,1,NULL,"aaa"), + (3,1,NULL,"aaa"), (4,1,NULL,"aaa"), (5,1,NULL,"aaa"), + (6,1,NULL,"aaa"), (7,1,NULL,"aaa"), (8,1,NULL,"aaa"), + (9,1,NULL,"aaa"), (10,1,NULL,"aaa"), (11,1,NULL,"aaa"), + (12,1,NULL,"aaa"), (13,1,NULL,"aaa"), (14,1,NULL,"aaa"), + (15,1,NULL,"aaa"), (16,1,NULL,"aaa"), (17,1,NULL,"aaa"), + (18,1,NULL,"aaa"), (19,1,NULL,"aaa"), (20,1,NULL,"aaa"); +select a.id1, b.idnull from t1 as a, t1 as b where a.id2=1 and a.id1=1 and b.id1=a.idnull order by b.id2 desc limit 1; +drop table t1; + diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index d562a47ef90..f464f1e2751 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -90,8 +90,8 @@ connection master; --error 1053; reap; connection slave; -sync_with_master; -#give the slave a chance to exit +# The SQL slave thread should now have stopped because the query was killed on +# the master (so it has a non-zero error code in the binlog). wait_for_slave_to_stop; # The following test can't be done because the result of Pos will differ diff --git a/mysql-test/t/rpl000018.test b/mysql-test/t/rpl000018.test index b8c09ed431d..884ec9727d2 100644 --- a/mysql-test/t/rpl000018.test +++ b/mysql-test/t/rpl000018.test @@ -6,6 +6,8 @@ require_manager; connect (master,localhost,root,,test,0,master.sock); connect (slave,localhost,root,,test,0,slave.sock); +connection master; +reset master; server_stop master; server_start master; connection slave; diff --git a/mysql-test/t/rpl_do_grant.test b/mysql-test/t/rpl_do_grant.test new file mode 100644 index 00000000000..89ff1afb5c9 --- /dev/null +++ b/mysql-test/t/rpl_do_grant.test @@ -0,0 +1,46 @@ +# Test that GRANT and SET PASSWORD are replicated to the slave + +source include/master-slave.inc; + +# do not be influenced by other tests. +connection master; +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +# if these DELETE did nothing on the master, we need to do them manually on the +# slave. +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; + +# test replication of GRANT +connection master; +grant select on *.* to rpl_do_grant@localhost; +grant drop on test.* to rpl_do_grant@localhost; +save_master_pos; +connection slave; +sync_with_master; +show grants for rpl_do_grant@localhost; + +# test replication of SET PASSWORD +connection master; +set password for rpl_do_grant@localhost=password("does it work?"); +save_master_pos; +connection slave; +sync_with_master; +select password<>'' from mysql.user where user='rpl_do_grant'; + +# clear what we have done, to not influence other tests. +connection master; +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +# no need to delete manually, as the DELETEs must have done some real job on +# master (updated binlog) +flush privileges; diff --git a/mysql-test/t/rpl_error_ignored_table-slave.opt b/mysql-test/t/rpl_error_ignored_table-slave.opt new file mode 100644 index 00000000000..0d3485f9e25 --- /dev/null +++ b/mysql-test/t/rpl_error_ignored_table-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=test.t1 diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test new file mode 100644 index 00000000000..686472433eb --- /dev/null +++ b/mysql-test/t/rpl_error_ignored_table.test @@ -0,0 +1,25 @@ +# Test for +# Bug #797: If a query is ignored on slave (replicate-ignore-table) the slave +# still checks that it has the same error as on the master. + +source include/master-slave.inc; +connection master; +create table t1 (a int primary key); +# generate an error that goes to the binlog +--error 1062; +insert into t1 values (1),(1); +save_master_pos; +connection slave; +# as the t1 table is ignored on the slave, the slave should be able to sync +sync_with_master; +# The port number is different when doing the release build with +# Do-compile, hence we have to replace the port number here accordingly +--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +show slave status; +# check that the table has been ignored, because otherwise the test is nonsense +show tables like 't1'; +connection master; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl_flush_log_loop.test b/mysql-test/t/rpl_flush_log_loop.test index 62bcf2c8b33..00fab13bac7 100644 --- a/mysql-test/t/rpl_flush_log_loop.test +++ b/mysql-test/t/rpl_flush_log_loop.test @@ -14,6 +14,7 @@ stop slave; eval change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=$SLAVE_MYPORT; start slave; +sleep 5; flush logs; sleep 5; --replace_result $SLAVE_MYPORT SLAVE_PORT diff --git a/mysql-test/t/rpl_ignore_grant-slave.opt b/mysql-test/t/rpl_ignore_grant-slave.opt new file mode 100644 index 00000000000..e931bfbd37e --- /dev/null +++ b/mysql-test/t/rpl_ignore_grant-slave.opt @@ -0,0 +1 @@ +--replicate-wild-ignore-table=mysql.% diff --git a/mysql-test/t/rpl_ignore_grant.test b/mysql-test/t/rpl_ignore_grant.test new file mode 100644 index 00000000000..2fd7f186b3e --- /dev/null +++ b/mysql-test/t/rpl_ignore_grant.test @@ -0,0 +1,57 @@ +# Test that GRANT is not replicated to the slave +# when --replicate-wild-ignore-table=mysql.% +# In BUG#980, this test would _randomly_ fail. + +source include/master-slave.inc; + +# do not be influenced by other tests. +connection master; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +# as these DELETE were not replicated, we need to do them manually on the +# slave. +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; + +# test non-replication of GRANT +connection master; +grant select on *.* to rpl_ignore_grant@localhost; +grant drop on test.* to rpl_ignore_grant@localhost; +show grants for rpl_ignore_grant@localhost; +save_master_pos; +connection slave; +sync_with_master; +--error 1141 #("no such grant for user") +show grants for rpl_ignore_grant@localhost; +# check it another way +select count(*) from mysql.user where user='rpl_ignore_grant'; +select count(*) from mysql.db where user='rpl_ignore_grant'; + +# test non-replication of SET PASSWORD +# first force creation of the user on slave (because as the user does not exist +# on slave, the SET PASSWORD may be replicated but silently do nothing; this is +# not what we want; we want it to be not-replicated). +grant select on *.* to rpl_ignore_grant@localhost; +connection master; +set password for rpl_ignore_grant@localhost=password("does it work?"); +save_master_pos; +connection slave; +sync_with_master; +select password<>'' from mysql.user where user='rpl_ignore_grant'; + +# clear what we have done, to not influence other tests. +connection master; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 3e84f86c092..b2b92dec7aa 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -4,6 +4,7 @@ # We also check how the foreign_key_check variable is replicated source include/master-slave.inc; +source include/have_innodb.inc connection master; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); @@ -21,8 +22,10 @@ connection master; #are replicated the same way drop table t1; drop table t2; -create table t1(a int auto_increment, key(a)); -create table t2(b int auto_increment, c int, key(b)); +--disable_warnings +create table t1(a int auto_increment, key(a)) type=innodb; +create table t2(b int auto_increment, c int, key(b), foreign key(b) references t1(a)) type=innodb; +--enable_warnings SET FOREIGN_KEY_CHECKS=0; insert into t1 values (10); insert into t1 values (null),(null),(null); diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index b540c3907e9..061066c7a31 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -2,10 +2,14 @@ # Honours autoincrement values # i.e. if the master and slave have the same sequence # -# check replication of load data for temporary tables with additional parameters +# check replication of load data for temporary tables with additional +# parameters # # check if duplicate entries trigger an error (they should unless IGNORE or # REPLACE was used on the master) (bug 571). +# +# check if START SLAVE, RESET SLAVE, CHANGE MASTER reset Last_slave_error and +# Last_slave_errno in SHOW SLAVE STATUS (1st and 3rd commands did not: bug 986) source include/master-slave.inc; @@ -37,21 +41,60 @@ connection slave; sync_with_master; insert into t1 values(1,10); +connection master; +load data infile '../../std_data/rpl_loaddata.dat' into table t1; + +save_master_pos; +connection slave; +# The SQL slave thread should be stopped now. +wait_for_slave_to_stop; + +# Skip the bad event and see if error is cleared in SHOW SLAVE STATUS by START +# SLAVE, even though we are not executing any event (as sql_slave_skip_counter +# takes us directly to the end of the relay log). -# NOTE UNTIL MERGE 4.0 INTO 4.1 -# Below we generate an error, but this error shows up in SHOW SLAVE STATUS -# in the next test. In 4.0 this is fixed (RESET SLAVE resets the error), but it -# has not been merged into 4.1 yet. So for the moment, I comment all lines -# below, to not generate the error, so that the test suite passes. -# When you do the 4.0 -> 4.1 merge, please remove this note and re-enable the -# error generation, by deleting the '#' characters below, and update the result. -# The changeset to merge in 4.1 is -# ChangeSet@1.1455.34.1, 2003-06-10 23:29:49+02:00, guilhem@mysql.com +set global sql_slave_skip_counter=1; +start slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; -#connection master; -#load data infile '../../std_data/rpl_loaddata.dat' into table t1; +# Trigger error again to test CHANGE MASTER -#save_master_pos; -#connection slave; +connection master; +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +save_master_pos; +connection slave; # The SQL slave thread should be stopped now. -#wait_for_slave_to_stop; +wait_for_slave_to_stop; + +# CHANGE MASTER and see if error is cleared in SHOW SLAVE STATUS. +stop slave; +change master to master_user='test'; +change master to master_user='root'; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; + +# Trigger error again to test RESET SLAVE + +set global sql_slave_skip_counter=1; +start slave; +sync_with_master; +connection master; +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +save_master_pos; +connection slave; +# The SQL slave thread should be stopped now. +wait_for_slave_to_stop; + +# RESET SLAVE and see if error is cleared in SHOW SLAVE STATUS. +stop slave; +reset slave; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; diff --git a/mysql-test/t/rpl_master_pos_wait.test b/mysql-test/t/rpl_master_pos_wait.test index a6aae222a89..24479636c91 100644 --- a/mysql-test/t/rpl_master_pos_wait.test +++ b/mysql-test/t/rpl_master_pos_wait.test @@ -5,5 +5,11 @@ save_master_pos; connection slave; sync_with_master; # Ask for a master log that has certainly not been reached yet -# timeout= 10 seconds -select master_pos_wait('master-bin.999999',0,10); +# timeout= 2 seconds +select master_pos_wait('master-bin.999999',0,2); +# Testcase for bug 651 (master_pos_wait() hangs if slave idle and STOP SLAVE). +send select master_pos_wait('master-bin.999999',0); +connection slave1; +stop slave sql_thread; +connection slave; +reap; diff --git a/mysql-test/t/rpl_max_relay_size.test b/mysql-test/t/rpl_max_relay_size.test new file mode 100644 index 00000000000..a2167b1ef36 --- /dev/null +++ b/mysql-test/t/rpl_max_relay_size.test @@ -0,0 +1,87 @@ +# Test of options max_binlog_size and max_relay_log_size and +# how they act (if max_relay_log_size == 0, use max_binlog_size +# for relay logs too). +# Test of manual relay log rotation with FLUSH LOGS. + +source include/master-slave.inc; +connection slave; +stop slave; +connection master; +# Generate a big enough master's binlog to cause relay log rotations +create table t1 (a int); +let $1=800; +disable_query_log; +begin; +while ($1) +{ +# eval means expand $ expressions + eval insert into t1 values( $1 ); + dec $1; +} +enable_query_log; +drop table t1; +save_master_pos; +connection slave; +reset slave; +set global max_binlog_size=8192; +set global max_relay_log_size=8192-1; # mapped to 4096 +select @@global.max_relay_log_size; +start slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +show slave status; +stop slave; +reset slave; +set global max_relay_log_size=(5*4096); +select @@global.max_relay_log_size; +start slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +show slave status; +stop slave; +reset slave; +set global max_relay_log_size=0; +select @@global.max_relay_log_size; +start slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +show slave status; + +# Tests below are mainly to ensure that we have not coded with wrong assumptions + +stop slave; +reset slave; +# test of relay log rotation when the slave is stopped +# (to make sure it does not crash). +flush logs; +--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +show slave status; + +reset slave; +start slave; +sync_with_master; +# test of relay log rotation when the slave is started +flush logs; +# We have now easy way to be sure that the SQL thread has now deleted the +# log we just closed. But a trick to achieve this is do an update on the master. +connection master; +create table t1 (a int); +save_master_pos; +connection slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +show slave status; +# one more rotation, to be sure Relay_log_space is correctly updated +flush logs; +connection master; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +show slave status; + +connection master; +# test that the absence of relay logs does not make a master crash +flush logs; +show master status; diff --git a/mysql-test/t/rpl_relayspace-slave.opt b/mysql-test/t/rpl_relayspace-slave.opt index 9365a2a0a26..05cb01731d2 100644 --- a/mysql-test/t/rpl_relayspace-slave.opt +++ b/mysql-test/t/rpl_relayspace-slave.opt @@ -1 +1 @@ - -O relay_log_space_limit=1024
\ No newline at end of file + -O relay_log_space_limit=10
\ No newline at end of file diff --git a/mysql-test/t/rpl_relayspace.test b/mysql-test/t/rpl_relayspace.test index 8d4f01339c7..bb82781b511 100644 --- a/mysql-test/t/rpl_relayspace.test +++ b/mysql-test/t/rpl_relayspace.test @@ -1,33 +1,32 @@ -# The slave is started with relay_log_space_limit=1024 bytes, -# to force the deadlock +# The slave is started with relay_log_space_limit=10 bytes, +# to force the deadlock after one event. source include/master-slave.inc; connection slave; stop slave; connection master; +# This will generate a master's binlog > 10 bytes create table t1 (a int); -let $1=200; -disable_query_log; -while ($1) -{ -# eval means expand $ expressions - eval insert into t1 values( $1 ); - dec $1; -} -# This will generate one 10kB master's binlog -enable_query_log; -save_master_pos; +drop table t1; +create table t1 (a int); +drop table t1; connection slave; reset slave; +start slave io_thread; +# Give the I/O thread time to block. +sleep 2; +# A bug caused the I/O thread to refuse stopping. +stop slave io_thread; +reset slave; start slave; # The I/O thread stops filling the relay log when -# it's 1kB. And the SQL thread cannot purge this relay log +# it's >10b. And the SQL thread cannot purge this relay log # as purge is done only when the SQL thread switches to another # relay log, which does not exist here. # So we should have a deadlock. # if it is not resolved automatically we'll detect -# it with master_pos_wait that waits for farther than 1kB; -# it will timeout after 45 seconds; +# it with master_pos_wait that waits for farther than 1Ob; +# it will timeout after 10 seconds; # also the slave will probably not cooperate to shutdown # (as 2 threads are locked) -select master_pos_wait('master-bin.001',5000,45)=-1; +select master_pos_wait('master-bin.001',200,6)=-1; diff --git a/mysql-test/t/rpl_reset_slave.test b/mysql-test/t/rpl_reset_slave.test new file mode 100644 index 00000000000..9c58ac0c787 --- /dev/null +++ b/mysql-test/t/rpl_reset_slave.test @@ -0,0 +1,26 @@ +# See SHOW SLAVE STATUS displays well after RESET SLAVE (it should display the +# --master-* options from mysqld, as this is what is going to be used next time +# slave threads will be started). In bug 985, it displayed old values (of before +# RESET SLAVE). + +source include/master-slave.inc; +connection master; +save_master_pos; +connection slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; + +stop slave; +change master to master_user='test'; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; + +reset slave; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; + +start slave; +sync_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; diff --git a/mysql-test/t/rpl_rotate_logs-master.opt b/mysql-test/t/rpl_rotate_logs-master.opt index f27601e0d7d..ad2c6a647b5 100644 --- a/mysql-test/t/rpl_rotate_logs-master.opt +++ b/mysql-test/t/rpl_rotate_logs-master.opt @@ -1 +1 @@ --O max_binlog_size=2048 +-O max_binlog_size=4096 diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test index df506c08e71..d36f49eee5c 100644 --- a/mysql-test/t/rpl_rotate_logs.test +++ b/mysql-test/t/rpl_rotate_logs.test @@ -20,14 +20,23 @@ connection slave; --disable_warnings drop table if exists t1, t2, t3, t4; --enable_warnings + +# START SLAVE will fail because it can't read the file (mode 000) +# (system error 13) --error 1201 start slave; system chmod 600 var/slave-data/master.info; +# It will fail again because the file is empty so the slave cannot get valuable +# info about how to connect to the master from it (failure in +# init_strvar_from_file() in init_master_info()). --error 1201 start slave; --replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT -# Will get error 13 on Unix systems becasue file is not readable -!eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; + +# CHANGE MASTER will fail because it first parses master.info before changing +# it (so when master.info is bad, people have to use RESET SLAVE first). +--error 1201 +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; reset slave; --replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; @@ -72,12 +81,9 @@ insert into t2 values(1234); #same value on the master connection master; -save_master_pos; set insert_id=1234; insert into t2 values(NULL); connection slave; -sync_with_master; - wait_for_slave_to_stop; #restart slave skipping one event @@ -126,8 +132,6 @@ show binary logs; show master status; save_master_pos; connection slave; -#stop slave; -#start slave; sync_with_master; select * from t4; diff --git a/mysql-test/t/sel000100.test b/mysql-test/t/sel000100.test index 2f9c06d5cf4..c9923d178c6 100644 --- a/mysql-test/t/sel000100.test +++ b/mysql-test/t/sel000100.test @@ -31,3 +31,18 @@ GROUP BY t1.id ORDER BY link; drop table t1,t2; + +# +# test case for #674 +# +CREATE TABLE t1 ( + html varchar(5) default NULL, + rin int(11) default '0', + out int(11) default '0' +) TYPE=MyISAM; + +INSERT INTO t1 VALUES ('1',1,0); + +SELECT DISTINCT html,SUM(out)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; + +drop table t1; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 3c26cf1903b..4593eeb0691 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1527,10 +1527,24 @@ select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 25 # # Test of left join. # +insert into t2 (fld1, companynr) values (999999,99); select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; +delete from t2 where fld1=999999; + +# +# Test left join optimization + +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; +# Following can't be optimized +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; # # Joins with forms. @@ -1821,3 +1835,23 @@ CREATE TABLE t2 ( id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) TYPE=M INSERT INTO t2 VALUES (2517), (2518), (2519), (2520), (2521), (2522); select * from t1, t2 WHERE t1.t2_id = t2.id and t1.t2_id > 0 order by t1.id LIMIT 0, 5; drop table t1,t2; + +# +# outer join, impossible on condition, where, and usable key for range +# +create table t1 (id1 int NOT NULL); +create table t2 (id2 int NOT NULL); +create table t3 (id3 int NOT NULL); +create table t4 (id4 int NOT NULL, id44 int NOT NULL, KEY (id4)); + +insert into t1 values (1); +insert into t1 values (2); +insert into t2 values (1); +insert into t4 values (1,1); + +explain select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; +select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; + +drop table t1,t2,t3,t4; diff --git a/mysql-test/t/select_safe.test b/mysql-test/t/select_safe.test index be25c7c05d1..1f46355d39b 100644 --- a/mysql-test/t/select_safe.test +++ b/mysql-test/t/select_safe.test @@ -15,7 +15,7 @@ delete from t1 where a=1; insert into t1 values(1,"test"),(2,"test2"); SELECT SQL_BUFFER_RESULT * from t1; update t1 set b="a" where a=1; -select 1 from t1,t1 as t2,t1 as t3,t1 as t4; +select 1 from t1,t1 as t2,t1 as t3; # The following should give errors: --error 1175 @@ -39,19 +39,31 @@ delete from t1 where a+0=1 limit 2; # Test SQL_BIG_SELECTS +alter table t1 add key b (b); SET MAX_JOIN_SIZE=2; SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); --error 1104 -SELECT * from t1; +SELECT * from t1 order by a; SET SQL_BIG_SELECTS=1; -SELECT * from t1; +SELECT * from t1 order by a; SET MAX_JOIN_SIZE=2; --error 1104 SELECT * from t1; SET MAX_JOIN_SIZE=DEFAULT; SELECT * from t1; +# +# Test MAX_SEEKS_FOR_KEY +# +SELECT @@MAX_SEEKS_FOR_KEY; +analyze table t1; +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +explain select * from t1,t1 as t2 where t1.b=t2.b; +set MAX_SEEKS_FOR_KEY=1; +explain select * from t1,t1 as t2 where t1.b=t2.b; +SET MAX_SEEKS_FOR_KEY=DEFAULT; + drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test index 67126930e60..a8daf36ed10 100644 --- a/mysql-test/t/symlink.test +++ b/mysql-test/t/symlink.test @@ -5,6 +5,7 @@ enable_query_log; --disable_warnings drop table if exists t1,t2,t7,t8,t9; +drop database if exists mysqltest; --enable_warnings # @@ -68,26 +69,25 @@ create table t1 (a int not null auto_increment, b char(16) not null, primary key # Check that we cannot link over a table from another database. -drop database if exists test_mysqltest; -create database test_mysqltest; +create database mysqltest; --error 1,1 -create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist"; +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist"; --error 1103,1103 -create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path"; +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path"; --error 1,1 -eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="$MYSQL_TEST_DIR/var/run"; +eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="$MYSQL_TEST_DIR/var/run"; --error 1,1 -eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp"; +eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp"; enable_query_log; -# Check moving table t9 from default database to test_mysqltest; +# Check moving table t9 from default database to mysqltest; # In this case the symlinks should be removed. -alter table t9 rename test_mysqltest.t9; -select count(*) from test_mysqltest.t9; -show create table test_mysqltest.t9; -drop database test_mysqltest; +alter table t9 rename mysqltest.t9; +select count(*) from mysqltest.t9; +show create table mysqltest.t9; +drop database mysqltest; diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index 6319a3990e6..5a53c635e6e 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -37,6 +37,7 @@ INSERT INTO t1 VALUES ( "2000-1-3" ); INSERT INTO t1 VALUES ( "2000-1-4" ); INSERT INTO t1 VALUES ( "2000-1-5" ); SELECT * FROM t1 WHERE datum BETWEEN "2000-1-2" AND "2000-1-4"; +SELECT * FROM t1 WHERE datum BETWEEN "2000-1-2" AND datum - INTERVAL 100 DAY; DROP TABLE t1; # diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index e9c45b2908f..d2611973101 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -39,8 +39,11 @@ drop table t1; # create table t1 (id int, dt datetime); -insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00"); +insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00"),(4,"2003-09-15 01:20:30"); select * from t1 where dt='2001-08-14 00:00:00' and dt = if(id=1,'2001-08-14 00:00:00','1999-08-15'); +create index dt on t1 (dt); +select * from t1 where dt > 20021020; +select * from t1 ignore index (dt) where dt > 20021020; drop table t1; # diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index aeea27ade0f..c5aa725a459 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -26,8 +26,10 @@ select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 g --error 1248 (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; -#(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; -#select found_rows(); +(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; +select found_rows(); +select sql_calc_found_rows a,b from t1 union all select a,b from t2 limit 2; +select found_rows(); # # Test some error conditions with UNION @@ -176,6 +178,22 @@ SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left drop table t1,t2,t3,t4,t5,t6; # +# Test insert ... SELECT with UNION +# + +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); +create table t3 select a,b from t1 union select a,b from t2; +create table t4 (select a,b from t1) union (select a,b from t2) limit 2; +insert into t4 select a,b from t1 union select a,b from t2; +insert into t3 (select a,b from t1) union (select a,b from t2) limit 2; +select * from t3; +select * from t4; +drop table t1,t2,t3,t4; + +# # Test for another bug with UNION and LEFT JOIN # CREATE TABLE t1 ( id int(3) unsigned default '0') TYPE=MyISAM; diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 6260db8c370..514eace25a3 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -21,3 +21,9 @@ explain select * from t1 where @vv1:=@vv1+1 and i=@vv1; explain select @vv1:=i from t1 where i=@vv1; explain select * from t1 where i=@vv1; drop table t1,t2; + +# Check types of variables +select @a:=10, @b:=1, @a > @b, @a < @b; +select @a:="10", @b:="1", @a > @b, @a < @b; +select @a:=10, @b:=2, @a > @b, @a < @b; +select @a:="10", @b:="2", @a > @b, @a < @b; diff --git a/mysys/default.c b/mysys/default.c index a592e8b42e1..9f7181b7da9 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -33,8 +33,6 @@ ** --print-defaults ; Print the modified command line and exit ****************************************************************************/ -#undef SAFEMALLOC /* safe_malloc is not yet initailized */ - #include "mysys_priv.h" #include "m_string.h" #include "m_ctype.h" diff --git a/mysys/mf_format.c b/mysys/mf_format.c index e68f7df9d83..114e19759c8 100644 --- a/mysys/mf_format.c +++ b/mysys/mf_format.c @@ -105,7 +105,7 @@ my_string fn_format(my_string to, const char *name, const char *dir, strmov(buff,to); (void) my_readlink(to, buff, MYF(0)); } - DBUG_RETURN (to); + DBUG_RETURN(to); } /* fn_format */ diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index 8fba14f626b..b3aa347006e 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -253,15 +253,27 @@ void symdirget(char *dir) } #endif /* USE_SYMDIR */ - /* Unpacks dirname to name that can be used by open... */ - /* Make that last char of to is '/' if from not empty and - from doesn't end in FN_DEVCHAR */ - /* Uses cleanup_dirname and changes ~/.. to home_dir/.. */ - /* Returns length of new directory */ -uint unpack_dirname(my_string to, const char *from) +/* + Fixes a directroy name so that can be used by open() + + SYNOPSIS + unpack_dirname() + to Store result here. May be = from + from 'Packed' directory name (may contain ~) + + IMPLEMENTATION + Make that last char of to is '/' if from not empty and + from doesn't end in FN_DEVCHAR + Uses cleanup_dirname and changes ~/.. to home_dir/.. - /* to may be == from */ + Changes a UNIX filename to system filename (replaces / with \ on windows) + + RETURN + Length of new directory name (= length of to) +*/ + +uint unpack_dirname(my_string to, const char *from) { uint length,h_length; char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion; diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index d539489cf1e..cbbf876ac06 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -670,9 +670,9 @@ static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err) ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp) { - if ((ulonglong) num > (ulonglong) (ulong) optp->max_value && + if ((ulonglong) num > (ulonglong) optp->max_value && optp->max_value) /* if max value is not set -> no upper limit */ - num= (ulonglong) (ulong) optp->max_value; + num= (ulonglong) optp->max_value; if (optp->block_size > 1) { num/= (ulonglong) optp->block_size; diff --git a/mysys/my_static.c b/mysys/my_static.c index bbf7582a454..b24ef28b7b1 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -69,14 +69,13 @@ uint sf_malloc_prehunc=0, /* If you have problem with core- */ sf_malloc_endhunc=0, /* dump when malloc-message.... */ /* set theese to 64 or 128 */ sf_malloc_quick=0; /* set if no calls to sanity */ -long lCurMemory = 0L; /* Current memory usage */ -long lMaxMemory = 0L; /* Maximum memory usage */ -uint cNewCount = 0; /* Number of times NEW() was called */ +ulong sf_malloc_cur_memory= 0L; /* Current memory usage */ +ulong sf_malloc_max_memory= 0L; /* Maximum memory usage */ +uint sf_malloc_count= 0; /* Number of times NEW() was called */ byte *sf_min_adress= (byte*) ~(unsigned long) 0L, *sf_max_adress= (byte*) 0L; - -/* Root of the linked list of remembers */ -struct remember *pRememberRoot = NULL; +/* Root of the linked list of struct st_irem */ +struct st_irem *sf_malloc_root = NULL; /* from my_alarm */ int volatile my_have_got_alarm=0; /* declare variable to reset */ diff --git a/mysys/my_static.h b/mysys/my_static.h index c1893f4074f..1a33bcf21f3 100644 --- a/mysys/my_static.h +++ b/mysys/my_static.h @@ -33,27 +33,23 @@ struct st_remember { }; /* - The size of the following structure MUST be dividable by 8 to not cause - alignment problems on some cpu's + Structure that stores information of a allocated memory block + The data is at &struct_adr+sizeof(ALIGN_SIZE(sizeof(struct irem))) + The lspecialvalue is at the previous 4 bytes from this, which may not + necessarily be in the struct if the struct size isn't aligned at a 8 byte + boundary. */ -struct irem +struct st_irem { - struct remember *_pNext; /* Linked list of structures */ - struct remember *_pPrev; /* Other link */ - char *_sFileName; /* File in which memory was new'ed */ - uint32 _uLineNum; /* Line number in above file */ - uint32 _uDataSize; /* Size requested */ -#if SIZEOF_CHARP == 8 - long _filler; /* For alignment */ -#endif - long _lSpecialValue; /* Underrun marker value */ + struct st_irem *next; /* Linked list of structures */ + struct st_irem *prev; /* Other link */ + char *filename; /* File in which memory was new'ed */ + uint32 linenum; /* Line number in above file */ + uint32 datasize; /* Size requested */ + uint32 SpecialValue; /* Underrun marker value */ }; -struct remember { - struct irem tInt; - char aData[1]; -}; extern char NEAR curr_dir[FN_REFLEN],NEAR home_dir_buff[FN_REFLEN]; @@ -70,8 +66,8 @@ extern int _my_tempnam_used; #endif extern byte *sf_min_adress,*sf_max_adress; -extern uint cNewCount; -extern struct remember *pRememberRoot; +extern uint sf_malloc_count; +extern struct st_irem *sf_malloc_root; #if defined(THREAD) && !defined(__WIN__) extern sigset_t my_signals; /* signals blocked by mf_brkhant */ diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index 9cbb178edb4..07c40fd91b6 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* 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 @@ -69,22 +69,15 @@ #include "my_static.h" #include "mysys_err.h" -ulonglong safemalloc_mem_limit = ~(ulonglong)0; - -#define pNext tInt._pNext -#define pPrev tInt._pPrev -#define sFileName tInt._sFileName -#define uLineNum tInt._uLineNum -#define uDataSize tInt._uDataSize -#define lSpecialValue tInt._lSpecialValue +ulonglong sf_malloc_mem_limit= ~(ulonglong)0; #ifndef PEDANTIC_SAFEMALLOC /* - Set to 1 after TERMINATE() if we had to fiddle with cNewCount and + Set to 1 after TERMINATE() if we had to fiddle with sf_malloc_count and the linked list of blocks so that _sanity() will not fuss when it is not supposed to */ -static int sf_malloc_tampered = 0; +static int sf_malloc_tampered= 0; #endif @@ -92,11 +85,11 @@ static int sf_malloc_tampered = 0; static int check_ptr(const char *where, byte *ptr, const char *sFile, uint uLine); -static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine); +static int _checkchunk(struct st_irem *pRec, const char *sFile, uint uLine); /* - Note: both these refer to the NEW'ed data only. They do not include - malloc() roundoff or the extra space required by the remember + Note: We only fill up the allocated block. This do not include + malloc() roundoff or the extra space required by the irem structures. */ @@ -127,218 +120,211 @@ static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine); /* Allocate some memory. */ -gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags) +gptr _mymalloc(uint size, const char *filename, uint lineno, myf MyFlags) { - struct remember *pTmp; - DBUG_ENTER("_mymalloc"); - DBUG_PRINT("enter",("Size: %u",uSize)); - + struct st_irem *irem; + char *data; + DBUG_ENTER("_mymalloc"); + DBUG_PRINT("enter",("Size: %u",size)); - if (!sf_malloc_quick) - (void) _sanity (sFile, uLine); + if (!sf_malloc_quick) + (void) _sanity (filename, lineno); - if (uSize + lCurMemory > safemalloc_mem_limit) - pTmp = 0; - else - { - /* Allocate the physical memory */ - pTmp = (struct remember *) malloc ( - ALIGN_SIZE(sizeof(struct irem)) /* remember data */ - + sf_malloc_prehunc - + uSize /* size requested */ - + 4 /* overrun mark */ - + sf_malloc_endhunc - ); - } - /* Check if there isn't anymore memory avaiable */ - if (pTmp == NULL) + if (size + sf_malloc_cur_memory > sf_malloc_mem_limit) + irem= 0; + else + { + /* Allocate the physical memory */ + irem= (struct st_irem *) malloc (ALIGN_SIZE(sizeof(struct st_irem)) + + sf_malloc_prehunc + + size + /* size requested */ + 4 + /* overrun mark */ + sf_malloc_endhunc); + } + /* Check if there isn't anymore memory avaiable */ + if (!irem) + { + if (MyFlags & MY_FAE) + error_handler_hook=fatal_error_handler_hook; + if (MyFlags & (MY_FAE+MY_WME)) { - if (MyFlags & MY_FAE) - error_handler_hook=fatal_error_handler_hook; - if (MyFlags & (MY_FAE+MY_WME)) - { - char buff[SC_MAXWIDTH]; - my_errno=errno; - sprintf(buff,"Out of memory at line %d, '%s'", uLine, sFile); - my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG)); - sprintf(buff,"needed %d byte (%ldk), memory in use: %ld bytes (%ldk)", - uSize, (uSize + 1023L) / 1024L, - lMaxMemory, (lMaxMemory + 1023L) / 1024L); - my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG)); - } - DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'", - lMaxMemory,uLine, sFile)); - if (MyFlags & MY_FAE) - exit(1); - DBUG_RETURN ((gptr) NULL); + char buff[SC_MAXWIDTH]; + my_errno=errno; + sprintf(buff,"Out of memory at line %d, '%s'", lineno, filename); + my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG)); + sprintf(buff,"needed %d byte (%ldk), memory in use: %ld bytes (%ldk)", + size, (size + 1023L) / 1024L, + sf_malloc_max_memory, (sf_malloc_max_memory + 1023L) / 1024L); + my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG)); } + DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'", + sf_malloc_max_memory,lineno, filename)); + if (MyFlags & MY_FAE) + exit(1); + DBUG_RETURN ((gptr) 0); + } - /* Fill up the structure */ - *((long*) ((char*) &pTmp -> lSpecialValue+sf_malloc_prehunc)) = MAGICKEY; - pTmp -> aData[uSize + sf_malloc_prehunc+0] = MAGICEND0; - pTmp -> aData[uSize + sf_malloc_prehunc+1] = MAGICEND1; - pTmp -> aData[uSize + sf_malloc_prehunc+2] = MAGICEND2; - pTmp -> aData[uSize + sf_malloc_prehunc+3] = MAGICEND3; - pTmp -> sFileName = (my_string) sFile; - pTmp -> uLineNum = uLine; - pTmp -> uDataSize = uSize; - pTmp -> pPrev = NULL; - - /* Add this remember structure to the linked list */ - pthread_mutex_lock(&THR_LOCK_malloc); - if ((pTmp->pNext=pRememberRoot)) - { - pRememberRoot -> pPrev = pTmp; - } - pRememberRoot = pTmp; + /* Fill up the structure */ + data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) + + sf_malloc_prehunc); + *((uint32*) (data-sizeof(uint32)))= MAGICKEY; + data[size + 0]= MAGICEND0; + data[size + 1]= MAGICEND1; + data[size + 2]= MAGICEND2; + data[size + 3]= MAGICEND3; + irem->filename= (my_string) filename; + irem->linenum= lineno; + irem->datasize= size; + irem->prev= NULL; + + /* Add this remember structure to the linked list */ + pthread_mutex_lock(&THR_LOCK_malloc); + if ((irem->next= sf_malloc_root)) + sf_malloc_root->prev= irem; + sf_malloc_root= irem; + + /* Keep the statistics */ + sf_malloc_cur_memory+= size; + if (sf_malloc_cur_memory > sf_malloc_max_memory) + sf_malloc_max_memory= sf_malloc_cur_memory; + sf_malloc_count++; + pthread_mutex_unlock(&THR_LOCK_malloc); - /* Keep the statistics */ - lCurMemory += uSize; - if (lCurMemory > lMaxMemory) { - lMaxMemory = lCurMemory; - } - cNewCount++; - pthread_mutex_unlock(&THR_LOCK_malloc); - - /* Set the memory to the aribtrary wierd value */ - if ((MyFlags & MY_ZEROFILL) || !sf_malloc_quick) - bfill(&pTmp -> aData[sf_malloc_prehunc],uSize, - (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL)); - /* Return a pointer to the real data */ - DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc]))); - if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc])) - sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]); - if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc])) - sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]); - DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc])); + /* Set the memory to the aribtrary wierd value */ + if ((MyFlags & MY_ZEROFILL) || !sf_malloc_quick) + bfill(data, size, (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL)); + /* Return a pointer to the real data */ + DBUG_PRINT("exit",("ptr: %lx", data)); + if (sf_min_adress > data) + sf_min_adress= data; + if (sf_max_adress < data) + sf_max_adress= data; + DBUG_RETURN ((gptr) data); } + /* Allocate some new memory and move old memoryblock there. Free then old memoryblock */ -gptr _myrealloc (register gptr pPtr, register uint uSize, - const char *sFile, uint uLine, myf MyFlags) +gptr _myrealloc(register gptr ptr, register uint size, + const char *filename, uint lineno, myf MyFlags) { - struct remember *pRec; - gptr ptr; + struct st_irem *irem; + char *data; DBUG_ENTER("_myrealloc"); - if (!pPtr && (MyFlags & MY_ALLOW_ZERO_PTR)) - DBUG_RETURN(_mymalloc(uSize,sFile,uLine,MyFlags)); + if (!ptr && (MyFlags & MY_ALLOW_ZERO_PTR)) + DBUG_RETURN(_mymalloc(size, filename, lineno, MyFlags)); if (!sf_malloc_quick) - (void) _sanity (sFile, uLine); + (void) _sanity (filename, lineno); - if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine)) + if (check_ptr("Reallocating", (byte*) ptr, filename, lineno)) DBUG_RETURN((gptr) NULL); - pRec = (struct remember *) ((char*) pPtr - ALIGN_SIZE(sizeof(struct irem))- - sf_malloc_prehunc); - if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) - != MAGICKEY) + irem= (struct st_irem *) (((char*) ptr) - ALIGN_SIZE(sizeof(struct st_irem))- + sf_malloc_prehunc); + if (*((uint32*) (((char*) ptr)- sizeof(uint32))) != MAGICKEY) { fprintf(stderr, "Error: Reallocating unallocated data at line %d, '%s'\n", - uLine, sFile); + lineno, filename); DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'", - uLine, sFile)); + lineno, filename)); (void) fflush(stderr); DBUG_RETURN((gptr) NULL); } - if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */ + if ((data= _mymalloc(size,filename,lineno,MyFlags))) /* Allocate new area */ { - uSize=min(uSize,pRec-> uDataSize); /* Move as much as possibly */ - memcpy((byte*) ptr,pPtr,(size_t) uSize); /* Copy old data */ - _myfree(pPtr,sFile,uLine,0); /* Free not needed area */ + size=min(size, irem->datasize); /* Move as much as possibly */ + memcpy((byte*) data, ptr, (size_t) size); /* Copy old data */ + _myfree(ptr, filename, lineno, 0); /* Free not needed area */ } else { if (MyFlags & MY_HOLD_ON_ERROR) - DBUG_RETURN(pPtr); + DBUG_RETURN(ptr); if (MyFlags & MY_FREE_ON_ERROR) - _myfree(pPtr,sFile,uLine,0); + _myfree(ptr, filename, lineno, 0); } - DBUG_RETURN(ptr); + DBUG_RETURN(data); } /* _myrealloc */ /* Deallocate some memory. */ -void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags) +void _myfree(gptr ptr, const char *filename, uint lineno, myf myflags) { - struct remember *pRec; + struct st_irem *irem; DBUG_ENTER("_myfree"); - DBUG_PRINT("enter",("ptr: %lx",pPtr)); + DBUG_PRINT("enter",("ptr: %lx", ptr)); if (!sf_malloc_quick) - (void) _sanity (sFile, uLine); + (void) _sanity (filename, lineno); - if ((!pPtr && (myflags & MY_ALLOW_ZERO_PTR)) || - check_ptr("Freeing",(byte*) pPtr,sFile,uLine)) + if ((!ptr && (myflags & MY_ALLOW_ZERO_PTR)) || + check_ptr("Freeing",(byte*) ptr,filename,lineno)) DBUG_VOID_RETURN; /* Calculate the address of the remember structure */ - pRec = (struct remember *) ((byte*) pPtr- ALIGN_SIZE(sizeof(struct irem))- - sf_malloc_prehunc); + irem= (struct st_irem *) ((char*) ptr- ALIGN_SIZE(sizeof(struct st_irem))- + sf_malloc_prehunc); /* Check to make sure that we have a real remember structure. Note: this test could fail for four reasons: - (1) The memory was already free'ed - (2) The memory was never new'ed - (3) There was an underrun - (4) A stray pointer hit this location + (1) The memory was already free'ed + (2) The memory was never new'ed + (3) There was an underrun + (4) A stray pointer hit this location */ - if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) - != MAGICKEY) + if (*((uint32*) ((char*) ptr- sizeof(uint32))) != MAGICKEY) { fprintf(stderr, "Error: Freeing unallocated data at line %d, '%s'\n", - uLine, sFile); - DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",uLine,sFile)); + lineno, filename); + DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",lineno,filename)); (void) fflush(stderr); DBUG_VOID_RETURN; } /* Remove this structure from the linked list */ pthread_mutex_lock(&THR_LOCK_malloc); - if (pRec -> pPrev) { - pRec -> pPrev -> pNext = pRec -> pNext; - } else { - pRememberRoot = pRec -> pNext; - } - if (pRec -> pNext) { - pRec -> pNext -> pPrev = pRec -> pPrev; - } + if (irem->prev) + irem->prev->next= irem->next; + else + sf_malloc_root= irem->next; + + if (irem->next) + irem->next->prev= irem->prev; /* Handle the statistics */ - lCurMemory -= pRec -> uDataSize; - cNewCount--; + sf_malloc_cur_memory-= irem->datasize; + sf_malloc_count--; pthread_mutex_unlock(&THR_LOCK_malloc); #ifndef HAVE_purify /* Mark this data as free'ed */ if (!sf_malloc_quick) - bfill(&pRec->aData[sf_malloc_prehunc],pRec->uDataSize,(pchar) FREE_VAL); + bfill(ptr, irem->datasize, (pchar) FREE_VAL); #endif - *((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) = ~MAGICKEY; - + *((uint32*) ((char*) ptr- sizeof(uint32)))= ~MAGICKEY; /* Actually free the memory */ - free ((my_string ) pRec); + free((char*) irem); DBUG_VOID_RETURN; } /* Check if we have a wrong pointer */ -static int check_ptr(const char *where, byte *ptr, const char *sFile, - uint uLine) +static int check_ptr(const char *where, byte *ptr, const char *filename, + uint lineno) { if (!ptr) { fprintf(stderr, "Error: %s NULL pointer at line %d, '%s'\n", - where,uLine, sFile); - DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile)); + where,lineno, filename); + DBUG_PRINT("safe",("Null pointer at line %d '%s'", lineno, filename)); (void) fflush(stderr); return 1; } @@ -346,9 +332,9 @@ static int check_ptr(const char *where, byte *ptr, const char *sFile, if ((long) ptr & (ALIGN_SIZE(1)-1)) { fprintf(stderr, "Error: %s wrong aligned pointer at line %d, '%s'\n", - where,uLine, sFile); + where,lineno, filename); DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'", - uLine,sFile)); + lineno,filename)); (void) fflush(stderr); return 1; } @@ -356,9 +342,9 @@ static int check_ptr(const char *where, byte *ptr, const char *sFile, if (ptr < sf_min_adress || ptr > sf_max_adress) { fprintf(stderr, "Error: %s pointer out of range at line %d, '%s'\n", - where,uLine, sFile); + where,lineno, filename); DBUG_PRINT("safe",("Pointer out of range at line %d '%s'", - uLine,sFile)); + lineno,filename)); (void) fflush(stderr); return 1; } @@ -372,9 +358,9 @@ static int check_ptr(const char *where, byte *ptr, const char *sFile, free'ed as well as the statistics. */ -void TERMINATE (FILE *file) +void TERMINATE(FILE *file) { - struct remember *pPtr; + struct st_irem *irem; DBUG_ENTER("TERMINATE"); pthread_mutex_lock(&THR_LOCK_malloc); @@ -384,14 +370,15 @@ void TERMINATE (FILE *file) NEWs than FREEs. <0, etc. */ - if (cNewCount) + if (sf_malloc_count) { if (file) { - fprintf(file, "Warning: Not freed memory segments: %d\n", cNewCount); + fprintf(file, "Warning: Not freed memory segments: %u\n", + sf_malloc_count); (void) fflush(file); } - DBUG_PRINT("safe",("cNewCount: %d",cNewCount)); + DBUG_PRINT("safe",("sf_malloc_count: %u", sf_malloc_count)); } /* @@ -399,42 +386,44 @@ void TERMINATE (FILE *file) but not free'ed with FREE. */ - if ((pPtr=pRememberRoot)) + if ((irem= sf_malloc_root)) { if (file) { - fprintf(file, "Warning: Memory that was not free'ed (%ld bytes):\n",lCurMemory); + fprintf(file, "Warning: Memory that was not free'ed (%ld bytes):\n", + sf_malloc_cur_memory); (void) fflush(file); } - DBUG_PRINT("safe",("Memory that was not free'ed (%ld bytes):",lCurMemory)); - while (pPtr) + DBUG_PRINT("safe",("Memory that was not free'ed (%ld bytes):", + sf_malloc_cur_memory)); + while (irem) { + char *data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) + + sf_malloc_prehunc); if (file) { fprintf(file, "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'", - pPtr -> uDataSize, - (ulong) &(pPtr -> aData[sf_malloc_prehunc]), - pPtr -> uLineNum, pPtr -> sFileName); + irem->datasize, (long) data, irem->linenum, irem->filename); fprintf(file, "\n"); (void) fflush(file); } DBUG_PRINT("safe", ("%6u bytes at 0x%09lx, allocated at line %4d in '%s'", - pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]), - pPtr -> uLineNum, pPtr -> sFileName)); - pPtr = pPtr -> pNext; + irem->datasize, data, irem->linenum, irem->filename)); + irem= irem->next; } } /* Report the memory usage statistics */ if (file) { fprintf(file, "Maximum memory usage: %ld bytes (%ldk)\n", - lMaxMemory, (lMaxMemory + 1023L) / 1024L); + sf_malloc_max_memory, (sf_malloc_max_memory + 1023L) / 1024L); (void) fflush(file); } DBUG_PRINT("safe",("Maximum memory usage: %ld bytes (%ldk)", - lMaxMemory, (lMaxMemory + 1023L) / 1024L)); + sf_malloc_max_memory, (sf_malloc_max_memory + 1023L) / + 1024L)); pthread_mutex_unlock(&THR_LOCK_malloc); DBUG_VOID_RETURN; } @@ -442,44 +431,41 @@ void TERMINATE (FILE *file) /* Returns 0 if chunk is ok */ -static int _checkchunk (register struct remember *pRec, const char *sFile, - uint uLine) +static int _checkchunk(register struct st_irem *irem, const char *filename, + uint lineno) { - reg1 uint uSize; - reg2 my_string magicp; - reg3 int flag=0; + int flag=0; + char *magicp, *data; + data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) + + sf_malloc_prehunc); /* Check for a possible underrun */ - if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) - != MAGICKEY) + if (*((uint32*) (data- sizeof(uint32))) != MAGICKEY) { fprintf(stderr, "Error: Memory allocated at %s:%d was underrun,", - pRec -> sFileName, pRec -> uLineNum); - fprintf(stderr, " discovered at %s:%d\n", sFile, uLine); + irem->filename, irem->linenum); + fprintf(stderr, " discovered at %s:%d\n", filename, lineno); (void) fflush(stderr); DBUG_PRINT("safe",("Underrun at %lx, allocated at %s:%d", - &(pRec -> aData[sf_malloc_prehunc]), - pRec -> sFileName, - pRec -> uLineNum)); + data, irem->filename, irem->linenum)); flag=1; } /* Check for a possible overrun */ - uSize = pRec -> uDataSize; - magicp = &(pRec -> aData[uSize+sf_malloc_prehunc]); + magicp= data + irem->datasize; if (*magicp++ != MAGICEND0 || *magicp++ != MAGICEND1 || *magicp++ != MAGICEND2 || *magicp++ != MAGICEND3) { fprintf(stderr, "Error: Memory allocated at %s:%d was overrun,", - pRec -> sFileName, pRec -> uLineNum); - fprintf(stderr, " discovered at '%s:%d'\n", sFile, uLine); + irem->filename, irem->linenum); + fprintf(stderr, " discovered at '%s:%d'\n", filename, lineno); (void) fflush(stderr); DBUG_PRINT("safe",("Overrun at %lx, allocated at %s:%d", - &(pRec -> aData[sf_malloc_prehunc]), - pRec -> sFileName, - pRec -> uLineNum)); + data, + irem->filename, + irem->linenum)); flag=1; } return(flag); @@ -488,28 +474,28 @@ static int _checkchunk (register struct remember *pRec, const char *sFile, /* Returns how many wrong chunks */ -int _sanity (const char *sFile, uint uLine) +int _sanity(const char *filename, uint lineno) { - reg1 struct remember *pTmp; + reg1 struct st_irem *irem; reg2 int flag=0; uint count=0; pthread_mutex_lock(&THR_LOCK_malloc); #ifndef PEDANTIC_SAFEMALLOC - if (sf_malloc_tampered && cNewCount < 0) - cNewCount=0; + if (sf_malloc_tampered && (int) sf_malloc_count < 0) + sf_malloc_count=0; #endif - count=cNewCount; - for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext) - flag+=_checkchunk (pTmp, sFile, uLine); + count=sf_malloc_count; + for (irem= sf_malloc_root; irem != NULL && count-- ; irem= irem->next) + flag+= _checkchunk (irem, filename, lineno); pthread_mutex_unlock(&THR_LOCK_malloc); - if (count || pTmp) + if (count || irem) { const char *format="Error: Safemalloc link list destroyed, discovered at '%s:%d'"; - fprintf(stderr, format, sFile, uLine); fputc('\n',stderr); - fprintf(stderr, "root=%p,count=%d,pTmp=%p\n", pRememberRoot,count,pTmp); + fprintf(stderr, format, filename, lineno); fputc('\n',stderr); + fprintf(stderr, "root=%p,count=%d,irem=%p\n", sf_malloc_root,count,irem); (void) fflush(stderr); - DBUG_PRINT("safe",(format, sFile, uLine)); + DBUG_PRINT("safe",(format, filename, lineno)); flag=1; } return flag; @@ -518,33 +504,33 @@ int _sanity (const char *sFile, uint uLine) /* malloc and copy */ -gptr _my_memdup(const byte *from, uint length, const char *sFile, uint uLine, - myf MyFlags) +gptr _my_memdup(const byte *from, uint length, const char *filename, + uint lineno, myf MyFlags) { gptr ptr; - if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0) + if ((ptr=_mymalloc(length,filename,lineno,MyFlags)) != 0) memcpy((byte*) ptr, (byte*) from,(size_t) length); return(ptr); } /*_my_memdup */ -char *_my_strdup(const char *from, const char *sFile, uint uLine, +char *_my_strdup(const char *from, const char *filename, uint lineno, myf MyFlags) { gptr ptr; uint length=(uint) strlen(from)+1; - if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0) + if ((ptr=_mymalloc(length,filename,lineno,MyFlags)) != 0) memcpy((byte*) ptr, (byte*) from,(size_t) length); return((char*) ptr); } /* _my_strdup */ char *_my_strdup_with_length(const byte *from, uint length, - const char *sFile, uint uLine, + const char *filename, uint lineno, myf MyFlags) { gptr ptr; - if ((ptr=_mymalloc(length+1,sFile,uLine,MyFlags)) != 0) + if ((ptr=_mymalloc(length+1,filename,lineno,MyFlags)) != 0) { memcpy((byte*) ptr, (byte*) from,(size_t) length); ptr[length]=0; diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 7a845e3eb00..2289f8208bc 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -220,8 +220,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) { ALARM *alarm_data; sigset_t old_mask; - uint i; - my_bool found=0; + uint i, found=0; DBUG_ENTER("thr_end_alarm"); pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); @@ -235,11 +234,13 @@ void thr_end_alarm(thr_alarm_t *alarmed) queue_remove(&alarm_queue,i),MYF(0); if (alarm_data->malloced) my_free((gptr) alarm_data,MYF(0)); - found=1; + found++; +#ifndef DBUG_OFF break; +#endif } } - DBUG_ASSERT(!*alarmed || found); + DBUG_ASSERT(!*alarmed || found == 1); if (!found) { if (*alarmed) @@ -717,7 +718,7 @@ sig_handler process_alarm(int sig __attribute__((unused))) } -bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm) +my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm) { (*alrm)= &alarm->alarmed; if (alarm_aborted) diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index b6e7cb47234..0e3ccfc0452 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -172,10 +172,13 @@ static int check_lock(struct st_lock_list *list, const char* lock_type, return 0; } + static void check_locks(THR_LOCK *lock, const char *where, my_bool allow_no_locks) { uint old_found_errors=found_errors; + DBUG_ENTER("check_locks"); + if (found_errors < MAX_FOUND_ERRORS) { if (check_lock(&lock->write,"write",where,1,1) | @@ -252,18 +255,21 @@ static void check_locks(THR_LOCK *lock, const char *where, } if (lock->read.data) { - if ((!pthread_equal(lock->write.data->thread, - lock->read.data->thread) && - lock->write.data->type > TL_WRITE_DELAYED && - lock->write.data->type != TL_WRITE_ONLY) || - ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT || - lock->write.data->type == TL_WRITE_ALLOW_WRITE) && - lock->read_no_write_count)) + if (!pthread_equal(lock->write.data->thread, + lock->read.data->thread) && + ((lock->write.data->type > TL_WRITE_DELAYED && + lock->write.data->type != TL_WRITE_ONLY) || + ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT || + lock->write.data->type == TL_WRITE_ALLOW_WRITE) && + lock->read_no_write_count))) { found_errors++; fprintf(stderr, "Warning at '%s': Found lock of type %d that is write and read locked\n", where, lock->write.data->type); + DBUG_PRINT("warning",("At '%s': Found lock of type %d that is write and read locked\n", + where, lock->write.data->type)); + } } if (lock->read_wait.data) @@ -286,6 +292,7 @@ static void check_locks(THR_LOCK *lock, const char *where, DBUG_PRINT("error",("Found wrong lock")); } } + DBUG_VOID_RETURN; } #else /* EXTRA_DEBUG */ diff --git a/mysys/tree.c b/mysys/tree.c index 91d2f9771b5..42c58131100 100644 --- a/mysys/tree.c +++ b/mysys/tree.c @@ -109,6 +109,11 @@ void init_tree(TREE *tree, uint default_alloc_size, uint memory_limit, if (!free_element && size >= 0 && ((uint) size <= sizeof(void*) || ((uint) size & (sizeof(void*)-1)))) { + /* + We know that the data doesn't have to be aligned (like if the key + contains a double), so we can store the data combined with the + TREE_ELEMENT. + */ tree->offset_to_key=sizeof(TREE_ELEMENT); /* Put key after element */ /* Fix allocation size so that we don't lose any memory */ default_alloc_size/=(sizeof(TREE_ELEMENT)+size); diff --git a/scripts/Makefile.am b/scripts/Makefile.am index ff35170dcf3..7ccf35b9580 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -17,6 +17,7 @@ ## Process this file with automake to create Makefile.in bin_SCRIPTS = @server_scripts@ \ + make_win_src_distribution \ msql2mysql \ mysql_config \ mysql_fix_privilege_tables \ diff --git a/scripts/make_win_src_distribution.old b/scripts/make_win_src_distribution.old new file mode 100755 index 00000000000..df7ac29ee0d --- /dev/null +++ b/scripts/make_win_src_distribution.old @@ -0,0 +1,402 @@ +#!/bin/sh + +# +# Script to create a Windows src package +# + +version=@VERSION@ +export version +SOURCE=`pwd` +CP="cp -p" + +DEBUG=0 +SILENT=0 +SUFFIX="" +DIRNAME="" +OUTTAR=0 + +# +# This script must run from MySQL top directory +# + +if [ ! -f scripts/make_win_src_distribution ]; then + echo "ERROR : You must run this script from the MySQL top-level directory" + exit 1 +fi + +# +# Check for source compilation/configuration +# + +if [ ! -f sql/sql_yacc.cc ]; then + echo "ERROR : Sorry, you must run this script after the complete build," + echo " hope you know what you are trying to do !!" + exit 1 +fi + +# +# Debug print of the status +# + +print_debug() +{ + for statement + do + if [ "$DEBUG" = "1" ] ; then + echo $statement + fi + done +} + +# +# Usage of the script +# + +show_usage() +{ + echo "MySQL utility script to create a Windows src package, and it takes" + echo "the following arguments:" + echo "" + echo " --debug Debug, without creating the package" + echo " --tmp Specify the temporary location" + echo " --suffix Suffix name for the package" + echo " --dirname Directory name to copy files (intermediate)" + echo " --silent Do not list verbosely files processed" + echo " --tar Create tar.gz package instead of .zip" + echo " --help Show this help message" + + exit 0 +} + +# +# Parse the input arguments +# + +parse_arguments() { + for arg do + case "$arg" in + --debug) DEBUG=1;; + --tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;; + --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; + --dirname=*) DIRNAME=`echo "$arg" | sed -e "s;--dirname=;;"` ;; + --silent) SILENT=1 ;; + --tar) OUTTAR=1 ;; + --help) show_usage ;; + *) + echo "Unknown argument '$arg'" + exit 1 + ;; + esac + done +} + +parse_arguments "$@" + +# +# Assign the tmp directory if it was set from the environment variables +# + +for i in $TMP $TMPDIR $TEMPDIR $TEMP /tmp +do + if [ "$i" ]; then + print_debug "Setting TMP to '$i'" + TMP=$i + break + fi +done + + +# + +# +# Create a tmp dest directory to copy files +# + +BASE=$TMP/my_win_dist$SUFFIX + +if [ -d $BASE ] ; then + print_debug "Destination directory '$BASE' already exists, deleting it" + rm -r -f $BASE +fi + +$CP -r $SOURCE/VC++Files $BASE +( +find $BASE \( -name "*.dsp" -o -name "*.dsw" \) -and -not -path \*SCCS\* -print +)|( + while read v + do + print_debug "Replacing LF -> CRLF from '$v'" + + # ^M -> type CTRL V + CTRL M + cat $v | sed 's/
//' | sed 's/$/
/' > $v.tmp + rm $v + mv $v.tmp $v + done +) + +# +# Move all error message files to root directory +# + +$CP -r $SOURCE/sql/share $BASE/ +rm -r -f "$BASE/share/Makefile" +rm -r -f "$BASE/share/Makefile.in" +rm -r -f "$BASE/share/Makefile.am" + +# +# Clean up if we did this from a bk tree +# + +if [ -d $BASE/SCCS ] +then + find $BASE/ -type d -name SCCS -printf " \"%p\"" | xargs rm -r -f +fi + +mkdir $BASE/Docs $BASE/extra $BASE/include + + +# +# Copy directory files +# + +copy_dir_files() +{ + for arg do + print_debug "Copying files from directory '$arg'" + cd $SOURCE/$arg + if [ ! -d $BASE/$arg ]; then + print_debug "Creating directory '$arg'" + mkdir $BASE/$arg + fi + for i in *.c *.cpp *.h *.ih *.i *.ic *.asm *.def \ + README INSTALL* LICENSE + do + if [ -f $i ] + then + $CP $SOURCE/$arg/$i $BASE/$arg/$i + fi + done + for i in *.cc + do + if [ -f $i ] + then + i=`echo $i | sed 's/.cc$//g'` + $CP $SOURCE/$arg/$i.cc $BASE/$arg/$i.cpp + fi + done + done +} + +# +# Copy directory contents recursively +# + +copy_dir_dirs() { + + for arg do + + basedir=$arg + + if [ ! -d $BASE/$arg ]; then + mkdir $BASE/$arg + fi + + copy_dir_files $arg + + cd $SOURCE/$arg/ + for i in * + do + if [ -d $SOURCE/$basedir/$i ] && [ "$i" != "SCCS" ]; then + copy_dir_files $basedir/$i + fi + done + done +} + +# +# Input directories to be copied +# + +for i in client dbug extra heap include isam \ + libmysql libmysqld merge myisam \ + myisammrg mysys regex sql strings sql-common \ + vio zlib +do + copy_dir_files $i +done + +# +# Input directories to be copied recursively +# + +for i in bdb innobase +do + copy_dir_dirs $i +done + +# +# Create dummy innobase configure header +# + +if [ -f $BASE/innobase/ib_config.h ]; then + rm -f $BASE/innobase/ib_config.h +fi +touch $BASE/innobase/ib_config.h + + +# +# Copy miscellaneous files +# + +cd $SOURCE +for i in COPYING ChangeLog README \ + INSTALL-SOURCE INSTALL-WIN \ + INSTALL-WIN-SOURCE \ + Docs/manual_toc.html Docs/manual.html \ + Docs/mysqld_error.txt Docs/INSTALL-BINARY + +do + print_debug "Copying file '$i'" + if [ -f $i ] + then + $CP $i $BASE/$i + fi +done + +# +# Fix some windows files +# + +./extra/replace std:: "" -- $BASE/sql/sql_yacc.cpp + +# +# Initialize the initial data directory +# + +if [ -f scripts/mysql_install_db ]; then + print_debug "Initializing the 'data' directory" + scripts/mysql_install_db --no-defaults --windows --datadir=$BASE/data +fi + +# +# Specify the distribution package name and copy it +# + +if test -z $DIRNAME +then + NEW_DIR_NAME=mysql@MYSQL_SERVER_SUFFIX@-$version$SUFFIX +else + NEW_DIR_NAME=$DIRNAME +fi +NEW_NAME=$NEW_DIR_NAME-win-src + +BASE2=$TMP/$NEW_DIR_NAME +rm -r -f $BASE2 +mv $BASE $BASE2 +BASE=$BASE2 + +# +# If debugging, don't create a zip/tar/gz +# + +if [ "$DEBUG" = "1" ] ; then + echo "Please check the distribution files from $BASE" + echo "Exiting (without creating the package).." + exit +fi + +# +# This is needed to prefere gnu tar instead of tar because tar can't +# always handle long filenames +# + +PATH_DIRS=`echo $PATH | sed -e 's/^:/. /' -e 's/:$/ ./' -e 's/::/ . /g' -e 's/:/ /g' ` +which_1 () +{ + for cmd + do + for d in $PATH_DIRS + do + for file in $d/$cmd + do + if test -x $file -a ! -d $file + then + echo $file + exit 0 + fi + done + done + done + exit 1 +} + +# +# Create the result zip/tar file +# + +set_tarzip_options() +{ + for arg + do + if [ "$arg" = "tar" ]; then + ZIPFILE1=gnutar + ZIPFILE2=gtar + OPT=cvf + EXT=".tar" + NEED_COMPRESS=1 + if [ "$SILENT" = "1" ] ; then + OPT=cf + fi + else + ZIPFILE1=zip + ZIPFILE2="" + OPT="-r" + EXT=".zip" + NEED_COMPRESS=0 + if [ "$SILENT" = "1" ] ; then + OPT="$OPT -q" + fi + fi + done +} + +if [ "$OUTTAR" = "1" ]; then + set_tarzip_options 'tar' +else + set_tarzip_options 'zip' +fi + +tar=`which_1 $ZIPFILE1 $ZIPFILE2` +if test "$?" = "1" -o "$tar" = "" +then + print_debug "Search failed for '$ZIPFILE1', '$ZIPFILE2', using default 'tar'" + tar=tar + set_tarzip_options 'tar' +fi + +# +# Create the archive +# + +print_debug "Using $tar to create archive" + +cd $TMP + +rm -f $SOURCE/$NEW_NAME$EXT +$tar $OPT $SOURCE/$NEW_NAME$EXT $NEW_DIR_NAME +cd $SOURCE + +if [ "$NEED_COMPRESS" = "1" ] +then + print_debug "Compressing archive" + gzip -9 $NEW_NAME$EXT + EXT="$EXT.gz" +fi + +print_debug "Removing temporary directory" +rm -r -f $BASE + +if [ "$SILENT" = "0" ] ; then + echo "$NEW_NAME$EXT created successfully !!" +fi +# End of script diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh index df7ac29ee0d..8f8ee344e93 100755 --- a/scripts/make_win_src_distribution.sh +++ b/scripts/make_win_src_distribution.sh @@ -219,7 +219,7 @@ copy_dir_dirs() { for i in client dbug extra heap include isam \ libmysql libmysqld merge myisam \ - myisammrg mysys regex sql strings sql-common \ + myisammrg mysys regex sql strings \ vio zlib do copy_dir_files $i diff --git a/scripts/mysql_explain_log.sh b/scripts/mysql_explain_log.sh index c4a4ef21568..973d9e8a363 100644 --- a/scripts/mysql_explain_log.sh +++ b/scripts/mysql_explain_log.sh @@ -14,12 +14,14 @@ $Param->{host}=''; $Param->{user}=''; $Param->{password}=''; $Param->{PrintError}=0; +$Param->{socket}=''; if (!GetOptions ('date|d:i' => \$Param->{ViewDate}, 'host|h:s' => \$Param->{host}, 'user|u:s' => \$Param->{user}, 'password|p:s' => \$Param->{password}, 'printerror|e:s' => \$Param->{PrintError}, + 'socket|s:s' => \$Param->{socket}, )) { ShowOptions(); } @@ -50,7 +52,7 @@ else { #print "Date=$Param->{ViewDate}, host=$Param->{host}, user=$Param->{user}, password=$Param->{password}\n"; - $Param->{dbh}=DBI->connect("DBI:mysql:host=$Param->{host}",$Param->{user},$Param->{password},{PrintError=>0}); + $Param->{dbh}=DBI->connect("DBI:mysql:host=$Param->{host}".($Param->{socket}?";mysql_socket=$Param->{socket}":""),$Param->{user},$Param->{password},{PrintError=>0}); if (DBI::err()) { print "Error: " . DBI::errstr() . "\n"; } @@ -313,6 +315,8 @@ Usage: $0 [OPTIONS] < LOGFILE -u=USERNAME --password=PASSWORD password of db-user -p=PASSWORD +--socket=SOCKET mysqld socket file to connect +-s=SOCKET Read logfile from STDIN an try to EXPLAIN all SELECT statements. All UPDATE statements are rewritten to an EXPLAIN SELECT statement. The results of the EXPLAIN statement are collected and counted. All results with type=ALL are collected in an separete list. Results are printed to STDOUT. @@ -344,7 +348,7 @@ Then add indices to avoid table scans and remove those which aren't used. =head1 USAGE -explain_log.pl [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] < logfile +explain_log.pl [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] [--socket=/path/to/socket] < logfile --date=YYMMDD select only entrys of date @@ -362,14 +366,19 @@ explain_log.pl [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] -p=PASSWORD +--socket=SOCKET change path to the socket + +-s=SOCKET + =head1 EXAMPLE explain_log.pl --host=localhost --user=foo --password=bar < /var/lib/mysql/mobile.log -=head1 AUTHOR +=head1 AUTHORS Stefan Nitz Jan Willamowius <jan@mobile.de>, http://www.mobile.de + Dennis Haney <davh@davh.dk> (Added socket support) =head1 RECRUITING diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh index 4b6f74eae06..bf7f082203d 100644 --- a/scripts/mysql_fix_privilege_tables.sh +++ b/scripts/mysql_fix_privilege_tables.sh @@ -88,12 +88,12 @@ fi # The following test is to make this script compatible with the 4.0 where # the first argument was the password -if test -z $password +if test -z "$password" then password=`echo $args | sed -e 's/ *//g'` fi -if test -z $password ; then +if test -z "$password" ; then cmd="$bindir/mysql -f --user=$user --host=$host mysql" else cmd="$bindir/mysql -f --user=$user --password=$password --host=$host mysql" diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index a69995e51a0..309463441b5 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -138,7 +138,13 @@ then fi fi -hostname=`@HOSTNAME@` # Install this too in the user table +# Try to determine the fully qualified domain name (FQDN) +HOSTNAME="@HOSTNAME@" +if $HOSTNAME -f > /dev/null 2>&1 ; then + hostname=`$HOSTNAME -f` +else + hostname=`$HOSTNAME` +fi # Check if hostname is valid if test "$windows" -eq 0 -a "$in_rpm" -eq 0 -a $force -eq 0 diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index e400c27b84c..d7e3eedb84e 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -10,6 +10,8 @@ # mysql.server works by first doing a cd to the base directory and from there # executing mysqld_safe +KILL_MYSQLD=1; + trap '' 1 2 3 15 # we shouldn't let anyone kill us umask 007 @@ -34,6 +36,9 @@ parse_arguments() { for arg do case "$arg" in + --skip-kill-mysqld*) + KILL_MYSQLD=0; + ;; # these get passed explicitly to mysqld --basedir=*) MY_BASEDIR_VERSION=`echo "$arg" | sed -e "s;--basedir=;;"` ;; --datadir=*) DATADIR=`echo "$arg" | sed -e "s;--datadir=;;"` ;; @@ -70,6 +75,7 @@ parse_arguments() { MYSQLD="mysqld" fi ;; + --nice=*) niceness=`echo "$arg" | sed -e "s;--nice=;;"` ;; *) if test -n "$pick_args" then @@ -82,6 +88,7 @@ parse_arguments() { done } + MY_PWD=`pwd` # Check if we are starting this relative (for the binary release) if test -d $MY_PWD/data/mysql -a -f ./share/mysql/english/errmsg.sys -a \ @@ -110,6 +117,7 @@ fi MYSQL_UNIX_PORT=${MYSQL_UNIX_PORT:-@MYSQL_UNIX_ADDR@} MYSQL_TCP_PORT=${MYSQL_TCP_PORT:-@MYSQL_TCP_PORT@} user=@MYSQLD_USER@ +niceness=0 # Use the mysqld-max binary by default if the user doesn't specify a binary if test -x $ledir/mysqld-max @@ -167,7 +175,12 @@ export MYSQL_UNIX_PORT export MYSQL_TCP_PORT -NOHUP_NICENESS="nohup" +if test $niceness -eq 0 +then + NOHUP_NICENESS="nohup" +else + NOHUP_NICENESS="nohup nice -$niceness" +fi # Using nice with no args to get the niceness level is GNU-specific. # This check could be extended for other operating systems (e.g., @@ -198,8 +211,10 @@ then nice --$nice_value_diff echo testing > /dev/null 2>&1 then # nohup increases the priority (bad), and we are permitted - # to lower the priority - NOHUP_NICENESS="nice --$nice_value_diff nohup" + # to lower the priority with respect to the value the user + # might have been given + niceness=`expr $niceness - $nice_value_diff` + NOHUP_NICENESS="nice -$niceness nohup" fi fi else @@ -259,12 +274,16 @@ then fi # -# Uncomment the following lines if you want all tables to be automaticly -# checked and repaired at start +# Uncomment the following lines if you want all tables to be automatically +# checked and repaired during startup. You should add sensible key_buffer +# and sort_buffer values to my.cnf to improve check performance or require +# less disk space. +# Alternatively, you can start mysqld with the "myisam-recover" option. See +# the manual for details. # # echo "Checking tables in $DATADIR" -# $MY_BASEDIR_VERSION/bin/myisamchk --silent --force --fast --medium-check -O key_buffer=64M -O sort_buffer=64M $DATADIR/*/*.MYI -# $MY_BASEDIR_VERSION/bin/isamchk --silent --force -O sort_buffer=64M $DATADIR/*/*.ISM +# $MY_BASEDIR_VERSION/bin/myisamchk --silent --force --fast --medium-check $DATADIR/*/*.MYI +# $MY_BASEDIR_VERSION/bin/isamchk --silent --force $DATADIR/*/*.ISM echo "Starting $MYSQLD daemon with databases from $DATADIR" @@ -289,7 +308,7 @@ do break fi - if @IS_LINUX@ + if test @IS_LINUX@ -a $KILL_MYSQLD -eq 1 then # Test if one process was hanging. # This is only a fix for Linux (running as base 3 mysqld processes) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index a89a8919752..f23955da06a 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -37,7 +37,7 @@ WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. # Documentation continued at end of file -my $VERSION = "1.18"; +my $VERSION = "1.19"; my $opt_tmpdir = $ENV{TMPDIR} || "/tmp"; @@ -81,8 +81,11 @@ sub usage { die @_, $OPTIONS; } +# Do not initialize user or password options; that way, any user/password +# options specified in option files will be used. If no values are specified +# all, the defaults will be used (login name, no password). + my %opt = ( - user => scalar getpwuid($>), noindices => 0, allowold => 0, # for safety keepold => 0, @@ -165,6 +168,9 @@ $dsn = ";host=" . (defined($opt{host}) ? $opt{host} : "localhost"); $dsn .= ";port=$opt{port}" if $opt{port}; $dsn .= ";mysql_socket=$opt{socket}" if $opt{socket}; +# use mysql_read_default_group=mysqlhotcopy so that [client] and +# [mysqlhotcopy] groups will be read from standard options files. + my $dbh = DBI->connect("dbi:mysql:$dsn;mysql_read_default_group=mysqlhotcopy", $opt{user}, $opt{password}, { @@ -563,22 +569,22 @@ sub copy_files { print "Copying ".@$files." files...\n" unless $opt{quiet}; if ($method =~ /^s?cp\b/) { # cp or scp with optional flags - my @cp = ($method); + my $cp = $method; # add option to preserve mod time etc of copied files # not critical, but nice to have - push @cp, "-p" if $^O =~ m/^(solaris|linux|freebsd|darwin)$/; + $cp.= " -p" if $^O =~ m/^(solaris|linux|freebsd|darwin)$/; # add recursive option for scp - push @cp, "-r" if $^O =~ /m^(solaris|linux|freebsd|darwin)$/ && $method =~ /^scp\b/; + $cp.= " -r" if $^O =~ /m^(solaris|linux|freebsd|darwin)$/ && $method =~ /^scp\b/; my @non_raid = map { "'$_'" } grep { ! m:/\d{2}/[^/]+$: } @$files; # add files to copy and the destination directory - safe_system( @cp, @non_raid, "'$target'" ) if (@non_raid); + safe_system( $cp, @non_raid, "'$target'" ) if (@non_raid); foreach my $rd ( @$raid_dirs ) { my @raid = map { "'$_'" } grep { m:$rd/: } @$files; - safe_system( @cp, @raid, "'$target'/$rd" ) if ( @raid ); + safe_system( $cp, @raid, "'$target'/$rd" ) if ( @raid ); } } else @@ -640,26 +646,54 @@ sub copy_index } -sub safe_system -{ - my @cmd= @_; - - if ( $opt{dryrun} ) - { - print "@cmd\n"; - return; +sub safe_system { + my @sources= @_; + my $method= shift @sources; + my $target= pop @sources; + ## @sources = list of source file names + + ## We have to deal with very long command lines, otherwise they may generate + ## "Argument list too long". + ## With 10000 tables the command line can be around 1MB, much more than 128kB + ## which is the common limit on Linux (can be read from + ## /usr/src/linux/include/linux/binfmts.h + ## see http://www.linuxjournal.com/article.php?sid=6060). + + my $chunk_limit= 100 * 1024; # 100 kB + my @chunk= (); + my $chunk_length= 0; + foreach (@sources) { + push @chunk, $_; + $chunk_length+= length($_); + if ($chunk_length > $chunk_limit) { + safe_simple_system($method, @chunk, $target); + @chunk=(); + $chunk_length= 0; + } } - - ## for some reason system fails but backticks works ok for scp... - print "Executing '@cmd'\n" if $opt{debug}; - my $cp_status = system "@cmd > /dev/null"; - if ($cp_status != 0) { - warn "Burp ('scuse me). Trying backtick execution...\n" if $opt{debug}; #' - ## try something else - `@cmd` && die "Error: @cmd failed ($cp_status) while copying files.\n"; + if ($chunk_length > 0) { # do not forget last small chunk + safe_simple_system($method, @chunk, $target); } } +sub safe_simple_system { + my @cmd= @_; + + if ( $opt{dryrun} ) { + print "@cmd\n"; + } + else { + ## for some reason system fails but backticks works ok for scp... + print "Executing '@cmd'\n" if $opt{debug}; + my $cp_status = system "@cmd > /dev/null"; + if ($cp_status != 0) { + warn "Executing command failed ($cp_status). Trying backtick execution...\n"; + ## try something else + `@cmd` || die "Error: @cmd failed ($?) while copying files.\n"; + } + } +} + sub retire_directory { my ( @dir ) = @_; @@ -770,6 +804,10 @@ sub quote_names { my ($db, $table, @cruft) = split( /\./, $name ); die "Invalid db.table name '$name'" if (@cruft || !defined $db || !defined $table ); + # Earlier versions of DBD return table name non-quoted, + # such as DBD-2.1012 and the newer ones, such as DBD-2.9002 + # returns it quoted. Let's have a support for both. + $table=~ s/\`//g; return "`$db`.`$table`"; } diff --git a/sql/Makefile.am b/sql/Makefile.am index 5781b6181d2..69b9c58dd6d 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -123,8 +123,8 @@ sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS) $(CXXCOMPILE) $(LM_CFLAGS) -c $< lex_hash.h: lex.h gen_lex_hash.cc sql_yacc.h - $(MAKE) gen_lex_hash - ./gen_lex_hash > $@ + $(MAKE) gen_lex_hash$(EXEEXT) + ./gen_lex_hash$(EXEEXT) > $@ # Hack to ensure that lex_hash.h is built early sql_lex.o: lex_hash.h diff --git a/sql/field.h b/sql/field.h index 79c45a99a43..794b4a89542 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1066,6 +1066,7 @@ public: uint offset,pack_flag; create_field() :after(0) {} create_field(Field *field, Field *orig_field); + void create_length_to_internal_length(void); }; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 44e30afb880..6510a03f5a6 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* 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 diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1cf123dbec6..d870d0debfd 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -42,7 +42,9 @@ InnoDB */ pthread_mutex_t innobase_mutex; /* Store MySQL definition of 'byte': in Linux it is char while InnoDB -uses unsigned char */ +uses unsigned char; the header univ.i which we include next defines +'byte' as a macro which expands to 'unsigned char' */ + typedef byte mysql_byte; #define INSIDE_HA_INNOBASE_CC @@ -130,11 +132,44 @@ static void innobase_print_error(const char* db_errpfx, char* buffer); /* General functions */ /********************************************************************** +Save some CPU by testing the value of srv_thread_concurrency in inline +functions. */ +inline +void +innodb_srv_conc_enter_innodb( +/*=========================*/ + trx_t* trx) /* in: transaction handle */ +{ + if (srv_thread_concurrency >= 500) { + + return; + } + + srv_conc_enter_innodb(trx); +} + +/********************************************************************** +Save some CPU by testing the value of srv_thread_concurrency in inline +functions. */ +inline +void +innodb_srv_conc_exit_innodb( +/*========================*/ + trx_t* trx) /* in: transaction handle */ +{ + if (srv_thread_concurrency >= 500) { + + return; + } + + srv_conc_exit_innodb(trx); +} + +/********************************************************************** Releases possible search latch and InnoDB thread FIFO ticket. These should be released at each SQL statement end, and also when mysqld passes the control to the client. It does no harm to release these also in the middle of an SQL statement. */ -static inline void innobase_release_stat_resources( @@ -183,7 +218,9 @@ innobase_active_small(void) } /************************************************************************ -Converts an InnoDB error code to a MySQL error code. */ +Converts an InnoDB error code to a MySQL error code and also tells to MySQL +about a possible transaction rollback inside InnoDB caused by a lock wait +timeout or a deadlock. */ static int convert_error_code_to_mysql( @@ -206,10 +243,10 @@ convert_error_code_to_mysql( } else if (error == (int) DB_ERROR) { - return(HA_ERR_NO_ACTIVE_RECORD); + return(-1); /* unspecified error */ } else if (error == (int) DB_DEADLOCK) { - /* Since we roll back the whole transaction, we must + /* Since we rolled back the whole transaction, we must tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ @@ -221,11 +258,10 @@ convert_error_code_to_mysql( } else if (error == (int) DB_LOCK_WAIT_TIMEOUT) { - /* Since we roll back the whole transaction, we must + /* Since we rolled back the whole transaction, we must tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ - if (thd) { ha_rollback(thd); } @@ -271,6 +307,9 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CORRUPTION) { return(HA_ERR_CRASHED); + } else if (error == (int) DB_NO_SAVEPOINT) { + + return(HA_ERR_NO_SAVEPOINT); } else { return(-1); // Unknown error } @@ -624,6 +663,8 @@ ha_innobase::init_table_handle_for_HANDLER(void) prebuilt = (row_prebuilt_t*)innobase_prebuilt; + innobase_release_stat_resources(prebuilt->trx); + /* If the transaction is not started yet, start it */ trx_start_if_not_started_noninline(prebuilt->trx); @@ -891,7 +932,7 @@ innobase_flush_logs(void) DBUG_ENTER("innobase_flush_logs"); - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); DBUG_RETURN(result); } @@ -960,17 +1001,28 @@ innobase_commit( DBUG_ENTER("innobase_commit"); DBUG_PRINT("trans", ("ending transaction")); - /* The flag thd->transaction.all.innodb_active_trans is set to 1 - in ::external_lock and ::start_stmt, and it is only set to 0 in - a commit or a rollback. If it is 0 we know there cannot be resources - to be freed and we can return immediately. */ + trx = check_trx_exists(thd); - if (thd->transaction.all.innodb_active_trans == 0) { + /* Release a possible FIFO ticket and search latch. Since we will + reserve the kernel mutex, we have to release the search system latch + first to obey the latching order. */ - DBUG_RETURN(0); - } + innobase_release_stat_resources(trx); - trx = check_trx_exists(thd); + /* The flag thd->transaction.all.innodb_active_trans is set to 1 in + ::external_lock, ::start_stmt, and innobase_savepoint, and it is only + set to 0 in a commit or a rollback. If it is 0 we know there cannot be + resources to be freed and we could return immediately. For the time + being we play safe and do the cleanup though there should be nothing + to clean up. */ + + if (thd->transaction.all.innodb_active_trans == 0 + && trx->conc_state != TRX_NOT_STARTED) { + + fprintf(stderr, +"InnoDB: Error: thd->transaction.all.innodb_active_trans == 0\n" +"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + } if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { @@ -983,9 +1035,7 @@ innobase_commit( /* If we had reserved the auto-inc lock for some table in this SQL statement we release it now */ - srv_conc_enter_innodb(trx); row_unlock_table_autoinc_for_mysql(trx); - srv_conc_exit_innodb(trx); } /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next @@ -994,9 +1044,6 @@ innobase_commit( trx_mark_sql_stat_end(trx); } - /* Release a possible FIFO ticket and search latch */ - innobase_release_stat_resources(trx); - /* Tell the InnoDB server that there might be work for utility threads: */ @@ -1069,7 +1116,7 @@ innobase_commit_complete( } /********************************************************************* -Rolls back a transaction or the latest SQL statement in an InnoDB database. */ +Rolls back a transaction or the latest SQL statement. */ int innobase_rollback( @@ -1089,54 +1136,138 @@ innobase_rollback( trx = check_trx_exists(thd); + /* Release a possible FIFO ticket and search latch. Since we will + reserve the kernel mutex, we have to release the search system latch + first to obey the latching order. */ + + innobase_release_stat_resources(trx); + if (trx->auto_inc_lock) { - - /* If we had reserved the auto-inc lock for - some table in this SQL statement, we release it now */ - - srv_conc_enter_innodb(trx); + /* If we had reserved the auto-inc lock for some table (if + we come here to roll back the latest SQL statement) we + release it now before a possibly lengthy rollback */ + row_unlock_table_autoinc_for_mysql(trx); - srv_conc_exit_innodb(trx); } - srv_conc_enter_innodb(trx); + if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle + || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { - if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { error = trx_rollback_for_mysql(trx); - thd->transaction.all.innodb_active_trans=0; + thd->transaction.all.innodb_active_trans = 0; } else { error = trx_rollback_last_sql_stat_for_mysql(trx); } - srv_conc_exit_innodb(trx); + DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); +} + +/********************************************************************* +Rolls back a transaction to a savepoint. */ + +int +innobase_rollback_to_savepoint( +/*===========================*/ + /* out: 0 if success, HA_ERR_NO_SAVEPOINT if + no savepoint with the given name */ + THD* thd, /* in: handle to the MySQL thread of the user + whose transaction should be rolled back */ + char* savepoint_name, /* in: savepoint name */ + my_off_t* binlog_cache_pos)/* out: position which corresponds to the + savepoint in the binlog cache of this + transaction, not defined if error */ +{ + ib_longlong mysql_binlog_cache_pos; + int error = 0; + trx_t* trx; + + DBUG_ENTER("innobase_rollback_to_savepoint"); + + trx = check_trx_exists(thd); + + /* Release a possible FIFO ticket and search latch. Since we will + reserve the kernel mutex, we have to release the search system latch + first to obey the latching order. */ - /* Release a possible FIFO ticket and search latch */ innobase_release_stat_resources(trx); + error = trx_rollback_to_savepoint_for_mysql(trx, savepoint_name, + &mysql_binlog_cache_pos); + + *binlog_cache_pos = (my_off_t)mysql_binlog_cache_pos; + DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); } /********************************************************************* -Frees a possible InnoDB trx object associated with the current -THD. */ +Sets a transaction savepoint. */ + +int +innobase_savepoint( +/*===============*/ + /* out: always 0, that is, always succeeds */ + THD* thd, /* in: handle to the MySQL thread */ + char* savepoint_name, /* in: savepoint name */ + my_off_t binlog_cache_pos)/* in: offset up to which the current + transaction has cached log entries to its + binlog cache, not defined if no transaction + active, or we are in the autocommit state, or + binlogging is not switched on */ +{ + int error = 0; + trx_t* trx; + + DBUG_ENTER("innobase_savepoint"); + + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { + /* In the autocommit state there is no sense to set a + savepoint: we return immediate success */ + DBUG_RETURN(0); + } + + trx = check_trx_exists(thd); + + /* Release a possible FIFO ticket and search latch. Since we will + reserve the kernel mutex, we have to release the search system latch + first to obey the latching order. */ + + innobase_release_stat_resources(trx); + + /* Setting a savepoint starts a transaction inside InnoDB since + it allocates resources for it (memory to store the savepoint name, + for example) */ + + thd->transaction.all.innodb_active_trans = 1; + + error = trx_savepoint_for_mysql(trx, savepoint_name, + (ib_longlong)binlog_cache_pos); + + DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); +} + +/********************************************************************* +Frees a possible InnoDB trx object associated with the current THD. */ int innobase_close_connection( /*======================*/ - /* out: 0 or error number */ - THD* thd) /* in: handle to the MySQL thread of the user - whose transaction should be rolled back */ + /* out: 0 or error number */ + THD* thd) /* in: handle to the MySQL thread of the user + whose transaction should be rolled back */ { - if (NULL != thd->transaction.all.innobase_tid) { + trx_t* trx; - trx_rollback_for_mysql((trx_t*) - (thd->transaction.all.innobase_tid)); - trx_free_for_mysql((trx_t*) - (thd->transaction.all.innobase_tid)); - thd->transaction.all.innobase_tid = NULL; - } + trx = (trx_t*)thd->transaction.all.innobase_tid; - return(0); + if (NULL != trx) { + innobase_rollback(thd, (void*)trx); + + trx_free_for_mysql(trx); + + thd->transaction.all.innobase_tid = NULL; + } + + return(0); } /********************************************************************** @@ -1239,7 +1370,6 @@ ha_innobase::open( { dict_table_t* ib_table; int error = 0; - uint buff_len; char norm_name[1000]; DBUG_ENTER("ha_innobase::open"); @@ -1264,11 +1394,11 @@ ha_innobase::open( fields when packed actually became 1 byte longer, when we also stored the string length as the first byte. */ - buff_len = table->reclength + table->max_key_length + upd_and_key_val_buff_len = table->reclength + table->max_key_length + MAX_REF_PARTS * 3; if (!(mysql_byte*) my_multi_malloc(MYF(MY_WME), - &upd_buff, buff_len, - &key_val_buff, buff_len, + &upd_buff, upd_and_key_val_buff_len, + &key_val_buff, upd_and_key_val_buff_len, NullS)) { free_share(share); DBUG_RETURN(1); @@ -1519,8 +1649,12 @@ innobase_mysql_cmp( case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: - // BAR TODO: Discuss with heikki.tuuri@innodb.com - // so that he sends CHARSET_INFO for the field to this function. + case FIELD_TYPE_TINY_BLOB: + case FIELD_TYPE_MEDIUM_BLOB: + case FIELD_TYPE_BLOB: + case FIELD_TYPE_LONG_BLOB: + // BAR TODO: Discuss with heikki.tuuri@innodb.com + // so that he sends CHARSET_INFO for the field to this function. ret = my_strnncoll(default_charset_info, a, a_length, b, b_length); @@ -1548,7 +1682,7 @@ get_innobase_type_from_mysql_type( /* out: DATA_BINARY, DATA_VARCHAR, ... */ Field* field) /* in: MySQL field */ { - /* The following asserts check that MySQL type code fits in + /* The following asserts check that the MySQL type code fits in 8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to the type */ @@ -1559,6 +1693,8 @@ get_innobase_type_from_mysql_type( DBUG_ASSERT((ulint)FIELD_TYPE_DECIMAL < 256); switch (field->type()) { + /* NOTE that we only allow string types in DATA_MYSQL + and DATA_VARMYSQL */ case FIELD_TYPE_VAR_STRING: if (field->binary()) { return(DATA_BINARY); @@ -1612,8 +1748,7 @@ get_innobase_type_from_mysql_type( } /*********************************************************************** -Stores a key value for a row to a buffer. This must currently only be used -to store a row reference to the 'ref' buffer of this table handle! */ +Stores a key value for a row to a buffer. */ uint ha_innobase::store_key_val_for_row( @@ -1621,41 +1756,108 @@ ha_innobase::store_key_val_for_row( /* out: key value length as stored in buff */ uint keynr, /* in: key number */ char* buff, /* in/out: buffer for the key value (in MySQL - format); currently this MUST be the 'ref' - buffer! */ + format) */ + uint buff_len,/* in: buffer length */ const mysql_byte* record)/* in: row in MySQL format */ { KEY* key_info = table->key_info + keynr; KEY_PART_INFO* key_part = key_info->key_part; KEY_PART_INFO* end = key_part + key_info->key_parts; char* buff_start = buff; + enum_field_types mysql_type; + Field* field; + ulint blob_len; + byte* blob_data; + ibool is_null; DBUG_ENTER("store_key_val_for_row"); + /* The format for storing a key field in MySQL is the following: + + 1. If the column can be NULL, then in the first byte we put 1 if the + field value is NULL, 0 otherwise. + + 2. If the column is of a BLOB type (it must be a column prefix field + in this case), then we put the length of the data in the field to the + next 2 bytes, in the little-endian format. If the field is SQL NULL, + then these 2 bytes are set to 0. Note that the length of data in the + field is <= column prefix length. + + 3. In a column prefix field, prefix_len next bytes are reserved for + data. In a normal field the max field length next bytes are reserved + for data. For a VARCHAR(n) the max field length is n. If the stored + value is the SQL NULL then these data bytes are set to 0. */ + + /* We have to zero-fill the buffer so that MySQL is able to use a + simple memcmp to compare two key values to determine if they are + equal. MySQL does this to compare contents of two 'ref' values. */ + + bzero(buff, buff_len); + for (; key_part != end; key_part++) { + is_null = FALSE; if (key_part->null_bit) { - /* Store 0 if the key part is a NULL part */ - if (record[key_part->null_offset] & key_part->null_bit) { - *buff++ = 1; - continue; - } - - *buff++ = 0; + *buff = 1; + is_null = TRUE; + } else { + *buff = 0; + } + buff++; } - memcpy(buff, record + key_part->offset, key_part->length); - buff += key_part->length; + field = key_part->field; + mysql_type = field->type(); + + if (mysql_type == FIELD_TYPE_TINY_BLOB + || mysql_type == FIELD_TYPE_MEDIUM_BLOB + || mysql_type == FIELD_TYPE_BLOB + || mysql_type == FIELD_TYPE_LONG_BLOB) { + + ut_a(key_part->key_part_flag & HA_PART_KEY); + + if (is_null) { + buff += key_part->length + 2; + + continue; + } + + blob_data = row_mysql_read_blob_ref(&blob_len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + (ulint) field->pack_length()); + + ut_a(get_field_offset(table, field) + == key_part->offset); + if (blob_len > key_part->length) { + blob_len = key_part->length; + } + + /* MySQL reserves 2 bytes for the length and the + storage of the number is little-endian */ + + ut_a(blob_len < 256); + *((byte*)buff) = (byte)blob_len; + buff += 2; + + memcpy(buff, blob_data, blob_len); + + buff += key_part->length; + } else { + if (is_null) { + buff += key_part->length; + + continue; + } + memcpy(buff, record + key_part->offset, + key_part->length); + buff += key_part->length; + } } - /* - We have to zero-fill the 'ref' buffer so that MySQL is able to - use a simple memcmp to compare two key values to determine if they - are equal - */ - bzero(buff, (ref_length- (uint) (buff - buff_start))); + ut_a(buff <= buff_start + buff_len); DBUG_RETURN((uint)(buff - buff_start)); } @@ -1693,7 +1895,11 @@ build_template( if (prebuilt->read_just_key) { /* MySQL has instructed us that it is enough to - fetch the columns in the key */ + fetch the columns in the key; looks like MySQL + can set this flag also when there is only a + prefix of the column in the key: in that case we + retrieve the whole column from the clustered + index */ fetch_all_in_key = TRUE; } else { @@ -1709,12 +1915,6 @@ build_template( } if (prebuilt->select_lock_type == LOCK_X) { - /* In versions < 3.23.50 we always retrieved the clustered - index record if prebuilt->select_lock_type == LOCK_S, - but there is really not need for that, and in some cases - performance could be seriously degraded because the MySQL - optimizer did not know about our convention! */ - /* We always retrieve the whole clustered index record if we use exclusive row level locks, for example, if the read is done in an UPDATE statement. */ @@ -1723,6 +1923,11 @@ build_template( } if (templ_type == ROW_MYSQL_REC_FIELDS) { + /* In versions < 3.23.50 we always retrieved the clustered + index record if prebuilt->select_lock_type == LOCK_S, + but there is really not need for that, and in some cases + performance could be seriously degraded because the MySQL + optimizer did not know about our convention! */ index = prebuilt->index; } else { index = clust_index; @@ -1768,9 +1973,8 @@ build_template( is fixed!!!!!!!!!!!!!!!!! if (templ_type == ROW_MYSQL_REC_FIELDS - && !(fetch_all_in_key && - ULINT_UNDEFINED != dict_index_get_nth_col_pos( - index, i)) + && !(fetch_all_in_key + && dict_index_contains_col_or_prefix(index, i)) && thd->query_id != field->query_id && thd->query_id != (field->query_id ^ MAX_ULONG_BIT) && thd->query_id != @@ -1942,9 +2146,9 @@ ha_innobase::write_row( The lock is released at each SQL statement's end. */ - srv_conc_enter_innodb(prebuilt->trx); + innodb_srv_conc_enter_innodb(prebuilt->trx); error = row_lock_table_autoinc_for_mysql(prebuilt); - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb(prebuilt->trx); if (error != DB_SUCCESS) { @@ -1955,14 +2159,15 @@ ha_innobase::write_row( dict_table_autoinc_update(prebuilt->table, auto_inc); } else { - srv_conc_enter_innodb(prebuilt->trx); + innodb_srv_conc_enter_innodb(prebuilt->trx); if (!prebuilt->trx->auto_inc_lock) { error = row_lock_table_autoinc_for_mysql( prebuilt); if (error != DB_SUCCESS) { - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb( + prebuilt->trx); error = convert_error_code_to_mysql( error, user_thd); @@ -1976,7 +2181,7 @@ ha_innobase::write_row( auto_inc = dict_table_autoinc_get(prebuilt->table); incremented_auto_inc_counter = TRUE; - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb(prebuilt->trx); /* We can give the new value for MySQL to place in the field */ @@ -1999,11 +2204,11 @@ ha_innobase::write_row( build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW); } - srv_conc_enter_innodb(prebuilt->trx); + innodb_srv_conc_enter_innodb(prebuilt->trx); error = row_insert_for_mysql((byte*) record, prebuilt); - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb(prebuilt->trx); if (error != DB_SUCCESS) { /* If the insert did not succeed we restore the value of @@ -2074,7 +2279,6 @@ innobase_convert_and_store_changed_col( while (len > 0 && data[len - 1] == ' ') { len--; } - } else if (col_type == DATA_INT) { /* Store integer data in InnoDB in a big-endian format, sign bit negated, if signed */ @@ -2112,9 +2316,11 @@ calc_row_difference( struct st_table* table, /* in: table in MySQL data dictionary */ mysql_byte* upd_buff, /* in: buffer to use */ + ulint buff_len, /* in: buffer length */ row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */ THD* thd) /* in: user thread */ { + mysql_byte* original_upd_buff = upd_buff; Field* field; uint n_fields; ulint o_len; @@ -2196,12 +2402,13 @@ calc_row_difference( (prebuilt->table->cols + i)->clust_pos; n_changed++; } - ; } uvect->n_fields = n_changed; uvect->info_bits = 0; + ut_a(buf <= (byte*)original_upd_buff + buff_len); + return(0); } @@ -2250,17 +2457,19 @@ ha_innobase::update_row( (uses upd_buff of the handle) */ calc_row_difference(uvect, (mysql_byte*) old_row, new_row, table, - upd_buff, prebuilt, user_thd); + upd_buff, (ulint)upd_and_key_val_buff_len, + prebuilt, user_thd); + /* This is not a delete */ prebuilt->upd_node->is_delete = FALSE; assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW); - srv_conc_enter_innodb(prebuilt->trx); + innodb_srv_conc_enter_innodb(prebuilt->trx); error = row_update_for_mysql((byte*) old_row, prebuilt); - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb(prebuilt->trx); error = convert_error_code_to_mysql(error, user_thd); @@ -2304,11 +2513,11 @@ ha_innobase::delete_row( prebuilt->upd_node->is_delete = TRUE; - srv_conc_enter_innodb(prebuilt->trx); + innodb_srv_conc_enter_innodb(prebuilt->trx); error = row_update_for_mysql((byte*) record, prebuilt); - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb(prebuilt->trx); error = convert_error_code_to_mysql(error, user_thd); @@ -2491,10 +2700,11 @@ ha_innobase::index_read( prebuilt->search_tuple */ row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple, - (byte*) key_val_buff, - index, - (byte*) key_ptr, - (ulint) key_len); + (byte*) key_val_buff, + (ulint)upd_and_key_val_buff_len, + index, + (byte*) key_ptr, + (ulint) key_len); } else { /* We position the cursor to the last or the first entry in the index */ @@ -2516,11 +2726,11 @@ ha_innobase::index_read( last_match_mode = match_mode; - srv_conc_enter_innodb(prebuilt->trx); + innodb_srv_conc_enter_innodb(prebuilt->trx); ret = row_search_for_mysql((byte*) buf, mode, prebuilt, match_mode, 0); - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb(prebuilt->trx); if (ret == DB_SUCCESS) { error = 0; @@ -2670,11 +2880,11 @@ ha_innobase::general_fetch( ut_a(prebuilt->trx == (trx_t*) current_thd->transaction.all.innobase_tid); - srv_conc_enter_innodb(prebuilt->trx); + innodb_srv_conc_enter_innodb(prebuilt->trx); ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode, direction); - srv_conc_exit_innodb(prebuilt->trx); + innodb_srv_conc_exit_innodb(prebuilt->trx); if (ret == DB_SUCCESS) { error = 0; @@ -2963,7 +3173,8 @@ ha_innobase::position( memcpy(ref, prebuilt->row_id, len); } else { - len = store_key_val_for_row(primary_key, (char*) ref, record); + len = store_key_val_for_row(primary_key, (char*)ref, + ref_length, record); } /* Since we do not store len to the buffer 'ref', we must assume @@ -2977,7 +3188,6 @@ ha_innobase::position( } } - /********************************************************************* Creates a table definition to an InnoDB database. */ static @@ -2996,6 +3206,8 @@ create_table_def( ulint col_type; ulint nulls_allowed; ulint unsigned_type; + ulint binary_type; + ulint nonlatin1_type; ulint i; DBUG_ENTER("create_table_def"); @@ -3024,9 +3236,24 @@ create_table_def( unsigned_type = 0; } + if (col_type == DATA_BLOB + && strcmp(default_charset_info->name, "latin1") != 0) { + nonlatin1_type = DATA_NONLATIN1; + } else { + nonlatin1_type = 0; + } + + if (field->flags & BINARY_FLAG) { + binary_type = DATA_BINARY_TYPE; + nonlatin1_type = 0; + } else { + binary_type = 0; + } + dict_mem_table_add_col(table, (char*) field->field_name, col_type, (ulint)field->type() - | nulls_allowed | unsigned_type, + | nulls_allowed | unsigned_type + | nonlatin1_type | binary_type, field->pack_length(), 0); } @@ -3049,6 +3276,7 @@ create_index( const char* table_name, /* in: table name */ uint key_num) /* in: index number */ { + Field* field; dict_index_t* index; int error; ulint n_fields; @@ -3058,6 +3286,7 @@ create_index( ulint col_type; ulint prefix_len; ulint i; + ulint j; DBUG_ENTER("create_index"); @@ -3084,31 +3313,63 @@ create_index( for (i = 0; i < n_fields; i++) { key_part = key->key_part + i; - if (key_part->length != key_part->field->pack_length()) { + /* (The flag HA_PART_KEY denotes in MySQL a column prefix + field in an index: we only store a specified number of first + bytes of the column to the index field.) The flag does not + seem to be properly set by MySQL. Let us fall back on testing + the length of the key part versus the column. */ + + field = NULL; + for (j = 0; j < form->fields; j++) { + + field = form->field[j]; + + if (strlen(field->field_name) + == strlen(key_part->field->field_name) + && 0 == ut_cmp_in_lower_case( + (char*)field->field_name, + (char*)key_part->field->field_name, + strlen(field->field_name))) { + /* Found the corresponding column */ + + break; + } + } + + ut_a(j < form->fields); + + col_type = get_innobase_type_from_mysql_type(key_part->field); + + if (DATA_BLOB == col_type + || key_part->length < field->pack_length()) { + prefix_len = key_part->length; - col_type = get_innobase_type_from_mysql_type( - key_part->field); if (col_type == DATA_INT || col_type == DATA_FLOAT || col_type == DATA_DOUBLE || col_type == DATA_DECIMAL) { fprintf(stderr, "InnoDB: error: MySQL is trying to create a column prefix index field\n" -"InnoDB: on an inappropriate data type %lu. Table name %s, column name %s.\n", - col_type, table_name, - key_part->field->field_name); +"InnoDB: on an inappropriate data type. Table name %s, column name %s.\n", + table_name, key_part->field->field_name); prefix_len = 0; } } else { prefix_len = 0; - } + } + + if (prefix_len >= DICT_MAX_COL_PREFIX_LEN) { + DBUG_RETURN(-1); + } /* We assume all fields should be sorted in ascending order, hence the '0': */ + dict_mem_index_add_field(index, - (char*) key_part->field->field_name, 0); + (char*) key_part->field->field_name, + 0, prefix_len); } error = row_create_index_for_mysql(index, trx); @@ -3172,6 +3433,13 @@ ha_innobase::create( DBUG_ASSERT(thd != NULL); + if (form->fields > 1000) { + /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020, + but we play safe here */ + + return(HA_ERR_TO_BIG_ROW); + } + /* Get the transaction associated with the current thd, or create one if not yet created */ @@ -3314,7 +3582,7 @@ ha_innobase::create( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); innobase_table = dict_table_get(norm_name, NULL); @@ -3389,7 +3657,7 @@ ha_innobase::delete_table( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3459,7 +3727,7 @@ innobase_drop_database( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3531,7 +3799,7 @@ ha_innobase::rename_table( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); + log_buffer_flush_to_disk(); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3574,6 +3842,8 @@ ha_innobase::records_in_range( table->reclength + table->max_key_length + 100, MYF(MY_WME)); + ulint buff2_len = table->reclength + + table->max_key_length + 100; dtuple_t* range_start; dtuple_t* range_end; ib_longlong n_rows; @@ -3610,12 +3880,15 @@ ha_innobase::records_in_range( dict_index_copy_types(range_end, index, key->key_parts); row_sel_convert_mysql_key_to_innobase( - range_start, (byte*) key_val_buff, index, + range_start, (byte*) key_val_buff, + (ulint)upd_and_key_val_buff_len, + index, (byte*) start_key, (ulint) start_key_len); row_sel_convert_mysql_key_to_innobase( - range_end, (byte*) key_val_buff2, index, + range_end, (byte*) key_val_buff2, + buff2_len, index, (byte*) end_key, (ulint) end_key_len); @@ -3825,8 +4098,32 @@ ha_innobase::info( } for (i = 0; i < table->keys; i++) { + if (index == NULL) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: table %s contains less indexes inside InnoDB\n" +"InnoDB: than are defined in the MySQL .frm file. Have you mixed up\n" +"InnoDB: .frm files from different installations? See section\n" +"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n", + ib_table->name); + break; + } + for (j = 0; j < table->key_info[i].key_parts; j++) { + if (j + 1 > index->n_uniq) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: index %s of %s has %lu columns unique inside InnoDB\n" +"InnoDB: but MySQL is asking statistics for %lu columns. Have you mixed up\n" +"InnoDB: .frm files from different installations? See section\n" +"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n", + index->name, + ib_table->name, index->n_uniq, + j + 1); + break; + } + if (index->stat_n_diff_key_vals[j + 1] == 0) { rec_per_key = records; @@ -3885,6 +4182,12 @@ ha_innobase::analyze( return(0); } + +int ha_innobase::optimize(THD* thd, HA_CHECK_OPT* check_opt) +{ + return ha_innobase::analyze(thd,check_opt); +} + /*********************************************************************** Tries to check that an InnoDB table is not corrupted. If corruption is noticed, prints to stderr information about it. In case of corruption @@ -4094,10 +4397,11 @@ ha_innobase::reset(void) } /********************************************************************** -MySQL calls this function at the start of each SQL statement. Inside LOCK -TABLES the ::external_lock method does not work to mark SQL statement -borders. Note also a special case: if a temporary table is created inside -LOCK TABLES, MySQL has not called external_lock() at all on that table. */ +MySQL calls this function at the start of each SQL statement inside LOCK +TABLES. Inside LOCK TABLES the ::external_lock method does not work to +mark SQL statement borders. Note also a special case: if a temporary table +is created inside LOCK TABLES, MySQL has not called external_lock() at all +on that table. */ int ha_innobase::start_stmt( @@ -4254,6 +4558,12 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked = 0; prebuilt->used_in_HANDLER = FALSE; + /* Release a possible FIFO ticket and search latch. Since we + may reserve the kernel mutex, we have to release the search + system latch first to obey the latching order. */ + + innobase_release_stat_resources(trx); + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { if (thd->transaction.all.innodb_active_trans != 0) { @@ -4269,11 +4579,6 @@ ha_innobase::external_lock( read_view_close_for_mysql(trx); } } - - /* Here we release the search latch and the InnoDB thread FIFO - ticket if they were reserved. */ - - innobase_release_stat_resources(trx); } DBUG_RETURN(error); @@ -4289,7 +4594,9 @@ innodb_show_status( THD* thd) /* in: the MySQL query thread of the caller */ { char* buf; + trx_t* trx; Protocol *protocol= thd->protocol; + DBUG_ENTER("innodb_show_status"); if (innodb_skip) { @@ -4299,12 +4606,16 @@ innodb_show_status( DBUG_RETURN(-1); } - /* We let the InnoDB Monitor to output at most 200 kB of text, add - a safety margin of 10 kB for buffer overruns */ + trx = check_trx_exists(thd); + + innobase_release_stat_resources(trx); + + /* We let the InnoDB Monitor to output at most 60 kB of text, add + a safety margin of 100 kB for buffer overruns */ - buf = (char*)ut_malloc(210 * 1024); + buf = (char*)ut_malloc(160 * 1024); - srv_sprintf_innodb_monitor(buf, 200 * 1024); + srv_sprintf_innodb_monitor(buf, 60 * 1024); List<Item> field_list; @@ -4479,6 +4790,11 @@ ha_innobase::innobase_read_and_init_auto_inc( (trx_t*) current_thd->transaction.all.innobase_tid); ut_a(prebuilt->table); + /* In case MySQL calls this in the middle of a SELECT query, release + possible adaptive hash latch to avoid deadlocks of threads */ + + trx_search_latch_release_if_reserved(prebuilt->trx); + auto_inc = dict_table_autoinc_read(prebuilt->table); if (auto_inc != 0) { @@ -4488,9 +4804,7 @@ ha_innobase::innobase_read_and_init_auto_inc( return(0); } - srv_conc_enter_innodb(prebuilt->trx); error = row_lock_table_autoinc_for_mysql(prebuilt); - srv_conc_exit_innodb(prebuilt->trx); if (error != DB_SUCCESS) { error = convert_error_code_to_mysql(error, user_thd); diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 9ca8475e75e..13337f466bf 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -32,7 +32,6 @@ typedef struct st_innobase_share { uint table_name_length,use_count; } INNOBASE_SHARE; - /* The class defining a handle to an Innodb table */ class ha_innobase: public handler { @@ -52,6 +51,9 @@ class ha_innobase: public handler byte* key_val_buff; /* buffer used in converting search key values from MySQL format to Innodb format */ + ulong upd_and_key_val_buff_len; + /* the length of each of the previous + two buffers */ ulong int_table_flags; uint primary_key; uint last_dup_key; @@ -73,7 +75,8 @@ class ha_innobase: public handler longlong auto_inc_counter_for_this_stat; ulong max_row_length(const byte *buf); - uint store_key_val_for_row(uint keynr, char* buff, const byte* record); + uint store_key_val_for_row(uint keynr, char* buff, uint buff_len, + const byte* record); int update_thd(THD* thd); int change_active_index(uint keynr); int general_fetch(byte* buf, uint direction, uint match_mode); @@ -83,13 +86,15 @@ class ha_innobase: public handler public: ha_innobase(TABLE *table): handler(table), int_table_flags(HA_REC_NOT_IN_SEQ | - HA_KEYPOS_TO_RNDPOS | HA_LASTKEY_ORDER | - HA_NULL_KEY | HA_CAN_SQL_HANDLER | + HA_KEYPOS_TO_RNDPOS | + HA_LASTKEY_ORDER | + HA_NULL_KEY | + HA_BLOB_KEY | + HA_CAN_SQL_HANDLER | HA_NOT_EXACT_COUNT | HA_NO_WRITE_DELAYED | HA_PRIMARY_KEY_IN_READ_INDEX | HA_DROP_BEFORE_CREATE | - HA_NO_PREFIX_CHAR_KEYS | HA_TABLE_SCAN_ON_INDEX), last_dup_key((uint) -1), start_of_scan(0) @@ -153,6 +158,7 @@ class ha_innobase: public handler void position(const byte *record); void info(uint); int analyze(THD* thd,HA_CHECK_OPT* check_opt); + int optimize(THD* thd,HA_CHECK_OPT* check_opt); int extra(enum ha_extra_function operation); int reset(void); int external_lock(THD *thd, int lock_type); @@ -219,6 +225,14 @@ int innobase_report_binlog_offset_and_commit( int innobase_commit_complete( void* trx_handle); int innobase_rollback(THD *thd, void* trx_handle); +int innobase_rollback_to_savepoint( + THD* thd, + char* savepoint_name, + my_off_t* binlog_cache_pos); +int innobase_savepoint( + THD* thd, + char* savepoint_name, + my_off_t binlog_cache_pos); int innobase_close_connection(THD *thd); int innobase_drop_database(char *path); int innodb_show_status(THD* thd); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 70322cef6fd..e8e4798c2b2 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -572,7 +572,8 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) strmov(fixed_name,file->filename); // Don't lock tables if we have used LOCK TABLE - if (!thd->locked_tables && mi_lock_database(file,F_WRLCK)) + if (!thd->locked_tables && + mi_lock_database(file, table->tmp_table ? F_EXTRA_LCK : F_WRLCK)) { mi_check_print_error(¶m,ER(ER_CANT_LOCK),my_errno); DBUG_RETURN(HA_ADMIN_FAILED); @@ -802,6 +803,7 @@ void ha_myisam::deactivate_non_unique_index(ha_rows rows) } } enable_activate_all_index=1; + info(HA_STATUS_CONST); // Read new key info } else enable_activate_all_index=0; @@ -834,6 +836,7 @@ bool ha_myisam::activate_all_index(THD *thd) param.sort_buffer_length= thd->variables.myisam_sort_buff_size; param.tmpdir=&mysql_tmpdir_list; error=repair(thd,param,0) != HA_ADMIN_OK; + info(HA_STATUS_CONST); thd->proc_info=save_proc_info; } else @@ -1017,8 +1020,9 @@ void ha_myisam::info(uint flag) ref_length=info.reflength; table->db_options_in_use = info.options; block_size=myisam_block_size; - table->keys_in_use&= info.key_map; - table->keys_for_keyread&= info.key_map; + table->keys_in_use= (set_bits(key_map, table->keys) & + (key_map) info.key_map); + table->keys_for_keyread= table->keys_in_use & ~table->read_only_keys; table->db_record_offset=info.record_offset; if (table->key_parts) memcpy((char*) table->key_info[0].rec_per_key, @@ -1087,9 +1091,9 @@ int ha_myisam::delete_table(const char *name) int ha_myisam::external_lock(THD *thd, int lock_type) { - if (!table->tmp_table) - return mi_lock_database(file,lock_type); - return 0; + return mi_lock_database(file, !table->tmp_table ? + lock_type : ((lock_type == F_UNLCK) ? + F_UNLCK : F_EXTRA_LCK)); } diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h index 008f5339caf..cfe4b47ef10 100644 --- a/sql/ha_myisammrg.h +++ b/sql/ha_myisammrg.h @@ -40,7 +40,8 @@ class ha_myisammrg: public handler } ulong index_flags(uint inx) const { - ulong flags=(HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER); + ulong flags=(HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | + HA_NOT_READ_PREFIX_LAST); // This - last - flag is ONLY for 4.0 !!! return (flags | ((table->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ? 0 : HA_KEY_READ_ONLY)); } diff --git a/sql/handler.cc b/sql/handler.cc index 90fd754a4c5..b4d370491bb 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -389,7 +389,6 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) trans->innodb_active_trans=0; if (trans == &thd->transaction.all) operation_done= transaction_commited= 1; - } #endif #ifdef HAVE_QUERY_CACHE @@ -457,6 +456,70 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) DBUG_RETURN(error); } + +/* +Rolls the current transaction back to a savepoint. +Return value: 0 if success, 1 if there was not a savepoint of the given +name. +*/ + +int ha_rollback_to_savepoint(THD *thd, char *savepoint_name) +{ + my_off_t binlog_cache_pos=0; + bool operation_done=0; + int error=0; + DBUG_ENTER("ha_rollback_to_savepoint"); +#ifdef USING_TRANSACTIONS + if (opt_using_transactions) + { +#ifdef HAVE_INNOBASE_DB + /* + Retrieve the trans_log binlog cache position corresponding to the + savepoint, and if the rollback is successful inside InnoDB reset the write + position in the binlog cache to what it was at the savepoint. + */ + if ((error=innobase_rollback_to_savepoint(thd, savepoint_name, + &binlog_cache_pos))) + { + my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error); + error=1; + } + else + reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, + binlog_cache_pos, 0, 0); + operation_done=1; +#endif + if (operation_done) + statistic_increment(ha_rollback_count,&LOCK_status); + } +#endif /* USING_TRANSACTIONS */ + + DBUG_RETURN(error); +} + + +/* +Sets a transaction savepoint. +Return value: always 0, that is, succeeds always +*/ + +int ha_savepoint(THD *thd, char *savepoint_name) +{ + my_off_t binlog_cache_pos=0; + int error=0; + DBUG_ENTER("ha_savepoint"); +#ifdef USING_TRANSACTIONS + if (opt_using_transactions) + { + binlog_cache_pos=my_b_tell(&thd->transaction.trans_log); +#ifdef HAVE_INNOBASE_DB + innobase_savepoint(thd,savepoint_name, binlog_cache_pos); +#endif + } +#endif /* USING_TRANSACTIONS */ + DBUG_RETURN(error); +} + bool ha_flush_logs() { bool result=0; @@ -759,6 +822,9 @@ void handler::print_error(int error, myf errflag) int textno=ER_GET_ERRNO; switch (error) { + case EACCES: + textno=ER_OPEN_AS_READONLY; + break; case EAGAIN: textno=ER_FILE_USED; break; diff --git a/sql/handler.h b/sql/handler.h index 08a7c83d328..b1b5cfb02b0 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -192,39 +192,41 @@ class handler :public Sql_alloc { protected: struct st_table *table; /* The table definition */ - uint active_index; public: byte *ref; /* Pointer to current row */ byte *dupp_ref; /* Pointer to dupp row */ - uint ref_length; /* Length of ref (1-8) */ - uint block_size; /* index block size */ - ha_rows records; /* Records i datafilen */ - ha_rows deleted; /* Deleted records */ ulonglong data_file_length; /* Length off data file */ ulonglong max_data_file_length; /* Length off data file */ ulonglong index_file_length; ulonglong max_index_file_length; ulonglong delete_length; /* Free bytes */ ulonglong auto_increment_value; - uint raid_type,raid_chunks; + ha_rows records; /* Records in table */ + ha_rows deleted; /* Deleted records */ ulong raid_chunksize; - uint errkey; /* Last dup key */ - uint sortkey, key_used_on_scan; + ulong mean_rec_length; /* physical reclength */ time_t create_time; /* When table was created */ time_t check_time; time_t update_time; - ulong mean_rec_length; /* physical reclength */ + uint errkey; /* Last dup key */ + uint sortkey, key_used_on_scan; + uint active_index; + /* Length of ref (1-8 or the clustered key length) */ + uint ref_length; + uint block_size; /* index block size */ + uint raid_type,raid_chunks; FT_INFO *ft_handler; bool auto_increment_column_changed; - handler(TABLE *table_arg) : table(table_arg),active_index(MAX_REF_PARTS), - ref(0),ref_length(sizeof(my_off_t)), block_size(0),records(0),deleted(0), - data_file_length(0), max_data_file_length(0), index_file_length(0), - delete_length(0), auto_increment_value(0), raid_type(0), - key_used_on_scan(MAX_KEY), - create_time(0), check_time(0), update_time(0), mean_rec_length(0), - ft_handler(0) + handler(TABLE *table_arg) :table(table_arg), + ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0), + delete_length(0), auto_increment_value(0), + records(0), deleted(0), mean_rec_length(0), + create_time(0), check_time(0), update_time(0), + key_used_on_scan(MAX_KEY), active_index(MAX_REF_PARTS), + ref_length(sizeof(my_off_t)), block_size(0), + raid_type(0), ft_handler(0) {} virtual ~handler(void) {} int ha_open(const char *name, int mode, int test_if_locked); @@ -234,7 +236,7 @@ public: uint get_dup_key(int error); void change_table_ptr(TABLE *table_arg) { table=table_arg; } virtual double scan_time() - { return ulonglong2double(data_file_length) / IO_SIZE + 1; } + { return ulonglong2double(data_file_length) / IO_SIZE + 2; } virtual double read_time(uint index, uint ranges, ha_rows rows) { return rows2double(ranges+rows); } virtual bool fast_key_read() { return 0;} @@ -395,6 +397,8 @@ int ha_commit_complete(THD *thd); int ha_release_temporary_latches(THD *thd); int ha_commit_trans(THD *thd, THD_TRANS *trans); int ha_rollback_trans(THD *thd, THD_TRANS *trans); +int ha_rollback_to_savepoint(THD *thd, char *savepoint_name); +int ha_savepoint(THD *thd, char *savepoint_name); int ha_autocommit_or_rollback(THD *thd, int error); void ha_set_spin_retries(uint retries); bool ha_flush_logs(void); diff --git a/sql/item.h b/sql/item.h index 621dc017d25..457978fced6 100644 --- a/sql/item.h +++ b/sql/item.h @@ -144,7 +144,24 @@ public: virtual double val_result() { return val(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } + /* bit map of tables used by item */ virtual table_map used_tables() const { return (table_map) 0L; } + /* + Return table map of tables that can't be NULL tables (tables that are + used in a context where if they would contain a NULL row generated + by a LEFT or RIGHT join, the item would not be true). + This expression is used on WHERE item to determinate if a LEFT JOIN can be + converted to a normal join. + Generally this function should return used_tables() if the function + would return null if any of the arguments are null + As this is only used in the beginning of optimization, the value don't + have to be updated in update_used_tables() + */ + virtual table_map not_null_tables() const { return used_tables(); } + /* + Returns true if this is a simple constant item like an integer, not + a constant expression + */ virtual bool basic_const_item() const { return 0; } virtual Item *new_item() { return 0; } /* Only for const items */ virtual cond_result eq_cmp_result() const { return COND_OK; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7d8da16338b..b9e7b1d14ad 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -109,7 +109,7 @@ longlong Item_func_not::val_int() static bool convert_constant_item(Field *field, Item **item) { - if ((*item)->const_item() && (*item)->type() != Item::INT_ITEM) + if ((*item)->const_item()) { if (!(*item)->save_in_field(field, 1) && !((*item)->null_value)) { @@ -535,6 +535,7 @@ void Item_func_interval::fix_length_and_dec() maybe_null= 0; max_length= 2; used_tables_cache|= row->used_tables(); + not_null_tables_cache&= row->not_null_tables(); with_sum_func= with_sum_func || row->with_sum_func; } @@ -548,25 +549,27 @@ void Item_func_interval::fix_length_and_dec() longlong Item_func_interval::val_int() { - double value=row->el(0)->val(); + double value= row->el(0)->val(); + uint i; + if (row->el(0)->null_value) return -1; // -1 if null if (intervals) { // Use binary search to find interval uint start,end; - start=1; end=row->cols()-2; + start= 1; + end= row->cols()-2; while (start != end) { - uint mid=(start+end+1)/2; + uint mid= (start + end + 1) / 2; if (intervals[mid] <= value) - start=mid; + start= mid; else - end=mid-1; + end= mid - 1; } - return (value < intervals[start]) ? 0 : start+1; + return (value < intervals[start]) ? 0 : start + 1; } - uint i; for (i=1 ; i < row->cols() ; i++) { if (row->el(i)->val() > value) @@ -1454,7 +1457,6 @@ void Item_func_in::fix_length_and_dec() } maybe_null= args[0]->maybe_null; max_length= 1; - const_item_cache&=args[0]->const_item(); } @@ -1535,13 +1537,19 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) #ifndef EMBEDDED_LIBRARY char buff[sizeof(char*)]; // Max local vars in function #endif - used_tables_cache=0; - const_item_cache=0; + not_null_tables_cache= used_tables_cache= 0; + const_item_cache= 0; + /* + and_table_cache is the value that Item_cond_or() returns for + not_null_tables() + */ + and_tables_cache= ~(table_map) 0; if (thd && check_stack_overrun(thd,buff)) return 0; // Fatal error flag is set! while ((item=li++)) { + table_map tmp_table_map; while (item->type() == Item::COND_ITEM && ((Item_cond*) item)->functype() == functype()) { // Identical function @@ -1556,9 +1564,12 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) item->top_level_item(); if (item->fix_fields(thd, tables, li.ref()) || item->check_cols(1)) return 1; /* purecov: inspected */ - used_tables_cache|=item->used_tables(); - with_sum_func= with_sum_func || item->with_sum_func; - const_item_cache&=item->const_item(); + used_tables_cache|= item->used_tables(); + tmp_table_map= item->not_null_tables(); + not_null_tables_cache|= tmp_table_map; + and_tables_cache&= tmp_table_map; + const_item_cache&= item->const_item(); + with_sum_func= with_sum_func || item->with_sum_func; if (item->maybe_null) maybe_null=1; } @@ -1608,17 +1619,19 @@ Item_cond::used_tables() const return used_tables_cache; } + void Item_cond::update_used_tables() { - used_tables_cache=0; - const_item_cache=1; List_iterator_fast<Item> li(list); Item *item; + + used_tables_cache=0; + const_item_cache=1; while ((item=li++)) { item->update_used_tables(); - used_tables_cache|=item->used_tables(); - const_item_cache&= item->const_item(); + used_tables_cache|= item->used_tables(); + const_item_cache&= item->const_item(); } } @@ -1722,12 +1735,16 @@ Item *and_expressions(Item *a, Item *b, Item **org_item) { Item_cond *res; if ((res= new Item_cond_and(a, (Item*) b))) + { res->used_tables_cache= a->used_tables() | b->used_tables(); + res->not_null_tables_cache= a->not_null_tables() | b->not_null_tables(); + } return res; } if (((Item_cond_and*) a)->add((Item*) b)) return 0; ((Item_cond_and*) a)->used_tables_cache|= b->used_tables(); + ((Item_cond_and*) a)->not_null_tables_cache|= b->not_null_tables(); return a; } @@ -1898,6 +1915,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 1; used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); + not_null_tables_cache= (args[0]->not_null_tables() | + args[1]->not_null_tables()); const_item_cache=args[0]->const_item() && args[1]->const_item(); if (!regex_compiled && args[1]->const_item()) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 25cc97d60bf..2570a86ea80 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -291,6 +291,7 @@ public: enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } + table_map not_null_tables() const { return 0; } }; @@ -312,6 +313,7 @@ public: } void fix_length_and_dec(); const char *func_name() const { return "if"; } + table_map not_null_tables() const { return 0; } }; @@ -328,6 +330,7 @@ public: enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "nullif"; } + table_map not_null_tables() const { return 0; } }; @@ -344,8 +347,10 @@ public: void fix_length_and_dec(); enum Item_result result_type () const { return cached_result_type; } const char *func_name() const { return "coalesce"; } + table_map not_null_tables() const { return 0; } }; + class Item_func_case :public Item_func { int first_expr_num, else_expr_num; @@ -376,6 +381,7 @@ public: longlong val_int(); String *val_str(String *); void fix_length_and_dec(); + table_map not_null_tables() const { return 0; } enum Item_result result_type () const { return cached_result_type; } const char *func_name() const { return "case"; } void print(String *str); @@ -668,6 +674,7 @@ public: } } } + table_map not_null_tables() const { return 0; } optimize_type select_optimize() const { return OPTIMIZE_NULL; } }; @@ -699,8 +706,10 @@ public: } const char *func_name() const { return "isnotnull"; } optimize_type select_optimize() const { return OPTIMIZE_NULL; } + table_map not_null_tables() const { return 0; } }; + class Item_func_like :public Item_bool_func2 { char escape; @@ -773,6 +782,8 @@ class Item_cond :public Item_bool_func protected: List<Item> list; bool abort_on_null; + table_map and_tables_cache; + public: /* Item_cond() is only used to create top level items */ Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; } @@ -812,15 +823,23 @@ public: enum Functype functype() const { return COND_OR_FUNC; } longlong val_int(); const char *func_name() const { return "or"; } + table_map not_null_tables() const { return and_tables_cache; } }; +/* + XOR is Item_cond, not an Item_int_func bevause we could like to + optimize (a XOR b) later on. It's low prio, though +*/ + class Item_cond_xor :public Item_cond { public: Item_cond_xor() :Item_cond() {} Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2) {} enum Functype functype() const { return COND_XOR_FUNC; } + /* TODO: remove the next line when implementing XOR optimization */ + enum Type type() const { return FUNC_ITEM; } longlong val_int(); const char *func_name() const { return "xor"; } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 815aeba1e23..c960b6ad54e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -175,7 +175,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item **arg,**arg_end; char buff[STACK_BUFF_ALLOC]; // Max argument in function - used_tables_cache=0; + used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; if (thd && check_stack_overrun(thd,buff)) @@ -194,8 +194,9 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) maybe_null=1; with_sum_func= with_sum_func || item->with_sum_func; - used_tables_cache|=item->used_tables(); - const_item_cache&= item->const_item(); + used_tables_cache|= item->used_tables(); + not_null_tables_cache|= item->not_null_tables(); + const_item_cache&= item->const_item(); } } fix_length_and_dec(); @@ -252,6 +253,13 @@ table_map Item_func::used_tables() const return used_tables_cache; } + +table_map Item_func::not_null_tables() const +{ + return not_null_tables_cache; +} + + void Item_func::print(String *str) { str->append(func_name()); @@ -2118,6 +2126,7 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, if (Item_func::fix_fields(thd, tables, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; + entry->type= cached_result_type; entry->update_query_id=thd->query_id; return 0; } @@ -2676,6 +2685,9 @@ double Item_func_match::val() if (ft_handler == NULL) DBUG_RETURN(-1.0); + if (table->null_row) /* NULL row from an outer join */ + return 0.0; + if (join_key) { if (table->file->ft_handler) diff --git a/sql/item_func.h b/sql/item_func.h index 56ee0379cd5..3d1de6a7a5f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -35,7 +35,7 @@ protected: uint allowed_arg_cols; public: uint arg_count; - table_map used_tables_cache; + table_map used_tables_cache, not_null_tables_cache; bool const_item_cache; enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC,FT_FUNC, @@ -107,6 +107,7 @@ public: ~Item_func() {} /* Nothing to do; Items are freed automaticly */ bool fix_fields(THD *,struct st_table_list *, Item **ref); table_map used_tables() const; + table_map not_null_tables() const; void update_used_tables(); bool eq(const Item *item, bool binary_cmp) const; virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } @@ -767,6 +768,7 @@ public: return res; } Item_result result_type () const { return udf.result_type(); } + table_map not_null_tables() const { return 0; } }; @@ -1004,6 +1006,7 @@ public: } enum Functype functype() const { return FT_FUNC; } void update_used_tables() {} + table_map not_null_tables() const { return 0; } bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); bool eq(const Item *, bool binary_cmp) const; longlong val_int() { return val()!=0.0; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b92839e6c1e..b0b9cc01bf1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -637,9 +637,10 @@ void Item_func_concat_ws::fix_length_and_dec() max_length=MAX_BLOB_WIDTH; maybe_null=1; } - used_tables_cache|=separator->used_tables(); - const_item_cache&=separator->const_item(); - with_sum_func= with_sum_func || separator->with_sum_func; + used_tables_cache|= separator->used_tables(); + not_null_tables_cache&= separator->not_null_tables(); + const_item_cache&= separator->const_item(); + with_sum_func= with_sum_func || separator->with_sum_func; } void Item_func_concat_ws::update_used_tables() @@ -1627,6 +1628,10 @@ String *Item_func_format::val_str(String *str) return 0; /* purecov: inspected */ dec= decimals ? decimals+1 : 0; str->set(nr,decimals,default_charset()); +#ifdef HAVE_ISNAN + if (isnan(nr)) + return str; +#endif str_length=str->length(); if (nr < 0) str_length--; // Don't count sign @@ -1639,7 +1644,7 @@ String *Item_func_format::val_str(String *str) str= copy_if_not_alloced(&tmp_str,str,length); str->length(length); tmp= (char*) str->ptr()+length - dec-1; - for (pos= (char*) str->ptr()+length ; pos != tmp; pos--) + for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--) pos[0]= pos[-(int) diff]; while (diff) { @@ -1675,40 +1680,40 @@ void Item_func_elt::fix_length_and_dec() double Item_func_elt::val() { uint tmp; + null_value=1; if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) - { - null_value=1; return 0.0; - } - null_value=0; - return args[tmp]->val(); + double result= args[tmp]->val(); + null_value= args[tmp]->null_value; + return result; } + longlong Item_func_elt::val_int() { uint tmp; + null_value=1; if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) - { - null_value=1; return 0; - } - null_value=0; - return args[tmp]->val_int(); + + longlong result= args[tmp]->val_int(); + null_value= args[tmp]->null_value; + return result; } + String *Item_func_elt::val_str(String *str) { uint tmp; - String *res; + null_value=1; if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) - { - null_value=1; return NULL; - } - null_value=0; - res= args[tmp]->val_str(str); - res->set_charset(collation.collation); - return res; + + String *result= args[tmp]->val_str(str); + if (result) + result->set_charset(collation.collation); + null_value= args[tmp]->null_value; + return result; } @@ -1738,8 +1743,9 @@ void Item_func_make_set::fix_length_and_dec() for (uint i=0 ; i < arg_count ; i++) max_length+=args[i]->max_length; - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); + used_tables_cache|= item->used_tables(); + not_null_tables_cache&= item->not_null_tables(); + const_item_cache&= item->const_item(); with_sum_func= with_sum_func || item->with_sum_func; } @@ -1953,7 +1959,7 @@ String *Item_func_rpad::val_str(String *str) String *res =args[0]->val_str(str); String *rpad = args[2]->val_str(str); - if (!res || args[1]->null_value || !rpad) + if (!res || args[1]->null_value || !rpad || count < 0) goto err; null_value=0; if (count <= (int32) (res_length=res->length())) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 62d8afd7ec0..c3e441b33a4 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1289,14 +1289,12 @@ String *Item_date_add_interval::val_str(String *str) longlong Item_date_add_interval::val_int() { TIME ltime; + longlong date; if (Item_date_add_interval::get_date(<ime,0)) return (longlong) 0; - return ((longlong) (((ulong) ltime.year)*10000L+ - (((uint) ltime.month)*100+ - (uint) ltime.day))*(longlong) 1000000L+ - (longlong) ((ulong) ((uint) ltime.hour)*10000L+ - (ulong) (((uint)ltime.minute)*100L+ - (uint) ltime.second))); + date = (ltime.year*100L + ltime.month)*100L + ltime.day; + return ltime.time_type == TIMESTAMP_DATE ? date : + ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second; } void Item_extract::fix_length_and_dec() @@ -1388,6 +1386,22 @@ longlong Item_extract::val_int() return 0; // Impossible } +bool Item_extract::eq(const Item *item, bool binary_cmp) const +{ + if (this == item) + return 1; + if (item->type() != FUNC_ITEM || + func_name() != ((Item_func*)item)->func_name()) + return 0; + + Item_extract* ie= (Item_extract*)item; + if (ie->int_type != int_type) + return 0; + + if (!args[0]->eq(ie->args[0], binary_cmp)) + return 0; + return 1; +} void Item_typecast::print(String *str) { diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a6fb9b11de4..4b0ef02f20d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -516,6 +516,7 @@ class Item_extract :public Item_int_func longlong val_int(); const char *func_name() const { return "extract"; } void fix_length_and_dec(); + bool eq(const Item *item, bool binary_cmp) const; }; diff --git a/sql/lex.h b/sql/lex.h index c2860f4551a..15d33e761ef 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -340,6 +340,7 @@ static SYMBOL symbols[] = { { "ROW", SYM(ROW_SYM),0,0}, { "ROWS", SYM(ROWS_SYM),0,0}, { "RTREE", SYM(RTREE_SYM),0,0}, + { "SAVEPOINT", SYM(SAVEPOINT_SYM),0,0}, { "SECOND", SYM(SECOND_SYM),0,0}, { "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM),0,0}, { "SEPARATOR", SYM(SEPARATOR_SYM),0,0}, diff --git a/sql/log.cc b/sql/log.cc index dd544dcac93..b3f7e753010 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* 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 @@ -85,11 +85,13 @@ static int find_uniq_filename(char *name) MYSQL_LOG::MYSQL_LOG() :bytes_written(0), last_time(0), query_start(0), name(0), file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0), - no_rotate(0), need_start_event(1) + need_start_event(1) { /* - We don't want to intialize LOCK_Log here as the thread system may - not have been initailized yet. We do it instead at 'open'. + We don't want to initialize LOCK_Log here as such initialization depends on + safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is + called only in main(). Doing initialization here would make it happen + before main(). */ index_file_name[0] = 0; bzero((char*) &log_file,sizeof(log_file)); @@ -102,12 +104,14 @@ MYSQL_LOG::~MYSQL_LOG() cleanup(); } +/* this is called only once */ + void MYSQL_LOG::cleanup() { if (inited) { - close(1); inited= 0; + close(LOG_CLOSE_INDEX); (void) pthread_mutex_destroy(&LOCK_log); (void) pthread_mutex_destroy(&LOCK_index); (void) pthread_cond_destroy(&update_cond); @@ -135,18 +139,26 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name) void MYSQL_LOG::init(enum_log_type log_type_arg, enum cache_type io_cache_type_arg, - bool no_auto_events_arg) + bool no_auto_events_arg, + ulong max_size_arg) { + DBUG_ENTER("MYSQL_LOG::init"); log_type = log_type_arg; io_cache_type = io_cache_type_arg; no_auto_events = no_auto_events_arg; - if (!inited) - { - inited= 1; - (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW); - (void) pthread_cond_init(&update_cond, 0); - } + max_size=max_size_arg; + DBUG_PRINT("info",("log_type: %d max_size: %lu", log_type, max_size)); + DBUG_VOID_RETURN; +} + + +void MYSQL_LOG::init_pthread_objects() +{ + DBUG_ASSERT(inited == 0); + inited= 1; + (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW); + (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW); + (void) pthread_cond_init(&update_cond, 0); } @@ -167,7 +179,8 @@ void MYSQL_LOG::init(enum_log_type log_type_arg, bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, const char *new_name, const char *index_file_name_arg, enum cache_type io_cache_type_arg, - bool no_auto_events_arg) + bool no_auto_events_arg, + ulong max_size) { char buff[512]; File file= -1, index_file_nr= -1; @@ -178,9 +191,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, last_time=query_start=0; write_error=0; - if (!inited && log_type_arg == LOG_BIN && *fn_ext(log_name)) - no_rotate = 1; - init(log_type_arg,io_cache_type_arg,no_auto_events_arg); + init(log_type_arg,io_cache_type_arg,no_auto_events_arg,max_size); if (!(name=my_strdup(log_name,MYF(MY_WME)))) goto err; @@ -311,6 +322,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, break; } case LOG_CLOSED: // Impossible + case LOG_TO_BE_OPENED: DBUG_ASSERT(1); break; } @@ -328,7 +340,7 @@ shutdown the MySQL server and restart it.", log_name, errno); end_io_cache(&log_file); end_io_cache(&index_file); safeFree(name); - log_type=LOG_CLOSED; + log_type= LOG_CLOSED; DBUG_RETURN(1); } @@ -561,7 +573,7 @@ bool MYSQL_LOG::reset_logs(THD* thd) save_name=name; name=0; // Protect against free save_log_type=log_type; - close(0); // Don't close the index file + close(LOG_CLOSE_TO_BE_OPENED); /* First delete all old log files */ @@ -579,12 +591,12 @@ bool MYSQL_LOG::reset_logs(THD* thd) } /* Start logging with a new file */ - close(1); // Close index file + close(LOG_CLOSE_INDEX); my_delete(index_file_name, MYF(MY_WME)); // Reset (open will update) if (!thd->slave_thread) need_start_event=1; open(save_name, save_log_type, 0, index_file_name, - io_cache_type, no_auto_events); + io_cache_type, no_auto_events, max_size); my_free((gptr) save_name, MYF(0)); err: @@ -736,7 +748,6 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads) RETURN VALUES 0 ok - LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated LOG_INFO_EOF to_log not found */ @@ -835,9 +846,6 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) DBUG_ENTER("purge_logs_before_date"); - if (no_rotate) - DBUG_RETURN(LOG_INFO_PURGE_NO_ROTATE); - pthread_mutex_lock(&LOCK_index); /* @@ -888,14 +896,11 @@ err: void MYSQL_LOG::make_log_name(char* buf, const char* log_ident) { - if (inited) // QQ When is this not true ? - { - uint dir_len = dirname_length(log_file_name); - if (dir_len > FN_REFLEN) - dir_len=FN_REFLEN-1; - strnmov(buf, log_file_name, dir_len); - strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len); - } + uint dir_len = dirname_length(log_file_name); + if (dir_len > FN_REFLEN) + dir_len=FN_REFLEN-1; + strnmov(buf, log_file_name, dir_len); + strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len); } @@ -905,7 +910,7 @@ void MYSQL_LOG::make_log_name(char* buf, const char* log_ident) bool MYSQL_LOG::is_active(const char *log_file_name_arg) { - return inited && !strcmp(log_file_name, log_file_name_arg); + return !strcmp(log_file_name, log_file_name_arg); } @@ -926,8 +931,12 @@ void MYSQL_LOG::new_file(bool need_lock) char new_name[FN_REFLEN], *new_name_ptr, *old_name; enum_log_type save_log_type; + DBUG_ENTER("MYSQL_LOG::new_file"); if (!is_open()) - return; // Should never happen + { + DBUG_PRINT("info",("log is closed")); + DBUG_VOID_RETURN; + } if (need_lock) { @@ -937,52 +946,50 @@ void MYSQL_LOG::new_file(bool need_lock) safe_mutex_assert_owner(&LOCK_log); safe_mutex_assert_owner(&LOCK_index); - // Reuse old name if not binlog and not update log + /* Reuse old name if not binlog and not update log */ new_name_ptr= name; /* - Only rotate open logs that are marked non-rotatable - (binlog with constant name are non-rotatable) + If user hasn't specified an extension, generate a new log name + We have to do this here and not in open as we want to store the + new file name in the current binary log file. */ - if (!no_rotate) + if (generate_new_name(new_name, name)) + goto end; + new_name_ptr=new_name; + + if (log_type == LOG_BIN) { - /* - If user hasn't specified an extension, generate a new log name - We have to do this here and not in open as we want to store the - new file name in the current binary log file. - */ - if (generate_new_name(new_name, name)) - goto end; - new_name_ptr=new_name; - - if (log_type == LOG_BIN) + if (!no_auto_events) { - if (!no_auto_events) - { - /* - We log the whole file name for log file as the user may decide - to change base names at some point. - */ - THD* thd = current_thd; - Rotate_log_event r(thd,new_name+dirname_length(new_name)); - r.set_log_pos(this); - r.write(&log_file); - bytes_written += r.get_event_len(); - } /* - Update needs to be signalled even if there is no rotate event - log rotation should give the waiting thread a signal to - discover EOF and move on to the next log. + We log the whole file name for log file as the user may decide + to change base names at some point. */ - signal_update(); + THD* thd = current_thd; + Rotate_log_event r(thd,new_name+dirname_length(new_name)); + r.set_log_pos(this); + r.write(&log_file); + bytes_written += r.get_event_len(); } + /* + Update needs to be signalled even if there is no rotate event + log rotation should give the waiting thread a signal to + discover EOF and move on to the next log. + */ + signal_update(); } old_name=name; save_log_type=log_type; name=0; // Don't free name - close(); + close(LOG_CLOSE_TO_BE_OPENED); + + /* + Note that at this point, log_type == LOG_CLOSED (important for is_open()). + */ + open(old_name, save_log_type, new_name_ptr, index_file_name, io_cache_type, - no_auto_events); + no_auto_events, max_size); my_free(old_name,MYF(0)); end: @@ -991,6 +998,7 @@ end: pthread_mutex_unlock(&LOCK_index); pthread_mutex_unlock(&LOCK_log); } + DBUG_VOID_RETURN; } @@ -998,7 +1006,8 @@ bool MYSQL_LOG::append(Log_event* ev) { bool error = 0; pthread_mutex_lock(&LOCK_log); - + DBUG_ENTER("MYSQL_LOG::append"); + DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); /* Log_event::write() is smart enough to use my_b_write() or @@ -1010,7 +1019,8 @@ bool MYSQL_LOG::append(Log_event* ev) goto err; } bytes_written += ev->get_event_len(); - if ((uint) my_b_append_tell(&log_file) > max_binlog_size) + DBUG_PRINT("info",("max_size: %lu",max_size)); + if ((uint) my_b_append_tell(&log_file) > max_size) { pthread_mutex_lock(&LOCK_index); new_file(0); @@ -1020,13 +1030,14 @@ bool MYSQL_LOG::append(Log_event* ev) err: pthread_mutex_unlock(&LOCK_log); signal_update(); // Safe as we don't call close - return error; + DBUG_RETURN(error); } bool MYSQL_LOG::appendv(const char* buf, uint len,...) { bool error= 0; + DBUG_ENTER("MYSQL_LOG::appendv"); va_list(args); va_start(args,len); @@ -1042,8 +1053,8 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...) } bytes_written += len; } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); - - if ((uint) my_b_append_tell(&log_file) > max_binlog_size) + DBUG_PRINT("info",("max_size: %lu",max_size)); + if ((uint) my_b_append_tell(&log_file) > max_size) { pthread_mutex_lock(&LOCK_index); new_file(0); @@ -1054,7 +1065,7 @@ err: pthread_mutex_unlock(&LOCK_log); if (!error) signal_update(); - return error; + DBUG_RETURN(error); } @@ -1158,14 +1169,13 @@ bool MYSQL_LOG::write(Log_event* event_info) bool should_rotate = 0; DBUG_ENTER("MYSQL_LOG::write(event)"); - if (!inited) // Can't use mutex if not init - { - DBUG_PRINT("error",("not initied")); - DBUG_RETURN(0); - } pthread_mutex_lock(&LOCK_log); - /* In most cases this is only called if 'is_open()' is true */ + /* + In most cases this is only called if 'is_open()' is true; in fact this is + mostly called if is_open() *was* true a few instructions before, but it + could have changed since. + */ if (is_open()) { const char *local_db = event_info->get_db(); @@ -1177,6 +1187,11 @@ bool MYSQL_LOG::write(Log_event* event_info) IO_CACHE *file = &log_file; #endif #ifdef HAVE_REPLICATION + /* + In the future we need to add to the following if tests like + "do the involved tables match (to be implemented) + binlog_[wild_]{do|ignore}_table?" (WL#1049)" + */ if ((thd && !(thd->options & OPTION_BIN_LOG) && (thd->master_access & SUPER_ACL)) || (local_db && !db_ok(local_db, binlog_do_db, binlog_ignore_db))) @@ -1328,8 +1343,9 @@ bool MYSQL_LOG::write(Log_event* event_info) called_handler_commit=1; } } - /* we wrote to the real log, check automatic rotation */ - should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size); + /* We wrote to the real log, check automatic rotation; */ + DBUG_PRINT("info",("max_size: %lu",max_size)); + should_rotate= (my_b_tell(file) >= (my_off_t) max_size); } error=0; @@ -1467,7 +1483,8 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) log_file.pos_in_file))) goto err; signal_update(); - if (my_b_tell(&log_file) >= (my_off_t) max_binlog_size) + DBUG_PRINT("info",("max_size: %lu",max_size)); + if (my_b_tell(&log_file) >= (my_off_t) max_size) { pthread_mutex_lock(&LOCK_index); new_file(0); // inside mutex @@ -1505,123 +1522,123 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, time_t query_start_arg) { bool error=0; + time_t current_time; + if (!is_open()) + return 0; + VOID(pthread_mutex_lock(&LOCK_log)); if (is_open()) - { - time_t current_time; - VOID(pthread_mutex_lock(&LOCK_log)); - if (is_open()) - { // Safety agains reopen - int tmp_errno=0; - char buff[80],*end; - end=buff; - if (!(thd->options & OPTION_UPDATE_LOG) && - (thd->master_access & SUPER_ACL)) - { - VOID(pthread_mutex_unlock(&LOCK_log)); - return 0; - } - if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg) - { - current_time=time(NULL); - if (current_time != last_time) - { - last_time=current_time; - struct tm tm_tmp; - struct tm *start; - localtime_r(¤t_time,&tm_tmp); - start=&tm_tmp; - /* Note that my_b_write() assumes it knows the length for this */ - sprintf(buff,"# Time: %02d%02d%02d %2d:%02d:%02d\n", - start->tm_year % 100, - start->tm_mon+1, - start->tm_mday, - start->tm_hour, - start->tm_min, - start->tm_sec); - if (my_b_write(&log_file, (byte*) buff,24)) - tmp_errno=errno; - } - if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n", - thd->priv_user, - thd->user, - thd->host ? thd->host : "", - thd->ip ? thd->ip : "") == (uint) -1) - tmp_errno=errno; - } - if (query_start_arg) - { - /* For slow query log */ - if (my_b_printf(&log_file, - "# Query_time: %lu Lock_time: %lu Rows_sent: %lu Rows_examined: %lu\n", - (ulong) (current_time - query_start_arg), - (ulong) (thd->time_after_lock - query_start_arg), - (ulong) thd->sent_row_count, - (ulong) thd->examined_row_count) == (uint) -1) - tmp_errno=errno; - } - if (thd->db && strcmp(thd->db,db)) - { // Database changed - if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1) - tmp_errno=errno; - strmov(db,thd->db); - } - if (thd->last_insert_id_used) - { - end=strmov(end,",last_insert_id="); - end=longlong10_to_str((longlong) thd->current_insert_id,end,-10); - } - // Save value if we do an insert. - if (thd->insert_id_used) - { - if (specialflag & SPECIAL_LONG_LOG_FORMAT) - { - end=strmov(end,",insert_id="); - end=longlong10_to_str((longlong) thd->last_insert_id,end,-10); - } - } - if (thd->query_start_used) + { // Safety agains reopen + int tmp_errno=0; + char buff[80],*end; + end=buff; + if (!(thd->options & OPTION_UPDATE_LOG) && + (thd->master_access & SUPER_ACL)) + { + VOID(pthread_mutex_unlock(&LOCK_log)); + return 0; + } + if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg) + { + current_time=time(NULL); + if (current_time != last_time) { - if (query_start_arg != thd->query_start()) - { - query_start_arg=thd->query_start(); - end=strmov(end,",timestamp="); - end=int10_to_str((long) query_start_arg,end,10); - } + last_time=current_time; + struct tm tm_tmp; + struct tm *start; + localtime_r(¤t_time,&tm_tmp); + start=&tm_tmp; + /* Note that my_b_write() assumes it knows the length for this */ + sprintf(buff,"# Time: %02d%02d%02d %2d:%02d:%02d\n", + start->tm_year % 100, + start->tm_mon+1, + start->tm_mday, + start->tm_hour, + start->tm_min, + start->tm_sec); + if (my_b_write(&log_file, (byte*) buff,24)) + tmp_errno=errno; } - if (end != buff) + if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n", + thd->priv_user, + thd->user, + thd->host ? thd->host : "", + thd->ip ? thd->ip : "") == (uint) -1) + tmp_errno=errno; + } + if (query_start_arg) + { + /* For slow query log */ + if (my_b_printf(&log_file, + "# Query_time: %lu Lock_time: %lu Rows_sent: %lu Rows_examined: %lu\n", + (ulong) (current_time - query_start_arg), + (ulong) (thd->time_after_lock - query_start_arg), + (ulong) thd->sent_row_count, + (ulong) thd->examined_row_count) == (uint) -1) + tmp_errno=errno; + } + if (thd->db && strcmp(thd->db,db)) + { // Database changed + if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1) + tmp_errno=errno; + strmov(db,thd->db); + } + if (thd->last_insert_id_used) + { + end=strmov(end,",last_insert_id="); + end=longlong10_to_str((longlong) thd->current_insert_id,end,-10); + } + // Save value if we do an insert. + if (thd->insert_id_used) + { + if (specialflag & SPECIAL_LONG_LOG_FORMAT) { - *end++=';'; - *end='\n'; - if (my_b_write(&log_file, (byte*) "SET ",4) || - my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff))) - tmp_errno=errno; + end=strmov(end,",insert_id="); + end=longlong10_to_str((longlong) thd->last_insert_id,end,-10); } - if (!query) + } + if (thd->query_start_used) + { + if (query_start_arg != thd->query_start()) { - end=strxmov(buff, "# administrator command: ", - command_name[thd->command], NullS); - query_length=(ulong) (end-buff); - query=buff; + query_start_arg=thd->query_start(); + end=strmov(end,",timestamp="); + end=int10_to_str((long) query_start_arg,end,10); } - if (my_b_write(&log_file, (byte*) query,query_length) || - my_b_write(&log_file, (byte*) ";\n",2) || - flush_io_cache(&log_file)) - tmp_errno=errno; - if (tmp_errno) + } + if (end != buff) + { + *end++=';'; + *end='\n'; + if (my_b_write(&log_file, (byte*) "SET ",4) || + my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff))) + tmp_errno=errno; + } + if (!query) + { + end=strxmov(buff, "# administrator command: ", + command_name[thd->command], NullS); + query_length=(ulong) (end-buff); + query=buff; + } + if (my_b_write(&log_file, (byte*) query,query_length) || + my_b_write(&log_file, (byte*) ";\n",2) || + flush_io_cache(&log_file)) + tmp_errno=errno; + if (tmp_errno) + { + error=1; + if (! write_error) { - error=1; - if (! write_error) - { - write_error=1; - sql_print_error(ER(ER_ERROR_ON_WRITE),name,error); - } + write_error=1; + sql_print_error(ER(ER_ERROR_ON_WRITE),name,error); } } - VOID(pthread_mutex_unlock(&LOCK_log)); } + VOID(pthread_mutex_unlock(&LOCK_log)); return error; } + /* Wait until we get a signal that the binary log has been updated @@ -1655,25 +1672,26 @@ void MYSQL_LOG:: wait_for_update(THD* thd) SYNOPSIS close() - exiting Set to 1 if we should also close the index file - This can be set to 0 if we are going to do call open - at once after close, in which case we don't want to - close the index file. - We only write a 'stop' event to the log if exiting is set + exiting Bitmask for one or more of the following bits: + LOG_CLOSE_INDEX if we should close the index file + LOG_CLOSE_TO_BE_OPENED if we intend to call open + at once after close. + LOG_CLOSE_STOP_EVENT write a 'stop' event to the log NOTES One can do an open on the object at once after doing a close. The internal structures are not freed until cleanup() is called */ -void MYSQL_LOG::close(bool exiting) +void MYSQL_LOG::close(uint exiting) { // One can't set log_type here! DBUG_ENTER("MYSQL_LOG::close"); DBUG_PRINT("enter",("exiting: %d", (int) exiting)); - if (is_open()) + if (log_type != LOG_CLOSED && log_type != LOG_TO_BE_OPENED) { #ifdef HAVE_REPLICATION - if (log_type == LOG_BIN && !no_auto_events && exiting) + if (log_type == LOG_BIN && !no_auto_events && + (exiting & LOG_CLOSE_STOP_EVENT)) { Stop_log_event s; s.set_log_pos(this); @@ -1694,7 +1712,7 @@ void MYSQL_LOG::close(bool exiting) called a not complete close earlier and the index file is still open. */ - if (exiting && my_b_inited(&index_file)) + if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file)) { end_io_cache(&index_file); if (my_close(index_file.file, MYF(0)) < 0 && ! write_error) @@ -1703,12 +1721,30 @@ void MYSQL_LOG::close(bool exiting) sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno); } } - log_type= LOG_CLOSED; + log_type= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED; safeFree(name); DBUG_VOID_RETURN; } +void MYSQL_LOG::set_max_size(ulong max_size_arg) +{ + /* + We need to take locks, otherwise this may happen: + new_file() is called, calls open(old_max_size), then before open() starts, + set_max_size() sets max_size to max_size_arg, then open() starts and + uses the old_max_size argument, so max_size_arg has been overwritten and + it's like if the SET command was never run. + */ + DBUG_ENTER("MYSQL_LOG::set_max_size"); + pthread_mutex_lock(&LOCK_log); + if (is_open()) + max_size= max_size_arg; + pthread_mutex_unlock(&LOCK_log); + DBUG_VOID_RETURN; +} + + /* Check if a string is a valid number diff --git a/sql/log_event.cc b/sql/log_event.cc index 749732384c7..9f7d09785ac 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* 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 @@ -72,7 +72,7 @@ static void pretty_print_str(FILE* file, char* str, int len) } fputc('\'', file); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ /* @@ -82,33 +82,35 @@ static void pretty_print_str(FILE* file, char* str, int len) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) inline int ignored_error_code(int err_code) { - return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code); + return ((err_code == ER_SLAVE_IGNORED_TABLE) || + (use_slave_mask && bitmap_is_set(&slave_error_mask, err_code))); } #endif + /* pretty_print_str() */ #ifndef MYSQL_CLIENT -static char* pretty_print_str(char* packet, char* str, int len) +static char *pretty_print_str(char *packet, char *str, int len) { - char* end = str + len; - char* pos= packet; + char *end= str + len; + char *pos= packet; *pos++= '\''; while (str < end) { char c; switch ((c=*str++)) { - case '\n': pos= strmov(pos, "\\n"); break; - case '\r': pos= strmov(pos, "\\r"); break; - case '\\': pos= strmov(pos, "\\\\"); break; - case '\b': pos= strmov(pos, "\\b"); break; - case '\t': pos= strmov(pos, "\\t"); break; - case '\'': pos= strmov(pos, "\\'"); break; - case 0 : pos= strmov(pos, "\\0"); break; + case '\n': *pos++= '\'; *pos++= 'n'; break; + case '\r': *pos++= '\'; *pos++= 'r'; break; + case '\\': *pos++= '\'; *pos++= '\'; break; + case '\b': *pos++= '\'; *pos++= 'b'; break; + case '\t': *pos++= '\'; *pos++= 't'; break; + case '\'': *pos++= '\'; *pos++= '\''; break; + case 0 : *pos++= '\'; *pos++= '0'; break; default: - *pos++= (char)c; + *pos++= c; break; } } @@ -126,7 +128,7 @@ static char* pretty_print_str(char* packet, char* str, int len) static inline char* slave_load_file_stem(char*buf, uint file_id, int event_server_id) { - fn_format(buf,"SQL_LOAD-",slave_load_tmpdir,"",0); /* 4+32); */ + fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME); buf = strend(buf); buf = int10_to_str(::server_id, buf, 10); *buf++ = '-'; @@ -136,6 +138,7 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, } #endif + /* cleanup_load_tmpdir() @@ -153,6 +156,8 @@ static void cleanup_load_tmpdir() MY_DIR *dirp; FILEINFO *file; uint i; + char fname[FN_REFLEN]; + if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) return; @@ -160,7 +165,10 @@ static void cleanup_load_tmpdir() { file=dirp->dir_entry+i; if (is_prefix(file->name,"SQL_LOAD-")) - my_delete(file->name, MYF(0)); + { + fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME); + my_delete(fname, MYF(0)); + } } my_dirend(dirp); @@ -220,7 +228,7 @@ const char* Log_event::get_type_str() case EXEC_LOAD_EVENT: return "Exec_load"; case RAND_EVENT: return "RAND"; case USER_VAR_EVENT: return "User var"; - default: /* impossible */ return "Unknown"; + default: return "Unknown"; /* impossible */ } } @@ -390,7 +398,7 @@ void Log_event::init_show_field_list(List<Item>* field_list) field_list->push_back(new Item_empty_string("Info", 20)); } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ /* Log_event::write() @@ -485,7 +493,7 @@ end: pthread_mutex_unlock(log_lock); DBUG_RETURN(result); } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ #ifndef MYSQL_CLIENT #define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock); @@ -558,8 +566,9 @@ err: UNLOCK_MUTEX; if (error) { - sql_print_error("Error in Log_event::read_log_event(): '%s', \ -data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]); + sql_print_error("\ +Error in Log_event::read_log_event(): '%s', data_len: %d, event_type: %d", + error,data_len,head[EVENT_TYPE_OFFSET]); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); /* The SQL slave thread will check if file->error<0 to know @@ -596,8 +605,6 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, ev = new Query_log_event(buf, event_len, old_format); break; case LOAD_EVENT: - ev = new Load_log_event(buf, event_len, old_format); - break; case NEW_LOAD_EVENT: ev = new Load_log_event(buf, event_len, old_format); break; @@ -700,7 +707,8 @@ void Log_event::print_timestamp(FILE* file, time_t* ts) res->tm_sec); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ + /* Log_event::set_log_pos() @@ -712,7 +720,7 @@ void Log_event::set_log_pos(MYSQL_LOG* log) if (!log_pos) log_pos = my_b_tell(&log->log_file); } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ /************************************************************************** @@ -735,8 +743,7 @@ void Query_log_event::pack_info(Protocol *protocol) { pos= strmov(buf, "use `"); memcpy(pos, db, db_len); - pos+= db_len; - pos= strmov(pos, "`; "); + pos= strmov(pos+db_len, "`; "); } if (query && q_len) { @@ -801,6 +808,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, } #endif /* MYSQL_CLIENT */ + /* Query_log_event::Query_log_event() */ @@ -885,8 +893,9 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Query_log_event::exec_event(struct st_relay_log_info* rli) { - int expected_error,actual_error = 0; - thd->db = rewrite_db((char*)db); + int expected_error,actual_error= 0; + init_sql_alloc(&thd->mem_root, 8192,0); + thd->db= (char*) rewrite_db(db); /* InnoDB internally stores the master log position it has executed so far, @@ -908,11 +917,10 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) thd->query = (char*)query; thd->query_id = query_id++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); - thd->query_error= 0; // clear error + thd->query_error= 0; // clear error thd->clear_error(); - thd->variables.pseudo_thread_id= thread_id; // for temp tables - + /* Sanity check to make sure the master did not get a really bad error on the query. @@ -924,6 +932,10 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) DBUG_PRINT("query",("%s",thd->query)); mysql_parse(thd, thd->query, q_len); + /* + If we expected a non-zero error code, and we don't get the same error + code, and none of them should be ignored. + */ DBUG_PRINT("info",("expected_error: %d last_errno: %d", expected_error, thd->net.last_errno)); if ((expected_error != (actual_error= thd->net.last_errno)) && @@ -931,14 +943,22 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) !ignored_error_code(actual_error) && !ignored_error_code(expected_error)) { - const char* errmsg = "Slave: did not get the expected error\ - running query from master - expected: '%s' (%d), got '%s' (%d)"; - sql_print_error(errmsg, ER_SAFE(expected_error), - expected_error, - actual_error ? thd->net.last_error: "no error", - actual_error); - thd->query_error = 1; + slave_print_error(rli, 0, + "\ +Query '%s' caused different errors on master and slave. \ +Error on master: '%s' (%d), Error on slave: '%s' (%d). \ +Default database: '%s'", + query, + ER_SAFE(expected_error), + expected_error, + actual_error ? thd->net.last_error: "no error", + actual_error, + print_slave_db_safe(db)); + thd->query_error= 1; } + /* + If we get the same error code as expected, or they should be ignored. + */ else if (expected_error == actual_error || ignored_error_code(actual_error)) { @@ -947,37 +967,39 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) *rli->last_slave_error = 0; rli->last_slave_errno = 0; } - } - else - { - // master could be inconsistent, abort and tell DBA to check/fix it - VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->db = thd->query = 0; - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - //thd->variables.convert_set = 0; - close_thread_tables(thd); - free_root(&thd->mem_root,0); - return 1; - } - } - thd->db= 0; // prevent db from being freed + /* + Other cases: mostly we expected no error and get one. + */ + else if (thd->query_error || thd->is_fatal_error) + { + slave_print_error(rli,actual_error, + "Error '%s' on query '%s'. Default database: '%s'", + (actual_error ? thd->net.last_error : + "unexpected success or fatal error"), + query, + print_slave_db_safe(db)); + thd->query_error= 1; + } + } + /* + End of sanity check. If the test was wrong, the query got a really bad + error on the master, which could be inconsistent, abort and tell DBA to + check/fix it. check_expected_error() already printed the message to + stderr and rli, and set thd->query_error to 1. + */ + } /* End of if (db_ok(... */ + +end: + VOID(pthread_mutex_lock(&LOCK_thread_count)); + thd->db= 0; // prevent db from being freed thd->query= 0; // just to be sure VOID(pthread_mutex_unlock(&LOCK_thread_count)); // assume no convert for next query unless set explictly //thd->variables.convert_set = 0; - close_thread_tables(thd); - - if (thd->query_error || thd->is_fatal_error) - { - slave_print_error(rli,actual_error, "error '%s' on query '%s'", - actual_error ? thd->net.last_error : - "unexpected success or fatal error", query); - free_root(&thd->mem_root,0); - return 1; - } + close_thread_tables(thd); free_root(&thd->mem_root,0); - return Log_event::exec_event(rli); + return (thd->query_error ? thd->query_error : Log_event::exec_event(rli)); } #endif @@ -997,8 +1019,8 @@ void Start_log_event::pack_info(Protocol *protocol) pos= strmov(buf, "Server ver: "); pos= strmov(pos, server_version); pos= strmov(pos, ", Binlog ver: "); - pos=int10_to_str(binlog_version, pos, 10); - protocol->store(buf, pos-buf, &my_charset_bin); + pos= int10_to_str(binlog_version, pos, 10); + protocol->store(buf, (uint) (pos-buf), &my_charset_bin); } #endif @@ -1016,7 +1038,9 @@ void Start_log_event::print(FILE* file, bool short_form, char* last_db) print_header(file); fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, server_version); - print_timestamp(file, &created); + print_timestamp(file); + if (created) + fprintf(file," at startup"); fputc('\n', file); fflush(file); } @@ -1057,13 +1081,10 @@ int Start_log_event::write_data(IO_CACHE* file) The master started IMPLEMENTATION - - To handle the case where the master died without having time to write DROP - TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is TODO), - we clean up all temporary tables + locks that we got. - However, we don't clean temporary tables if the master was 3.23 - (this is because a 3.23 master writes a Start_log_event at every - binlog rotation; if we were not careful we would remove temp tables - on the slave when FLUSH LOGS is issued on the master). + - To handle the case where the master died without having time to write + DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is + TODO), we clean up all temporary tables that we got, if we are sure we + can (see below). TODO - Remove all active user locks. @@ -1078,8 +1099,8 @@ int Start_log_event::write_data(IO_CACHE* file) the table changes are committed, rollback has occured on the master; we should rather rollback on the slave and go on. If we don't rollback, and the next query is not BEGIN, then it will be considered as part of the - unfinished transaction, and so will be rolled back at next BEGIN, which is - a bug. + unfinished transaction, and so will be rolled back at next BEGIN, which + is a bug. */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) @@ -1087,23 +1108,46 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) { DBUG_ENTER("Start_log_event::exec_event"); - if (!rli->mi->old_format) - { + switch (rli->mi->old_format) { + case BINLOG_FORMAT_CURRENT: + /* + This is 4.x, so a Start_log_event is only at master startup, + so we are sure the master has restarted and cleared his temp tables. + */ + /* If the master died before writing the COMMIT to the binlog, rollback; otherwise it does not hurt to rollback. */ ha_rollback(thd); + close_temporary_tables(thd); + cleanup_load_tmpdir(); + break; + /* - If 4.0 master, all temporary tables have been deleted on the master; - if 3.23 master, this is far from sure. + Now the older formats; in that case load_tmpdir is cleaned up by the I/O + thread. */ - close_temporary_tables(thd); + case BINLOG_FORMAT_323_LESS_57: /* - If we have old format, load_tmpdir is cleaned up by the I/O thread + Cannot distinguish a Start_log_event generated at master startup and + one generated by master FLUSH LOGS, so cannot be sure temp tables + have to be dropped. So do nothing. */ - cleanup_load_tmpdir(); + break; + case BINLOG_FORMAT_323_GEQ_57: + /* + Can distinguish, based on the value of 'created', + which was generated at master startup. + */ + if (created) + close_temporary_tables(thd); + break; + default: + /* this case is impossible */ + return 1; } + DBUG_RETURN(Log_event::exec_event(rli)); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -1125,6 +1169,7 @@ void Load_log_event::pack_info(Protocol *protocol) buf_len= 5 + db_len + 3 + // "use DB; " 18 + fname_len + 2 + // "LOAD DATA INFILE 'file''" + 7 + // LOCAL 9 + // " REPLACE or IGNORE " 11 + table_name_len + // "INTO TABLE table" 21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" @@ -1135,22 +1180,22 @@ void Load_log_event::pack_info(Protocol *protocol) 15 + 22 + // " IGNORE xxx LINES" 3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)" - buf= my_malloc(buf_len, MYF(MY_WME)); - if (!buf) + if (!(buf= my_malloc(buf_len, MYF(MY_WME)))) return; pos= buf; if (db && db_len) { pos= strmov(pos, "use `"); memcpy(pos, db, db_len); - pos+= db_len; - pos= strmov(pos, "`; "); + pos= strmov(pos+db_len, "`; "); } - pos= strmov(pos, "LOAD DATA INFILE '"); + pos= strmov(pos, "LOAD DATA "); + if (check_fname_outside_temp_buf()) + pos= strmov(pos, "LOCAL "); + pos= strmov(pos, "INFILE '"); memcpy(pos, fname, fname_len); - pos+= fname_len; - pos= strmov(pos, "' "); + pos= strmov(pos+fname_len, "' "); if (sql_ex.opt_flags & REPLACE_FLAG) pos= strmov(pos, " REPLACE "); @@ -1197,31 +1242,34 @@ void Load_log_event::pack_info(Protocol *protocol) pos= pretty_print_str(pos, sql_ex.line_start, sql_ex.line_start_len); } - if ((int)skip_lines > 0) + if ((long) skip_lines > 0) { pos= strmov(pos, " IGNORE "); - pos= longlong10_to_str((long) skip_lines, pos, 10); + pos= longlong10_to_str((longlong) skip_lines, pos, 10); pos= strmov(pos," LINES "); } if (num_fields) { uint i; - const char* field = fields; + const char *field= fields; pos= strmov(pos, " ("); for (i = 0; i < num_fields; i++) { if (i) - pos= strmov(pos, " ,"); + { + *pos++= ' '; + *pos++= ','; + } memcpy(pos, field, field_lens[i]); - pos+= field_lens[i]; - field += field_lens[i] + 1; + pos+= field_lens[i]; + field+= field_lens[i] + 1; } *pos++= ')'; } protocol->store(buf, pos-buf, &my_charset_bin); - my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); + my_free(buf, MYF(0)); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -1527,7 +1575,8 @@ void Load_log_event::set_fields(List<Item> &field_list) field+= field_lens[i] + 1; } } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ + #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) /* @@ -1559,11 +1608,12 @@ void Load_log_event::set_fields(List<Item> &field_list) int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, bool use_rli_only_for_errors) { - thd->db = rewrite_db((char*)db); + init_sql_alloc(&thd->mem_root, 8192,0); + thd->db= (char*) rewrite_db(db); DBUG_ASSERT(thd->query == 0); thd->query = 0; // Should not be needed thd->query_error = 0; - + if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { thd->set_time((time_t)when); @@ -1643,12 +1693,14 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, thd->query_error = 1; if (thd->cuted_fields) { - /* - log_pos is the position of the LOAD event in the master log - */ - sql_print_error("Slave: load data infile at position %s in log \ -'%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME, - thd->cuted_fields ); + /* log_pos is the position of the LOAD event in the master log */ + sql_print_error("\ +Slave: load data infile on table '%s' at log position %s in log \ +'%s' produced %ld warning(s). Default database: '%s'", + (char*) table_name, + llstr(log_pos,llbuff), RPL_LOG_NAME, + (ulong) thd->cuted_fields, + print_slave_db_safe(db)); } if (net) net->pkt_nr= thd->net.pkt_nr; @@ -1680,9 +1732,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, sql_errno=ER_UNKNOWN_ERROR; err=ER(sql_errno); } - slave_print_error(rli,sql_errno, - "Error '%s' running load data infile", - err); + slave_print_error(rli,sql_errno,"\ +Error '%s' running lOAD DATA INFILE on table '%s'. Default database: '%s'", + err, (char*)table_name, print_slave_db_safe(db)); free_root(&thd->mem_root,0); return 1; } @@ -1690,7 +1742,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, if (thd->is_fatal_error) { - sql_print_error("Fatal error running LOAD DATA INFILE"); + slave_print_error(rli,ER_UNKNOWN_ERROR, "\ +Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'", + (char*)table_name, print_slave_db_safe(db)); return 1; } @@ -1713,12 +1767,10 @@ void Rotate_log_event::pack_info(Protocol *protocol) char *buf, *b_pos; if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME)))) return; - b_pos= buf; memcpy(buf, new_log_ident, ident_len); - b_pos+= ident_len; - b_pos= strmov(b_pos, ";pos="); - b_pos=longlong10_to_str(pos, b_pos, 10); - protocol->store(buf, b_pos-buf, &my_charset_bin); + b_pos= strmov(buf + ident_len, ";pos="); + b_pos= longlong10_to_str(pos, b_pos, 10); + protocol->store(buf, (uint) (b_pos-buf), &my_charset_bin); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } #endif @@ -1744,7 +1796,7 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) fputc('\n', file); fflush(file); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ /* @@ -1790,7 +1842,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len, int Rotate_log_event::write_data(IO_CACHE* file) { char buf[ROTATE_HEADER_LEN]; - int8store(buf, pos + R_POS_OFFSET); + int8store(buf + R_POS_OFFSET, pos); return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) || my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); } @@ -1823,7 +1875,8 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) rli->group_master_log_pos = pos; rli->event_relay_log_pos += get_event_len(); rli->group_relay_log_pos = rli->event_relay_log_pos; - DBUG_PRINT("info", ("group_master_log_pos: %d", (ulong) rli->group_master_log_pos)); + DBUG_PRINT("info", ("group_master_log_pos: %lu", + (ulong) rli->group_master_log_pos)); pthread_mutex_unlock(&rli->data_lock); pthread_cond_broadcast(&rli->data_cond); flush_relay_log_info(rli); @@ -1845,9 +1898,9 @@ void Intvar_log_event::pack_info(Protocol *protocol) { char buf[64], *pos; pos= strmov(buf, get_var_type_name()); - *(pos++)='='; + *pos++= '='; pos= longlong10_to_str(val, pos, -10); - protocol->store(buf, pos-buf, &my_charset_bin); + protocol->store(buf, (uint) (pos-buf), &my_charset_bin); } #endif @@ -1994,7 +2047,7 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db) llstr(seed1, llbuff),llstr(seed2, llbuff2)); fflush(file); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) @@ -2005,7 +2058,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli) rli->inc_event_relay_log_pos(get_event_len()); return 0; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ /************************************************************************** @@ -2063,7 +2116,7 @@ void User_var_log_event::pack_info(Protocol* protocol) protocol->store(buf, event_len, &my_charset_bin); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ User_var_log_event::User_var_log_event(const char* buf, bool old_format) @@ -2236,7 +2289,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) rli->inc_event_relay_log_pos(get_event_len()); return 0; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ /************************************************************************** @@ -2258,7 +2311,7 @@ void Unknown_log_event::print(FILE* file, bool short_form, char* last_db) #ifndef MYSQL_CLIENT void Slave_log_event::pack_info(Protocol *protocol) { - char buf[256], *pos; + char buf[256+HOSTNAME_LENGTH], *pos; pos= strmov(buf, "host="); pos= strnmov(pos, master_host, HOSTNAME_LENGTH); pos= strmov(pos, ",port="); @@ -2269,7 +2322,7 @@ void Slave_log_event::pack_info(Protocol *protocol) pos= longlong10_to_str(master_pos, pos, 10); protocol->store(buf, pos-buf, &my_charset_bin); } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ #ifndef MYSQL_CLIENT @@ -2306,7 +2359,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg, pthread_mutex_unlock(&mi->data_lock); DBUG_VOID_RETURN; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ Slave_log_event::~Slave_log_event() @@ -2323,11 +2376,11 @@ void Slave_log_event::print(FILE* file, bool short_form, char* last_db) return; print_header(file); fputc('\n', file); - fprintf(file, "Slave: master_host: '%s' master_port: %d \ -master_log: '%s' master_pos: %s\n", + fprintf(file, "\ +Slave: master_host: '%s' master_port: %d master_log: '%s' master_pos: %s\n", master_host, master_port, master_log, llstr(master_pos, llbuff)); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ int Slave_log_event::get_data_size() @@ -2383,7 +2436,7 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli) mysql_bin_log.write(this); return Log_event::exec_event(rli); } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ /************************************************************************** @@ -2404,7 +2457,7 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, "\tStop\n"); fflush(file); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ /* @@ -2431,7 +2484,7 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli) could give false triggers in MASTER_POS_WAIT() that we have reached the target position when in fact we have not. */ - rli->inc_group_relay_log_pos(get_event_len(), 0); + rli->inc_group_relay_log_pos(get_event_len(), 0); flush_relay_log_info(rli); return 0; } @@ -2460,7 +2513,7 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex, { sql_ex.force_new_format(); } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ /* @@ -2563,12 +2616,13 @@ void Create_file_log_event::print(FILE* file, bool short_form, fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); } + void Create_file_log_event::print(FILE* file, bool short_form, char* last_db) { print(file,short_form,last_db,0); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ /* @@ -2581,15 +2635,13 @@ void Create_file_log_event::pack_info(Protocol *protocol) char buf[NAME_LEN*2 + 30 + 21*2], *pos; pos= strmov(buf, "db="); memcpy(pos, db, db_len); - pos+= db_len; - pos= strmov(pos, ";table="); + pos= strmov(pos + db_len, ";table="); memcpy(pos, table_name, table_name_len); - pos+= table_name_len; - pos= strmov(pos, ";file_id="); + pos= strmov(pos + table_name_len, ";file_id="); pos= int10_to_str((long) file_id, pos, 10); pos= strmov(pos, ";block_len="); pos= int10_to_str((long) block_len, pos, 10); - protocol->store(buf, pos-buf, &my_charset_bin); + protocol->store(buf, (uint) (pos-buf), &my_charset_bin); } #endif @@ -2720,7 +2772,7 @@ void Append_block_log_event::print(FILE* file, bool short_form, fprintf(file, "#Append_block: file_id: %d block_len: %d\n", file_id, block_len); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ /* @@ -2735,7 +2787,7 @@ void Append_block_log_event::pack_info(Protocol *protocol) length= (uint) my_sprintf(buf, (buf, ";file_id=%u;block_len=%u", file_id, block_len)); - protocol->store(buf, (int32) length, &my_charset_bin); + protocol->store(buf, length, &my_charset_bin); } #endif @@ -2829,7 +2881,7 @@ void Delete_file_log_event::print(FILE* file, bool short_form, fputc('\n', file); fprintf(file, "#Delete_file: file_id=%u\n", file_id); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ /* Delete_file_log_event::pack_info() @@ -2982,8 +3034,24 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) */ if (lev->exec_event(0,rli,1)) { - slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname); - thd->options = save_options; + /* + We want to indicate the name of the file that could not be loaded + (SQL_LOADxxx). + But as we are here we are sure the error is in rli->last_slave_error and + rli->last_slave_errno (example of error: duplicate entry for key), so we + don't want to overwrite it with the filename. + What we want instead is add the filename to the current error message. + */ + char *tmp= my_strdup(rli->last_slave_error,MYF(MY_WME)); + if (tmp) + { + slave_print_error(rli, + rli->last_slave_errno, /* ok to re-use error code */ + "%s. Failed executing load from '%s'", + tmp, fname); + my_free(tmp,MYF(0)); + } + thd->options= save_options; goto err; } thd->options = save_options; @@ -3089,5 +3157,3 @@ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) } return buf; } - - diff --git a/sql/log_event.h b/sql/log_event.h index bd5e1a82be4..a58479e2589 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -559,10 +559,15 @@ public: /* fname doesn't point to memory inside Log_event::temp_buf */ void set_fname_outside_temp_buf(const char *afname, uint alen) - {fname=afname;fname_len=alen;} + { + fname= afname; + fname_len= alen; + } /* fname doesn't point to memory inside Log_event::temp_buf */ int check_fname_outside_temp_buf() - {return fname<temp_buf || fname>temp_buf+cached_event_len;} + { + return fname < temp_buf || fname > temp_buf+ cached_event_len; + } #ifndef MYSQL_CLIENT String field_lens_buf; @@ -619,6 +624,26 @@ extern char server_version[SERVER_VERSION_LENGTH]; class Start_log_event: public Log_event { public: + /* + If this event is at the start of the first binary log since server startup + 'created' should be the timestamp when the event (and the binary log) was + created. + In the other case (i.e. this event is at the start of a binary log created + by FLUSH LOGS or automatic rotation), 'created' should be 0. + This "trick" is used by MySQL >=4.0.14 slaves to know if they must drop the + stale temporary tables or not. + Note that when 'created'!=0, it is always equal to the event's timestamp; + indeed Start_log_event is written only in log.cc where the first + constructor below is called, in which 'created' is set to 'when'. + So in fact 'created' is a useless variable. When it is 0 + we can read the actual value from timestamp ('when') and when it is + non-zero we can read the same value from timestamp ('when'). Conclusion: + - we use timestamp to print when the binlog was created. + - we use 'created' only to know if this is a first binlog or not. + In 3.23.57 we did not pay attention to this identity, so mysqlbinlog in + 3.23.57 does not print 'created the_date' if created was zero. This is now + fixed. + */ time_t created; uint16 binlog_version; char server_version[ST_SERVER_VER_LEN]; @@ -947,6 +972,7 @@ public: #endif /* HAVE_REPLICATION */ #else void print(FILE* file, bool short_form = 0, char* last_db = 0); + void print(FILE* file, bool short_form, char* last_db, bool enable_local); #endif Delete_file_log_event(const char* buf, int event_len); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c41d973f2e..2bca2c3eef2 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -77,6 +77,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; /* Password lengh for 4.1 version previous versions had 16 bytes password hash */ #define HASH_PASSWORD_LENGTH 45 #define HASH_OLD_PASSWORD_LENGTH 16 +#define MAX_PASSWORD_LENGTH 32 #define HOST_CACHE_SIZE 128 #define MAX_ACCEPT_RETRY 10 // Test accept this many times #define MAX_FIELDS_BEFORE_HASH 32 @@ -158,6 +159,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define TEST_NO_EXTRA 128 #define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */ #define TEST_NO_STACKTRACE 512 +#define TEST_SIGINT 1024 /* Allow sigint on threads */ /* options for select set by the yacc parser (stored in lex->options) */ #define SELECT_DISTINCT 1 @@ -285,6 +287,17 @@ typedef struct st_sql_list { next= next_ptr; *next=0; } + inline void save_and_clear(struct st_sql_list *save) + { + *save= *this; + empty(); + } + inline void push_front(struct st_sql_list *save) + { + *save->next= first; /* link current list last */ + first= save->first; + elements+= save->elements; + } } SQL_LIST; @@ -689,8 +702,8 @@ bool fn_format_relative_to_data_home(my_string to, const char *name, bool open_log(MYSQL_LOG *log, const char *hostname, const char *opt_name, const char *extension, const char *index_file_name, - enum_log_type type, bool read_append = 0, - bool no_auto_events = 0); + enum_log_type type, bool read_append, + bool no_auto_events, ulong max_size); /* External variables @@ -737,7 +750,8 @@ extern ulong max_insert_delayed_threads, max_user_connections; extern ulong long_query_count, what_to_log,flush_time; extern ulong query_buff_size, thread_stack,thread_stack_min; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; -extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size; +extern ulong max_binlog_size, max_relay_log_size; +extern ulong rpl_recovery_rank, thread_cache_size; extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log; extern ulong specialflag, current_pid; extern ulong expire_logs_days; @@ -916,6 +930,10 @@ Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name, /* log.cc */ bool flush_error_log(void); +/* sql_list.cc */ +void free_list(I_List <i_string_pair> *list); +void free_list(I_List <i_string> *list); + /* Some inline functions for more speed */ inline bool add_item_to_list(THD *thd, Item *item) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8ddcbdc572f..b5afbb422d5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -252,7 +252,7 @@ bool volatile ready_to_exit, shutdown_in_progress, grant_option; my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted my_bool opt_reckless_slave = 0; -my_bool opt_enable_named_pipe= 0; +my_bool opt_enable_named_pipe= 0, opt_debugging= 0; my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool lower_case_table_names, opt_old_rpl_compat; @@ -270,14 +270,15 @@ ulong back_log, connect_timeout, concurrency; ulong server_id, thd_startup_options; ulong table_cache_size, thread_stack, thread_stack_min, what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; -ulong open_files_limit, max_binlog_size; +ulong open_files_limit, max_binlog_size, max_relay_log_size; ulong slave_net_timeout; ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0; ulong query_cache_size=0; ulong com_stat[(uint) SQLCOM_END], com_other; ulong bytes_sent, bytes_received, net_big_packet_count; -ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */ -ulong query_id, long_query_count, aborted_threads, aborted_connects; +ulong refresh_version, flush_version; /* Increments on each reload */ +ulong query_id, long_query_count; +ulong aborted_threads, killed_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; ulong delayed_insert_errors,flush_time, thread_created; @@ -847,7 +848,6 @@ extern "C" void unireg_abort(int exit_code) sql_print_error("Aborting\n"); clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */ DBUG_PRINT("quit",("done with cleanup in unireg_abort")); - my_thread_end(); clean_up_mutexes(); my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); exit(exit_code); /* purecov: inspected */ @@ -900,6 +900,11 @@ void clean_up(bool print_message) free_max_user_conn(); #ifdef HAVE_REPLICATION end_slave_list(); + free_list(&replicate_do_db); + free_list(&replicate_ignore_db); + free_list(&binlog_do_db); + free_list(&binlog_ignore_db); + free_list(&replicate_rewrite_db); #endif #ifdef HAVE_OPENSSL if (ssl_acceptor_fd) @@ -1263,7 +1268,10 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused))) THD *thd=current_thd; DBUG_ENTER("end_thread_signal"); if (thd && ! thd->bootstrap) + { + statistic_increment(killed_threads, &LOCK_status); end_thread(thd,0); + } DBUG_VOID_RETURN; /* purecov: deadcode */ } @@ -1582,7 +1590,8 @@ static void init_signals(void) struct sigaction sa; DBUG_ENTER("init_signals"); - sigset(THR_KILL_SIGNAL,end_thread_signal); + if (test_flags & TEST_SIGINT) + sigset(THR_KILL_SIGNAL,end_thread_signal); sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) @@ -1641,7 +1650,8 @@ static void init_signals(void) sigaddset(&set,SIGTSTP); #endif sigaddset(&set,THR_SERVER_ALARM); - sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT + if (test_flags & TEST_SIGINT) + sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT sigdelset(&set,THR_CLIENT_ALARM); // For alarms sigprocmask(SIG_SETMASK,&set,NULL); pthread_sigmask(SIG_SETMASK,&set,NULL); @@ -1697,9 +1707,12 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) */ init_thr_alarm(max_connections+max_insert_delayed_threads+10); #if SIGINT != THR_KILL_SIGNAL - (void) sigemptyset(&set); // Setup up SIGINT for debug - (void) sigaddset(&set,SIGINT); // For debugging - (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL); + if (test_flags & TEST_SIGINT) + { + (void) sigemptyset(&set); // Setup up SIGINT for debug + (void) sigaddset(&set,SIGINT); // For debugging + (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL); + } #endif (void) sigemptyset(&set); // Setup up SIGINT for debug #ifdef USE_ONE_SIGNAL_HAND @@ -1931,7 +1944,7 @@ bool open_log(MYSQL_LOG *log, const char *hostname, const char *opt_name, const char *extension, const char *index_file_name, enum_log_type type, bool read_append, - bool no_auto_events) + bool no_auto_events, ulong max_size) { char tmp[FN_REFLEN]; if (!opt_name || !opt_name[0]) @@ -1948,16 +1961,13 @@ bool open_log(MYSQL_LOG *log, const char *hostname, if (type == LOG_BIN) { char *p = fn_ext(opt_name); - if (p) - { - uint length=(uint) (p-opt_name); - strmake(tmp,opt_name,min(length,FN_REFLEN)); - opt_name=tmp; - } + uint length=(uint) (p-opt_name); + strmake(tmp,opt_name,min(length,FN_REFLEN)); + opt_name=tmp; } return log->open(opt_name, type, 0, index_file_name, (read_append) ? SEQ_READ_APPEND : WRITE_CACHE, - no_auto_events); + no_auto_events, max_size); } @@ -1989,6 +1999,17 @@ static int init_common_variables(const char *conf_file_name, int argc, } #endif + /* + Init mutexes for the global MYSQL_LOG objects. + As safe_mutex depends on what MY_INIT() does, we can't init the mutexes of + global MYSQL_LOGs in their constructors, because then they would be inited + before MY_INIT(). So we do it here. + */ + mysql_log.init_pthread_objects(); + mysql_update_log.init_pthread_objects(); + mysql_slow_log.init_pthread_objects(); + mysql_bin_log.init_pthread_objects(); + if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0) strmov(glob_hostname,"mysql"); strmake(pidfile_name, glob_hostname, sizeof(pidfile_name)-5); @@ -2151,21 +2172,21 @@ static int init_server_components() /* Setup log files */ if (opt_log) open_log(&mysql_log, glob_hostname, opt_logname, ".log", NullS, - LOG_NORMAL); + LOG_NORMAL, 0, 0, 0); if (opt_update_log) { open_log(&mysql_update_log, glob_hostname, opt_update_logname, "", - NullS, LOG_NEW); +! NullS, LOG_NEW, 0, 0, 0); using_update_log=1; } if (opt_slow_log) open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log", - NullS, LOG_NORMAL); + NullS, LOG_NORMAL, 0, 0, 0); if (opt_bin_log) { open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin", - opt_binlog_index_name,LOG_BIN); + opt_binlog_index_name, LOG_BIN, 0, 0, max_binlog_size); using_update_log=1; #ifdef HAVE_REPLICATION if (expire_logs_days) @@ -2176,6 +2197,12 @@ static int init_server_components() } #endif } + else if (opt_log_slave_updates) + { + sql_print_error("\ +Warning: you need to use --log-bin to make --log-slave-updates work. \ +Now disabling --log-slave-updates."); + } if (opt_error_log) { @@ -2459,6 +2486,8 @@ The server will not act as a slave."); if (!opt_noacl) udf_init(); #endif + if (opt_bootstrap) /* If running with bootstrap, do not start replication. */ + opt_skip_slave_start= 1; /* init_slave() must be called after the thread keys are created */ init_slave(); @@ -2564,6 +2593,19 @@ int mysql_service(void *p) return 0; } + +/* Quote string if it contains space, else copy */ + +static char *add_quoted_string(char *to, const char *from, char *to_end) +{ + uint length= (uint) (to_end-to); + + if (!strchr(from, ' ')) + return strnmov(to, from, length); + return strxnmov(to, length, "\"", from, "\"", NullS); +} + + /* Handle basic handling of services, like installation and removal @@ -2573,25 +2615,41 @@ int mysql_service(void *p) servicename Internal name of service displayname Display name of service (in taskbar ?) file_path Path to this program + startup_option Startup option to mysqld RETURN VALUES 0 option handled 1 Could not handle option */ -bool default_service_handling(char **argv, - const char *servicename, - const char *displayname, - const char *file_path) +static bool +default_service_handling(char **argv, + const char *servicename, + const char *displayname, + const char *file_path, + const char *extra_opt) { + char path_and_service[FN_REFLEN+FN_REFLEN+32], *pos, *end; + end= path_and_service + sizeof(path_and_service)-1; + + /* We have to quote filename if it contains spaces */ + pos= add_quoted_string(path_and_service, file_path, end); + if (*extra_opt) + { + /* Add (possible quoted) option after file_path */ + *pos++= ' '; + pos= add_quoted_string(pos, extra_opt, end); + } + *pos= 0; // Ensure end null + if (Service.got_service_option(argv, "install")) { - Service.Install(1, servicename, displayname, file_path); + Service.Install(1, servicename, displayname, path_and_service); return 0; } if (Service.got_service_option(argv, "install-manual")) { - Service.Install(0, servicename, displayname, file_path); + Service.Install(0, servicename, displayname, path_and_service); return 0; } if (Service.got_service_option(argv, "remove")) @@ -2617,12 +2675,13 @@ int main(int argc, char **argv) { char file_path[FN_REFLEN]; my_path(file_path, argv[0], ""); /* Find name in path */ - fn_format(file_path,argv[0],file_path,"",1+4+16); /* Force full path */ + fn_format(file_path,argv[0],file_path,"", + MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS); if (argc == 2) { - if (!default_service_handling(argv,MYSQL_SERVICENAME, MYSQL_SERVICENAME, - file_path)) + if (!default_service_handling(argv, MYSQL_SERVICENAME, MYSQL_SERVICENAME, + file_path, "")) return 0; if (Service.IsService(argv[1])) { @@ -2635,12 +2694,8 @@ int main(int argc, char **argv) } else if (argc == 3) /* install or remove any optional service */ { - /* Add service name after filename */ - uint length=strlen(file_path); - *strxnmov(file_path + length, sizeof(file_path)-length-2, " ", - argv[2], NullS)= '\0'; - - if (!default_service_handling(argv, argv[2], argv[2], file_path)) + if (!default_service_handling(argv, argv[2], argv[2], file_path, + argv[2])) return 0; if (Service.IsService(argv[2])) { @@ -2662,10 +2717,8 @@ int main(int argc, char **argv) Install an optional service with optional config file mysqld --install-manual mysqldopt --defaults-file=c:\miguel\my.ini */ - uint length=strlen(file_path); - *strxnmov(file_path + length, sizeof(file_path)-length-2, " ", - argv[3], " ", argv[2], NullS)= '\0'; - if (!default_service_handling(argv, argv[2], argv[2], file_path)) + if (!default_service_handling(argv, argv[2], argv[2], file_path, + argv[3])) return 0; } else if (argc == 1 && Service.IsService(MYSQL_SERVICENAME)) @@ -2809,6 +2862,7 @@ static void create_new_thread(THD *thd) thread_count--; thd->killed=1; // Safety (void) pthread_mutex_unlock(&LOCK_thread_count); + statistic_increment(aborted_connects,&LOCK_status); net_printf(thd,ER_CANT_CREATE_THREAD,error); (void) pthread_mutex_lock(&LOCK_thread_count); close_connection(thd,0,0); @@ -3424,7 +3478,6 @@ enum options OPT_RPL_RECOVERY_RANK,OPT_INIT_RPL_ROLE, OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE, OPT_SLAVE_SKIP_ERRORS, OPT_DES_KEY_FILE, OPT_LOCAL_INFILE, - OPT_RECKLESS_SLAVE, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_BACK_LOG, OPT_BINLOG_CACHE_SIZE, @@ -3438,8 +3491,9 @@ enum options OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE, OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS, OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE, - OPT_MAX_JOIN_SIZE, OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_SORT_LENGTH, - OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS, + OPT_MAX_JOIN_SIZE, OPT_MAX_RELAY_LOG_SIZE, OPT_MAX_SORT_LENGTH, + OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS, + OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE, OPT_MAX_ERROR_COUNT, OPT_MAX_PREP_STMT, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, @@ -3452,7 +3506,7 @@ enum options OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER, OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE, OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME, - OPT_READONLY, + OPT_READONLY, OPT_DEBUGGING, OPT_SORT_BUFFER, OPT_TABLE_CACHE, OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE, OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK, @@ -3607,6 +3661,10 @@ Disable with --skip-bdb (will save memory).", REQUIRED_ARG, 1024, 4, (long) ~0, 0, 1, 0}, /* We must always support the next option to make scripts like mysqltest easier to do */ + {"gdb", OPT_DEBUGGING, + "Set up signals usable for debugging", + (gptr*) &opt_debugging, (gptr*) &opt_debugging, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH, @@ -3638,7 +3696,7 @@ Disable with --skip-bdb (will save memory).", 0, 0, 0}, {"innodb_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN, "Speeds up server shutdown process.", (gptr*) &innobase_fast_shutdown, - (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"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}, @@ -3804,8 +3862,6 @@ Does nothing yet.", OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &mysqld_port, (gptr*) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"reckless-slave", OPT_RECKLESS_SLAVE, "Used for debugging.", 0, 0, 0, GET_NO_ARG, - NO_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-do-db", OPT_REPLICATE_DO_DB, "Tells the slave thread to restrict replication to the specified database. To specify more than one database, use the directive multiple times, once for each database. Note that this will only work if you do not use cross-database queries such as UPDATE some_db.some_table SET foo='bar' while having selected a different or no database. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-do-table=db_name.%.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -3920,7 +3976,7 @@ Disable with --skip-isam.", {"skip-stack-trace", OPT_SKIP_STACK_TRACE, "Don't print a stack trace on failure.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Depricated option. Use --skip-symbolic-links instead.", + {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Deprecated option. Use --skip-symbolic-links instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-thread-priority", OPT_SKIP_PRIOR, "Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, @@ -3974,10 +4030,10 @@ replicating a LOAD DATA INFILE command.", {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.", (gptr*) &opt_external_locking, (gptr*) &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"use-symbolic-links", 's', "Enable symbolic link support. Depricated option; Use --symbolic-links instead.", + {"use-symbolic-links", 's', "Enable symbolic link support. Deprecated option; Use --symbolic-links instead.", (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG, IF_PURIFY(0,1), 0, 0, 0, 0, 0}, - {"--symbolic-links", 's', "Enable symbolic link support.", + {"symbolic-links", 's', "Enable symbolic link support.", (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG, IF_PURIFY(0,1), 0, 0, 0, 0, 0}, {"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG, @@ -4144,9 +4200,11 @@ replicating a LOAD DATA INFILE command.", (gptr*) &max_binlog_cache_size, (gptr*) &max_binlog_cache_size, 0, GET_ULONG, REQUIRED_ARG, ~0L, IO_SIZE, ~0L, 0, IO_SIZE, 0}, {"max_binlog_size", OPT_MAX_BINLOG_SIZE, - "Binary log will be rotated automatically when the size crosses the limit.", + "Binary log will be rotated automatically when the size exceeds this \ +value. Will also apply to relay logs if max_relay_log_size is 0. \ +The minimum value for this variable is 4096.", (gptr*) &max_binlog_size, (gptr*) &max_binlog_size, 0, GET_ULONG, - REQUIRED_ARG, 1024*1024L*1024L, 1024, 1024*1024L*1024L, 0, 1, 0}, + REQUIRED_ARG, 1024*1024L*1024L, IO_SIZE, 1024*1024L*1024L, 0, IO_SIZE, 0}, {"max_connections", OPT_MAX_CONNECTIONS, "The number of simultaneous clients allowed.", (gptr*) &max_connections, (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 16384, 0, 1, @@ -4184,6 +4242,15 @@ replicating a LOAD DATA INFILE command.", (gptr*) &global_system_variables.max_prep_stmt_count, (gptr*) &max_system_variables.max_prep_stmt_count, 0, GET_ULONG, REQUIRED_ARG, DEFAULT_PREP_STMT_COUNT, 0, ~0L, 0, 1, 0}, + {"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE, + "If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 expected, the minimum value for this variable is 4096.", + (gptr*) &max_relay_log_size, (gptr*) &max_relay_log_size, 0, GET_ULONG, + REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0}, + { "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY, + "Limit assumed max number of seeks when looking up rows based on a key", + (gptr*) &global_system_variables.max_seeks_for_key, + (gptr*) &max_system_variables.max_seeks_for_key, 0, GET_ULONG, + REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0 }, {"max_sort_length", OPT_MAX_SORT_LENGTH, "The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).", (gptr*) &global_system_variables.max_sort_length, @@ -4427,6 +4494,7 @@ struct show_var_st status_vars[]= { {"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG}, {"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG}, {"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG}, + {"Com_savepoint", (char*) (com_stat+(uint) SQLCOM_SAVEPOINT),SHOW_LONG}, {"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG}, {"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG}, {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG}, @@ -4578,8 +4646,8 @@ static void usage(void) puts("\ Copyright (C) 2000 MySQL AB, by Monty and others\n\ This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ -and you are welcome to modify and redistribute it under the GPL license\n\ -Starts the MySQL server\n"); +and you are welcome to modify and redistribute it under the GPL license\n\n\ +Starts the MySQL database server\n"); printf("Usage: %s [OPTIONS]\n", my_progname); if (!opt_verbose) @@ -4689,7 +4757,7 @@ static void mysql_init_variables(void) protocol_version= PROTOCOL_VERSION; what_to_log= ~ (1L << (uint) COM_TIME); refresh_version= flush_version= 1L; /* Increments on each reload */ - thread_id= 1L; + query_id= thread_id= 1L; strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; my_bind_addr = htonl(INADDR_ANY); @@ -4872,7 +4940,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), #endif case OPT_SAFEMALLOC_MEM_LIMIT: #if !defined(DBUG_OFF) && defined(SAFEMALLOC) - safemalloc_mem_limit = atoi(argument); + sf_malloc_mem_limit = atoi(argument); #endif break; #ifdef EMBEDDED_LIBRARY @@ -5028,10 +5096,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), table_rules_on = 1; break; } - case (int)OPT_RECKLESS_SLAVE: - opt_reckless_slave = 1; - init_slave_skip_errors("all"); - break; #endif /* HAVE_REPLICATION */ case (int) OPT_SLOW_QUERY_LOG: opt_slow_log=1; @@ -5376,6 +5440,12 @@ static void get_options(int argc,char **argv) have_symlink=SHOW_OPTION_DISABLED; } #endif + if (opt_debugging) + { + /* Allow break with SIGINT, no core or stack trace */ + test_flags|= TEST_SIGINT | TEST_NO_STACKTRACE; + test_flags&= ~TEST_CORE_ON_SIGNAL; + } /* Set global MyISAM variables from delay_key_write_options */ fix_delay_key_write((THD*) 0, OPT_GLOBAL); diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 9e9eaf9eea1..f12705572d6 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -28,6 +28,9 @@ Read packets are reallocated dynamicly when reading big packets. Each logical packet has the following pre-info: 3 byte length & 1 byte package-number. + + This file needs to be written in C as it's used by the libmysql client as a + C file. */ /* diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 935abac5146..839804b20d5 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2390,9 +2390,17 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref) if (!quick) return 0; + if (cp_buffer_from_ref(ref)) + { + if (current_thd->fatal_error) + return 0; // End of memory + return quick; // empty range + } + QUICK_RANGE *range= new QUICK_RANGE(); - if (!range || cp_buffer_from_ref(ref)) + if (!range) goto err; + range->min_key=range->max_key=(char*) ref->key_buff; range->min_length=range->max_length=ref->key_length; range->flag= ((ref->key_length == key_info->key_length && diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 60af9a92c76..e9c3b1ed0b0 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -72,6 +72,7 @@ static int init_failsafe_rpl_thread(THD* thd) if (init_thr_lock() || thd->store_globals()) { close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed? + statistic_increment(aborted_connects,&LOCK_status); end_thread(thd,0); DBUG_RETURN(-1); } @@ -867,7 +868,7 @@ int load_master_data(THD* thd) of LOAD DATA FROM MASTER - no reason to forbid it, really, although it does not make much sense for the user to do it */ - if (row[0] && row[1]) + if (row && row[0] && row[1]) { strmake(active_mi->master_log_name, row[0], sizeof(active_mi->master_log_name)); diff --git a/sql/set_var.cc b/sql/set_var.cc index 6a6e010578f..eebefc8b79c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -88,6 +88,8 @@ static void fix_query_cache_size(THD *thd, enum_var_type type); static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type); static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); +static void fix_max_binlog_size(THD *thd, enum_var_type type); +static void fix_max_relay_log_size(THD *thd, enum_var_type type); static KEY_CACHE *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); @@ -155,7 +157,8 @@ sys_var_thd_ulong sys_max_allowed_packet("max_allowed_packet", sys_var_long_ptr sys_max_binlog_cache_size("max_binlog_cache_size", &max_binlog_cache_size); sys_var_long_ptr sys_max_binlog_size("max_binlog_size", - &max_binlog_size); + &max_binlog_size, + fix_max_binlog_size); sys_var_long_ptr sys_max_connections("max_connections", &max_connections); sys_var_long_ptr sys_max_connect_errors("max_connect_errors", @@ -175,6 +178,8 @@ sys_var_pseudo_thread_id sys_pseudo_thread_id("pseudo_thread_id", sys_var_thd_ha_rows sys_max_join_size("max_join_size", &SV::max_join_size, fix_max_join_size); +sys_var_thd_ulong sys_max_seeks_for_key("max_seeks_for_key", + &SV::max_seeks_for_key); sys_var_thd_ulong sys_max_length_for_sort_data("max_length_for_sort_data", &SV::max_length_for_sort_data); #ifndef TO_BE_DELETED /* Alias for max_join_size */ @@ -184,6 +189,9 @@ sys_var_thd_ha_rows sys_sql_max_join_size("sql_max_join_size", #endif sys_var_thd_ulong sys_max_prep_stmt_count("max_prepared_statements", &SV::max_prep_stmt_count); +sys_var_long_ptr sys_max_relay_log_size("max_relay_log_size", + &max_relay_log_size, + fix_max_relay_log_size); sys_var_thd_ulong sys_max_sort_length("max_sort_length", &SV::max_sort_length); sys_var_long_ptr sys_max_user_connections("max_user_connections", @@ -318,7 +326,6 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", OPTION_RELAXED_UNIQUE_CHECKS, 1); - /* Local state variables */ static sys_var_thd_ha_rows sys_select_limit("sql_select_limit", @@ -409,6 +416,8 @@ sys_var *sys_variables[]= &sys_max_join_size, &sys_max_length_for_sort_data, &sys_max_prep_stmt_count, + &sys_max_relay_log_size, + &sys_max_seeks_for_key, &sys_max_sort_length, &sys_max_tmp_tables, &sys_max_user_connections, @@ -573,8 +582,9 @@ struct show_var_st init_vars[]= { {sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS}, {sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS}, {sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS}, - {sys_max_length_for_sort_data.name, - (char*) &sys_max_length_for_sort_data, + {sys_max_relay_log_size.name, (char*) &sys_max_relay_log_size, SHOW_SYS}, + {sys_max_seeks_for_key.name, (char*) &sys_max_seeks_for_key, SHOW_SYS}, + {sys_max_length_for_sort_data.name, (char*) &sys_max_length_for_sort_data, SHOW_SYS}, {sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS}, {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS}, @@ -807,6 +817,26 @@ void fix_delay_key_write(THD *thd, enum_var_type type) } } +void fix_max_binlog_size(THD *thd, enum_var_type type) +{ + DBUG_ENTER("fix_max_binlog_size"); + DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu", + max_binlog_size, max_relay_log_size)); + mysql_bin_log.set_max_size(max_binlog_size); + if (!max_relay_log_size) + active_mi->rli.relay_log.set_max_size(max_binlog_size); + DBUG_VOID_RETURN; +} + +void fix_max_relay_log_size(THD *thd, enum_var_type type) +{ + DBUG_ENTER("fix_max_relay_log_size"); + DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu", + max_binlog_size, max_relay_log_size)); + active_mi->rli.relay_log.set_max_size(max_relay_log_size ? + max_relay_log_size: max_binlog_size); + DBUG_VOID_RETURN; +} bool sys_var_long_ptr::update(THD *thd, set_var *var) { @@ -1060,6 +1090,11 @@ err: } +void sys_var_thd_conv_charset::set_default(THD *thd, enum_var_type type) +{ + thd->variables.convert_set= global_system_variables.convert_set; +} + bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) { diff --git a/sql/set_var.h b/sql/set_var.h index 968687ad382..f9c5d8f7822 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -167,6 +167,7 @@ public: return type != STRING_RESULT; /* Only accept strings */ } bool check_default(enum_var_type type) { return 0; } + void set_default(THD *thd, enum_var_type type); }; diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index b43c4b43b50..1beffa81671 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -247,6 +247,7 @@ v/* "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 2eb9e6d2219..c13141fc669 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -241,6 +241,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 2a663a176f8..b454566f3ba 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -249,6 +249,7 @@ "Foutieve toepassing/plaatsing van '%s'", "Deze versie van MySQL ondersteunt nog geen '%s'", "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index f4019d63055..5655ad32d3d 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -119,7 +119,7 @@ "Unknown character set: '%-.64s'", "Too many tables. MySQL can only use %d tables in a join", "Too many columns", -"Too big row size. The maximum row size, not counting BLOBs, is %d. You have to change some fields to TEXTs or BLOBs", +"Too big row size. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some fields to TEXT or BLOBs", "Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed", "Cross dependency found in OUTER JOIN. Examine your ON conditions", "Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL", @@ -238,6 +238,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index d3a38ede5bc..8e7a7121dfa 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -243,6 +243,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index ccff24c5759..8a6d786bee8 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -238,6 +238,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 52f3eb78c11..db20cc5dad9 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -247,6 +247,7 @@ "Falsche Verwendung oder Platzierung von '%s'", "Diese MySQL-Version unterstützt momentan nicht '%s'.", "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des Binary Logs.", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Falsche Foreign-Key Definition für '%-64s': %s", "Schlüssel- und Tabellenreferenz passen nicht zueinander.", "Kardinalitäts-Fehler (mehr/oder weniger als %d Spalten).", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 1ce052bdf22..f844ee59dab 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -238,6 +238,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 6143ea2a1c4..7e60515aace 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -240,6 +240,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8164757d823..a624d90661d 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -238,6 +238,7 @@ "Uso/posizione di '%s' sbagliato", "Questa versione di MySQL non supporta ancora '%s'", "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 747d3611cc9..b5693fe6e41 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -240,6 +240,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 93d86d32937..bc2d6eb9caa 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -238,6 +238,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index e9319246fc6..9bf0d4845c7 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -240,6 +240,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index edb5854db7e..4a025e7218f 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -240,6 +240,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 27b4d0d661f..1a6634fb96c 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -242,6 +242,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 60ace09ab33..99a940e62ab 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -238,6 +238,7 @@ "Uso/localização errada de '%s'", "Esta versão de MySQL não suporta ainda '%s'", "Obteve fatal error %d: '%-.128s' a partir do master quando lendo dados do binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Definição errada da chave estrangeira para '%-.64s': %s", "Referência da chave e referência da tabela não coincidem", "Error de cardinalidade (mais/menos que %d colunas)", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 8824d64876a..61591d54d40 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -242,6 +242,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index ddfc0a8f7de..b1876f83008 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -240,6 +240,7 @@ "îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÉÌÉ × ÎÅ×ÅÒÎÏÍ ÍÅÓÔÅ ÕËÁÚÁÎ '%s'", "üÔÁ ×ÅÒÓÉÑ MySQL ÐÏËÁ ÅÝÅ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ '%s'", "ðÏÌÕÞÅÎÁ ÎÅÉÓÐÒÁ×ÉÍÁÑ ÏÛÉÂËÁ %d: '%-.128s' ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ × ÐÒÏÃÅÓÓÅ ×ÙÂÏÒËÉ ÄÁÎÎÙÈ ÉÚ Ä×ÏÉÞÎÏÇÏ ÖÕÒÎÁÌÁ", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "ïÛÉÂËÁ ÍÏÝØÎÏÓÔÉ ÍÎÏÖÅÓÔ×Á (ÂÏÌØÛÅ/ÍÅÎØÛÅ %d ËÏÌÏÎÏË)", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index ed1d8cadb80..a96d512cb72 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -246,6 +246,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 5f3a2f38109..df18b8bf7f0 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -212,14 +212,14 @@ "Bloqueos de actualización no pueden ser adqueridos durante una transición READ UNCOMMITTED", "DROP DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global", "CREATE DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global", -"Wrong arguments to %s", -"'%-.32s'@'%-.64s' is not allowed to create new users", -"Incorrect table definition; all MERGE tables must be in the same database", -"Deadlock found when trying to get lock; Try restarting transaction", -"The used table type doesn't support FULLTEXT indexes", -"Cannot add foreign key constraint", -"Cannot add a child row: a foreign key constraint fails", -"Cannot delete a parent row: a foreign key constraint fails", +"Argumentos errados para %s", +"'%-.32s`@`%-.64s` no es permitido para crear nuevos usuarios", +"Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos", +"Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición", +"El tipo de tabla usada no soporta índices FULLTEXT", +"No puede adicionar clave extranjera constraint", +"No puede adicionar una línea hijo: falla de clave extranjera constraint", +"No puede deletar una línea padre: falla de clave extranjera constraint", "Error de coneccion a master: %-128s", "Error executando el query en master: %-128%", "Error de %s: %-128%", @@ -239,6 +239,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index d108618834e..07187f7ca34 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -237,7 +237,8 @@ "Variabeln '%-.64s' kan endast sättas, inte läsas", "Fel använding/placering av '%s'", "Denna version av MySQL kan ännu inte utföra '%s'", -"Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen" +"Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen", +"Slav SQL tråden ignorerade frågan pga en replicate-*-table regel", "Felaktig FOREIGN KEY-definition för '%-.64s': %s", "Nyckelreferensen och tabellreferensen stämmer inte överens", "Kardinalitetsfel (fler/färre än %d kolumner)", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 96b9f40feac..a0604ba862c 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -243,6 +243,7 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Slave SQL thread ignored the query because of replicate-*-table rules", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (¦ÌØÛÅ/ÍÅÎØÛÅ Î¦Ö %d ÓÔÏ×Âæ×)", diff --git a/sql/slave.cc b/sql/slave.cc index 37979576b73..a6c86b08010 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -74,7 +74,6 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table); static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, const char* table_name); static int check_master_version(MYSQL* mysql, MASTER_INFO* mi); -char* rewrite_db(char* db); /* @@ -139,6 +138,8 @@ int init_slave() { DBUG_ENTER("init_slave"); + /* This is called when mysqld starts */ + /* TODO: re-write this to interate through the list of files for multi-master @@ -150,11 +151,16 @@ int init_slave() If master_host is specified, create the master_info file if it doesn't exists. */ - if (!active_mi || - init_master_info(active_mi,master_info_file,relay_log_info_file, + if (!active_mi) + { + sql_print_error("Failed to allocate memory for the master info structure"); + goto err; + } + + if (init_master_info(active_mi,master_info_file,relay_log_info_file, !master_host)) { - sql_print_error("Note: Failed to initialized master info"); + sql_print_error("Failed to initialize the master info structure"); goto err; } @@ -174,7 +180,7 @@ int init_slave() relay_log_info_file, SLAVE_IO | SLAVE_SQL)) { - sql_print_error("Warning: Can't create threads to handle slave"); + sql_print_error("Failed to create slave threads"); goto err; } } @@ -300,6 +306,7 @@ err: pthread_cond_broadcast(&rli->data_cond); if (need_data_lock) pthread_mutex_unlock(&rli->data_lock); + pthread_mutex_unlock(log_lock); DBUG_RETURN ((*errmsg) ? 1 : 0); } @@ -380,7 +387,10 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, rli->group_master_log_pos= 0; if (!rli->inited) + { + DBUG_PRINT("info", ("rli->inited == 0")); DBUG_RETURN(0); + } DBUG_ASSERT(rli->slave_running == 0); DBUG_ASSERT(rli->mi->slave_running == 0); @@ -872,15 +882,38 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli) } +/* + Writes an error message to rli->last_slave_error and rli->last_slave_errno + (which will be displayed by SHOW SLAVE STATUS), and prints it to stderr. + + SYNOPSIS + slave_print_error() + rli + err_code The error code + msg The error message (usually related to the error code, but can + contain more information). + ... (this is printf-like format, with % symbols in msg) + + RETURN VALUES + void +*/ + void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...) { va_list args; va_start(args,msg); my_vsnprintf(rli->last_slave_error, sizeof(rli->last_slave_error), msg, args); - sql_print_error("Slave: %s, error_code=%d", rli->last_slave_error, - err_code); rli->last_slave_errno = err_code; + /* If the error string ends with '.', do not add a ',' it would be ugly */ + if (rli->last_slave_error[0] && + (*(strend(rli->last_slave_error)-1) == '.')) + sql_print_error("Slave: %s Error_code: %d", rli->last_slave_error, + err_code); + else + sql_print_error("Slave: %s, Error_code: %d", rli->last_slave_error, + err_code); + } /* @@ -905,7 +938,7 @@ bool net_request_file(NET* net, const char* fname) } -char* rewrite_db(char* db) +const char *rewrite_db(const char* db) { if (replicate_rewrite_db.is_empty() || !db) return db; @@ -920,6 +953,17 @@ char* rewrite_db(char* db) return db; } +/* + From other comments and tests in code, it looks like + sometimes Query_log_event and Load_log_event can have db == 0 + (see rewrite_db() above for example) + (cases where this happens are unclear; it may be when the master is 3.23). +*/ + +const char *print_slave_db_safe(const char* db) +{ + return (db ? rewrite_db(db) : ""); +} /* Checks whether a db matches some do_db and ignore_db rules @@ -1027,13 +1071,19 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi) { const char* errmsg= 0; + /* + Note the following switch will bug when we have MySQL branch 30 ;) + */ switch (*mysql->server_version) { case '3': - mi->old_format = 1; + mi->old_format = + (strncmp(mysql->server_version, "3.23.57", 7) < 0) /* < .57 */ ? + BINLOG_FORMAT_323_LESS_57 : + BINLOG_FORMAT_323_GEQ_57 ; break; case '4': case '5': - mi->old_format = 0; + mi->old_format = BINLOG_FORMAT_CURRENT; break; default: errmsg = "Master reported unrecognized MySQL version"; @@ -1246,11 +1296,55 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) strmov(strcend(tmp,'.'),"-relay-bin"); opt_relay_logname=my_strdup(tmp,MYF(MY_WME)); } + + /* + The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE. It is + notable that the last kilobytes of it (8 kB for example) may live in + memory, not on disk (depending on what the thread using it does). While + this is efficient, it has a side-effect one must know: + The size of the relay log on disk (displayed by 'ls -l' on Unix) can be a + few kilobytes less than one would expect by doing SHOW SLAVE STATUS; this + happens when only the IO thread is started (not the SQL thread). The + "missing" kilobytes are in memory, are preserved during 'STOP SLAVE; START + SLAVE IO_THREAD', and are flushed to disk when the slave's mysqld stops. So + this does not cause any bug. Example of how disk size grows by leaps: + + Read_Master_Log_Pos: 7811 -rw-rw---- 1 guilhem qq 4 Jun 5 16:19 gbichot2-relay-bin.002 + ...later... + Read_Master_Log_Pos: 9744 -rw-rw---- 1 guilhem qq 8192 Jun 5 16:27 gbichot2-relay-bin.002 + + See how 4 is less than 7811 and 8192 is less than 9744. + + WARNING: this is risky because the slave can stay like this for a long + time; then if it has a power failure, master.info says the I/O thread has + read until 9744 while the relay-log contains only until 8192 (the + in-memory part from 8192 to 9744 has been lost), so the SQL slave thread + will miss some events, silently breaking replication. + Ideally we would like to flush master.info only when we know that the relay + log has no in-memory tail. + Note that the above problem may arise only when only the IO thread is + started, which is unlikely. + */ + + /* + For the maximum log size, we choose max_relay_log_size if it is + non-zero, max_binlog_size otherwise. If later the user does SET + GLOBAL on one of these variables, fix_max_binlog_size and + fix_max_relay_log_size will reconsider the choice (for example + if the user changes max_relay_log_size to zero, we have to + switch to using max_binlog_size for the relay log) and update + rli->relay_log.max_size (and mysql_bin_log.max_size). + */ + if (open_log(&rli->relay_log, glob_hostname, opt_relay_logname, "-relay-bin", opt_relaylog_index_name, LOG_BIN, 1 /* read_append cache */, - 1 /* no auto events */)) + 1 /* no auto events */, + max_relay_log_size ? max_relay_log_size : max_binlog_size)) + { + sql_print_error("Failed in open_log() called from init_relay_log_info()"); DBUG_RETURN(1); + } /* if file does not exist */ if (access(fname,F_OK)) @@ -1261,10 +1355,18 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) */ if (info_fd >= 0) my_close(info_fd, MYF(MY_WME)); - if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 || - init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, - MYF(MY_WME))) + if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { + sql_print_error("Failed to create a new relay log info file (\ +file '%s', errno %d)", fname, my_errno); + msg= current_thd->net.last_error; + goto err; + } + if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, + MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on relay log info file '%s'", + fname); msg= current_thd->net.last_error; goto err; } @@ -1272,7 +1374,10 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) /* Init relay log with first entry in the relay index file */ if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */, &msg)) + { + sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4"); goto err; + } rli->group_master_log_name[0]= 0; rli->group_master_log_pos= 0; rli->info_fd= info_fd; @@ -1281,18 +1386,34 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) { if (info_fd >= 0) reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0); - else if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 || - init_io_cache(&rli->info_file, info_fd, - IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME))) + else { - if (info_fd >= 0) - my_close(info_fd, MYF(0)); - rli->info_fd= -1; - rli->relay_log.close(1); - pthread_mutex_unlock(&rli->data_lock); - DBUG_RETURN(1); + int error=0; + if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) + { + sql_print_error("\ +Failed to open the existing relay log info file '%s' (errno %d)", + fname, my_errno); + error= 1; + } + else if (init_io_cache(&rli->info_file, info_fd, + IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on relay log info file '%s'", + fname); + error= 1; + } + if (error) + { + if (info_fd >= 0) + my_close(info_fd, MYF(0)); + rli->info_fd= -1; + rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); + pthread_mutex_unlock(&rli->data_lock); + DBUG_RETURN(1); + } } - + rli->info_fd = info_fd; int relay_log_pos, master_log_pos; if (init_strvar_from_file(rli->group_relay_log_name, @@ -1318,7 +1439,12 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) rli->group_relay_log_pos, 0 /* no data lock*/, &msg)) + { + char llbuf[22]; + sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)", + rli->relay_log_name, llstr(rli->relay_log_pos, llbuf)); goto err; + } } DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE); DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos); @@ -1327,7 +1453,8 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) before flush_relay_log_info */ reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1); - error= flush_relay_log_info(rli); + if ((error= flush_relay_log_info(rli))) + sql_print_error("Failed to flush relay log info file"); if (count_relay_log_space(rli)) { msg="Error counting relay log space"; @@ -1343,7 +1470,7 @@ err: if (info_fd >= 0) my_close(info_fd, MYF(0)); rli->info_fd= -1; - rli->relay_log.close(1); + rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); pthread_mutex_unlock(&rli->data_lock); DBUG_RETURN(1); } @@ -1372,7 +1499,7 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) { bool slave_killed=0; MASTER_INFO* mi = rli->mi; - const char* save_proc_info; + const char *save_proc_info; THD* thd = mi->io_thd; DBUG_ENTER("wait_for_relay_log_space"); @@ -1380,12 +1507,14 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) pthread_mutex_lock(&rli->log_space_lock); save_proc_info = thd->proc_info; thd->proc_info = "Waiting for relay log space to free"; - + save_proc_info= thd->enter_cond(&rli->log_space_cond, + &rli->log_space_lock, + "Waiting for relay log space to free"); while (rli->log_space_limit < rli->log_space_total && !(slave_killed=io_slave_killed(thd,mi)) && !rli->ignore_log_space_limit) pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock); - thd->proc_info = save_proc_info; + thd->exit_cond(save_proc_info); pthread_mutex_unlock(&rli->log_space_lock); DBUG_RETURN(slave_killed); } @@ -1406,9 +1535,36 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli) if (add_relay_log(rli,&linfo)) DBUG_RETURN(1); } while (!rli->relay_log.find_next_log(&linfo, 1)); + /* + As we have counted everything, including what may have written in a + preceding write, we must reset bytes_written, or we may count some space + twice. + */ + rli->relay_log.reset_bytes_written(); DBUG_RETURN(0); } +void init_master_info_with_options(MASTER_INFO* mi) +{ + mi->master_log_name[0] = 0; + mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number + + if (master_host) + strmake(mi->host, master_host, sizeof(mi->host) - 1); + if (master_user) + strmake(mi->user, master_user, sizeof(mi->user) - 1); + if (master_password) + strmake(mi->password, master_password, HASH_PASSWORD_LENGTH); + mi->port = master_port; + mi->connect_retry = master_connect_retry; +} + +void clear_last_slave_error(RELAY_LOG_INFO* rli) +{ + //Clear the errors displayed by SHOW SLAVE STATUS + rli->last_slave_error[0]=0; + rli->last_slave_errno=0; +} int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, @@ -1431,6 +1587,8 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, pthread_mutex_lock(&mi->data_lock); fd = mi->fd; + + /* does master.info exist ? */ if (access(fname,F_OK)) { @@ -1445,32 +1603,44 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, */ if (fd >= 0) my_close(fd, MYF(MY_WME)); - if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 || - init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0, + if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) + { + sql_print_error("Failed to create a new master info file (\ +file '%s', errno %d)", fname, my_errno); + goto err; + } + if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0, MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on master info file (\ +file '%s')", fname); goto err; + } - mi->master_log_name[0] = 0; - mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number mi->fd = fd; - - if (master_host) - strmake(mi->host, master_host, sizeof(mi->host) - 1); - if (master_user) - strmake(mi->user, master_user, sizeof(mi->user) - 1); - if (master_password) - strmake(mi->password, master_password, HASH_PASSWORD_LENGTH); - mi->port = master_port; - mi->connect_retry = master_connect_retry; + init_master_info_with_options(mi); + } else // file exists { if (fd >= 0) reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0); - else if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 || - init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L, - 0, MYF(MY_WME))) - goto err; + else + { + if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) + { + sql_print_error("Failed to open the existing master info file (\ +file '%s', errno %d)", fname, my_errno); + goto err; + } + if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L, + 0, MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on master info file (\ +file '%s')", fname); + goto err; + } + } mi->fd = fd; int port, connect_retry, master_log_pos; @@ -1511,7 +1681,8 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, mi->inited = 1; // now change cache READ -> WRITE - must do this before flush_master_info reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1); - error=test(flush_master_info(mi)); + if ((error=test(flush_master_info(mi)))) + sql_print_error("Failed to flush master info file"); pthread_mutex_unlock(&mi->data_lock); DBUG_RETURN(error); @@ -1653,6 +1824,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi) if (mi->host[0]) { + DBUG_PRINT("info",("host is set: '%s'", mi->host)); String *packet= &thd->packet; protocol->prepare_for_resend(); @@ -1732,8 +1904,8 @@ st_relay_log_info::st_relay_log_info() group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0; last_slave_error[0]=0; - bzero(&info_file,sizeof(info_file)); - bzero(&cache_buf, sizeof(cache_buf)); + bzero((char*) &info_file, sizeof(info_file)); + bzero((char*) &cache_buf, sizeof(cache_buf)); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST); @@ -1741,6 +1913,7 @@ st_relay_log_info::st_relay_log_info() pthread_cond_init(&start_cond, NULL); pthread_cond_init(&stop_cond, NULL); pthread_cond_init(&log_space_cond, NULL); + relay_log.init_pthread_objects(); } @@ -1799,11 +1972,17 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, pthread_mutex_lock(&data_lock); /* - This function will abort when it notices that - some CHANGE MASTER or RESET MASTER has changed - the master info. To catch this, these commands - modify abort_pos_wait ; we just monitor abort_pos_wait - and see if it has changed. + This function will abort when it notices that some CHANGE MASTER or + RESET MASTER has changed the master info. + To catch this, these commands modify abort_pos_wait ; We just monitor + abort_pos_wait and see if it has changed. + Why do we have this mechanism instead of simply monitoring slave_running + in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that + the SQL thread be stopped? + This is becasue if someones does: + STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE; + the change may happen very quickly and we may not notice that + slave_running briefly switches between 1/0/1. */ init_abort_pos_wait= abort_pos_wait; @@ -1824,7 +2003,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, error= -2; //means improper arguments goto err; } - //p points to '.' + /* p points to '.' */ log_name_extension= strtoul(++p, &p_end, 10); /* p_end points to the first invalid character. @@ -1837,10 +2016,10 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, goto err; } - //"compare and wait" main loop + /* The "compare and wait" main loop */ while (!thd->killed && init_abort_pos_wait == abort_pos_wait && - mi->slave_running) + slave_running) { bool pos_reached; int cmp_result= 0; @@ -1878,6 +2057,10 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, DBUG_PRINT("info",("Waiting for master update")); const char* msg = thd->enter_cond(&data_cond, &data_lock, "Waiting for master update"); + /* + We are going to pthread_cond_(timed)wait(); if the SQL thread stops it + will wake us up. + */ if (timeout > 0) { /* @@ -1895,6 +2078,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, } else pthread_cond_wait(&data_cond, &data_lock); + DBUG_PRINT("info",("Got signal of master update")); thd->exit_cond(msg); if (error == ETIMEDOUT || error == ETIME) { @@ -1903,6 +2087,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, } error=0; event_count++; + DBUG_PRINT("info",("Testing if killed or SQL thread not running")); } err: @@ -1911,11 +2096,11 @@ err: improper_arguments: %d timed_out: %d", (int) thd->killed, (int) (init_abort_pos_wait != abort_pos_wait), - (int) mi->slave_running, + (int) slave_running, (int) (error == -2), (int) (error == -1))); if (thd->killed || init_abort_pos_wait != abort_pos_wait || - !mi->slave_running) + !slave_running) { error= -2; } @@ -2137,14 +2322,13 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error) case ER_NET_ERROR_ON_WRITE: case ER_SERVER_SHUTDOWN: case ER_NEW_ABORTING_CONNECTION: - my_snprintf(rli->last_slave_error, sizeof(rli->last_slave_error), - "Slave: query '%s' partially completed on the master \ + slave_print_error(rli,expected_error, + "query '%s' partially completed on the master \ and was aborted. There is a chance that your master is inconsistent at this \ point. If you are sure that your master is ok, run this query manually on the\ slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;\ - SLAVE START;", thd->query); - rli->last_slave_errno = expected_error; - sql_print_error("%s",rli->last_slave_error); + SLAVE START; .", thd->query); + thd->query_error= 1; return 1; default: return 0; @@ -2158,8 +2342,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) DBUG_ASSERT(rli->sql_thd==thd); if (sql_slave_killed(thd,rli)) { - /* do not forget to free ev ! */ - if (ev) delete ev; + delete ev; return 1; } if (ev) @@ -2453,6 +2636,17 @@ reconnect done to recover from failed read"); for no reason, but this function will do a clean read, notice the clean value and exit immediately. */ +#ifndef DBUG_OFF + { + char llbuf1[22], llbuf2[22]; + DBUG_PRINT("info", ("log_space_limit=%s log_space_total=%s \ +ignore_log_space_limit=%d", + llstr(mi->rli.log_space_limit,llbuf1), + llstr(mi->rli.log_space_total,llbuf2), + (int) mi->rli.ignore_log_space_limit)); + } +#endif + if (mi->rli.log_space_limit && mi->rli.log_space_limit < mi->rli.log_space_total && !mi->rli.ignore_log_space_limit) @@ -2565,6 +2759,13 @@ slave_begin: pthread_mutex_unlock(&rli->run_lock); pthread_cond_broadcast(&rli->start_cond); + /* + Reset errors for a clean start (otherwise, if the master is idle, the SQL + thread may execute no Query_log_event, so the error will remain even + though there's no problem anymore). + */ + clear_last_slave_error(rli); + //tell the I/O thread to take relay_log_space_limit into account from now on pthread_mutex_lock(&rli->log_space_lock); rli->ignore_log_space_limit= 0; @@ -2624,8 +2825,16 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->proc_info = "Waiting for slave mutex on exit"; pthread_mutex_lock(&rli->run_lock); + /* We need data_lock, at least to wake up any waiting master_pos_wait() */ + pthread_mutex_lock(&rli->data_lock); DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun - rli->slave_running = 0; + /* When master_pos_wait() wakes up it will check this and terminate */ + rli->slave_running= 0; + /* Wake up master_pos_wait() */ + pthread_mutex_unlock(&rli->data_lock); + DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions")); + pthread_cond_broadcast(&rli->data_cond); + rli->ignore_log_space_limit= 0; /* don't need any lock */ rli->save_temporary_tables = thd->temporary_tables; /* @@ -3010,7 +3219,7 @@ void end_relay_log_info(RELAY_LOG_INFO* rli) rli->cur_log_fd = -1; } rli->inited = 0; - rli->relay_log.close(1); + rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); DBUG_VOID_RETURN; } @@ -3273,8 +3482,22 @@ Log_event* next_event(RELAY_LOG_INFO* rli) hot_log=0; // Using old binary log } } - DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE); - DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos); +#ifndef DBUG_OFF + { + char llbuf1[22], llbuf2[22]; + DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE); + /* + The next assertion sometimes (very rarely) fails, let's try to track + it + */ + DBUG_PRINT("info", ("\ +Before assert, my_b_tell(cur_log)=%s rli->relay_log_pos=%s rli->pending=%lu", + llstr(my_b_tell(cur_log),llbuf1), + llstr(rli->relay_log_pos,llbuf2), + rli->pending)); + DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos); + } +#endif /* Relay log is always in new format - if the master is 3.23, the I/O thread will convert the format for us @@ -3334,8 +3557,8 @@ Log_event* next_event(RELAY_LOG_INFO* rli) log), and also when the SQL thread starts. We should also reset ignore_log_space_limit to 0 when the user does RESET SLAVE, but in fact, no need as RESET SLAVE requires that the slave - be stopped, and when the SQL thread is later restarted - ignore_log_space_limit will be reset to 0. + be stopped, and the SQL thread sets ignore_log_space_limit to 0 when + it stops. */ pthread_mutex_lock(&rli->log_space_lock); // prevent the I/O thread from blocking next times @@ -3466,6 +3689,53 @@ err: DBUG_RETURN(0); } +/* + Rotate a relay log (this is used only by FLUSH LOGS; the automatic rotation + because of size is simpler because when we do it we already have all relevant + locks; here we don't, so this function is mainly taking locks). + Returns nothing as we cannot catch any error (MYSQL_LOG::new_file() is void). +*/ + +void rotate_relay_log(MASTER_INFO* mi) +{ + DBUG_ENTER("rotate_relay_log"); + RELAY_LOG_INFO* rli= &mi->rli; + + lock_slave_threads(mi); + pthread_mutex_lock(&rli->data_lock); + /* + We need to test inited because otherwise, new_file() will attempt to lock + LOCK_log, which may not be inited (if we're not a slave). + */ + if (!rli->inited) + { + DBUG_PRINT("info", ("rli->inited == 0")); + goto end; + } + + /* If the relay log is closed, new_file() will do nothing. */ + rli->relay_log.new_file(1); + + /* + We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately + be counted, so imagine a succession of FLUSH LOGS and assume the slave + threads are started: + relay_log_space decreases by the size of the deleted relay log, but does + not increase, so flush-after-flush we may become negative, which is wrong. + Even if this will be corrected as soon as a query is replicated on the + slave (because the I/O thread will then call harvest_bytes_written() which + will harvest all these BIN_LOG_HEADER_SIZE we forgot), it may give strange + output in SHOW SLAVE STATUS meanwhile. So we harvest now. + If the log is closed, then this will just harvest the last writes, probably + 0 as they probably have been harvested. + */ + rli->relay_log.harvest_bytes_written(&rli->log_space_total); +end: + pthread_mutex_unlock(&rli->data_lock); + unlock_slave_threads(mi); + DBUG_VOID_RETURN; +} + #ifdef __GNUC__ template class I_List_iterator<i_string>; diff --git a/sql/slave.h b/sql/slave.h index 668fff52d08..0cd291a50f8 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -47,6 +47,11 @@ extern "C" { extern ulong slave_net_timeout; }; +enum enum_binlog_formats { + BINLOG_FORMAT_CURRENT=0, /* 0 is important for easy 'if (mi->old_format)' */ + BINLOG_FORMAT_323_LESS_57, + BINLOG_FORMAT_323_GEQ_57 }; + /* TODO: this needs to be redone, but for now it does not matter since we do not have multi-master yet. @@ -284,20 +289,20 @@ Log_event* next_event(RELAY_LOG_INFO* rli); typedef struct st_master_info { char master_log_name[FN_REFLEN]; + char host[HOSTNAME_LENGTH+1]; + char user[USERNAME_LENGTH+1]; + char password[MAX_PASSWORD_LENGTH+1]; my_off_t master_log_pos; File fd; // we keep the file open, so we need to remember the file pointer IO_CACHE file; /* the variables below are needed because we can change masters on the fly */ - char host[HOSTNAME_LENGTH+1]; - char user[USERNAME_LENGTH+1]; - char password[HASH_PASSWORD_LENGTH+1]; pthread_mutex_t data_lock,run_lock; pthread_cond_t data_cond,start_cond,stop_cond; THD *io_thd; MYSQL* mysql; - uint32 file_id; /* for 3.23 load data infile */ + uint32 file_id; /* for 3.23 load data infile */ RELAY_LOG_INFO rli; uint port; uint connect_retry; @@ -305,16 +310,16 @@ typedef struct st_master_info int events_till_abort; #endif bool inited; - bool old_format; /* master binlog is in 3.23 format */ + enum enum_binlog_formats old_format; volatile bool abort_slave, slave_running; volatile ulong slave_run_id; st_master_info() - :fd(-1), io_thd(0), inited(0), old_format(0),abort_slave(0), - slave_running(0), slave_run_id(0) + :fd(-1), io_thd(0), inited(0), old_format(BINLOG_FORMAT_CURRENT), + abort_slave(0),slave_running(0), slave_run_id(0) { host[0] = 0; user[0] = 0; password[0] = 0; - bzero(&file, sizeof(file)); + bzero((char*) &file, sizeof(file)); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); pthread_cond_init(&data_cond, NULL); @@ -418,12 +423,15 @@ int add_table_rule(HASH* h, const char* table_spec); int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); void init_table_rule_hash(HASH* h, bool* h_inited); void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited); -char* rewrite_db(char* db); +const char *rewrite_db(const char* db); +const char *print_slave_db_safe(const char* db); int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code); void skip_load_data_infile(NET* net); -void slave_print_error(RELAY_LOG_INFO* rli,int err_code, const char* msg, ...); +void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...); void end_slave(); /* clean up */ +void init_master_info_with_options(MASTER_INFO* mi); +void clear_last_slave_error(RELAY_LOG_INFO* rli); int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, bool abort_if_no_master_info_file); @@ -438,6 +446,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos, int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, const char** errmsg); +void rotate_relay_log(MASTER_INFO* mi); extern "C" pthread_handler_decl(handle_slave_io,arg); extern "C" pthread_handler_decl(handle_slave_sql,arg); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 54a0ee05db2..08212bbf65b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* 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 @@ -155,7 +155,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) host.db= get_field(&mem, table->field[1]); host.access= get_access(table,2); host.access= fix_rights_for_db(host.access); - host.sort= get_sort(2,host.host.hostname,host.db); + host.sort= get_sort(2,host.host.hostname,host.db); #ifndef TO_BE_REMOVED if (table->fields == 8) { // Without grant @@ -175,8 +175,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) if (table->field[2]->field_length == 8 && protocol_version == PROTOCOL_VERSION) { - sql_print_error( - "Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */ + sql_print_error("Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */ protocol_version=9; /* purecov: tested */ } @@ -207,10 +206,11 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { user.pversion=get_password_version(user.password); /* Only passwords of specific lengths depending on version are allowed */ - if ( (!user.pversion && length % 8) || (user.pversion && length!=45 )) + if ((!user.pversion && (length % 8 || length > 16)) || + (user.pversion && length != 45)) { sql_print_error( - "Found invalid password for user: '%s@%s'; Ignoring user", + "Found invalid password for user: '%s'@'%s'; Ignoring user", user.user ? user.user : "", user.host.hostname ? user.host.hostname : ""); /* purecov: tested */ continue; /* purecov: tested */ @@ -221,7 +221,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) 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 */ + if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ { char *ssl_type=get_field(&mem, table->field[24]); if (!ssl_type) @@ -250,7 +250,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) else { user.ssl_type=SSL_TYPE_NONE; - bzero(&(user.user_resource),sizeof(user.user_resource)); + bzero((char *)&(user.user_resource),sizeof(user.user_resource)); #ifndef TO_BE_REMOVED if (table->fields <= 13) { // Without grant @@ -342,7 +342,14 @@ void acl_free(bool end) } } - /* Reload acl list if possible */ + +/* + Forget current privileges and read new privileges from the privilege tables + + SYNOPSIS + acl_reload() + thd Thread handle +*/ void acl_reload(THD *thd) { @@ -507,7 +514,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, ACL_USER *acl_user= NULL; DBUG_ENTER("acl_getroot"); - bzero(mqh,sizeof(USER_RESOURCES)); + bzero((char*) mqh, sizeof(USER_RESOURCES)); if (!initialized) { // If no data allow anything @@ -616,7 +623,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, We need to check for absence of SSL because without SSL we should reject connection. */ - if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_)) + if (vio_type(vio) == VIO_TYPE_SSL && + SSL_get_verify_result(vio->ssl_) == X509_V_OK && + SSL_get_peer_certificate(vio->ssl_)) user_access=acl_user->access; break; case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */ @@ -626,7 +635,8 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, If cipher name is specified, we compare it to actual cipher in use. */ - if (vio_type(vio) != VIO_TYPE_SSL) + if (vio_type(vio) != VIO_TYPE_SSL || + SSL_get_verify_result(vio->ssl_) != X509_V_OK) break; if (acl_user->ssl_cipher) { @@ -687,9 +697,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, } break; #else /* HAVE_OPENSSL */ - default: + default: /* - If we don't have SSL but SSL is required for this user the + If we don't have SSL but SSL is required for this user the authentication should fail. */ break; @@ -787,7 +797,7 @@ static void acl_insert_user(const char *user, const char *host, ulong privileges) { ACL_USER acl_user; - acl_user.user=strdup_root(&mem,user); + acl_user.user=*user ? strdup_root(&mem,user) : 0; update_hostname(&acl_user.host,strdup_root(&mem,host)); acl_user.password=0; acl_user.access=privileges; @@ -878,9 +888,10 @@ static void acl_insert_db(const char *user, const char *host, const char *db, } -/***************************************************************************** -** Get privilege for a host, user and db combination -*****************************************************************************/ + +/* + Get privilege for a host, user and db combination +*/ ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db, my_bool db_is_pattern) @@ -1003,11 +1014,14 @@ int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr) DBUG_RETURN (*str != '\0'); } -/***************************************************************************** -** check if there are any possible matching entries for this host -** All host names without wild cards are stored in a hash table, -** entries with wildcards are stored in a dynamic array -*****************************************************************************/ + +/* + Check if there are any possible matching entries for this host + + NOTES + All host names without wild cards are stored in a hash table, + entries with wildcards are stored in a dynamic array +*/ static void init_check_host(void) { @@ -1081,10 +1095,6 @@ bool acl_check_host(const char *host, const char *ip) return 1; // Host is not allowed } -/***************************************************************************** - Change password for the user if it's not an anonymous user - Note: This should write the error directly to the client! -*****************************************************************************/ /* Check if the user is allowed to change password @@ -1096,8 +1106,8 @@ bool acl_check_host(const char *host, const char *ip) user user name RETURN VALUE - 0 OK - 1 ERROR ; In this case the error is sent to the client. + 0 OK + 1 ERROR ; In this case the error is sent to the client. */ bool check_change_password(THD *thd, const char *host, const char *user) @@ -1212,7 +1222,11 @@ find_acl_user(const char *host, const char *user) { ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),", - user,acl_user->user,(host),(acl_user->host))); + user, + acl_user->user ? acl_user->user : "", + host, + acl_user->host.hostname ? acl_user->host.hostname : + "")); if (!acl_user->user && !user[0] || acl_user->user && !strcmp(user,acl_user->user)) { @@ -1225,15 +1239,18 @@ find_acl_user(const char *host, const char *user) DBUG_RETURN(0); } -/***************************************************************************** - Handle comparing of hostname - A hostname may be of type: - hostname (May include wildcards); monty.pp.sci.fi - ip (May include wildcards); 192.168.0.0 - ip/netmask 192.168.0.0/255.255.255.0 - A net mask of 0.0.0.0 is not allowed. -*****************************************************************************/ +/* + Comparing of hostnames + + NOTES + A hostname may be of type: + hostname (May include wildcards); monty.pp.sci.fi + ip (May include wildcards); 192.168.0.0 + ip/netmask 192.168.0.0/255.255.255.0 + + A net mask of 0.0.0.0 is not allowed. +*/ static const char *calc_ip(const char *ip, long *val, char end) { @@ -1281,9 +1298,9 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, } -/**************************************************************************** - Code to update grants in the user and database privilege tables -****************************************************************************/ +/* + Update grants in the user and database privilege tables +*/ static bool update_user_table(THD *thd, const char *host, const char *user, const char *new_password) @@ -1297,6 +1314,24 @@ static bool update_user_table(THD *thd, const char *host, const char *user, bzero((char*) &tables,sizeof(tables)); tables.alias=tables.real_name=(char*) "user"; tables.db=(char*) "mysql"; +#ifdef HAVE_REPLICATION + /* + GRANT and REVOKE are applied the slave in/exclusion rules as they are + some kind of updates to the mysql.% tables. + */ + if (thd->slave_thread && table_rules_on) + { + /* + The tables must be marked "updating" so that tables_ok() takes them into + account in tests. It's ok to leave 'updating' set after tables_ok. + */ + tables.updating= 1; + /* Thanks to bzero, tables.next==0 */ + if (!tables_ok(0, &tables)) + DBUG_RETURN(0); + } +#endif + if (!(table=open_ltable(thd,&tables,TL_WRITE))) DBUG_RETURN(1); /* purecov: deadcode */ table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1); @@ -1349,7 +1384,7 @@ static bool test_if_create_new_users(THD *thd) /**************************************************************************** -** Handle GRANT commands + Handle GRANT commands ****************************************************************************/ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, @@ -1372,8 +1407,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, && combo.password.length != HASH_OLD_PASSWORD_LENGTH) { my_printf_error(ER_PASSWORD_NO_MATCH, - "Password hash should be a %d-digit hexadecimal number", - MYF(0),HASH_PASSWORD_LENGTH); + "Password hash should be a %d-digit hexadecimal number", + MYF(0),HASH_PASSWORD_LENGTH); DBUG_RETURN(-1); } password=combo.password.str; @@ -1546,7 +1581,7 @@ static int replace_db_table(TABLE *table, const char *db, char what= (revoke_grant) ? 'N' : 'Y'; DBUG_ENTER("replace_db_table"); - // is there such a user in user table in memory ???? + /* Check if there is such a user in user table in memory? */ if (!initialized || !find_acl_user(combo.host.str,combo.user.str)) { my_error(ER_PASSWORD_NO_MATCH,MYF(0)); @@ -1558,7 +1593,7 @@ static int replace_db_table(TABLE *table, const char *db, table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); table->file->index_init(0); if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0, - HA_READ_KEY_EXACT)) + HA_READ_KEY_EXACT)) { if (what == 'N') { // no row, no revoke @@ -1589,7 +1624,7 @@ static int replace_db_table(TABLE *table, const char *db, if (old_row_exists) { - // update old existing row + /* update old existing row */ if (rights) { if ((error=table->file->update_row(table->record[1],table->record[0]))) @@ -1616,11 +1651,11 @@ static int replace_db_table(TABLE *table, const char *db, DBUG_RETURN(0); /* This could only happen if the grant tables got corrupted */ - table_error: +table_error: table->file->print_error(error,MYF(0)); /* purecov: deadcode */ table->file->index_end(); - abort: +abort: DBUG_RETURN(-1); } @@ -1736,7 +1771,7 @@ public: if (!(mem_check = new GRANT_COLUMN(*res, fix_rights_for_column(priv)))) { - // Don't use this entry + /* Don't use this entry */ privs = cols = 0; /* purecov: deadcode */ return; /* purecov: deadcode */ } @@ -1918,7 +1953,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_length, HA_READ_KEY_EXACT)) goto end; - // Scan trough all rows with the same host,db,user and table + /* Scan through all rows with the same host,db,user and table */ do { ulong privileges = (ulong) table->field[6]->val_int(); @@ -1968,7 +2003,7 @@ static int replace_column_table(GRANT_TABLE *g_t, !key_cmp(table,key,0,key_length)); } - end: +end: table->file->index_end(); DBUG_RETURN(result); } @@ -2037,7 +2072,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, if (revoke_grant) { - // column rights are already fixed in mysql_table_grant ! + /* column rights are already fixed in mysql_table_grant */ store_table_rights=j & ~store_table_rights; } else @@ -2073,7 +2108,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, if (rights | col_rights) { grant_table->privs= rights; - grant_table->cols= col_rights; + grant_table->cols= col_rights; } else { @@ -2081,19 +2116,36 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } DBUG_RETURN(0); - /* This should never happen */ - table_error: + /* This should never happen */ +table_error: table->file->print_error(error,MYF(0)); /* purecov: deadcode */ DBUG_RETURN(-1); /* purecov: deadcode */ } +/* + Store table level and column level grants in the privilege tables + + SYNOPSIS + mysql_table_grant() + thd Thread handle + table_list List of tables to give grant + user_list List of users to give grant + columns List of columns to give grant + rights Table level grant + revoke_grant Set to 1 if this is a REVOKE command + + RETURN + 0 ok + 1 error +*/ + int mysql_table_grant(THD *thd, TABLE_LIST *table_list, List <LEX_USER> &user_list, List <LEX_COLUMN> &columns, ulong rights, bool revoke_grant) { - ulong column_priv = 0; + ulong column_priv= 0; List_iterator <LEX_USER> str_list (user_list); LEX_USER *Str; TABLE_LIST tables[3]; @@ -2103,7 +2155,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (!initialized) { send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: inspected */ - return 1; /* purecov: inspected */ + DBUG_RETURN(1); /* purecov: inspected */ } if (rights & ~TABLE_ACLS) { @@ -2114,21 +2166,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (columns.elements && !revoke_grant) { TABLE *table; - class LEX_COLUMN *check; - List_iterator <LEX_COLUMN> iter(columns); + class LEX_COLUMN *column; + List_iterator <LEX_COLUMN> column_iter(columns); if (!(table=open_ltable(thd,table_list,TL_READ))) DBUG_RETURN(-1); - while ((check = iter++)) + while ((column = column_iter++)) { - if (!find_field_in_table(thd,table,check->column.ptr(), - check->column.length(),0,0)) + if (!find_field_in_table(thd,table,column->column.ptr(), + column->column.length(),0,0)) { my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), - check->column.c_ptr(), table_list->alias); + column->column.c_ptr(), table_list->alias); DBUG_RETURN(-1); } - column_priv |= check->rights | (rights & COL_ACLS); + column_priv|= column->rights; } close_thread_tables(thd); } @@ -2164,8 +2216,16 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && table_rules_on && !tables_ok(0, tables)) - DBUG_RETURN(0); + if (thd->slave_thread && table_rules_on) + { + /* + The tables must be marked "updating" so that tables_ok() takes them into + account in tests. + */ + tables[0].updating= tables[1].updating= tables[2].updating= 1; + if (!tables_ok(0, tables)) + DBUG_RETURN(0); + } #endif if (open_and_lock_tables(thd,tables)) @@ -2233,21 +2293,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, /* If revoke_grant, calculate the new column privilege for tables_priv */ if (revoke_grant) { - class LEX_COLUMN *check; - List_iterator <LEX_COLUMN> iter(columns); + class LEX_COLUMN *column; + List_iterator <LEX_COLUMN> column_iter(columns); GRANT_COLUMN *grant_column; /* Fix old grants */ - while ((check = iter++)) + while ((column = column_iter++)) { grant_column = column_hash_search(grant_table, - check->column.ptr(), - check->column.length()); + column->column.ptr(), + column->column.length()); if (grant_column) - grant_column->rights&= ~(check->rights | rights); + grant_column->rights&= ~(column->rights | rights); } /* scan trough all columns to get new column grant */ - column_priv=0; + column_priv= 0; for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++) { grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns, @@ -2330,8 +2390,16 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && table_rules_on && !tables_ok(0, tables)) - DBUG_RETURN(0); + if (thd->slave_thread && table_rules_on) + { + /* + The tables must be marked "updating" so that tables_ok() takes them into + account in tests. + */ + tables[0].updating= tables[1].updating= 1; + if (!tables_ok(0, tables)) + DBUG_RETURN(0); + } #endif if (open_and_lock_tables(thd,tables)) @@ -2343,7 +2411,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, if (!revoke_grant) create_new_users= test_if_create_new_users(thd); - // go through users in user_list + /* go through users in user_list */ rw_wrlock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); grant_version++; @@ -2359,16 +2427,25 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, continue; } if ((replace_user_table(thd, - tables[0].table, + tables[0].table, *Str, (!db ? rights : 0), revoke_grant, create_new_users))) result= -1; - else + else if (db) { - if (db && replace_db_table(tables[1].table, db, *Str, rights & DB_ACLS, - revoke_grant)) + ulong db_rights= rights & DB_ACLS; + if (db_rights == rights) + { + if (replace_db_table(tables[1].table, db, *Str, db_rights, + revoke_grant)) + result= -1; + } + else + { + net_printf(&thd->net,ER_WRONG_USAGE,"DB GRANT","GLOBAL PRIVILEGES"); result= -1; + } } } VOID(pthread_mutex_unlock(&acl_cache->lock)); @@ -2481,7 +2558,16 @@ end: } -/* Reload grant array (table and column privileges) if possible */ +/* + Reload grant array (table and column privileges) if possible + + SYNOPSIS + grant_reload() + thd Thread handler + + NOTES + Locked tables are checked by acl_init and doesn't have to be checked here +*/ void grant_reload(THD *thd) { @@ -2490,8 +2576,6 @@ void grant_reload(THD *thd) MEM_ROOT old_mem; DBUG_ENTER("grant_reload"); - // Locked tables are checked by acl_init and doesn't have to be checked here - rw_wrlock(&LOCK_grant); grant_version++; old_column_priv_hash= column_priv_hash; @@ -2568,29 +2652,29 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, rw_unlock(&LOCK_grant); return 0; - err: +err: rw_unlock(&LOCK_grant); if (!no_errors) // Not a silent skip of table { const char *command=""; if (want_access & SELECT_ACL) - command ="select"; + command= "select"; else if (want_access & INSERT_ACL) - command = "insert"; + command= "insert"; else if (want_access & UPDATE_ACL) - command = "update"; + command= "update"; else if (want_access & DELETE_ACL) - command = "delete"; + command= "delete"; else if (want_access & DROP_ACL) - command = "drop"; + command= "drop"; else if (want_access & CREATE_ACL) - command = "create"; + command= "create"; else if (want_access & ALTER_ACL) - command = "alter"; + command= "alter"; else if (want_access & INDEX_ACL) - command = "index"; + command= "index"; else if (want_access & GRANT_ACL) - command = "grant"; + command= "grant"; net_printf(thd,ER_TABLEACCESS_DENIED_ERROR, command, thd->priv_user, @@ -2613,7 +2697,7 @@ bool check_grant_column(THD *thd,TABLE *table, const char *name, rw_rdlock(&LOCK_grant); - // reload table if someone has modified any grants + /* reload table if someone has modified any grants */ if (table->grant.version != grant_version) { @@ -2641,7 +2725,7 @@ bool check_grant_column(THD *thd,TABLE *table, const char *name, #endif /* We must use my_printf_error() here! */ - err: +err: rw_unlock(&LOCK_grant); if (!show_tables) { @@ -2677,7 +2761,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) rw_rdlock(&LOCK_grant); - // reload table if someone has modified any grants + /* reload table if someone has modified any grants */ if (table->grant.version != grant_version) { @@ -2687,7 +2771,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) table->real_name,0); /* purecov: inspected */ table->grant.version=grant_version; /* purecov: inspected */ } - // The following should always be true + /* The following should always be true */ if (!(grant_table=table->grant.grant_table)) goto err; /* purecov: inspected */ @@ -2705,11 +2789,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) err: rw_unlock(&LOCK_grant); err2: - const char *command=""; + const char *command= ""; if (want_access & SELECT_ACL) - command ="select"; + command= "select"; else if (want_access & INSERT_ACL) - command = "insert"; + command= "insert"; my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, ER(ER_COLUMNACCESS_DENIED_ERROR), MYF(0), @@ -2722,11 +2806,11 @@ err2: } -/**************************************************************************** +/* Check if a user has the right to access a database Access is accepted if he has a grant for any table in the database Return 1 if access is denied -****************************************************************************/ +*/ bool check_grant_db(THD *thd,const char *db) { @@ -2771,8 +2855,8 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) #ifdef EMBEDDED_LIBRARY grant_table= NULL; #else - grant_table = table_hash_search(thd->host,thd->ip,db,user, - table->real_name,0); + grant_table= table_hash_search(thd->host, thd->ip, db, user, + table->real_name, 0); #endif table->grant.grant_table=grant_table; // Remember for column test table->grant.version=grant_version; @@ -2791,7 +2875,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) ulong priv; rw_rdlock(&LOCK_grant); - // reload table if someone has modified any grants + /* reload table if someone has modified any grants */ if (table->grant.version != grant_version) { table->grant.grant_table= @@ -2816,11 +2900,20 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) return priv; } +/* Help function for mysql_show_grants */ -/***************************************************************************** - SHOW GRANTS : send to client grant-like strings depicting user@host - privileges -*****************************************************************************/ +static void add_user_option(String *grant, ulong value, const char *name) +{ + if (value) + { + char buff[22], *p; // just as in int2str + grant->append(' '); + grant->append(name, strlen(name)); + grant->append(' '); + p=int10_to_str(value, buff, 10); + grant->append(buff,p-buff); + } +} static const char *command_array[]= { @@ -2829,12 +2922,20 @@ static const char *command_array[]= "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", }; + static uint command_lengths[]= { 6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18 }; +/* + SHOW GRANTS; Send grants for a user to the client + + IMPLEMENTATION + Send to client grant-like strings depicting user@host privileges +*/ + int mysql_show_grants(THD *thd,LEX_USER *lex_user) { ulong want_access; @@ -2940,25 +3041,25 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append(" REQUIRE ",9); if (acl_user->x509_issuer) { - ssl_options++; - global.append("ISSUER \'",8); - global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); + ssl_options++; + global.append("ISSUER \'",8); + global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); global.append('\''); } if (acl_user->x509_subject) { - if (ssl_options++) - global.append(' '); - global.append("SUBJECT \'",9); - global.append(acl_user->x509_subject,strlen(acl_user->x509_subject)); + if (ssl_options++) + global.append(' '); + global.append("SUBJECT \'",9); + global.append(acl_user->x509_subject,strlen(acl_user->x509_subject)); global.append('\''); } if (acl_user->ssl_cipher) { - if (ssl_options++) - global.append(' '); - global.append("CIPHER '",8); - global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher)); + if (ssl_options++) + global.append(' '); + global.append("CIPHER '",8); + global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher)); global.append('\''); } } @@ -2969,27 +3070,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append(" WITH",5); if (want_access & GRANT_ACL) global.append(" GRANT OPTION",13); - if (acl_user->user_resource.questions) - { - char buff[22], *p; // just as in int2str - global.append(" MAX_QUERIES_PER_HOUR ",22); - p=int10_to_str(acl_user->user_resource.questions,buff,10); - global.append(buff,p-buff); - } - if (acl_user->user_resource.updates) - { - char buff[22], *p; // just as in int2str - global.append(" MAX_UPDATES_PER_HOUR ",22); - p=int10_to_str(acl_user->user_resource.updates,buff,10); - global.append(buff,p-buff); - } - if (acl_user->user_resource.connections) - { - char buff[22], *p; // just as in int2str - global.append(" MAX_CONNECTIONS_PER_HOUR ",26); - p=int10_to_str(acl_user->user_resource.connections,buff,10); - global.append(buff,p-buff); - } + add_user_option(&global, acl_user->user_resource.questions, + "MAX_QUERIES_PER_HOUR"); + add_user_option(&global, acl_user->user_resource.updates, + "MAX_UPDATES_PER_HOUR"); + add_user_option(&global, acl_user->user_resource.connections, + "MAX_CONNECTIONS_PER_HOUR"); } protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); @@ -3024,7 +3110,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL))) db.append("ALL PRIVILEGES",14); else if (!(want_access & ~GRANT_ACL)) - db.append("USAGE",5); + db.append("USAGE",5); else { int found=0, cnt; @@ -3075,32 +3161,32 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (!strcmp(lex_user->user.str,user) && !my_strcasecmp(&my_charset_latin1, lex_user->host.str, host)) { - want_access=grant_table->privs; - if ((want_access | grant_table->cols) != 0) + ulong table_access= grant_table->privs; + if ((table_access | grant_table->cols) != 0) { String global(buff,sizeof(buff),&my_charset_latin1); global.length(0); global.append("GRANT ",6); - if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL))) + if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL))) global.append("ALL PRIVILEGES",14); else { - int found=0; - ulong j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL; + int found= 0; + ulong j,test_access= (table_access | grant_table->cols) & ~GRANT_ACL; - for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1) + for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1) { if (test_access & j) { if (found) global.append(", ",2); - found = 1; + found= 1; global.append(command_array[counter],command_lengths[counter]); if (grant_table->cols) { - uint found_col=0; + uint found_col= 0; for (uint col_index=0 ; col_index < grant_table->hash_columns.records ; col_index++) @@ -3111,8 +3197,18 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) { if (!found_col) { + found_col= 1; + /* + If we have a duplicated table level privilege, we + must write the access privilege name again. + */ + if (table_access & j) + { + global.append(", ", 2); + global.append(command_array[counter], + command_lengths[counter]); + } global.append(" (",2); - found_col=1; } else global.append(", ",2); @@ -3135,7 +3231,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append("'@'",3); global.append(lex_user->host.str,lex_user->host.length); global.append('\''); - if (want_access & GRANT_ACL) + if (table_access & GRANT_ACL) global.append(" WITH GRANT OPTION",18); protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); @@ -3147,7 +3243,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } } } - end: +end: VOID(pthread_mutex_unlock(&acl_cache->lock)); rw_unlock(&LOCK_grant); @@ -3223,9 +3319,9 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) */ if (thd->slave_thread && table_rules_on) { - /* - The tables must be marked "updating" so that tables_ok() takes them into - account in tests. + /* + The tables must be marked "updating" so that tables_ok() takes them into + account in tests. */ tables[0].updating=tables[1].updating=tables[2].updating=tables[3].updating=1; if (!tables_ok(0, tables)) @@ -3265,9 +3361,10 @@ ACL_USER *check_acl_user(LEX_USER *user_name, return 0; *acl_user_idx= counter; - return acl_user; + return acl_user; } + int mysql_drop_user(THD *thd, List <LEX_USER> &list) { uint counter, user_id; @@ -3351,10 +3448,10 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list) continue; } - tables[0].table->field[0]->store(user_name->host.str,(uint) + tables[0].table->field[0]->store(user_name->host.str,(uint) user_name->host.length, system_charset_info); - tables[0].table->field[1]->store(user_name->user.str,(uint) + tables[0].table->field[1]->store(user_name->user.str,(uint) user_name->user.length, system_charset_info); if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0, @@ -3409,7 +3506,7 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list) result= -1; continue; } - + if (replace_user_table(thd, tables[0].table, *lex_user, ~0, 1, 0)) { diff --git a/sql/sql_acl.h b/sql/sql_acl.h index ca976f43999..0dc8c058b3d 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -76,8 +76,8 @@ #define get_rights_for_db(A) (((A) & 63) | (((A) & DB_CHUNK1) >> 4) | (((A) & DB_CHUNK2) >> 6)) #define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4)) #define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4)) -#define fix_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) << 7)) -#define get_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) >> 7)) +#define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8)) +#define get_rights_for_column(A) (((A) & 7) | ((A) >> 8)) /* Classes */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a5807914abd..fd0768d6ae7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2024,11 +2024,11 @@ bool setup_tables(TABLE_LIST *tables) table->used_fields=0; table->const_table=0; - table->outer_join=table->null_row=0; + table->null_row=0; table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= table->keys_in_use; table->used_keys= table->keys_for_keyread; - table->maybe_null=test(table->outer_join=table_list->outer_join); + table->maybe_null=test(table->outer_join= table_list->outer_join); table->tablenr=tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; @@ -2150,6 +2150,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { + table_map not_null_tables= 0; DBUG_ENTER("setup_conds"); thd->set_query_id=1; @@ -2159,6 +2160,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) thd->where="where clause"; if ((*conds)->fix_fields(thd, tables, conds) || (*conds)->check_cols(1)) DBUG_RETURN(1); + not_null_tables= (*conds)->not_null_tables(); } /* Check if we are using outer joins */ @@ -2173,9 +2175,15 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) DBUG_RETURN(1); thd->lex.current_select->cond_count++; - /* If it's a normal join, add the ON/USING expression to the WHERE */ - if (!table->outer_join) + /* + If it's a normal join or a LEFT JOIN which can be optimized away + add the ON/USING expression to the WHERE + */ + if (!table->outer_join || + ((table->table->map & not_null_tables) && + !(specialflag & SPECIAL_NO_NEW_FUNC))) { + table->outer_join= 0; if (!(*conds=and_conds(*conds, table->on_expr))) DBUG_RETURN(1); table->on_expr=0; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 767a1a46dcc..64e8be8e224 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -760,9 +760,9 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) DBUG_VOID_RETURN; uint8 tables_type= 0; - if ((local_tables = is_cacheable(thd, thd->query_length, - thd->query, &thd->lex, tables_used, - &tables_type))) + if ((local_tables= is_cacheable(thd, thd->query_length, + thd->query, &thd->lex, tables_used, + &tables_type))) { NET *net= &thd->net; byte flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index eea542e9d06..f6eb7c7a0fb 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -61,7 +61,7 @@ #define QUERY_CACHE_PACK_ITERATION 2 #define QUERY_CACHE_PACK_LIMIT (512*1024L) -#define TABLE_COUNTER_TYPE uint8 +#define TABLE_COUNTER_TYPE uint struct Query_cache_block; struct Query_cache_block_table; diff --git a/sql/sql_class.h b/sql/sql_class.h index f6336cb7dd9..414b4eac6a6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -30,22 +30,26 @@ class Slave_log_event; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY }; enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE, DUP_UPDATE }; -enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN }; +enum enum_log_type { LOG_CLOSED, LOG_TO_BE_OPENED, LOG_NORMAL, LOG_NEW, LOG_BIN}; enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, DELAY_KEY_WRITE_ALL }; extern char internal_table_name[2]; -// log info errors +/* log info errors */ #define LOG_INFO_EOF -1 #define LOG_INFO_IO -2 #define LOG_INFO_INVALID -3 #define LOG_INFO_SEEK -4 -#define LOG_INFO_PURGE_NO_ROTATE -5 #define LOG_INFO_MEM -6 #define LOG_INFO_FATAL -7 #define LOG_INFO_IN_USE -8 +/* bitmap to SQL_LOG::close() */ +#define LOG_CLOSE_INDEX 1 +#define LOG_CLOSE_TO_BE_OPENED 2 +#define LOG_CLOSE_STOP_EVENT 4 + struct st_relay_log_info; typedef struct st_log_info @@ -70,8 +74,10 @@ typedef struct st_user_var_events class Log_event; -class MYSQL_LOG { +class MYSQL_LOG + { private: + /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ pthread_mutex_t LOCK_log, LOCK_index; pthread_cond_t update_cond; ulonglong bytes_written; @@ -86,15 +92,20 @@ class MYSQL_LOG { uint open_count; // For replication volatile enum_log_type log_type; enum cache_type io_cache_type; - bool write_error,inited; - /* - For binlog - if log name can never change we should not try to rotate it - or write any rotation events. The user should use FLUSH MASTER instead - of FLUSH LOGS for purging. - */ - bool no_rotate; + bool write_error, inited; bool need_start_event; - bool no_auto_events; // for relay binlog + bool no_auto_events; // For relay binlog + /* + The max size before rotation (usable only if log_type == LOG_BIN: binary + logs and relay logs). + For a binlog, max_size should be max_binlog_size. + For a relay log, it should be max_relay_log_size if this is non-zero, + max_binlog_size otherwise. + max_size is set in init(), and dynamically changed (when one does SET + GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and + fix_max_relay_log_size). + */ + ulong max_size; friend class Log_event; public: @@ -116,17 +127,19 @@ public: bytes_written=0; DBUG_VOID_RETURN; } + void set_max_size(ulong max_size_arg); void signal_update() { pthread_cond_broadcast(&update_cond);} void wait_for_update(THD* thd); void set_need_start_event() { need_start_event = 1; } void init(enum_log_type log_type_arg, - enum cache_type io_cache_type_arg = WRITE_CACHE, - bool no_auto_events_arg = 0); + enum cache_type io_cache_type_arg, + bool no_auto_events_arg, ulong max_size); + void init_pthread_objects(); void cleanup(); bool open(const char *log_name,enum_log_type log_type, const char *new_name, const char *index_file_name_arg, enum cache_type io_cache_type_arg, - bool no_auto_events_arg); + bool no_auto_events_arg, ulong max_size); void new_file(bool need_lock= 1); bool write(THD *thd, enum enum_server_command command, const char *format,...); @@ -152,8 +165,7 @@ public: int purge_logs_before_date(time_t purge_time); int purge_first_log(struct st_relay_log_info* rli, bool included); bool reset_logs(THD* thd); - // if we are exiting, we also want to close the index file - void close(bool exiting = 0); + void close(uint exiting); // iterating through the log index file int find_log_pos(LOG_INFO* linfo, const char* log_name, @@ -161,7 +173,6 @@ public: int find_next_log(LOG_INFO* linfo, bool need_mutex); int get_current_log(LOG_INFO* linfo); uint next_file_id(); - inline bool is_open() { return log_type != LOG_CLOSED; } inline char* get_index_fname() { return index_file_name;} inline char* get_log_fname() { return log_file_name; } @@ -376,6 +387,7 @@ struct system_variables ulong tx_isolation; ulong sql_mode; ulong default_week_format; + ulong max_seeks_for_key; ulong group_concat_max_len; /* In slave thread we need to know in behalf of which @@ -1003,11 +1015,12 @@ class Unique :public Sql_alloc TREE tree; byte *record_pointers; bool flush(); + uint size; public: ulong elements; Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, - uint size, ulong max_in_memory_size_arg); + uint size_arg, ulong max_in_memory_size_arg); ~Unique(); inline bool unique_add(gptr ptr) { @@ -1022,10 +1035,11 @@ public: friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique); }; -class multi_delete : public select_result + +class multi_delete :public select_result { TABLE_LIST *delete_tables, *table_being_deleted; - Unique **tempfiles; + Unique **tempfiles; THD *thd; ha_rows deleted; uint num_of_tables; @@ -1045,7 +1059,7 @@ public: }; -class multi_update : public select_result +class multi_update :public select_result { TABLE_LIST *all_tables, *update_tables, *table_being_updated; THD *thd; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ebb09b99df7..13038435986 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -164,7 +164,15 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, else { table->file->print_error(error,MYF(0)); - error=0; + /* + In < 4.0.14 we set the error number to 0 here, but that + was not sensible, because then MySQL would not roll back the + failed DELETE, and also wrote it to the binlog. For MyISAM + tables a DELETE probably never should fail (?), but for + InnoDB it can fail in a FOREIGN KEY error or an + out-of-tablespace error. + */ + error= 1; break; } } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 79d13039784..0387f02e83f 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -203,6 +203,13 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, Item *item; for (key_len=0 ; (item=it_ke++) ; key_part++) { + if (item->fix_fields(thd, tables)) + goto err; + if (item->used_tables() & ~RAND_TABLE_BIT) + { + my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ"); + goto err; + } (void) item->save_in_field(key_part->field, 1); key_len+=key_part->store_length; } @@ -237,7 +244,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } if (cond && !cond->val_int()) continue; - if (!err && num_rows >= offset_limit) + if (num_rows >= offset_limit) { String *packet = &thd->packet; Item *item; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6b3da620fc1..03a0f7beda9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -61,7 +61,9 @@ enum enum_sql_command { SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_PRELOAD_KEYS, SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, - SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, + SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, + SQLCOM_COMMIT, SQLCOM_SAVEPOINT, + SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, @@ -487,9 +489,10 @@ typedef struct st_lex List<List_item> many_values; List<set_var_base> var_list; List<Item> param_list; - SQL_LIST proc_list, auxilliary_table_list; + SQL_LIST proc_list, auxilliary_table_list, save_list; TYPELIB *interval; create_field *last_field; + char *savepoint_name; // Transaction savepoint id Item *default_value, *comment; uint uint_geom_type; LEX_USER *grant_user; diff --git a/sql/sql_list.cc b/sql/sql_list.cc index 1124605ca24..c99cfb8c918 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -22,3 +22,18 @@ #include "mysql_priv.h" list_node end_of_list; + +void free_list(I_List <i_string_pair> *list) +{ + i_string_pair *tmp; + while ((tmp= list->get())) + delete tmp; +} + + +void free_list(I_List <i_string> *list) +{ + i_string *tmp; + while ((tmp= list->get())) + delete tmp; +} diff --git a/sql/sql_list.h b/sql/sql_list.h index 2450b2051f2..7200046e6c5 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -15,12 +15,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* mysql standard open memoryallocator */ - #ifdef __GNUC__ #pragma interface /* gcc class implementation */ #endif +/* mysql standard class memoryallocator */ class Sql_alloc { @@ -48,14 +47,15 @@ public: }; + /* -** basic single linked list -** Used for item and item_buffs. -** All list ends with a pointer to the 'end_of_list' element, which -** data pointer is a null pointer and the next pointer points to itself. -** This makes it very fast to traverse lists as we don't have to -** test for a specialend condition for list that can't contain a null -** pointer. + Basic single linked list + Used for item and item_buffs. + All list ends with a pointer to the 'end_of_list' element, which + data pointer is a null pointer and the next pointer points to itself. + This makes it very fast to traverse lists as we don't have to + test for a specialend condition for list that can't contain a null + pointer. */ class list_node :public Sql_alloc @@ -75,9 +75,11 @@ public: friend class base_list_iterator; }; + extern list_node end_of_list; -class base_list :public Sql_alloc { +class base_list :public Sql_alloc +{ protected: list_node *first,**last; @@ -267,6 +269,7 @@ public: inline T** ref(void) { return (T**) base_list_iterator::ref(); } }; + template <class T> class List_iterator_fast :public base_list_iterator { protected: @@ -288,11 +291,12 @@ public: /* -** A simple intrusive list which automaticly removes element from list -** on delete (for THD element) + A simple intrusive list which automaticly removes element from list + on delete (for THD element) */ -struct ilink { +struct ilink +{ struct ilink **prev,*next; static void *operator new(size_t size) { @@ -317,9 +321,11 @@ struct ilink { virtual ~ilink() { unlink(); } /*lint -e1740 */ }; + template <class T> class I_List_iterator; -class base_ilist { +class base_ilist +{ public: struct ilink *first,last; inline void empty() { first= &last; last.prev= &first; } @@ -368,7 +374,8 @@ public: template <class T> -class I_List :private base_ilist { +class I_List :private base_ilist +{ public: I_List() :base_ilist() {} inline void empty() { base_ilist::empty(); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5880a9d4c8a..d9f6b93d2bb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -216,7 +216,7 @@ static int check_user(THD *thd,enum_server_command command, const char *user, thd->db=0; thd->db_length=0; USER_RESOURCES ur; - char tmp_passwd[SCRAMBLE41_LENGTH]; + char tmp_passwd[SCRAMBLE41_LENGTH+1]; DBUG_ENTER("check_user"); /* @@ -304,10 +304,11 @@ static int check_user(THD *thd,enum_server_command command, const char *user, db ? db : (char*) ""); thd->db_access=0; /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || ur.connections) && + if ((ur.questions || ur.updates || ur.connections || max_user_connections) && get_or_create_user_conn(thd,user,thd->host_or_ip,&ur)) DBUG_RETURN(1); - if (thd->user_connect && thd->user_connect->user_resources.connections && + if (thd->user_connect && ((thd->user_connect->user_resources.connections) || + max_user_connections) && check_for_max_user_connections(thd, thd->user_connect)) DBUG_RETURN(1); @@ -356,7 +357,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc) DBUG_ENTER("check_for_max_user_connections"); if (max_user_connections && - (max_user_connections <= (uint) uc->connections)) + (max_user_connections < (uint) uc->connections)) { net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; @@ -567,7 +568,10 @@ check_connections(THD *thd) #if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread) /* Fast local hostname resolve for Win32 */ if (!strcmp(thd->ip,"127.0.0.1")) - thd->host=(char*) localhost; + { + thd->host= (char*) localhost; + thd->host_or_ip= localhost; + } else #endif { @@ -694,6 +698,11 @@ check_connections(THD *thd) if (thd->client_capabilities & CLIENT_SSL) { /* Do the SSL layering. */ + if (!ssl_acceptor_fd) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } DBUG_PRINT("info", ("IO layer change in progress...")); if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout)) { @@ -1444,7 +1453,8 @@ restore_user: pos = uint4korr(packet); flags = uint2korr(packet + 4); thd->server_id=0; /* avoid suicide */ - kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6)); + if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0 + kill_zombie_dump_threads(slave_server_id); thd->server_id = slave_server_id; mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags); unregister_slave(thd,1,1); @@ -1503,9 +1513,10 @@ restore_user: opened_tables,refresh_version, cached_tables(), uptime ? (float)thd->query_id/(float)uptime : 0); #ifdef SAFEMALLOC - if (lCurMemory) // Using SAFEMALLOC + if (sf_malloc_cur_memory) // Using SAFEMALLOC sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK", - (lCurMemory+1023L)/1024L,(lMaxMemory+1023L)/1024L); + (sf_malloc_cur_memory+1023L)/1024L, + (sf_malloc_max_memory+1023L)/1024L); #endif VOID(my_net_write(net, buff,(uint) strlen(buff))); VOID(net_flush(net)); @@ -1670,7 +1681,11 @@ mysql_execute_command(THD *thd) given and the table list says the query should not be replicated */ if (table_rules_on && tables && !tables_ok(thd,tables)) + { + /* we warn the slave SQL thread */ + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); DBUG_VOID_RETURN; + } #ifndef TO_BE_DELETED /* This is a workaround to deal with the shortcoming in 3.23.44-3.23.46 @@ -1710,14 +1725,8 @@ mysql_execute_command(THD *thd) } } } - if ((&lex->select_lex != lex->all_selects_list && - lex->unit.create_total_list(thd, lex, &tables, 0)) -#ifdef HAVE_REPLICATION - || - (table_rules_on && tables && thd->slave_thread && - !tables_ok(thd,tables)) -#endif - ) + if (&lex->select_lex != lex->all_selects_list && + lex->unit.create_total_list(thd, lex, &tables, 0)) DBUG_VOID_RETURN; /* @@ -2445,13 +2454,15 @@ mysql_execute_command(THD *thd) if (find_real_table_in_list(tables->next, tables->db, tables->real_name)) { - net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name); - DBUG_VOID_RETURN; + /* Using same table for INSERT and SELECT */ + select_lex->options |= OPTION_BUFFER_RESULT; } /* Skip first table, which is the table we are inserting in */ lex->select_lex.table_list.first= (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next); + lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE; + if (!(res=open_and_lock_tables(thd, tables))) { if ((result=new select_insert(tables->table,&lex->field_list, @@ -2684,6 +2695,14 @@ mysql_execute_command(THD *thd) } if (check_access(thd,SELECT_ACL,db,&thd->col_access)) goto error; /* purecov: inspected */ + if (!thd->col_access && check_grant_db(thd,db)) + { + net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, + thd->priv_user, + thd->priv_host, + db); + goto error; + } /* grant is checked in mysqld_show_tables */ if (select_lex->options & SELECT_DESCRIBE) res= mysqld_extend_show_tables(thd,db, @@ -2842,7 +2861,10 @@ mysql_execute_command(THD *thd) if (thd->slave_thread && (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) || !db_ok_with_wild_table(lex->name))) + { + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); break; + } #endif if (check_access(thd,CREATE_ACL,lex->name,0,1)) break; @@ -2867,7 +2889,10 @@ mysql_execute_command(THD *thd) if (thd->slave_thread && (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) || !db_ok_with_wild_table(lex->name))) + { + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); break; + } #endif if (check_access(thd,DROP_ACL,lex->name,0,1)) break; @@ -3105,8 +3130,12 @@ mysql_execute_command(THD *thd) res = mysql_ha_close(thd, tables); break; case SQLCOM_HA_READ: - if (check_db_used(thd,tables) || - check_table_access(thd,SELECT_ACL, tables)) + /* + There is no need to check for table permissions here, because + if a user has no permissions to read a table, he won't be + able to open it (with SQLCOM_HA_OPEN) in the first place. + */ + if (check_db_used(thd,tables)) goto error; res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir, lex->insert_list, lex->ha_rkey_mode, select_lex->where, @@ -3162,6 +3191,23 @@ mysql_execute_command(THD *thd) res= -1; thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); break; + case SQLCOM_ROLLBACK_TO_SAVEPOINT: + if (!ha_rollback_to_savepoint(thd, lex->savepoint_name)) + { + if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) + send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0); + else + send_ok(&thd->net); + } + else + res= -1; + break; + case SQLCOM_SAVEPOINT: + if (!ha_savepoint(thd, lex->savepoint_name)) + send_ok(&thd->net); + else + res= -1; + break; default: /* Impossible */ send_ok(thd); break; @@ -3612,8 +3658,7 @@ void mysql_init_multi_delete(LEX *lex) mysql_init_select(lex); lex->select_lex.select_limit= lex->unit.select_limit_cnt= HA_POS_ERROR; - lex->auxilliary_table_list= lex->select_lex.table_list; - lex->select_lex.table_list.empty(); + lex->select->table_list.save_and_clear(&lex->auxilliary_table_list); } @@ -4273,6 +4318,11 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } if (options & REFRESH_LOG) { + /* + Flush the normal query log, the update log, the binary log, + the slow query log, and the relay log (if it exists). + */ + /* Writing this command to the binlog may result in infinite loops when doing mysqlbinlog|mysql, and anyway it does not really make sense to log it @@ -4282,6 +4332,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, mysql_log.new_file(1); mysql_update_log.new_file(1); mysql_bin_log.new_file(1); + mysql_slow_log.new_file(1); #ifdef HAVE_REPLICATION if (expire_logs_days) { @@ -4289,8 +4340,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (purge_time >= 0) mysql_bin_log.purge_logs_before_date(purge_time); } + LOCK_ACTIVE_MI; + rotate_relay_log(active_mi); + UNLOCK_ACTIVE_MI; #endif - mysql_slow_log.new_file(1); if (ha_flush_logs()) result=1; if (flush_error_log()) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 121411379f8..faf128d5e02 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -51,7 +51,7 @@ int check_binlog_magic(IO_CACHE* log, const char** errmsg) } static int fake_rotate_event(NET* net, String* packet, char* log_file_name, - const char**errmsg) + ulonglong position, const char**errmsg) { char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN]; memset(header, 0, 4); // when does not matter @@ -68,9 +68,7 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name, int4store(header + LOG_POS_OFFSET, 0); packet->append(header, sizeof(header)); - /* We need to split the next statement because of problem with cxx */ - int4store(buf,4); // tell slave to skip magic number - int4store(buf+4,0); + int8store(buf+R_POS_OFFSET,position); packet->append(buf, ROTATE_HEADER_LEN); packet->append(p,ident_len); if (my_net_write(net, (char*)packet->ptr(), packet->length())) @@ -159,10 +157,18 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, File file; DBUG_ENTER("open_binlog"); - if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0 || - init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0, + if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0) + { + sql_print_error("Failed to open log (\ +file '%s', errno %d)", log_file_name, my_errno); + *errmsg = "Could not open log file"; // This will not be sent + goto err; + } + if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME | MY_DONT_CHECK_FILESIZE))) { + sql_print_error("Failed to create a cache on log (\ +file '%s')", log_file_name); *errmsg = "Could not open log file"; // This will not be sent goto err; } @@ -258,22 +264,20 @@ bool log_in_use(const char* log_name) int purge_error_message(THD* thd, int res) { - const char* errmsg = 0; + const char *errmsg= 0; - switch(res) { + switch (res) { case 0: break; - case LOG_INFO_EOF: errmsg = "Target log not found in binlog index"; break; - case LOG_INFO_IO: errmsg = "I/O error reading log index file"; break; - case LOG_INFO_INVALID: errmsg = "Server configuration does not permit \ -binlog purge"; break; - case LOG_INFO_SEEK: errmsg = "Failed on fseek()"; break; - case LOG_INFO_PURGE_NO_ROTATE: errmsg = "Cannot purge unrotatable log"; - break; - case LOG_INFO_MEM: errmsg = "Out of memory"; break; - case LOG_INFO_FATAL: errmsg = "Fatal error during purge"; break; - case LOG_INFO_IN_USE: errmsg = "A purgeable log is in use, will not purge"; + case LOG_INFO_EOF: errmsg= "Target log not found in binlog index"; break; + case LOG_INFO_IO: errmsg= "I/O error reading log index file"; break; + case LOG_INFO_INVALID: + errmsg= "Server configuration does not permit binlog purge"; break; + case LOG_INFO_SEEK: errmsg= "Failed on fseek()"; break; + case LOG_INFO_MEM: errmsg= "Out of memory"; break; + case LOG_INFO_FATAL: errmsg= "Fatal error during purge"; break; + case LOG_INFO_IN_USE: errmsg= "A purgeable log is in use, will not purge"; break; - default: errmsg = "Unknown error during purge"; break; + default: errmsg= "Unknown error during purge"; break; } if (errmsg) @@ -281,19 +285,24 @@ binlog purge"; break; send_error(thd, 0, errmsg); return 1; } - else - send_ok(thd); + send_ok(thd); return 0; } + int purge_master_logs(THD* thd, const char* to_log) { char search_file_name[FN_REFLEN]; + if (!mysql_bin_log.is_open()) + { + send_ok(); + return 0; + } mysql_bin_log.make_log_name(search_file_name, to_log); - int res = mysql_bin_log.purge_logs(search_file_name, 0, 1, 1, NULL); - - return purge_error_message(thd, res); + return purge_error_message(thd, + mysql_bin_log.purge_logs(search_file_name, 0, 1, + 1, NULL); } @@ -385,17 +394,31 @@ impossible position"; */ packet->set("\0", 1, &my_charset_bin); - // if we are at the start of the log - if (pos == BIN_LOG_HEADER_SIZE) + /* + Before 4.0.14 we called fake_rotate_event below only if + (pos == BIN_LOG_HEADER_SIZE), because if this is false then the slave + already knows the binlog's name. + Now we always call fake_rotate_event; if the slave already knew the log's + name (ex: CHANGE MASTER TO MASTER_LOG_FILE=...) this is useless but does + not harm much. It is nice for 3.23 (>=.58) slaves which test Rotate events + to see if the master is 4.0 (then they choose to stop because they can't + replicate 4.0); by always calling fake_rotate_event we are sure that + 3.23.58 and newer will detect the problem as soon as replication starts + (BUG#198). + Always calling fake_rotate_event makes sending of normal + (=from-binlog) Rotate events a priori unneeded, but it is not so simple: + the 2 Rotate events are not equivalent, the normal one is before the Stop + event, the fake one is after. If we don't send the normal one, then the + Stop event will be interpreted (by existing 4.0 slaves) as "the master + stopped", which is wrong. So for safety, given that we want minimum + modification of 4.0, we send the normal and fake Rotates. + */ + if (fake_rotate_event(net, packet, log_file_name, pos, &errmsg)) { - // tell the client log name with a fake rotate_event - if (fake_rotate_event(net, packet, log_file_name, &errmsg)) - { - my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; - goto err; - } - packet->set("\0", 1, &my_charset_bin); + my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; + goto err; } + packet->set("\0", 1, &my_charset_bin); while (!net->error && net->vio != 0 && !thd->killed) { @@ -514,6 +537,11 @@ Increase max_allowed_packet on master"; case LOG_READ_EOF: DBUG_PRINT("wait",("waiting for data in binary log")); + if (thd->server_id==0) // for mysqlbinlog (mysqlbinlog.server_id==0) + { + pthread_mutex_unlock(log_lock); + goto end; + } if (!thd->killed) { /* Note that the following call unlocks lock_log */ @@ -588,10 +616,12 @@ Increase max_allowed_packet on master"; end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); - // fake Rotate_log event just in case it did not make it to the log - // otherwise the slave make get confused about the offset + /* + Even if the previous log contained a Rotate_log_event, we still fake + one. + */ if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 || - fake_rotate_event(net, packet, log_file_name, &errmsg)) + fake_rotate_event(net, packet, log_file_name, BIN_LOG_HEADER_SIZE, &errmsg)) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; @@ -601,6 +631,7 @@ Increase max_allowed_packet on master"; } } +end: end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); @@ -611,7 +642,7 @@ Increase max_allowed_packet on master"; pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; - err: +err: thd->proc_info = "waiting to finalize termination"; end_io_cache(&log); /* @@ -774,9 +805,15 @@ int reset_slave(THD *thd, MASTER_INFO* mi) &errmsg))) goto err; - // Clear master's log coordinates (only for good display of SHOW SLAVE STATUS) - mi->master_log_name[0]= 0; - mi->master_log_pos= BIN_LOG_HEADER_SIZE; + /* + Clear master's log coordinates and reset host/user/etc to the values + specified in mysqld's options (only for good display of SHOW SLAVE STATUS; + next init_master_info() (in start_slave() for example) would have set them + the same way; but here this is for the case where the user does SHOW SLAVE + STATUS; before doing START SLAVE; + */ + init_master_info_with_options(mi); + clear_last_slave_error(&mi->rli); // close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0 end_master_info(mi); // and delete these two files @@ -801,6 +838,25 @@ err: DBUG_RETURN(error); } +/* + + Kill all Binlog_dump threads which previously talked to the same slave + ("same" means with the same server id). Indeed, if the slave stops, if the + Binlog_dump thread is waiting (pthread_cond_wait) for binlog update, then it + will keep existing until a query is written to the binlog. If the master is + idle, then this could last long, and if the slave reconnects, we could have 2 + Binlog_dump threads in SHOW PROCESSLIST, until a query is written to the + binlog. To avoid this, when the slave reconnects and sends COM_BINLOG_DUMP, + the master kills any existing thread with the slave's server id (if this id is + not zero; it will be true for real slaves, but false for mysqlbinlog when it + sends COM_BINLOG_DUMP to get a remote binlog dump). + + SYNOPSIS + kill_zombie_dump_threads() + slave_server_id the slave's server id + +*/ + void kill_zombie_dump_threads(uint32 slave_server_id) { @@ -852,7 +908,7 @@ int change_master(THD* thd, MASTER_INFO* mi) // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0)) { - send_error(thd, 0, "Could not initialize master info"); + send_error(thd, ER_MASTER_INFO); unlock_slave_threads(mi); DBUG_RETURN(1); } @@ -862,16 +918,21 @@ int change_master(THD* thd, MASTER_INFO* mi) and we have the hold on the run locks which will keep all threads that could possibly modify the data structures from running */ + + /* + If the user specified host or port without binlog or position, + reset binlog's name to FIRST and position to 4. + */ + if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos) { - // if we change host or port, we must reset the postion mi->master_log_name[0] = 0; mi->master_log_pos= BIN_LOG_HEADER_SIZE; } if (lex_mi->log_file_name) strmake(mi->master_log_name, lex_mi->log_file_name, - sizeof(mi->master_log_name)); + sizeof(mi->master_log_name)-1); if (lex_mi->pos) { mi->master_log_pos= lex_mi->pos; @@ -879,11 +940,11 @@ int change_master(THD* thd, MASTER_INFO* mi) DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); if (lex_mi->host) - strmake(mi->host, lex_mi->host, sizeof(mi->host)); + strmake(mi->host, lex_mi->host, sizeof(mi->host)-1); if (lex_mi->user) - strmake(mi->user, lex_mi->user, sizeof(mi->user)); + strmake(mi->user, lex_mi->user, sizeof(mi->user)-1); if (lex_mi->password) - strmake(mi->password, lex_mi->password, sizeof(mi->password)); + strmake(mi->password, lex_mi->password, sizeof(mi->password)-1); if (lex_mi->port) mi->port = lex_mi->port; if (lex_mi->connect_retry) @@ -936,13 +997,25 @@ int change_master(THD* thd, MASTER_INFO* mi) } mi->rli.group_master_log_pos = mi->master_log_pos; DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); + /* If changing RELAY_LOG_FILE or RELAY_LOG_POS, this will be nonsense: */ + mi->rli.master_log_pos = mi->master_log_pos; strmake(mi->rli.group_master_log_name,mi->master_log_name, sizeof(mi->rli.group_master_log_name)-1); if (!mi->rli.group_master_log_name[0]) // uninitialized case mi->rli.group_master_log_pos=0; pthread_mutex_lock(&mi->rli.data_lock); - mi->rli.abort_pos_wait++; + mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */ + /* Clear the error, for a clean start. */ + clear_last_slave_error(&mi->rli); + /* + If we don't write new coordinates to disk now, then old will remain in + relay-log.info until START SLAVE is issued; but if mysqld is shutdown + before START SLAVE, then old will remain in relay-log.info, and will be the + in-memory value at restart (thus causing errors, as the old relay log does + not exist anymore). + */ + flush_relay_log_info(&mi->rli); pthread_cond_broadcast(&mi->data_cond); pthread_mutex_unlock(&mi->rli.data_lock); @@ -1112,7 +1185,7 @@ int show_binlog_info(THD* thd) /* - Send a lost of all binary logs to client + Send a list of all binary logs to client SYNOPSIS show_binlogs() @@ -1125,7 +1198,6 @@ int show_binlog_info(THD* thd) int show_binlogs(THD* thd) { - const char *errmsg; IO_CACHE *index_file; char fname[FN_REFLEN]; NET* net = &thd->net; @@ -1138,8 +1210,8 @@ int show_binlogs(THD* thd) if (!mysql_bin_log.is_open()) { //TODO: Replace with ER() error message - errmsg= "You are not using binary logging"; - goto err_with_msg; + send_error(net, 0, "You are not using binary logging"); + return 1; } field_list.push_back(new Item_empty_string("Log_name", 255)); @@ -1164,8 +1236,6 @@ int show_binlogs(THD* thd) send_eof(thd); DBUG_RETURN(0); -err_with_msg: - send_error(thd, ER_UNKNOWN_ERROR, errmsg); err: mysql_bin_log.unlock_index(); DBUG_RETURN(1); diff --git a/sql/sql_repl.h b/sql/sql_repl.h index e3d600b9798..fe1b7167d4a 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -7,7 +7,7 @@ typedef struct st_slave_info uint32 rpl_recovery_rank, master_id; char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; - char password[HASH_PASSWORD_LENGTH+1]; + char password[MAX_PASSWORD_LENGTH+1]; uint16 port; THD* thd; } SLAVE_INFO; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 71c0d0bdddc..a75f9ddf3b6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -525,6 +525,8 @@ JOIN::optimize() DBUG_RETURN(1); } + /* Remove distinct if only const tables */ + select_distinct= select_distinct && (const_tables != tables); thd->proc_info= "preparing"; if (result->initialize_tables(this)) { @@ -1723,9 +1725,11 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, /* Set a max range of how many seeks we can expect when using keys - This was (s->read_time*5), but this was too low with small rows + This is can't be to high as otherwise we are likely to use + table scan. */ - s->worst_seeks= (double) s->found_records / 5; + s->worst_seeks= min((double) s->found_records / 10, + (double) s->read_time*3); if (s->worst_seeks < 2.0) // Fix for small tables s->worst_seeks=2.0; @@ -2148,6 +2152,9 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) key_field->field->table->reginfo.not_exists_optimize=1; } + +#define FT_KEYPART (MAX_REF_PARTS+10) + static void add_ft_keys(DYNAMIC_ARRAY *keyuse_array, JOIN_TAB *stat,COND *cond,table_map usable_tables) @@ -2167,17 +2174,17 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, { Item_func *arg0=(Item_func *)(func->arguments()[0]), *arg1=(Item_func *)(func->arguments()[1]); - if ((functype == Item_func::GE_FUNC || - functype == Item_func::GT_FUNC) && - arg0->type() == Item::FUNC_ITEM && - arg0->functype() == Item_func::FT_FUNC && - arg1->const_item() && arg1->val()>0) + if (arg1->const_item() && + ((functype == Item_func::GE_FUNC && arg1->val()> 0) || + (functype == Item_func::GT_FUNC && arg1->val()>=0)) && + arg0->type() == Item::FUNC_ITEM && + arg0->functype() == Item_func::FT_FUNC) cond_func=(Item_func_match *) arg0; - else if ((functype == Item_func::LE_FUNC || - functype == Item_func::LT_FUNC) && + else if (arg0->const_item() && + ((functype == Item_func::LE_FUNC && arg0->val()> 0) || + (functype == Item_func::LT_FUNC && arg0->val()>=0)) && arg1->type() == Item::FUNC_ITEM && - arg1->functype() == Item_func::FT_FUNC && - arg0->const_item() && arg0->val()>0) + arg1->functype() == Item_func::FT_FUNC) cond_func=(Item_func_match *) arg1; } } @@ -2188,34 +2195,20 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) { Item *item; - /* - I'm (Sergei) too lazy to implement proper recursive descent here, - and anyway, nobody will use such a stupid queries - that will require it :-) - May be later... - */ while ((item=li++)) - { - if (item->type() == Item::FUNC_ITEM && - ((Item_func *)item)->functype() == Item_func::FT_FUNC) - { - cond_func=(Item_func_match *)item; - break; - } - } + add_ft_keys(keyuse_array,stat,item,usable_tables); } } - if (!cond_func || cond_func->key == NO_SUCH_KEY) + if (!cond_func || cond_func->key == NO_SUCH_KEY || + !(usable_tables & cond_func->table->map)) return; KEYUSE keyuse; - keyuse.table= cond_func->table; keyuse.val = cond_func; keyuse.key = cond_func->key; -#define FT_KEYPART (MAX_REF_PARTS+10) - keyuse.keypart=FT_KEYPART; + keyuse.keypart= FT_KEYPART; keyuse.used_tables=cond_func->key_item()->used_tables(); VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); } @@ -2443,6 +2436,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, best=best_time=records=DBL_MAX; KEYUSE *best_key=0; uint best_max_key_part=0; + my_bool found_constrain= 0; if (s->keyuse) { /* Use key if possible */ @@ -2507,6 +2501,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, } else { + found_constrain= 1; /* Check if we found full key */ @@ -2544,16 +2539,18 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, records=2.0; // Can't be as good as a unique } } + /* Limit the number of matched rows */ + tmp= records; + set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); if (table->used_keys & ((key_map) 1 << key)) { /* we can use only index tree */ uint keys_per_block= table->file->block_size/2/ (keyinfo->key_length+table->file->ref_length)+1; - tmp=(record_count*(records+keys_per_block-1)/ - keys_per_block); + tmp=record_count*(tmp+keys_per_block-1)/keys_per_block; } else - tmp=record_count*min(records,s->worst_seeks); + tmp=record_count*min(tmp,s->worst_seeks); } } else @@ -2584,7 +2581,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, { /* Assume that the first key part matches 1% of the file - and that the hole key matches 10 (dupplicates) or 1 + and that the hole key matches 10 (duplicates) or 1 (unique) records. Assume also that more key matches proportionally more records @@ -2622,6 +2619,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, records*= 2.0; } } + /* Limit the number of matched rows */ + set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); if (table->used_keys & ((key_map) 1 << key)) { /* we can use only index tree */ @@ -2664,20 +2663,31 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, s->table->used_keys && best_key) && !(s->table->force_index && best_key)) { // Check full join + ha_rows rnd_records= s->found_records; if (s->on_expr) { - tmp=rows2double(s->found_records); // Can't use read cache + tmp=rows2double(rnd_records); // Can't use read cache } else { tmp=(double) s->read_time; - /* Calculate time to read through cache */ + /* Calculate time to read previous rows through cache */ tmp*=(1.0+floor((double) cache_record_length(join,idx)* record_count / (double) thd->variables.join_buff_size)); } + + /* + If there is a restriction on the table, assume that 25% of the + rows can be skipped on next part. + This is to force tables that this table depends on before this + table + */ + if (found_constrain) + rnd_records-= rnd_records/4; + if (best == DBL_MAX || - (tmp + record_count/(double) TIME_FOR_COMPARE*s->found_records < + (tmp + record_count/(double) TIME_FOR_COMPARE*rnd_records < best + record_count/(double) TIME_FOR_COMPARE*records)) { /* @@ -2685,7 +2695,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, will ensure that this will be used */ best=tmp; - records= rows2double(s->found_records); + records= rows2double(rnd_records); best_key=0; } } @@ -3194,9 +3204,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->best_positions[i].records_read && !(join->select_options & OPTION_FOUND_ROWS))) { - /* Join with outer join condition */ - COND *orig_cond=sel->cond; - sel->cond=and_conds(sel->cond,tab->on_expr); if (sel->test_quick_select(tab->keys, used_tables & ~ current_map, (join->select_options & @@ -3204,7 +3211,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) HA_POS_ERROR : join->unit->select_limit_cnt)) < 0) DBUG_RETURN(1); // Impossible range - sel->cond=orig_cond; /* Fix for EXPLAIN */ if (sel->quick) join->best_positions[i].records_read= sel->quick->records; @@ -3222,7 +3228,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) (select->quick && (select->quick->records >= 100L)))) ? 2 : 1; - sel->read_tables= used_tables; + sel->read_tables= used_tables & ~current_map; } if (i != join->const_tables && tab->use_quick != 2) { /* Read with cache */ @@ -4271,6 +4277,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::STRING_ITEM: case Item::REF_ITEM: case Item::NULL_ITEM: + case Item::VARBIN_ITEM: { bool maybe_null=item->maybe_null; Field *new_field; @@ -6534,6 +6541,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ if (!select->quick->reverse_sorted()) { + if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST) + DBUG_RETURN(0); // Use filesort // ORDER BY range_key DESC QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick, used_key_parts); @@ -6675,6 +6684,8 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order, /* We have a ref on a const; Change this to a range that filesort can use. + For impossible ranges (like when doing a lookup on NULL on a NOT NULL + field, quick will contain an empty record set. */ if (!(select->quick=get_ft_or_quick_select_for_ref(table, tab))) goto err; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e16d7a0067d..b99dec8f250 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -761,6 +761,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, sql_field->flags|= NOT_NULL_FLAG; sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; } + else + key_info->flags|= HA_NULL_PART_KEY; if (!(file->table_flags() & HA_NULL_KEY)) { my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX), @@ -772,7 +774,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0)); DBUG_RETURN(-1); } - key_info->flags|= HA_NULL_PART_KEY; } if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) { @@ -1088,7 +1089,8 @@ mysql_rename_table(enum db_type base, wait_while_table_is_used() thd Thread handler table Table to remove from cache - + function HA_EXTRA_PREPARE_FOR_DELETE if table is to be deleted + HA_EXTRA_FORCE_REOPEN if table is not be used NOTES When returning, the table will be unusable for other threads until the table is closed. @@ -1098,13 +1100,14 @@ mysql_rename_table(enum db_type base, Win32 clients must also have a WRITE LOCK on the table ! */ -static void wait_while_table_is_used(THD *thd,TABLE *table) +static void wait_while_table_is_used(THD *thd,TABLE *table, + enum ha_extra_function function) { DBUG_PRINT("enter",("table: %s", table->real_name)); DBUG_ENTER("wait_while_table_is_used"); safe_mutex_assert_owner(&LOCK_open); - VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files + VOID(table->file->extra(function)); /* Mark all tables that are in use as 'old' */ mysql_lock_abort(thd, table); // end threads waiting on lock @@ -1140,7 +1143,7 @@ static bool close_cached_table(THD *thd, TABLE *table) { DBUG_ENTER("close_cached_table"); - wait_while_table_is_used(thd,table); + wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DELETE); /* Close lock if this is not got with LOCK TABLES */ if (thd->lock) { @@ -1366,6 +1369,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); + mysql_ha_closeall(thd, tables); for (table = tables; table; table = table->next) { char table_name[NAME_LEN*2+2]; @@ -1852,7 +1856,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, break; case ENABLE: VOID(pthread_mutex_lock(&LOCK_open)); - wait_while_table_is_used(thd, table); + wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); error= table->file->activate_all_index(thd); /* COND_refresh will be signaled in close_thread_tables() */ @@ -1861,7 +1865,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (table->db_type == DB_TYPE_MYISAM) { VOID(pthread_mutex_lock(&LOCK_open)); - wait_while_table_is_used(thd, table); + wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); table->file->deactivate_non_unique_index(HA_POS_ERROR); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 57044a8370a..4a61639b3ee 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -83,7 +83,7 @@ bool select_union::send_data(List<Item> &values) { thd->clear_error(); // do not report user about table overflow if (create_myisam_from_heap(thd, table, &tmp_table_param, - info.last_errno, 0)) + info.last_errno, 1)) return 1; } else @@ -211,7 +211,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, select_limit_cnt= sl->select_limit+sl->offset_limit; if (select_limit_cnt < sl->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR) + if (select_limit_cnt == HA_POS_ERROR && !sl->braces) sl->options&= ~OPTION_FOUND_ROWS; res= join->prepare(&sl->ref_pointer_array, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index e1c28dd0e4d..199693df7d6 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -91,6 +91,7 @@ int mysql_update(THD *thd, bzero((char*) &tables,sizeof(tables)); // For ORDER BY tables.table= table; + tables.alias= table_list->alias; if (setup_tables(update_table_list) || setup_conds(thd,update_table_list,&conds) || diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index aef58e6cb94..f3631263735 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -154,6 +154,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token RESET_SYM %token ROLLBACK_SYM %token ROLLUP_SYM +%token SAVEPOINT_SYM %token SELECT_SYM %token SHOW %token SLAVE @@ -616,7 +617,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); key_alg opt_btree_or_rtree %type <string_list> - key_usage_list + key_usage_list %type <key_part> key_part @@ -665,7 +666,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); query verb_clause create change select do drop insert replace insert2 insert_values update delete truncate rename show describe load alter optimize preload flush - reset purge begin commit rollback slave master_def master_defs + reset purge begin commit rollback savepoint + slave master_def master_defs repair restore backup analyze check start field_list field_list_item field_spec kill column_def key_def preload_list preload_keys @@ -746,6 +748,7 @@ verb_clause: | restore | revoke | rollback + | savepoint | select | set | slave @@ -814,10 +817,10 @@ master_def: MASTER_LOG_POS_SYM EQ ulonglong_num { Lex->mi.pos = $3; - /* + /* If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it - instead of causing subsequent errors. - We need to do it in this file, because only there we know that + instead of causing subsequent errors. + We need to do it in this file, because only there we know that MASTER_LOG_POS has been explicitely specified. On the contrary in change_master() (sql_repl.cc) we cannot distinguish between 0 (MASTER_LOG_POS explicitely specified as 0) and 0 (unspecified), @@ -876,7 +879,7 @@ create: lex->name=0; } create2 - {} + { Lex->select= &Lex->select_lex; } | CREATE opt_unique_or_fulltext INDEX ident key_alg ON table_ident { LEX *lex=Lex; @@ -896,7 +899,7 @@ create: lex->key_list.push_back(new Key($2,$4.str, $5, lex->col_list)); lex->col_list.empty(); } - | CREATE DATABASE opt_if_not_exists ident + | CREATE DATABASE opt_if_not_exists ident { Lex->create_info.table_charset=NULL; } opt_create_database_options { @@ -921,7 +924,7 @@ create: ; create2: - '(' field_list ')' opt_create_table_options create3 {} + '(' create2a {} | opt_create_table_options create3 {} | LIKE table_ident { @@ -935,14 +938,31 @@ create2: if (!(lex->name= (char *)$3)) YYABORT; } - ; + ; + +create2a: + field_list ')' opt_create_table_options create3 {} + | create_select ')' { Select->braces= 1;} union_opt {} + ; create3: /* empty */ {} - | opt_duplicate opt_as SELECT_SYM + | opt_duplicate opt_as create_select + { Select->braces= 0;} opt_union {} + | opt_duplicate opt_as '(' create_select ')' + { Select->braces= 1;} union_opt {} + ; + +create_select: + SELECT_SYM { LEX *lex=Lex; lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; + if (lex->sql_command == SQLCOM_INSERT) + lex->sql_command= SQLCOM_INSERT_SELECT; + else if (lex->sql_command == SQLCOM_REPLACE) + lex->sql_command= SQLCOM_REPLACE_SELECT; + lex->select->table_list.save_and_clear(&lex->save_list); mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST; } @@ -950,8 +970,9 @@ create3: { Select->parsing_place= SELECT_LEX_NODE::NO_MATTER; } - opt_select_from union_clause {} - ; + opt_select_from + { Lex->select->table_list.push_front(&Lex->save_list); } + ; opt_as: /* empty */ {} @@ -1169,10 +1190,10 @@ type: | char opt_binary { Lex->length=(char*) "1"; $$=FIELD_TYPE_STRING; } | nchar '(' NUM ')' { Lex->length=$3.str; - $$=FIELD_TYPE_STRING; + $$=FIELD_TYPE_STRING; Lex->charset=national_charset_info; } | nchar { Lex->length=(char*) "1"; - $$=FIELD_TYPE_STRING; + $$=FIELD_TYPE_STRING; Lex->charset=national_charset_info; } | BINARY '(' NUM ')' { Lex->length=$3.str; Lex->charset=&my_charset_bin; @@ -1351,8 +1372,8 @@ attribute: | UNIQUE_SYM { Lex->type|= UNIQUE_FLAG; } | UNIQUE_SYM KEY_SYM { Lex->type|= UNIQUE_KEY_FLAG; } | COMMENT_SYM text_literal { Lex->comment= $2; } - | COLLATE_SYM collation_name - { + | COLLATE_SYM collation_name + { if (Lex->charset && !my_charset_same(Lex->charset,$2)) { net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH, @@ -1817,7 +1838,7 @@ optimize: { LEX *lex=Lex; lex->sql_command = SQLCOM_OPTIMIZE; - lex->no_write_to_binlog= $2; + lex->no_write_to_binlog= $2; lex->check_opt.init(); } table_list opt_mi_check_type @@ -1846,7 +1867,7 @@ table_to_table_list: table_to_table: table_ident TO_SYM table_ident { - LEX *lex=Lex; + LEX *lex=Lex; SELECT_LEX_NODE *sl= lex->current_select; if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING, TL_IGNORE) || @@ -1874,8 +1895,8 @@ preload_keys: { LEX *lex=Lex; SELECT_LEX *sel= &lex->select_lex; - if (!sel->add_table_to_list(lex->thd, $1, NULL, $3, - TL_READ, + if (!sel->add_table_to_list(lex->thd, $1, NULL, $3, + TL_READ, sel->get_use_index(), (List<String> *)0)) YYABORT; @@ -1884,13 +1905,13 @@ preload_keys: preload_keys_spec: keys_or_index { Select->select_lex()->interval_list.empty(); } - preload_key_list_or_empty + preload_key_list_or_empty { LEX *lex=Lex; SELECT_LEX *sel= &lex->select_lex; sel->use_index= sel->interval_list; sel->use_index_ptr= &sel->use_index; - } + } ; preload_key_list_or_empty: @@ -2274,7 +2295,7 @@ interval_expr: simple_expr: simple_ident | simple_expr COLLATE_SYM ident_or_text %prec NEG - { + { $$= new Item_func_set_collation($1, new Item_string($3.str, $3.length, @@ -2324,7 +2345,7 @@ simple_expr: { Select->add_ftfunc_to_list((Item_func_match *) ($$=new Item_func_match_bool(*$2,$5))); } | ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); } - | BINARY expr %prec NEG + | BINARY expr %prec NEG { $$= new Item_func_set_collation($2,new Item_string(binary_keyword, 6, &my_charset_latin1)); @@ -2500,14 +2521,14 @@ simple_expr: | LINEFROMTEXT '(' expr ',' expr ')' { $$= new Item_func_geometry_from_text($3, $5); } | MASTER_POS_WAIT '(' expr ',' expr ')' - { + { $$= new Item_master_pos_wait($3, $5); - Lex->safe_to_cache_query=0; + Lex->safe_to_cache_query=0; } | MASTER_POS_WAIT '(' expr ',' expr ',' expr ')' - { + { $$= new Item_master_pos_wait($3, $5, $7); - Lex->safe_to_cache_query=0; + Lex->safe_to_cache_query=0; } | MICROSECOND_SYM '(' expr ')' { $$= new Item_func_microsecond($3); } @@ -2670,9 +2691,9 @@ simple_expr: | USER '(' ')' { $$= new Item_func_user(); Lex->safe_to_cache_query=0; } | WEEK_SYM '(' expr ')' - { + { $$= new Item_func_week($3,new Item_int((char*) "0", - YYTHD->variables.default_week_format,1)); + YYTHD->variables.default_week_format,1)); } | WEEK_SYM '(' expr ',' expr ')' { $$= new Item_func_week($3,$5); } @@ -2723,9 +2744,10 @@ sum_expr: { $$=new Item_sum_variance($3); } | SUM_SYM '(' in_sum_expr ')' { $$=new Item_sum_sum($3); } - | GROUP_CONCAT_SYM '(' opt_distinct expr_list opt_gorder_clause opt_gconcat_separator ')' - { - $$=new Item_func_group_concat($3,$4,Lex->gorder_list,$6); + | GROUP_CONCAT_SYM '(' opt_distinct expr_list opt_gorder_clause + opt_gconcat_separator ')' + { + $$=new Item_func_group_concat($3,$4,Lex->gorder_list,$6); $4->empty(); }; @@ -2736,10 +2758,10 @@ opt_distinct: opt_gconcat_separator: /* empty */ { $$ = new String(",",1,default_charset_info); } |SEPARATOR_SYM text_string { $$ = $2; }; - + opt_gorder_clause: - /* empty */ + /* empty */ { LEX *lex=Lex; lex->gorder_list = NULL; @@ -2750,7 +2772,7 @@ opt_gorder_clause: lex->gorder_list= (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list,sizeof(st_sql_list)); lex->current_select->order_list.empty(); }; - + in_sum_expr: opt_all @@ -2839,7 +2861,7 @@ join_table_list: | join_table_list normal_join join_table_list ON expr { add_join_on($3,$5); $$=$3; } | join_table_list normal_join join_table_list - USING + USING { SELECT_LEX *sel= Select->select_lex(); sel->db1=$1->db; sel->table1=$1->alias; @@ -2925,8 +2947,9 @@ select_derived: { LEX *lex= Lex; lex->derived_tables= 1; - if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN && - lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) + if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN && + lex->sql_command <= (int)SQLCOM_HA_READ) || + lex->sql_command == (int)SQLCOM_KILL) { send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; @@ -3368,7 +3391,7 @@ drop: LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_USER; lex->users_list.empty(); - } + } user_list {} ; @@ -3411,6 +3434,7 @@ insert: opt_ignore insert2 { Select->set_lock_for_tables($3); + Lex->select= &Lex->select_lex; } insert_field_spec opt_insert_update {} @@ -3427,6 +3451,7 @@ replace: replace_lock_option insert2 { Select->set_lock_for_tables($3); + Lex->select= &Lex->select_lex; } insert_field_spec {} @@ -3458,7 +3483,9 @@ insert_table: }; insert_field_spec: - opt_field_spec insert_values {} + insert_values {} + | '(' ')' insert_values {} + | '(' fields ')' insert_values {} | SET { LEX *lex=Lex; @@ -3480,27 +3507,9 @@ fields: insert_values: VALUES values_list {} | VALUE_SYM values_list {} - | SELECT_SYM - { - LEX *lex=Lex; - lex->sql_command = (lex->sql_command == SQLCOM_INSERT ? - SQLCOM_INSERT_SELECT : SQLCOM_REPLACE_SELECT); - lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; - mysql_init_select(lex); - /* - it is not simple select => table list will be - preprocessed before passing to handle_select - */ - lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE; - lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST; - } - select_options select_item_list - { - Select->parsing_place= SELECT_LEX_NODE::NO_MATTER; - } - opt_select_from select_lock_type - union_clause {} - ; + | create_select { Select->braces= 0;} opt_union {} + | '(' create_select ')' { Select->braces= 1;} union_opt {} + ; values_list: values_list ',' no_braces @@ -3905,7 +3914,7 @@ flush: { LEX *lex=Lex; lex->sql_command= SQLCOM_FLUSH; lex->type=0; - lex->no_write_to_binlog= $2; + lex->no_write_to_binlog= $2; } flush_options {} @@ -3974,7 +3983,7 @@ purge_option: if ($2->check_cols(1) || $2->fix_fields(Lex->thd, 0, &$2)) { net_printf(Lex->thd, ER_WRONG_ARGUMENTS, "PURGE LOGS BEFORE"); - YYABORT; + YYABORT; } Item *tmp= new Item_func_unix_timestamp($2); Lex->sql_command = SQLCOM_PURGE_BEFORE; @@ -4146,8 +4155,8 @@ literal: { Item *tmp= new Item_varbinary($2.str,$2.length); String *str= tmp ? tmp->val_str((String*) 0) : (String*) 0; - $$ = new Item_string(str ? str->ptr() : "", str ? str->length() : 0, - Lex->charset); + $$ = new Item_string(str ? str->ptr() : "", str ? str->length() : + 0, Lex->charset); } | DATE_SYM text_literal { $$ = $2; } | TIME_SYM text_literal { $$ = $2; } @@ -4162,7 +4171,7 @@ insert_ident: | table_wild { $$=$1; }; table_wild: - ident '.' '*' + ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); Lex->current_select->select_lex()->with_wild++; @@ -4195,7 +4204,7 @@ simple_ident: SELECT_LEX_NODE *sel= lex->current_select; if (sel->no_table_names_allowed) { - my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, + my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, ER(ER_TABLENAME_NOT_ALLOWED_HERE), MYF(0), $1.str, thd->where); } @@ -4211,7 +4220,7 @@ simple_ident: SELECT_LEX_NODE *sel= lex->current_select; if (sel->no_table_names_allowed) { - my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, + my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, ER(ER_TABLENAME_NOT_ALLOWED_HERE), MYF(0), $2.str, thd->where); } @@ -4227,7 +4236,7 @@ simple_ident: SELECT_LEX_NODE *sel= lex->current_select; if (sel->no_table_names_allowed) { - my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, + my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, ER(ER_TABLENAME_NOT_ALLOWED_HERE), MYF(0), $3.str, thd->where); } @@ -4489,6 +4498,7 @@ keyword: | ROWS_SYM {} | ROW_FORMAT_SYM {} | ROW_SYM {} + | SAVEPOINT_SYM {} | SECOND_SYM {} | SERIAL_SYM {} | SERIALIZABLE_SYM {} @@ -4838,7 +4848,7 @@ grant: lex->select_lex.db= 0; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; - bzero(&(lex->mqh),sizeof(lex->mqh)); + bzero((char *)&(lex->mqh),sizeof(lex->mqh)); } grant_privileges ON opt_table TO_SYM user_list require_clause grant_options @@ -5099,8 +5109,21 @@ commit: COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;}; rollback: - ROLLBACK_SYM { Lex->sql_command = SQLCOM_ROLLBACK;}; - + ROLLBACK_SYM + { + Lex->sql_command = SQLCOM_ROLLBACK; + } + | ROLLBACK_SYM TO_SYM SAVEPOINT_SYM ident + { + Lex->sql_command = SQLCOM_ROLLBACK_TO_SAVEPOINT; + Lex->savepoint_name = $4.str; + }; +savepoint: + SAVEPOINT_SYM ident + { + Lex->sql_command = SQLCOM_SAVEPOINT; + Lex->savepoint_name = $2.str; + }; /* UNIONS : glue selects together diff --git a/sql/table.cc b/sql/table.cc index 1cee0587f17..a76bdc84690 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -484,7 +484,10 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, /* This has to be done after the above fulltext correction */ index_flags=outparam->file->index_flags(key); if (!(index_flags & HA_KEY_READ_ONLY)) + { + outparam->read_only_keys|= ((key_map) 1 << key); outparam->keys_for_keyread&= ~((key_map) 1 << key); + } if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME)) { diff --git a/sql/table.h b/sql/table.h index 2fab0087da4..4b8a5a78e1f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -76,7 +76,7 @@ struct st_table { uint uniques; uint null_fields; /* number of null fields */ uint blob_fields; /* number of blob fields */ - key_map keys_in_use, keys_for_keyread; + key_map keys_in_use, keys_for_keyread, read_only_keys; key_map quick_keys, used_keys, keys_in_use_for_query; KEY *key_info; /* data of keys in database */ TYPELIB keynames; /* Pointers to keynames */ diff --git a/sql/uniques.cc b/sql/uniques.cc index c6fb0f25643..4514de834a8 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -49,8 +49,8 @@ int unique_write_to_ptrs(gptr key, element_count count, Unique *unique) } Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, - uint size, ulong max_in_memory_size_arg) - :max_in_memory_size(max_in_memory_size_arg),elements(0) + uint size_arg, ulong max_in_memory_size_arg) + :max_in_memory_size(max_in_memory_size_arg), size(size_arg), elements(0) { my_b_clear(&file); init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, @@ -101,7 +101,7 @@ bool Unique::get(TABLE *table) { /* Whole tree is in memory; Don't use disk if you don't need to */ if ((record_pointers=table->sort.record_pointers= (byte*) - my_malloc(tree.size_of_element * tree.elements_in_tree, MYF(0)))) + my_malloc(size * tree.elements_in_tree, MYF(0)))) { (void) tree_walk(&tree, (tree_walk_action) unique_write_to_ptrs, this, left_root_right); diff --git a/strings/strmake.c b/strings/strmake.c index 2e384fc168a..d2252f648f6 100644 --- a/strings/strmake.c +++ b/strings/strmake.c @@ -21,7 +21,7 @@ strmake(dst,src,length) moves length characters, or until end, of src to dst and appends a closing NUL to dst. - Note that is strlen(src) >= length then dst[length] will be set to \0 + Note that if strlen(src) >= length then dst[length] will be set to \0 strmake() returns pointer to closing null */ diff --git a/support-files/MySQL-shared-compat.spec.sh b/support-files/MySQL-shared-compat.spec.sh index f569dc20f42..06dfec1f6f9 100644 --- a/support-files/MySQL-shared-compat.spec.sh +++ b/support-files/MySQL-shared-compat.spec.sh @@ -69,4 +69,4 @@ rpm2cpio %{SOURCE1} | cpio -iv --make-directories %files %defattr(-, root, root) -/usr/lib/libmysqlclient* +%{_libdir}/libmysqlclient* diff --git a/support-files/my-innodb-heavy-4G.cnf.sh b/support-files/my-innodb-heavy-4G.cnf.sh new file mode 100644 index 00000000000..ed2c2ce9dfd --- /dev/null +++ b/support-files/my-innodb-heavy-4G.cnf.sh @@ -0,0 +1,509 @@ +#BEGIN CONFIG INFO +#DESCR: 4GB RAM, InnoDB only, ACID, few connections, heavy queries +#TYPE: SYSTEM +#END CONFIG INFO + +# +# This is a MySQL example config file for systems with 4GB of memory +# running mostly MySQL using InnoDB only tables and performing complex +# queries with few connections. +# +# You can copy this file to /etc/my.cnf to set global options, +# mysql-data-dir/my.cnf to set server-specific options +# (@localstatedir@ for this installation) or to +# ~/.my.cnf to set user-specific options. +# +# In this file, you can use all long options that the program supports. +# If you want to know the options a program supports, run the program +# with the "--help" option. +# +# More detailed information about the individual options can also be +# found in the manual. +# + +# +# The following options will be read by MySQL client applications. +# Note that only client applications shipped by MySQL are guaranteed +# to read this section. If you want your own MySQL client program to +# honor these values, you need to specify it as an option during the +# MySQL client library initialization. +# +[client] +#password = [your_password] +port = @MYSQL_TCP_PORT@ +socket = @MYSQL_UNIX_ADDR@ + +# *** Application-specific options follow here *** + +# +# The MySQL server +# +[mysqld] + +# generic configuration options +port = @MYSQL_TCP_PORT@ +socket = @MYSQL_UNIX_ADDR@ + +# back_log is the number of connections the operating system can keep in +# the listen queue, before the MySQL connection manager thread has +# processed them. If you have a very high connection rate and experience +# "connection refused" errors, you might need to increase this value. +# Check your OS documentation for the maximum value of this parameter. +# Attempting to set back_log higher than your operating system limit +# will have no effect. +back_log = 50 + +# Don't listen on a TCP/IP port at all. This can be a security +# enhancement, if all processes that need to connect to mysqld run +# on the same host. All interaction with mysqld must be made via Unix +# sockets or named pipes. +# Note that using this option without enabling named pipes on Windows +# (via the "enable-named-pipe" option) will render mysqld useless! +#skip-networking + +# The maximum amount of concurrent sessions the MySQL server will +# allow. One of these connections will be reserved for a user with +# SUPER privileges to allow the administrator to login even if the +# connection limit has been reached. +max_connections = 100 + +# Maximum amount of errors allowed per host. If this limit is reached, +# the host will be blocked from connecting to the MySQL server until +# "FLUSH HOSTS" has been run or the server was restarted. Invalid +# passwords and other errors during the connect phase result in +# increasing this value. See the "Aborted_Connects" status variable for +# global counter. +max_connect_errors = 10 + +# The number of open tables for all threads. Increasing this value +# increases the number of file descriptors that mysqld requires. +# Therefore you have to make sure to set the amount of open files +# allowed to at least 4096 in the variable "open-files-limit" in +# section [mysqld_safe] +table_cache = 2048 + +# Enable external file level locking. Enabled file locking will have a +# negative impact on performance, so only use it in case you have +# multiple database instances running on the same files (note some +# restrictions still apply!) or if you use other software relying on +# locking MyISAM tables on file level. +#external-locking + +# The maximum size of a query packet the server can handle as well as +# maximum query size server can process (Important when working with +# large BLOBs). enlarged dynamically, for each connection. +max_allowed_packet = 16M + +# The size of the cache to hold the SQL statements for the binary log +# during a transaction. If you often use big, multi-statement +# transactions you can increase this value to get more performance. All +# statements from transactions are buffered in the binary log cache and +# are being written to the binary log at once after the COMMIT. If the +# transaction is larger than this value, temporary file on disk is used +# instead. This buffer is allocated per connection on first update +# statement in transaction +binlog_cache_size = 1M + +# Maximum allowed size for a single HEAP (in memory) table. This option +# is a protection against the accidential creation of a very large HEAP +# table which could otherwise use up all memory resources. +max_heap_table_size = 64M + +# Sort buffer is used to perform sorts for some ORDER BY and GROUP BY +# queries. If sorted data does not fit into the sort buffer, a disk +# based merge sort is used instead - See "sort_merge_passes". Allocated +# per thread if sort is needed. +sort_buffer_size = 8M + +# This buffer is used for the optimization of full JOINs (JOINs without +# indexes). Such JOINs are very bad for performance in most cases +# anyway, but setting this variable to a large value reduces the +# performance impact. See the "select_full_join" status variable for a +# count of full JOINs. Allocated per thread if full join is found +join_buffer_size = 8M + +# How many threads we should keep in a cache for reuse. When a client +# disconnects, the client's threads are put in the cache if there aren't +# more than thread_cache_size threads from before. This greatly reduces +# the amount of thread creations needed if you have a lot of new +# connections. (Normally this doesn't give a notable performance +# improvement if you have a good thread implementation.) +thread_cache = 8 + +# This permits the application to give the threads system a hint for the +# desired number of threads that should be run at the same time. This +# value only makes sense on systems that support the thread_concurrency() +# function call (Sun Solaris, for example). +# You should try [number of CPUs]*(2..4) for thread_concurrency +thread_concurrency = 8 + +# Query cache is used to cache SELECT results and later return them +# without actual executing the same query once again. Having the query +# cache enabled may result in significant speed improvements, if your +# have a lot of identical queries and rarely changing tables. See the +# "Qcache_lowmem_prunes" status variable to check if the current value +# is high enough for your load. +# Note: In case your tables change very often or if your queries are +# textually different every time, the query cache may result in a +# slowdown instead of a performance improvement. +query_cache_size = 64M + +# Only cache result sets that are smaller than this limit. This is to +# protect the query cache of a very large result set overwriting all +# other query results. +query_cache_limit = 2M + +# Minimum word length to be indexed by the full text search index. +# You might wish to decrease it if you need to search for shorter words. +# Note that you need to rebuild your FULLTEXT index, after you have +# modified this value. +ft_min_word_len = 4 + +# If your system supports the memlock() function call, you might want to +# enable this option while running MySQL to keep it locked in memory and +# to avoid potential swapping out in case of high memory pressure. Good +# for performance. +#memlock + +# Table type which is used by default when creating new tables, if not +# specified differently during the CREATE TABLE statement. +default_table_type = MYISAM + +# Thread stack size to use. This amount of memory is always reserved at +# connection time. MySQL itself usually needs no more than 64K of +# memory, while if you use your own stack hungry UDF functions or your +# OS requires more stack for some operations, you might need to set this +# to a higher value. +thread_stack = 192K + +# Set the default transaction isolation level. Levels available are: +# READ-UNCOMMITED, READ-COMMITED, REPEATABLE-READ, SERIALIZABLE +transaction_isolation = REPEATABLE-READ + +# Maximum size for internal (in-memory) temporary tables. If a table +# grows larger than this value, it is automatically converted to disk +# based table This limitation is for a single table. There can be many +# of them. +tmp_table_size = 64M + +# Enable binary logging. This is required for acting as a MASTER in a +# replication configuration. You also need the binary log if you need +# the ability to do point in time recovery from your latest backup. +log_bin + +# If you're using replication with chained slaves (A->B->C), you need to +# enable this option on server B. It enables logging of updates done by +# the slave thread into the slave's binary log. +#log_slave_updates + +# Enable the full query log. Every query (even ones with incorrect +# syntax) that the server receives will be logged. This is useful for +# debugging, it is usually disabled in production use. +#log + +# Print warnings to the error log file. If you have any problem with +# MySQL you should enable logging of warnings and examine the error log +# for possible explanations. +#log_warnings + +# Log slow queries. Slow queries are queries which take more than the +# amount of time defined in "long_query_time" or which do not use +# indexes well, if log_long_format is enabled. It is normally good idea +# to have this turned on if you frequently add new queries to the +# system. +log_slow_queries + +# All queries taking more than this amount of time (in seconds) will be +# trated as slow. Do not use "1" as a value here, as this will result in +# even very fast queries being logged from time to time (as MySQL +# currently measures time with second accuracy only). +long_query_time = 2 + +# Log more information in the slow query log. Normally it is good to +# have this turned on. This will enable logging of queries that are not +# using indexes in addition to long running queries. +log_long_format + +# The directory used by MySQL for storing temporary files. For example, +# it is used to perform disk based large sorts, as well as for internal +# and explicit temporary tables. It might be good to put it on a +# swapfs/tmpfs filesystem, if you do not create very large temporary +# files. Alternatively you can put it on dedicated disk. You can +# specify multiple paths here by separating them by ";" - they will then +# be used in a round-robin fashion. +#tmpdir = /tmp + + +# *** Replication related settings + + +# Unique server identification number between 1 and 2^32-1. This value +# is required for both master and slave hosts. It defaults to 1 if +# "master-host" is not set, but will MySQL will not function as a master +# if it is omitted. +server-id = 1 + +# Replication Slave (comment out master section to use this) +# +# To configure this host as a replication slave, you can choose between +# two methods : +# +# 1) Use the CHANGE MASTER TO command (fully described in our manual) - +# the syntax is: +# +# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>, +# MASTER_USER=<user>, MASTER_PASSWORD=<password> ; +# +# where you replace <host>, <user>, <password> by quoted strings and +# <port> by the master's port number (3306 by default). +# +# Example: +# +# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306, +# MASTER_USER='joe', MASTER_PASSWORD='secret'; +# +# OR +# +# 2) Set the variables below. However, in case you choose this method, then +# start replication for the first time (even unsuccessfully, for example +# if you mistyped the password in master-password and the slave fails to +# connect), the slave will create a master.info file, and any later +# changes in this file to the variable values below will be ignored and +# overridden by the content of the master.info file, unless you shutdown +# the slave server, delete master.info and restart the slaver server. +# For that reason, you may want to leave the lines below untouched +# (commented) and instead use CHANGE MASTER TO (see above) +# +# required unique id between 2 and 2^32 - 1 +# (and different from the master) +# defaults to 2 if master-host is set +# but will not function as a slave if omitted +#server-id = 2 +# +# The replication master for this slave - required +#master-host = <hostname> +# +# The username the slave will use for authentication when connecting +# to the master - required +#master-user = <username> +# +# The password the slave will authenticate with when connecting to +# the master - required +#master-password = <password> +# +# The port the master is listening on. +# optional - defaults to 3306 +#master-port = <port> + +# Make the slave read-only. Only users with the SUPER privilege and the +# replication slave thread will be able to modify data on it. You can +# use this to ensure that no applications will accidently modify data on +# the slave instead of the master +#read_only + + +#*** MyISAM Specific options + + +# Size of the Key Buffer, used to cache index blocks for MyISAM tables. +# Do not set it larger than 30% of your available memory, as some memory +# is also required by the OS to cache rows. Even if you're not using +# MyISAM tables, you should still set it to 8-64M as it will also be +# used for internal temporary disk tables. +key_buffer_size = 32M + +# Size of the buffer used for doing full table scans of MyISAM tables. +# Allocated per thread, if a full scan is needed. +read_buffer_size = 2M + +# When reading rows in sorted order after a sort, the rows are read +# through this buffer to avoid a disk seeks. You can improve ORDER BY +# performance a lot, if set this to a high value. +# Allocated per thread, when needed. +read_rnd_buffer_size = 16M + +# MyISAM uses special tree-like cache to make bulk inserts (that is, +# INSERT ... SELECT, INSERT ... VALUES (...), (...), ..., and LOAD DATA +# INFILE) faster. This variable limits the size of the cache tree in +# bytes per thread. Setting it to 0 will disable this optimisation. Do +# not set it larger than "key_buffer_size" for optimal performance. +# This buffer is allocated when a bulk insert is detected. +bulk_insert_buffer_size = 64M + +# This buffer is allocated when MySQL needs to rebuild the index in +# REPAIR, OPTIMZE, ALTER table statements as well as in LOAD DATA INFILE +# into an empty table. It is allocated per thread so be careful with +# large settings. +myisam_sort_buffer_size = 128M + +# The maximum size of the temporary file MySQL is allowed to use while +# recreating the index (during REPAIR, ALTER TABLE or LOAD DATA INFILE. +# If the file-size would be bigger than this, the index will be created +# through the key cache (which is slower). +myisam_max_sort_file_size = 10G + +# If the temporary file used for fast index creation would be bigger +# than using the key cache by the amount specified here, then prefer the +# key cache method. This is mainly used to force long character keys in +# large tables to use the slower key cache method to create the index. +myisam_max_extra_sort_file_size = 10G + +# If a table has more than one index, MyISAM can use more than one +# thread to repair them by sorting in parallel. This makes sense if you +# have multiple CPUs and plenty of memory. +myisam_repair_threads = 1 + +# Automatically check and repair not properly closed MyISAM tables. +myisam_recover + + +# *** BDB Specific options *** + +# Use this option if you run a MySQL server with BDB support enabled but +# you do not plan to use it. This will save memory and may speed up some +# things. +skip-bdb + + +# *** INNODB Specific options *** + +# Use this option if you have a MySQL server with InnoDB support enabled +# but you do not plan to use it. This will save memory and disk space +# and speed up some things. +#skip-innodb + +# Additional memory pool that is used by InnoDB to store metadata +# information. If InnoDB requires more memory for this purpose it will +# start to allocate it from the OS. As this is fast enough on most +# recent operating systems, you normally do not need to change this +# value. SHOW INNODB STATUS will display the current amount used. +innodb_additional_mem_pool_size = 16M + +# InnoDB, unlike MyISAM, uses a buffer pool to cache both indexes and +# row data. The bigger you set this the less disk I/O is needed to +# access data in tables. On a dedicated database server you may set this +# parameter up to 80% of the machine physical memory size. Do not set it +# too large, though, because competition of the physical memory may +# cause paging in the operating system. Note that on 32bit systems you +# might be limited to 2-3.5G of user level memory per process, so do not +# set it too high. +innodb_buffer_pool_size = 2G + +# InnoDB stores data in one or more data files forming the tablespace. +# If you have a single logical drive for your data, a single +# autoextending file would be good enough. In other cases, a single file +# per device is often a good choice. You can configure InnoDB to use raw +# disk partitions as well - please refer to the manual for more info +# about this. +innodb_data_file_path = ibdata1:10M:autoextend + +# Set this option if you would like the InnoDB tablespace files to be +# stored in another location. By default this is the MySQL datadir. +#innodb_data_home_dir = <directory> + +# Number of IO threads to use for async IO operations. This value is +# hardcoded to 4 on Unix, but on Windows disk I/O may benefit from a +# larger number. +innodb_file_io_threads = 4 + +# If you run into InnoDB tablespace corruption, setting this to a nonzero +# value will likely help you to dump your tables. Start from value 1 and +# increase it until you're able to dump the table successfully. +#innodb_force_recovery=1 + +# Number of threads allowed inside the InnoDB kernel. The optimal value +# depends highly on the application, hardware as well as the OS +# scheduler properties. A too high value may lead to thread thrashing. +innodb_thread_concurrency = 16 + +# If set to 1, InnoDB will flush (fsync) the transaction logs to the +# disk at each commit, which offers full ACID behavior. If you are +# willing to compromise this safety, and you are running small +# transactions, you may set this to 0 or 2 to reduce disk I/O to the +# logs. Value 0 means that the log is only written to the log file and +# the log file flushed to disk approximately once per second. Value 2 +# means the log is written to the log file at each commit, but the log +# file is only flushed to disk approximately once per second. +innodb_flush_log_at_trx_commit = 1 + +# Speed up InnoDB shutdown. This will disable InnoDB to do a full purge +# and insert buffer merge on shutdown. It may increase shutdown time a +# lot, but InnoDB will have to do it on the next startup instead. +#innodb_fast_shutdown + +# The size of the buffer InnoDB uses for buffering log data. As soon as +# it is full, InnoDB will have to flush it to disk. As it is flushed +# once per second anyway, it does not make sense to have it very large +# (even with long transactions). +innodb_log_buffer_size = 8M + +# Size of each log file in a log group. You should set the combined size +# of log files to about 25%-100% of your buffer pool size to avoid +# unneeded buffer pool flush activity on log file overwrite. However, +# note that a larger logfile size will increase the time needed for the +# recovery process. +innodb_log_file_size = 256M + +# Total number of files in the log group. A value of 2-3 is usually good +# enough. +innodb_log_files_in_group = 3 + +# Location of the InnoDB log files. Default is the MySQL datadir. You +# may wish to point it to a dedicated hard drive or a RAID1 volume for +# improved performance +#innodb_log_group_home_dir + +# Maximum allowed percentage of dirty pages in the InnoDB buffer pool. +# If it is reached, InnoDB will start flushing them out agressively to +# not run out of clean pages at all. This is a soft limit, not +# guaranteed to be held. +innodb_max_dirty_pages_pct = 90 + +# The flush method InnoDB will use for Log. The tablespace always uses +# doublewrite flush logic. The default value is "fdatasync", another +# option is "O_DSYNC". +#innodb_flush_method=O_DSYNC + +# How long an InnoDB transaction should wait for a lock to be granted +# before being rolled back. InnoDB automatically detects transaction +# deadlocks in its own lock table and rolls back the transaction. If you +# use the LOCK TABLES command, or other transaction-safe storage engines +# than InnoDB in the same transaction, then a deadlock may arise which +# InnoDB cannot notice. In cases like this the timeout is useful to +# resolve the situation. +innodb_lock_wait_timeout = 120 + + +[mysqldump] +# Do not buffer the whole result set in memory before writing it to +# file. Required for dumping very large tables +quick + +max_allowed_packet = 16M + +[mysql] +no-auto-rehash + +# Only allow UPDATEs and DELETEs that use keys. +#safe-updates + +[isamchk] +key_buffer = 512M +sort_buffer_size = 512M +read_buffer = 8M +write_buffer = 8M + +[myisamchk] +key_buffer = 512M +sort_buffer_size = 512M +read_buffer = 8M +write_buffer = 8M + +[mysqlhotcopy] +interactive-timeout + +[mysqld_safe] +# Increase the amount of open files allowed per process. Warning: Make +# sure you have set the global system limit high enough! The high value +# is required for a large number of opened tables +open-files-limit = 8192 diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 81c05f9cc89..4afdac9914a 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1,7 +1,7 @@ %define mysql_version @VERSION@ -%define shared_lib_version @SHARED_LIB_VERSION@ %define release 0 %define mysqld_user mysql +%define server_suffix -standard %define see_base For a description of MySQL see the base MySQL RPM or http://www.mysql.com @@ -14,7 +14,6 @@ Version: @MYSQL_NO_DASH_VERSION@ Release: %{release} Copyright: GPL Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/mysql-%{mysql_version}.tar.gz -Icon: mysql.gif URL: http://www.mysql.com/ Packager: Lenz Grimmer <build@mysql.com> Vendor: MySQL AB @@ -194,6 +193,8 @@ BuildMySQL() { # The --enable-assembler simply does nothing on systems that does not # support assembler speedups. sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ + CC=\"${CC:-$MYSQL_BUILD_CC}\" \ + CXX=\"${CXX:-$MYSQL_BUILD_CXX}\" \ CFLAGS=\"${MYSQL_BUILD_CFLAGS:-$RPM_OPT_FLAGS}\" \ CXXFLAGS=\"${MYSQL_BUILD_CXXFLAGS:-$RPM_OPT_FLAGS \ -felide-constructors -fno-exceptions -fno-rtti \ @@ -206,15 +207,15 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --with-unix-socket-path=/var/lib/mysql/mysql.sock \ --prefix=/ \ --with-extra-charsets=complex \ - --exec-prefix=/usr \ - --libexecdir=/usr/sbin \ - --sysconfdir=/etc \ - --datadir=/usr/share \ + --exec-prefix=%{_exec_prefix} \ + --libexecdir=%{_sbindir} \ + --libdir=%{_libdir} \ + --sysconfdir=%{_sysconfdir} \ + --datadir=%{_datadir} \ --localstatedir=/var/lib/mysql \ --infodir=%{_infodir} \ - --includedir=/usr/include \ + --includedir=%{_includedir} \ --mandir=%{_mandir} \ - --with-embedded-server \ --enable-thread-safe-client \ --with-comment=\"Official MySQL RPM\"; # Add this for more debugging support @@ -243,7 +244,7 @@ MBD=$RPM_BUILD_DIR/mysql-%{mysql_version} # Clean up the BuildRoot first [ "$RBR" != "/" ] && [ -d $RBR ] && rm -rf $RBR; -mkdir -p $RBR +mkdir -p $RBR%{_libdir}/mysql # # Use MYSQL_BUILD_PATH so that we can use a dedicated version of gcc @@ -266,6 +267,7 @@ BuildMySQL "--enable-shared \ --with-berkeley-db \ --with-innodb \ --with-raid \ + --with-embedded-server \ --with-server-suffix='-Max'" # Save everything for debug @@ -275,6 +277,9 @@ BuildMySQL "--enable-shared \ mv sql/mysqld sql/mysqld-max nm --numeric-sort sql/mysqld-max > sql/mysqld-max.sym +# Install embedded server library in the build root +install -m 644 libmysqld/libmysqld.a $RBR%{_libdir}/mysql + # Save libraries (cd libmysql/.libs; tar cf $RBR/shared-libs.tar *.so*) (cd libmysql_r/.libs; tar rf $RBR/shared-libs.tar *.so*) @@ -285,69 +290,75 @@ make distclean mv Docs/manual.ps.save Docs/manual.ps # RPM:s destroys Makefile.in files, so we generate them here -automake +# aclocal; autoheader; aclocal; automake; autoconf +# (cd innobase && aclocal && autoheader && aclocal && automake && autoconf) # Now build the statically linked 4.0 binary (which includes InnoDB) BuildMySQL "--disable-shared \ --with-mysqld-ldflags='-all-static' \ --with-client-ldflags='-all-static' \ $USE_OTHER_LIBC_DIR \ + --with-server-suffix='%{server_suffix}' \ + --without-embedded-server \ --without-berkeley-db \ --with-innodb \ --without-vio \ --without-openssl" nm --numeric-sort sql/mysqld > sql/mysqld.sym -%install -n mysql-%{mysql_version} +%install RBR=$RPM_BUILD_ROOT MBD=$RPM_BUILD_DIR/mysql-%{mysql_version} # Ensure that needed directories exists -install -d $RBR/etc/{logrotate.d,init.d} +install -d $RBR%{_sysconfdir}/{logrotate.d,init.d} install -d $RBR/var/lib/mysql/mysql -install -d $RBR/usr/share/{sql-bench,mysql-test} +install -d $RBR%{_datadir}/{sql-bench,mysql-test} +install -d $RBR%{_includedir} +install -d $RBR%{_libdir} install -d $RBR%{_mandir} -install -d $RBR/usr/{sbin,lib,include} +install -d $RBR%{_sbindir} + # Install all binaries stripped -make install-strip DESTDIR=$RBR benchdir_root=/usr/share/ +make install-strip DESTDIR=$RBR benchdir_root=%{_datadir} # Install shared libraries (Disable for architectures that don't support it) -(cd $RBR/usr/lib; tar xf $RBR/shared-libs.tar) +(cd $RBR%{_libdir}; tar xf $RBR/shared-libs.tar; rm -f $RBR/shared-libs.tar) # install saved mysqld-max -install -s -m755 $MBD/sql/mysqld-max $RBR/usr/sbin/mysqld-max +install -s -m755 $MBD/sql/mysqld-max $RBR%{_sbindir}/mysqld-max # install symbol files ( for stack trace resolution) -install -m644 $MBD/sql/mysqld-max.sym $RBR/usr/lib/mysql/mysqld-max.sym -install -m644 $MBD/sql/mysqld.sym $RBR/usr/lib/mysql/mysqld.sym +install -m644 $MBD/sql/mysqld-max.sym $RBR%{_libdir}/mysql/mysqld-max.sym +install -m644 $MBD/sql/mysqld.sym $RBR%{_libdir}/mysql/mysqld.sym # Install logrotate and autostart -install -m644 $MBD/support-files/mysql-log-rotate $RBR/etc/logrotate.d/mysql -install -m755 $MBD/support-files/mysql.server $RBR/etc/init.d/mysql +install -m644 $MBD/support-files/mysql-log-rotate $RBR%{_sysconfdir}/logrotate.d/mysql +install -m755 $MBD/support-files/mysql.server $RBR%{_sysconfdir}/init.d/mysql # Create a symlink "rcmysql", pointing to the init.script. SuSE users # will appreciate that, as all services usually offer this. -ln -s ../../sbin/init.d/mysql $RPM_BUILD_ROOT/usr/sbin/rcmysql +ln -s %{_sysconfdir}/init.d/mysql $RPM_BUILD_ROOT%{_sbindir}/rcmysql # Create symbolic compatibility link safe_mysqld -> mysqld_safe # (safe_mysqld will be gone in MySQL 4.1) -ln -sf ./mysqld_safe $RBR/usr/bin/safe_mysqld +ln -sf ./mysqld_safe $RBR%{_bindir}/safe_mysqld # Touch the place where the my.cnf config file might be located # Just to make sure it's in the file list and marked as a config file -touch $RBR/etc/my.cnf +touch $RBR%{_sysconfdir}/my.cnf %pre server # Shut down a previously installed server first -if test -x /etc/init.d/mysql +if test -x %{_sysconfdir}/init.d/mysql then - /etc/init.d/mysql stop > /dev/null 2>&1 + %{_sysconfdir}/init.d/mysql stop > /dev/null 2>&1 echo "Giving mysqld a couple of seconds to exit nicely" sleep 5 -elif test -x /etc/rc.d/init.d/mysql +elif test -x %{_sysconfdir}/rc.d/init.d/mysql then - /etc/rc.d/init.d/mysql stop > /dev/null 2>&1 + %{_sysconfdir}/rc.d/init.d/mysql stop > /dev/null 2>&1 echo "Giving mysqld a couple of seconds to exit nicely" sleep 5 fi @@ -364,7 +375,7 @@ if test ! -d $mysql_datadir/test; then mkdir $mysql_datadir/test; fi # use insserv for older SuSE Linux versions if test -x /sbin/insserv then - /sbin/insserv /etc/init.d/mysql + /sbin/insserv %{_sysconfdir}/init.d/mysql # use chkconfig on Red Hat and newer SuSE releases elif test -x /sbin/chkconfig then @@ -390,7 +401,7 @@ chown -R mysql $mysql_datadir chmod -R og-rw $mysql_datadir/mysql # Restart in the same way that mysqld will be started normally. -/etc/init.d/mysql start +%{_sysconfdir}/init.d/mysql start # Allow safe_mysqld to start mysqld and print a message before we exit sleep 2 @@ -398,22 +409,22 @@ sleep 2 %post Max # Restart mysqld, to use the new binary. echo "Restarting mysqld." -/etc/init.d/mysql restart > /dev/null 2>&1 +%{_sysconfdir}/init.d/mysql restart > /dev/null 2>&1 %preun server if test $1 = 0 then # Stop MySQL before uninstalling it - if test -x /etc/init.d/mysql + if test -x %{_sysconfdir}/init.d/mysql then - /etc/init.d/mysql stop > /dev/null + %{_sysconfdir}/init.d/mysql stop > /dev/null fi # Remove autostart of mysql # for older SuSE Linux versions if test -x /sbin/insserv then - /sbin/insserv -r /etc/init.d/mysql + /sbin/insserv -r %{_sysconfdir}/init.d/mysql # use chkconfig on Red Hat and newer SuSE releases elif test -x /sbin/chkconfig then @@ -441,59 +452,63 @@ fi %doc %attr(644, root, man) %{_mandir}/man1/isamlog.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql_zap.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqld.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysql_fix_privilege_tables.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqld_multi.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqld_safe.1* %doc %attr(644, root, man) %{_mandir}/man1/perror.1* %doc %attr(644, root, man) %{_mandir}/man1/replace.1* -%ghost %config(noreplace,missingok) /etc/my.cnf - -%attr(755, root, root) /usr/bin/isamchk -%attr(755, root, root) /usr/bin/isamlog -%attr(755, root, root) /usr/bin/my_print_defaults -%attr(755, root, root) /usr/bin/myisamchk -%attr(755, root, root) /usr/bin/myisamlog -%attr(755, root, root) /usr/bin/myisampack -%attr(755, root, root) /usr/bin/mysql_convert_table_format -%attr(755, root, root) /usr/bin/mysql_explain_log -%attr(755, root, root) /usr/bin/mysql_fix_privilege_tables -%attr(755, root, root) /usr/bin/mysql_install_db -%attr(755, root, root) /usr/bin/mysql_secure_installation -%attr(755, root, root) /usr/bin/mysql_setpermission -%attr(755, root, root) /usr/bin/mysql_zap -%attr(755, root, root) /usr/bin/mysqlbug -%attr(755, root, root) /usr/bin/mysqld_multi -%attr(755, root, root) /usr/bin/mysqld_safe -%attr(755, root, root) /usr/bin/mysqlhotcopy -%attr(755, root, root) /usr/bin/mysqltest -%attr(755, root, root) /usr/bin/pack_isam -%attr(755, root, root) /usr/bin/perror -%attr(755, root, root) /usr/bin/replace -%attr(755, root, root) /usr/bin/resolve_stack_dump -%attr(755, root, root) /usr/bin/resolveip -%attr(755, root, root) /usr/bin/safe_mysqld - -%attr(755, root, root) /usr/sbin/mysqld -%attr(755, root, root) /usr/sbin/rcmysql -%attr(644, root, root) /usr/lib/mysql/mysqld.sym - -%attr(644, root, root) /etc/logrotate.d/mysql -%attr(755, root, root) /etc/init.d/mysql - -%attr(755, root, root) /usr/share/mysql/ +%ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf + +%attr(755, root, root) %{_bindir}/isamchk +%attr(755, root, root) %{_bindir}/isamlog +%attr(755, root, root) %{_bindir}/my_print_defaults +%attr(755, root, root) %{_bindir}/myisamchk +%attr(755, root, root) %{_bindir}/myisamlog +%attr(755, root, root) %{_bindir}/myisampack +%attr(755, root, root) %{_bindir}/mysql_convert_table_format +%attr(755, root, root) %{_bindir}/mysql_explain_log +%attr(755, root, root) %{_bindir}/mysql_fix_extensions +%attr(755, root, root) %{_bindir}/mysql_fix_privilege_tables +%attr(755, root, root) %{_bindir}/mysql_install_db +%attr(755, root, root) %{_bindir}/mysql_secure_installation +%attr(755, root, root) %{_bindir}/mysql_setpermission +%attr(755, root, root) %{_bindir}/mysql_zap +%attr(755, root, root) %{_bindir}/mysqlbug +%attr(755, root, root) %{_bindir}/mysqld_multi +%attr(755, root, root) %{_bindir}/mysqld_safe +%attr(755, root, root) %{_bindir}/mysqlhotcopy +%attr(755, root, root) %{_bindir}/mysqltest +%attr(755, root, root) %{_bindir}/pack_isam +%attr(755, root, root) %{_bindir}/perror +%attr(755, root, root) %{_bindir}/replace +%attr(755, root, root) %{_bindir}/resolve_stack_dump +%attr(755, root, root) %{_bindir}/resolveip +%attr(755, root, root) %{_bindir}/safe_mysqld + +%attr(755, root, root) %{_sbindir}/mysqld +%attr(755, root, root) %{_sbindir}/rcmysql +%attr(644, root, root) %{_libdir}/mysql/mysqld.sym + +%attr(644, root, root) %{_sysconfdir}/logrotate.d/mysql +%attr(755, root, root) %{_sysconfdir}/init.d/mysql + +%attr(755, root, root) %{_datadir}/mysql/ %files client -%attr(755, root, root) /usr/bin/msql2mysql -%attr(755, root, root) /usr/bin/mysql -%attr(755, root, root) /usr/bin/mysql_find_rows -%attr(755, root, root) /usr/bin/mysql_waitpid -%attr(755, root, root) /usr/bin/mysqlaccess -%attr(755, root, root) /usr/bin/mysqladmin -%attr(755, root, root) /usr/bin/mysqlbinlog -%attr(755, root, root) /usr/bin/mysqlcheck -%attr(755, root, root) /usr/bin/mysqldump -%attr(755, root, root) /usr/bin/mysqlimport -%attr(755, root, root) /usr/bin/mysqlshow +%attr(755, root, root) %{_bindir}/msql2mysql +%attr(755, root, root) %{_bindir}/mysql +%attr(755, root, root) %{_bindir}/mysql_find_rows +%attr(755, root, root) %{_bindir}/mysql_tableinfo +%attr(755, root, root) %{_bindir}/mysql_waitpid +%attr(755, root, root) %{_bindir}/mysqlaccess +%attr(755, root, root) %{_bindir}/mysqladmin +%attr(755, root, root) %{_bindir}/mysqlbinlog +%attr(755, root, root) %{_bindir}/mysqlcheck +%attr(755, root, root) %{_bindir}/mysqldump +%attr(755, root, root) %{_bindir}/mysqldumpslow +%attr(755, root, root) %{_bindir}/mysqlimport +%attr(755, root, root) %{_bindir}/mysqlshow %doc %attr(644, root, man) %{_mandir}/man1/mysql.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqlaccess.1* @@ -509,45 +524,64 @@ fi %files devel %defattr(644 root, root) -%attr(755, root, root) /usr/bin/comp_err -%attr(755, root, root) /usr/bin/mysql_config -%dir %attr(755, root, root) /usr/include/mysql -%dir %attr(755, root, root) /usr/lib/mysql -/usr/include/mysql/* -/usr/lib/mysql/libdbug.a -/usr/lib/mysql/libheap.a -/usr/lib/mysql/libmerge.a -/usr/lib/mysql/libmyisam.a -/usr/lib/mysql/libmyisammrg.a -/usr/lib/mysql/libmysqlclient.a -/usr/lib/mysql/libmysqlclient.la -/usr/lib/mysql/libmysqlclient_r.a -/usr/lib/mysql/libmysqlclient_r.la -/usr/lib/mysql/libmystrings.a -/usr/lib/mysql/libmysys.a -/usr/lib/mysql/libnisam.a -/usr/lib/mysql/libvio.a +%attr(755, root, root) %{_bindir}/comp_err +%attr(755, root, root) %{_bindir}/mysql_config +%dir %attr(755, root, root) %{_includedir}/mysql +%dir %attr(755, root, root) %{_libdir}/mysql +%{_includedir}/mysql/* +%{_libdir}/mysql/libdbug.a +%{_libdir}/mysql/libheap.a +%{_libdir}/mysql/libmerge.a +%{_libdir}/mysql/libmyisam.a +%{_libdir}/mysql/libmyisammrg.a +%{_libdir}/mysql/libmysqlclient.a +%{_libdir}/mysql/libmysqlclient.la +%{_libdir}/mysql/libmysqlclient_r.a +%{_libdir}/mysql/libmysqlclient_r.la +%{_libdir}/mysql/libmystrings.a +%{_libdir}/mysql/libmysys.a +%{_libdir}/mysql/libnisam.a +%{_libdir}/mysql/libvio.a %files shared %defattr(755 root, root) # Shared libraries (omit for architectures that don't support them) -/usr/lib/*.so* +%{_libdir}/*.so* %files bench -%attr(-, root, root) /usr/share/sql-bench -%attr(-, root, root) /usr/share/mysql-test -%attr(755, root, root) /usr/bin/mysqlmanager -%attr(755, root, root) /usr/bin/mysqlmanager-pwgen -%attr(755, root, root) /usr/bin/mysqlmanagerc +%attr(-, root, root) %{_datadir}/sql-bench +%attr(-, root, root) %{_datadir}/mysql-test +%attr(755, root, root) %{_bindir}/mysqlmanager +%attr(755, root, root) %{_bindir}/mysqlmanager-pwgen +%attr(755, root, root) %{_bindir}/mysqlmanagerc %files Max -%attr(755, root, root) /usr/sbin/mysqld-max -%attr(644, root, root) /usr/lib/mysql/mysqld-max.sym +%attr(755, root, root) %{_sbindir}/mysqld-max +%attr(644, root, root) %{_libdir}/mysql/mysqld-max.sym %files embedded -%attr(644, root, root) /usr/lib/mysql/libmysqld.a +%attr(644, root, root) %{_libdir}/mysql/libmysqld.a %changelog +* Tue Aug 05 2003 Lenz Grimmer <lenz@mysql.com> + +- Fixed BUG#959 (libmysqld not being compiled properly) +- Fixed BUG#998 (RPM build errors): added missing files to the + distribution (mysql_fix_extensions, mysql_tableinfo, mysqldumpslow, + mysql_fix_privilege_tables.1), removed "-n" from %install section. + +* Wed Jul 09 2003 Lenz Grimmer <lenz@mysql.com> + +- removed the GIF Icon (file was not included in the sources anyway) +- removed unused variable %shared_lib_version +- do not run automake before building the standard binary + (should not be necessary) +- add server suffix '-standard' to standard binary (to be in line + with the binary tarball distributions) +- Use more RPM macros (_exec_prefix, _sbindir, _libdir, _sysconfdir, + _datadir, _includedir) throughout the spec file. +- allow overriding CC and CXX (required when building with other compilers) + * Fri May 16 2003 Lenz Grimmer <lenz@mysql.com> - re-enabled RAID again diff --git a/vio/Makefile.am b/vio/Makefile.am index 16c70b12454..d5d26dec344 100644 --- a/vio/Makefile.am +++ b/vio/Makefile.am @@ -14,21 +14,24 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -INCLUDES = -I$(top_srcdir)/include $(openssl_includes) -LDADD = @CLIENT_EXTRA_LDFLAGS@ libvio.a $(openssl_libs) -pkglib_LIBRARIES = libvio.a +INCLUDES= -I$(top_srcdir)/include $(openssl_includes) +LDADD= @CLIENT_EXTRA_LDFLAGS@ $(openssl_libs) +pkglib_LIBRARIES= libvio.a noinst_PROGRAMS = test-ssl test-sslserver test-sslclient -noinst_HEADERS = -test_ssl_SOURCES = test-ssl.c -test_ssl_LDADD = @CLIENT_EXTRA_LDFLAGS@ ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \ - ../strings/libmystrings.a libvio.a $(openssl_libs) -test_sslserver_SOURCES = test-sslserver.c -test_sslserver_LDADD = @CLIENT_EXTRA_LDFLAGS@ ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \ - ../strings/libmystrings.a libvio.a $(openssl_libs) -test_sslclient_SOURCES = test-sslclient.c -test_sslclient_LDADD = @CLIENT_EXTRA_LDFLAGS@ ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \ - ../strings/libmystrings.a libvio.a $(openssl_libs) -libvio_a_SOURCES = vio.c viosocket.c viossl.c viosslfactories.c +noinst_HEADERS= +test_ssl_SOURCES= test-ssl.c +test_ssl_LDADD= @CLIENT_EXTRA_LDFLAGS@ ../dbug/libdbug.a libvio.a \ + ../mysys/libmysys.a ../strings/libmystrings.a \ + $(openssl_libs) +test_sslserver_SOURCES= test-sslserver.c +test_sslserver_LDADD= @CLIENT_EXTRA_LDFLAGS@ ../dbug/libdbug.a libvio.a \ + ../mysys/libmysys.a ../strings/libmystrings.a \ + $(openssl_libs) +test_sslclient_SOURCES= test-sslclient.c +test_sslclient_LDADD= @CLIENT_EXTRA_LDFLAGS@ ../dbug/libdbug.a libvio.a \ + ../mysys/libmysys.a ../strings/libmystrings.a \ + $(openssl_libs) +libvio_a_SOURCES= vio.c viosocket.c viossl.c viosslfactories.c # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/vio/viosocket.c b/vio/viosocket.c index 5f7e48f8e8b..ac2f7939a4c 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -26,8 +26,8 @@ #include <mysql_com.h> #include <errno.h> -#include <violite.h> #include <my_sys.h> +#include <violite.h> #include <my_net.h> #include <m_string.h> diff --git a/vio/viossl.c b/vio/viossl.c index 834343a77d9..fc95b0755ce 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -287,8 +287,7 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout) SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout); SSL_set_fd(vio->ssl_,vio->sd); SSL_set_accept_state(vio->ssl_); - if (SSL_do_handshake(vio->ssl_) < 1 || - SSL_get_verify_result(vio->ssl_) != X509_V_OK) + if (SSL_do_handshake(vio->ssl_) < 1) { DBUG_PRINT("error", ("SSL_do_handshake failure")); report_errors(); @@ -361,8 +360,7 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout) SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout); SSL_set_fd (vio->ssl_, vio->sd); SSL_set_connect_state(vio->ssl_); - if (SSL_do_handshake(vio->ssl_) < 1 || - SSL_get_verify_result(vio->ssl_) != X509_V_OK) + if (SSL_do_handshake(vio->ssl_) < 1) { DBUG_PRINT("error", ("SSL_do_handshake failure")); report_errors(); diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 31bc457d1ae..69d4f3007b8 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -18,8 +18,8 @@ #ifdef HAVE_OPENSSL -#include <my_sys.h> #include <mysql_com.h> +#include <my_sys.h> #include <violite.h> @@ -178,6 +178,11 @@ vio_verify_callback(int ok, X509_STORE_CTX *ctx) /************************ VioSSLConnectorFd **********************************/ +/* + TODO: + Add option --verify to mysql to be able to change verification mode +*/ + struct st_VioSSLConnectorFd * new_VioSSLConnectorFd(const char* key_file, const char* cert_file, @@ -185,7 +190,7 @@ new_VioSSLConnectorFd(const char* key_file, const char* ca_path, const char* cipher) { - int verify = SSL_VERIFY_PEER; + int verify = SSL_VERIFY_NONE; struct st_VioSSLConnectorFd* ptr; int result; DH *dh=NULL; @@ -264,7 +269,10 @@ ctor_failure: /************************ VioSSLAcceptorFd **********************************/ - +/* + TODO: + Add option --verify to mysqld to be able to change verification mode +*/ struct st_VioSSLAcceptorFd* new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, @@ -273,7 +281,6 @@ new_VioSSLAcceptorFd(const char *key_file, const char *cipher) { int verify = (SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE); struct st_VioSSLAcceptorFd* ptr; int result; |