diff options
author | unknown <monty@mysql.com> | 2004-10-06 19:14:33 +0300 |
---|---|---|
committer | unknown <monty@mysql.com> | 2004-10-06 19:14:33 +0300 |
commit | bbab9ec678f9e8a0309f0b018cf6d22cd93acf84 (patch) | |
tree | 4e2cfa6a6a8032773454e22aa802b2798b2935b8 | |
parent | 7d583c5834f420406c9abe8bb9c44518e49e74c3 (diff) | |
parent | 95e1c07483005b784aaefa35b5a8597ffb1d3932 (diff) | |
download | mariadb-git-bbab9ec678f9e8a0309f0b018cf6d22cd93acf84.tar.gz |
Merge with 4.0 for 4.1 release
Noteworthy:
- New HANDLER code
- New multi-update-grant-check code
- Table lock code in ha_innodb.cc was not applied
BitKeeper/etc/logging_ok:
auto-union
BitKeeper/deleted/.del-ctype-latin1_de.c~c5d8f9208bceb98e:
Auto merged
Build-tools/mysql-copyright-2:
Auto merged
acinclude.m4:
Auto merged
client/mysqladmin.c:
Auto merged
client/mysqldump.c:
Auto merged
include/config-win.h:
Auto merged
include/my_global.h:
Auto merged
include/myisam.h:
Auto merged
innobase/btr/btr0btr.c:
Auto merged
innobase/buf/buf0buf.c:
Auto merged
ltmain.sh:
Auto merged
innobase/dict/dict0dict.c:
Auto merged
innobase/fsp/fsp0fsp.c:
Auto merged
innobase/include/dict0dict.h:
Auto merged
innobase/include/row0mysql.h:
Auto merged
innobase/log/log0log.c:
Auto merged
innobase/log/log0recv.c:
Auto merged
innobase/pars/pars0opt.c:
Auto merged
innobase/row/row0row.c:
Auto merged
innobase/sync/sync0arr.c:
Auto merged
innobase/ut/ut0dbg.c:
Auto merged
myisam/mi_check.c:
Auto merged
myisam/mi_close.c:
Auto merged
myisam/mi_create.c:
Auto merged
myisam/mi_locking.c:
Auto merged
myisam/myisampack.c:
Auto merged
mysql-test/r/delete.result:
Auto merged
mysql-test/r/func_if.result:
Auto merged
Build-tools/mysql-copyright:
Merge with 4.0 (too most of the code from 4.0)
Makefile.am:
merge
client/mysql.cc:
Used 4.1 code
configure.in:
merge
innobase/os/os0file.c:
merge
innobase/row/row0mysql.c:
merge
mysql-test/r/ctype_latin1_de.result:
merge
mysql-test/r/flush_table.result:
merge
mysql-test/r/func_str.result:
merge
mysql-test/r/handler.result:
merge
mysql-test/r/multi_update.result:
merge
mysql-test/r/type_timestamp.result:
Removed testing of 'new' mode, as this is only relevant for 4.0
mysql-test/r/update.result:
merge
mysql-test/t/delete.test:
merge
mysql-test/t/flush_table.test:
merge
mysql-test/t/func_str.test:
merge
mysql-test/t/handler.test:
merge
mysql-test/t/multi_update.test:
merge
mysql-test/t/type_timestamp.test:
Removed testing of 'new' mode, as this is only relevant for 4.0
mysql-test/t/update.test:
merge
mysys/errors.c:
merge
mysys/my_fstream.c:
merge
mysys/my_pread.c:
merge
mysys/my_write.c:
merge
mysys/mysys_priv.h:
merge
scripts/mysqlhotcopy.sh:
merge
sql/field.cc:
Keep code from 4.1
sql/field.h:
Keep code from 4.1
sql/ha_innodb.cc:
Don't merge lock code from 4.0; Heikki will look at this
sql/ha_myisam.cc:
merge
sql/handler.cc:
merge
sql/item_cmpfunc.cc:
merge
sql/item_cmpfunc.h:
merge
sql/item_strfunc.cc:
merge
sql/mysql_priv.h:
merge
sql/mysqld.cc:
merge
sql/protocol.cc:
merge
sql/records.cc:
merge
sql/repl_failsafe.cc:
merge
mysql-test/r/lock_multi.result:
merge
mysql-test/t/ctype_latin1_de.test:
merge
mysql-test/t/func_if.test:
merge
mysql-test/t/lock_multi.test:
merge
sql/repl_failsafe.h:
merge
Remove unnessessary header protection
sql/slave.h:
merge
sql/sql_acl.cc:
merge
sql/sql_base.cc:
merge
sql/sql_cache.cc:
auto merge
sql/sql_class.cc:
merge
sql/sql_class.h:
merge
sql/sql_delete.cc:
merge
sql/sql_handler.cc:
Get new HANDLER code into 4.1
sql/sql_parse.cc:
Keep old file
sql/sql_repl.cc:
merge
sql/sql_repl.h:
merge
sql/sql_show.cc:
merge
sql/sql_table.cc:
merge
sql/sql_union.cc:
Applied the examine_rows bug fix from 4.0 by hand
sql/sql_update.cc:
New multi-update-grant-check code from 4.0
sql/sql_yacc.yy:
New multi-update-grant-check code from 4.0
sql/stacktrace.c:
merge
sql/table.h:
merge
83 files changed, 1895 insertions, 495 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index e3aefbf3efc..ac45466be22 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -52,6 +52,7 @@ gweir@build.mysql.com gweir@work.mysql.com harrison@mysql.com harry@corona.lordblink.com +hartmut@mysql.com heikki@donna.mysql.fi heikki@hundin.mysql.fi heikki@rescue. @@ -96,6 +97,7 @@ lenz@mysql.com magnus@neptunus.(none) magnus@shellback.(none) marko@hundin.mysql.fi +matt@mysql.com miguel@hegel.(none) miguel@hegel.br miguel@hegel.local diff --git a/Build-tools/mysql-copyright b/Build-tools/mysql-copyright index 0c091890e72..dbb18e4e866 100755 --- a/Build-tools/mysql-copyright +++ b/Build-tools/mysql-copyright @@ -1,9 +1,9 @@ -#!/usr/bin/perl -i +#!/usr/bin/perl -wi # Untar a MySQL distribution, change the copyright texts, # pack it up again to a given directory -$VER="1.3"; +$VER="1.4"; use Cwd; use File::Basename; @@ -104,7 +104,7 @@ sub main unlink("$destdir/COPYING", "$destdir/EXCEPTIONS-CLIENT"); copy("$WD/Docs/MySQLEULA.txt", "$destdir"); - # remove readline, bdb subdirs and update 'configure' + # remove subdirectories 'bdb', 'cmd-line-utils/readline' my @extra_fat= ('bdb', 'cmd-line-utils/readline'); foreach my $fat (@extra_fat) @@ -118,7 +118,10 @@ sub main # fix LICENSE tag in include/mysql_version.h &fix_mysql_version(); - + + # apply "autotools" - must be last to ensure proper timestamps + &run_autotools(); + # rename the directory with new distribution name chdir("$WD/$dir"); print "renaming $destdir $newdistname\n" if $opt_verbose; @@ -142,7 +145,7 @@ sub main } } exit(0); -} +} #### #### This function will s/GPL/Commercial/ in include/mysql_version.h for the @@ -150,6 +153,7 @@ sub main #### sub fix_mysql_version { + my $cwd= getcwd(); chdir("$destdir"); my $header_file= (-f 'include/mysql_version.h.in')? 'include/mysql_version.h.in' : 'include/mysql_version.h'; @@ -170,44 +174,73 @@ sub fix_mysql_version #### This function will remove unwanted parts of a src tree for the mysqlcom #### distributions. #### + sub trim_the_fat { - my $the_fat= shift; - my $cwd= getcwd(); - - system("rm -rf $destdir/${the_fat}"); - if (!$win_flag) - { - chdir("$destdir"); - unlink ("configure") or die "Can't delete $destdir/configure: $!\n"; - open(CONFIGURE,"<configure.in") or die "Unable to open configure.in for read: $!\n"; - undef $/; - my $configure= <CONFIGURE>; - close(CONFIGURE); - - # - # If $the_fat Makefile line closes the parenthesis, then - # replace that line with just the closing parenthesis. - # - if ($configure=~ m|${the_fat}/Makefile\)\n?|) - { - $configure=~ s|${the_fat}/Makefile(\)\n?)|$1|; - } - # - # Else just delete the line - # - else - { - $configure=~ s|${the_fat}/Makefile dnl\n?||; - } - - open(CONFIGURE,">configure.in") or die "Unable to open configure.in for write: $!\n"; - print CONFIGURE $configure; - close(CONFIGURE); - `aclocal && autoheader && aclocal && automake && autoconf`; - die "'./configure' was not produced!" unless (-f "configure"); - chdir("$cwd"); - } + my $the_fat= shift; + my $cwd= getcwd(); + + chdir("$destdir"); + if ( -d "${the_fat}" ) + { + system("rm -rf ${the_fat}"); + if (!$win_flag) + { + open(CONFIG_IN,"<configure.in") or die "Unable to open configure.in for read: $!\n"; + undef $/; + my $config_in= <CONFIG_IN>; + close(CONFIG_IN); + + # + # If $the_fat Makefile line closes the parenthesis, then + # replace that line with just the closing parenthesis. + # + if ($config_in=~ m|${the_fat}/Makefile\)\n?|) + { + $config_in=~ s|${the_fat}/Makefile(\)\n?)|$1|; + } + # + # Else just delete the line + # + else + { + $config_in=~ s|${the_fat}/Makefile dnl\n?||; + } + + open(CONFIG_IN,">configure.in") or die "Unable to open configure.in for write: $!\n"; + print CONFIG_IN $config_in; + close(CONFIG_IN); + } + } + chdir("$cwd"); +} + + +#### +#### This function will run the autotools on the reduced source tree. +#### + +sub run_autotools +{ + my $cwd= getcwd(); + + if (!$win_flag) + { + chdir("$destdir"); + unlink ("configure") or die "Can't delete $destdir/configure: $!\n"; + + # File "configure.in" has already been modified by "trim_the_fat()" + + `aclocal && autoheader && aclocal && automake && autoconf`; + die "'./configure' was not produced!" unless (-f "configure"); + + if (-d "autom4te.cache") { + print "Trying to delete autom4te.cache dir\n" if $opt_verbose; + system("rm -rf autom4te.cache") or print "Unable to delete autom4te.cache dir: $!\n"; + } + + chdir("$cwd"); + } } diff --git a/Build-tools/mysql-copyright-2 b/Build-tools/mysql-copyright-2 index a1a870526da..2ea2e8ef441 100755 --- a/Build-tools/mysql-copyright-2 +++ b/Build-tools/mysql-copyright-2 @@ -90,6 +90,7 @@ sub add_copyright $ARGV =~ /\.cc$/ || $ARGV =~ /\.h$/ || $ARGV =~ /\.cpp$/ || + $ARGV =~ /\.txt$/ || $ARGV =~ /\.yy$/) { $start_copyright="/* "; diff --git a/Makefile.am b/Makefile.am index 7c2ed820a23..0dbb5032e15 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,7 +30,7 @@ SUBDIRS = . include @docs_dirs@ @zlib_dir@ \ DIST_SUBDIRS = . include @docs_dirs@ zlib \ @readline_topdir@ sql-common \ @thread_dirs@ pstack @sql_client_dirs@ \ - @sql_server_dirs@ scripts man tests SSL\ + @sql_server_dirs@ scripts @man_dirs@ tests SSL\ BUILD netware os2 @libmysqld_dirs@ \ @bench_dirs@ support-files @fs_dirs@ @tools_dirs@ diff --git a/acinclude.m4 b/acinclude.m4 index c7d7ba0e9c9..7f25b447f10 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -976,7 +976,7 @@ AC_DEFUN([MYSQL_FIND_OPENSSL], [ AC_DEFUN([MYSQL_CHECK_OPENSSL], [ AC_MSG_CHECKING(for OpenSSL) AC_ARG_WITH([openssl], - [ --with-openssl Include the OpenSSL support], + [ --with-openssl[=DIR] Include the OpenSSL support], [openssl="$withval"], [openssl=no]) @@ -994,8 +994,19 @@ AC_MSG_CHECKING(for OpenSSL) [openssl_libs="$withval"], [openssl_libs=""]) - if test "$openssl" = "yes" + if test "$openssl" != "no" then + if test "$openssl" != "yes" + then + if test -z "$openssl_includes" + then + openssl_includes="$openssl/include" + fi + if test -z "$openssl_libs" + then + openssl_libs="$openssl/lib" + fi + fi MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs]) #force VIO use vio_dir="vio" @@ -1031,6 +1042,14 @@ AC_MSG_CHECKING(for OpenSSL) NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS $openssl_libs" else AC_MSG_RESULT(no) + if test ! -z "$openssl_includes" + then + AC_MSG_ERROR(Can't have --with-openssl-includes without --with-openssl); + fi + if test ! -z "$openssl_libs" + then + AC_MSG_ERROR(Can't have --with-openssl-libs without --with-openssl); + fi fi AC_SUBST(openssl_libs) AC_SUBST(openssl_includes) diff --git a/client/mysqladmin.c b/client/mysqladmin.c index df3e8dfed62..e21db53b470 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.c @@ -268,7 +268,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc,char *argv[]) { - int error, ho_error; + int error= 0, ho_error; MYSQL mysql; char **commands, **save_argv; @@ -313,10 +313,25 @@ int main(int argc,char *argv[]) mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif if (sql_connect(&mysql, option_wait)) - error = 1; + { + unsigned int err= mysql_errno(&mysql); + if (err >= CR_MIN_ERROR && err <= CR_MAX_ERROR) + error= 1; + else + { + /* Return 0 if all commands are PING */ + for (; argc > 0; argv++, argc--) + { + if (find_type(argv[0], &command_typelib, 2) != ADMIN_PING) + { + error= 1; + break; + } + } + } + } else { - error = 0; while (!interrupted && (!opt_count_iterations || nr_iterations)) { new_line = 0; diff --git a/configure.in b/configure.in index 2df5155ecbb..d81a50b9367 100644 --- a/configure.in +++ b/configure.in @@ -2282,6 +2282,21 @@ else fi AC_SUBST(docs_dirs) +# Shall we build the man pages? +AC_ARG_WITH(man, + [ --without-man Skip building of the man pages.], + [with_man=$withval], + [with_man=yes] +) + +if test "$with_man" = "yes" +then + man_dirs="man" +else + man_dirs="" +fi +AC_SUBST(man_dirs) + # Shall we build the bench code? AC_ARG_WITH(bench, [ --without-bench Skip building of the benchmark suite.], diff --git a/include/config-win.h b/include/config-win.h index 0ba8dd2cf43..d28bb25cd09 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -229,7 +229,13 @@ inline double ulonglong2double(ulonglong value) ((uint32) (uchar) (A)[0]))) #define sint4korr(A) (*((long *) (A))) #define uint2korr(A) (*((uint16 *) (A))) -#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF) +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) #define uint4korr(A) (*((unsigned long *) (A))) #define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ (((uint32) ((uchar) (A)[1])) << 8) +\ diff --git a/include/my_global.h b/include/my_global.h index 89a5363dc4b..8e2e8e0eb6a 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -919,7 +919,13 @@ typedef char bool; /* Ordinary boolean values 0 1 */ (((uint32) ((uchar) (A)[1])) << 8) +\ (((uint32) ((uchar) (A)[2])) << 16)) #else -#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF) +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) #endif #define uint4korr(A) (*((unsigned long *) (A))) #define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ diff --git a/include/myisam.h b/include/myisam.h index 02c56115dfd..6d097770646 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -98,6 +98,7 @@ typedef struct st_mi_create_info ha_rows reloc_rows; ulonglong auto_increment; ulonglong data_file_length; + ulonglong key_file_length; uint raid_type,raid_chunks; ulong raid_chunksize; uint old_options; diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c index ff389ede06e..ae967e0525e 100644 --- a/innobase/btr/btr0btr.c +++ b/innobase/btr/btr0btr.c @@ -610,8 +610,8 @@ btr_page_get_father_for_rec( fputs( "InnoDB: You should dump + drop + reimport the table to fix the\n" "InnoDB: corruption. If the crash happens at the database startup, see\n" -"InnoDB: section 6.1 of http://www.innodb.com/ibman.php about forcing\n" -"InnoDB: recovery. Then dump + drop + reimport.\n", stderr); +"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html about\n" +"InnoDB: forcing recovery. Then dump + drop + reimport.\n", stderr); } ut_a(btr_node_ptr_get_child_page_no(node_ptr) == diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index e039ff4f81f..adb69f3c3a7 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -1835,9 +1835,9 @@ buf_page_io_complete( "InnoDB: by dumping, dropping, and reimporting\n" "InnoDB: the corrupt table. You can use CHECK\n" "InnoDB: TABLE to scan your table for corruption.\n" - "InnoDB: Look also at section 6.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php about\n" - "InnoDB: forcing recovery.\n", stderr); + "InnoDB: See also " + "http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" + "InnoDB: about forcing recovery.\n", stderr); if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { fputs( diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index b5dd06b1bf1..aa7e90700f8 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -527,8 +527,10 @@ dict_index_contains_col_or_prefix( } /************************************************************************ -Looks for a matching field in an index. The column and the prefix len have -to be the same. */ +Looks for a matching field in an index. The column has to be the same. The +column in index must be complete, or must contain a prefix longer than the +column in index2. That is, we must be able to construct the prefix in index2 +from the prefix in index. */ ulint dict_index_get_nth_field_pos( @@ -556,7 +558,9 @@ dict_index_get_nth_field_pos( field = dict_index_get_nth_field(index, pos); if (field->col == field2->col - && field->prefix_len == field2->prefix_len) { + && (field->prefix_len == 0 + || (field->prefix_len >= field2->prefix_len + && field2->prefix_len != 0))) { return(pos); } @@ -2114,7 +2118,8 @@ dict_foreign_error_report( fputs("\nThe index in the foreign key in table is ", file); ut_print_name(file, NULL, fk->foreign_index->name); fputs( -"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", +"\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" +"for correct foreign key definition.\n", file); } mutex_exit(&dict_foreign_err_mutex); @@ -2589,7 +2594,9 @@ dict_strip_comments( char* str; const char* sptr; char* ptr; - + /* unclosed quote character (0 if none) */ + char quote = 0; + str = mem_alloc(strlen(sql_string) + 1); sptr = sql_string; @@ -2604,8 +2611,18 @@ scan_more: return(str); } - - if (*sptr == '#' + + if (*sptr == quote) { + /* Closing quote character: do not look for + starting quote or comments. */ + quote = 0; + } else if (quote) { + /* Within quotes: do not look for + starting quotes or comments. */ + } else if (*sptr == '"' || *sptr == '`') { + /* Starting quote: remember the quote character. */ + quote = *sptr; + } else if (*sptr == '#' || (0 == memcmp("-- ", sptr, 3))) { for (;;) { /* In Unix a newline is 0x0A while in Windows @@ -2620,9 +2637,7 @@ scan_more: sptr++; } - } - - if (*sptr == '/' && *(sptr + 1) == '*') { + } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') { for (;;) { if (*sptr == '*' && *(sptr + 1) == '/') { @@ -2950,7 +2965,8 @@ col_loop1: ut_print_name(ef, NULL, name); fprintf(ef, " where the columns appear\n" "as the first columns. Constraint:\n%s\n" -"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", +"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" +"for correct foreign key definition.\n", start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); @@ -3215,7 +3231,8 @@ try_find_index: "Cannot find an index in the referenced table where the\n" "referenced columns appear as the first columns, or column types\n" "in the table and the referenced table do not match for constraint.\n" -"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", +"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" +"for correct foreign key definition.\n", start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index 34b6de76ff4..e1621cc2765 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -2972,9 +2972,9 @@ fseg_free_page_low( "InnoDB: database!\n", (ulong) page); crash: fputs( -"InnoDB: If the InnoDB recovery crashes here, see section 6.1\n" -"InnoDB: of http://www.innodb.com/ibman.php about forcing recovery.\n", - stderr); +"InnoDB: Please refer to\n" +"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" +"InnoDB: about forcing recovery.\n", stderr); ut_error; } diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index a1a1ebdfe08..4dbbd5b4886 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -604,8 +604,10 @@ dict_index_contains_col_or_prefix( dict_index_t* index, /* in: index */ ulint n); /* in: column number */ /************************************************************************ -Looks for a matching field in an index. The column and the prefix len has -to be the same. */ +Looks for a matching field in an index. The column has to be the same. The +column in index must be complete, or must contain a prefix longer than the +column in index2. That is, we must be able to construct the prefix in index2 +from the prefix in index. */ ulint dict_index_get_nth_field_pos( diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 8f6264944ce..9437ed4b6ee 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -559,9 +559,11 @@ struct row_prebuilt_struct { dtuple_t* clust_ref; /* prebuilt dtuple used in sel/upd/del */ ulint select_lock_type;/* LOCK_NONE, LOCK_S, or LOCK_X */ - ulint stored_select_lock_type;/* inside LOCK TABLES, either - LOCK_S or LOCK_X depending on the lock - type */ + ulint stored_select_lock_type;/* this field is used to + remember the original select_lock_type + that was decided in ha_innodb.cc, + ::store_lock(), ::external_lock(), + etc. */ ulint mysql_row_len; /* length in bytes of a row in the MySQL format */ ulint n_rows_fetched; /* number of rows fetched after diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 923ab448e07..b6357fa2c76 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -689,10 +689,9 @@ failure: "InnoDB: To get mysqld to start up, set innodb_thread_concurrency in my.cnf\n" "InnoDB: to a lower value, for example, to 8. After an ERROR-FREE shutdown\n" "InnoDB: of mysqld you can adjust the size of ib_logfiles, as explained in\n" -"InnoDB: section 5 of http://www.innodb.com/ibman.php", +"InnoDB: http://dev.mysql.com/doc/mysql/en/Adding_and_removing.html\n" +"InnoDB: Cannot continue operation. Calling exit(1).\n", (ulong)srv_thread_concurrency); - fprintf(stderr, -"InnoDB: Cannot continue operation. Calling exit(1).\n"); exit(1); } diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index e5b0300239a..10f921bb1f0 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -538,8 +538,8 @@ recv_find_max_checkpoint( "InnoDB: If this error appears when you are creating an InnoDB database,\n" "InnoDB: the problem may be that during an earlier attempt you managed\n" "InnoDB: to create the InnoDB data files, but log file creation failed.\n" -"InnoDB: If that is the case, please refer to section 3.1 of\n" -"InnoDB: http://www.innodb.com/ibman.php\n"); +"InnoDB: If that is the case, please refer to\n" +"InnoDB: http://dev.mysql.com/doc/mysql/en/Error_creating_InnoDB.html\n"); return(DB_ERROR); } @@ -1884,7 +1884,7 @@ recv_report_corrupt_log( "InnoDB: far enough in recovery! Please run CHECK TABLE\n" "InnoDB: on your InnoDB tables to check that they are ok!\n" "InnoDB: If mysqld crashes after this recovery, look at\n" - "InnoDB: section 6.1 of http://www.innodb.com/ibman.php\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" "InnoDB: about forcing recovery.\n", stderr); fflush(stderr); diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 392580eb570..1040283f85e 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -234,8 +234,9 @@ os_file_get_last_error( "InnoDB: of the same name as a data file.\n"); } else { fprintf(stderr, - "InnoDB: See section 13.2 at http://www.innodb.com/ibman.php\n" - "InnoDB: about operating system error numbers.\n"); + "InnoDB: Some operating system error numbers are described at\n" + "InnoDB: " + "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); } } @@ -280,8 +281,9 @@ os_file_get_last_error( } fprintf(stderr, - "InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" - "InnoDB: about operating system error numbers.\n"); + "InnoDB: Some operating system error numbers are described at\n" + "InnoDB: " + "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); } } @@ -2174,8 +2176,9 @@ retry: fprintf(stderr, " InnoDB: Error: File pointer positioning to file %s failed at\n" "InnoDB: offset %lu %lu. Operating system error number %lu.\n" -"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.php\n" -"InnoDB: what the error number means.\n", +"InnoDB: Some operating system error numbers are described at\n" +"InnoDB: " +"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n", name, (ulong) offset_high, (ulong) offset, (ulong) GetLastError()); @@ -2232,8 +2235,9 @@ retry: } fprintf(stderr, -"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" -"InnoDB: about operating system error numbers.\n"); +"InnoDB: Some operating system error numbers are described at\n" +"InnoDB: " +"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); os_has_said_disk_full = TRUE; } @@ -2267,8 +2271,9 @@ retry: } fprintf(stderr, -"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" -"InnoDB: about operating system error numbers.\n"); +"InnoDB: Some operating system error numbers are described at\n" +"InnoDB: " +"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); os_has_said_disk_full = TRUE; } @@ -3466,6 +3471,8 @@ restart: /* NOTE! We only access constant fields in os_aio_array. Therefore we do not have to acquire the protecting mutex yet */ + srv_set_io_thread_op_info(global_segment, + "looking for i/o requests (a)"); ut_ad(os_aio_validate()); ut_ad(segment < array->n_segments); @@ -3484,6 +3491,9 @@ restart: os_mutex_enter(array->mutex); + srv_set_io_thread_op_info(global_segment, + "looking for i/o requests (b)"); + /* Check if there is a slot for which the i/o has already been done */ @@ -3596,6 +3606,8 @@ consecutive_loop: } } + srv_set_io_thread_op_info(global_segment, "consecutive i/o requests"); + /* We have now collected n_consecutive i/o requests in the array; allocate a single buffer which can hold all data, and perform the i/o */ @@ -3741,6 +3753,8 @@ slot_io_done: return(ret); wait_for_io: + srv_set_io_thread_op_info(global_segment, "resetting wait event"); + /* We wait here until there again can be i/os in the segment of this thread */ @@ -3832,9 +3846,17 @@ os_aio_print( ulint i; for (i = 0; i < srv_n_file_io_threads; i++) { - fprintf(file, "I/O thread %lu state: %s (%s)\n", (ulong) i, + fprintf(file, "I/O thread %lu state: %s (%s)", (ulong) i, srv_io_thread_op_info[i], srv_io_thread_function[i]); + +#ifndef __WIN__ + if (os_aio_segment_wait_events[i]->is_set) { + fprintf(file, " ev set"); + } +#endif + + fprintf(file, "\n"); } fputs("Pending normal aio reads:", file); diff --git a/innobase/pars/pars0opt.c b/innobase/pars/pars0opt.c index 0d487f6e54a..88022e2efe1 100644 --- a/innobase/pars/pars0opt.c +++ b/innobase/pars/pars0opt.c @@ -1094,6 +1094,19 @@ opt_clust_access( for (i = 0; i < n_fields; i++) { pos = dict_index_get_nth_field_pos(index, clust_index, i); + ut_a(pos != ULINT_UNDEFINED); + + /* We optimize here only queries to InnoDB's internal system + tables, and they should not contain column prefix indexes. */ + + if (dict_index_get_nth_field(index, pos)->prefix_len != 0 + || dict_index_get_nth_field(clust_index, i) + ->prefix_len != 0) { + fprintf(stderr, +"InnoDB: Error in pars0opt.c: table %s has prefix_len != 0\n", + index->table_name); + } + *(plan->clust_map + i) = pos; ut_ad((pos != ULINT_UNDEFINED) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 152bb0291c3..88227d61f1d 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -339,8 +339,9 @@ handle_new_error: "InnoDB: a case of widespread corruption, dump all InnoDB\n" "InnoDB: tables and recreate the whole InnoDB tablespace.\n" "InnoDB: If the mysqld server crashes after the startup or when\n" - "InnoDB: you dump the tables, look at section 6.1 of\n" - "InnoDB: http://www.innodb.com/ibman.html for help.\n", stderr); + "InnoDB: you dump the tables, look at\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html" + " for help.\n", stderr); } else { fprintf(stderr, "InnoDB: unknown error code %lu\n", @@ -1587,8 +1588,9 @@ row_create_table_for_mysql( "InnoDB: database and moving the .frm file to the current database.\n" "InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n" "InnoDB: succeed.\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n", stderr); + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n", stderr); } /* We may also get err == DB_ERROR if the .ibd file for the @@ -2369,6 +2371,7 @@ row_drop_table_for_mysql( memcpy(sql, str1, (sizeof str1) - 1); memcpy(sql + (sizeof str1) - 1, quoted_name, namelen); memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2); + mem_free(quoted_name); /* Serialize data dictionary operations with dictionary mutex: no deadlocks can occur then in these operations */ @@ -2409,8 +2412,9 @@ row_drop_table_for_mysql( "InnoDB: data dictionary though MySQL is trying to drop it.\n" "InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: MySQL database directory from another database?\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n", stderr); + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n", stderr); goto funct_exit; } @@ -2955,11 +2959,13 @@ row_rename_table_for_mysql( ut_print_name(stderr, trx, old_name); fputs(" to it.\n" "InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n" + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n" "InnoDB: If table ", stderr); - ut_print_name(stderr, trx, new_name); - fputs(" is a temporary table #sql..., then it can be that\n" + ut_print_name(stderr, trx, new_name); + fputs( + " is a temporary table #sql..., then it can be that\n" "InnoDB: there are still queries running on the table, and it will be\n" "InnoDB: dropped automatically when the queries end.\n" "InnoDB: You can drop the orphaned table inside InnoDB by\n" diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c index e7b39f0fe52..2de7ffc79c0 100644 --- a/innobase/row/row0row.c +++ b/innobase/row/row0row.c @@ -343,6 +343,7 @@ row_build_row_ref( ulint ref_len; ulint pos; byte* buf; + ulint clust_col_prefix_len; ulint i; ut_ad(index && rec && heap); @@ -375,6 +376,22 @@ row_build_row_ref( field = rec_get_nth_field(rec, pos, &len); dfield_set_data(dfield, field, len); + + /* If the primary key contains a column prefix, then the + secondary index may contain a longer prefix of the same + column, or the full column, and we must adjust the length + accordingly. */ + + clust_col_prefix_len = + dict_index_get_nth_field(clust_index, i)->prefix_len; + + if (clust_col_prefix_len > 0) { + if (len != UNIV_SQL_NULL + && len > clust_col_prefix_len) { + + dfield_set_len(dfield, clust_col_prefix_len); + } + } } ut_ad(dtuple_check_typed(ref)); @@ -406,6 +423,7 @@ row_build_row_ref_in_tuple( ulint len; ulint ref_len; ulint pos; + ulint clust_col_prefix_len; ulint i; ut_a(ref && index && rec); @@ -443,6 +461,22 @@ row_build_row_ref_in_tuple( field = rec_get_nth_field(rec, pos, &len); dfield_set_data(dfield, field, len); + + /* If the primary key contains a column prefix, then the + secondary index may contain a longer prefix of the same + column, or the full column, and we must adjust the length + accordingly. */ + + clust_col_prefix_len = + dict_index_get_nth_field(clust_index, i)->prefix_len; + + if (clust_col_prefix_len > 0) { + if (len != UNIV_SQL_NULL + && len > clust_col_prefix_len) { + + dfield_set_len(dfield, clust_col_prefix_len); + } + } } ut_ad(dtuple_check_typed(ref)); diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 7cd221df6a5..e5285cb7ebf 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -61,10 +61,7 @@ struct sync_cell_struct { thread */ ibool waiting; /* TRUE if the thread has already called sync_array_event_wait - on this cell but not yet - sync_array_free_cell (which - actually resets wait_object and thus - whole cell) */ + on this cell */ ibool event_set; /* TRUE if the event is set */ os_event_t event; /* operating system event semaphore handle */ diff --git a/innobase/ut/ut0dbg.c b/innobase/ut/ut0dbg.c index 2a0cfe1f13a..0f6a27d35d9 100644 --- a/innobase/ut/ut0dbg.c +++ b/innobase/ut/ut0dbg.c @@ -31,8 +31,9 @@ const char* ut_dbg_msg_trap = "InnoDB: Submit a detailed bug report to http://bugs.mysql.com.\n" "InnoDB: If you get repeated assertion failures or crashes, even\n" "InnoDB: immediately after the mysqld startup, there may be\n" -"InnoDB: corruption in the InnoDB tablespace. See section 6.1 of\n" -"InnoDB: http://www.innodb.com/ibman.php about forcing recovery.\n"; +"InnoDB: corruption in the InnoDB tablespace. Please refer to\n" +"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" +"InnoDB: about forcing recovery.\n"; const char* ut_dbg_msg_stop = "InnoDB: Thread %lu stopped in file %s line %lu\n"; diff --git a/ltmain.sh b/ltmain.sh index b28d160431c..c2c73cad224 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -51,6 +51,9 @@ fi # libtool 1.4.2 workaround SED=${SED:-sed} +# workaround against unset 'max_cmd_len': assume at least 4 kB +max_cmd_len=${max_cmd_len:-4096} + # The name of this program. progname=`$echo "$0" | ${SED} 's%^.*/%%'` modename="$progname" diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 1f6089d0a3c..4da388af1c7 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -3743,7 +3743,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) create_info.raid_chunksize= share.base.raid_chunksize; create_info.language = (param->language ? param->language : share.state.header.language); - + create_info.key_file_length= status_info.key_file_length; /* We don't have to handle symlinks here because we are using HA_DONT_TOUCH_DATA */ if (mi_create(filename, diff --git a/myisam/mi_close.c b/myisam/mi_close.c index deb0ccee8f3..62f5617de1a 100644 --- a/myisam/mi_close.c +++ b/myisam/mi_close.c @@ -70,6 +70,12 @@ int mi_close(register MI_INFO *info) error=my_errno; if (share->kfile >= 0) { + /* + If we are crashed, we can safely flush the current state as it will + not change the crashed state. + We can NOT write the state in other cases as other threads + may be using the file at this point + */ if (share->mode != O_RDONLY && mi_is_crashed(info)) mi_state_info_write(share->kfile, &share->state, 1); if (my_close(share->kfile,MYF(0))) diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 683640630f6..7fc7cc4edf1 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -48,7 +48,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ulong reclength, real_reclength,min_pack_length; char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; ulong pack_reclength; - ulonglong tot_length,max_rows; + ulonglong tot_length,max_rows, tmp; enum en_fieldtype type; MYISAM_SHARE share; MI_KEYDEF *keydef,tmp_keydef; @@ -464,10 +464,15 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, share.state.auto_increment=ci->auto_increment; share.options=options; share.base.rec_reflength=pointer; + /* Get estimate for index file length (this may be wrong for FT keys) */ + tmp= (tot_length + max_key_block_length * keys * + MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH; + /* + use maximum of key_file_length we calculated and key_file_length value we + got from MYI file header (see also myisampack.c:save_state) + */ share.base.key_reflength= - mi_get_pointer_length((tot_length + max_key_block_length * keys * - MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH, - 3); + mi_get_pointer_length(max(ci->key_file_length,tmp),3); share.base.keys= share.state.header.keys= keys; share.state.header.uniques= uniques; share.state.header.fulltext_keys= fulltext_keys; diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index b13ebfb4cad..2487f68d170 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -19,7 +19,20 @@ reads info from a isam-table. Must be first request before doing any furter calls to any isamfunktion. Is used to allow many process use the same isamdatabase. - */ +*/ + +/* + state.open_count in the .MYI file is used the following way: + - For the first change of the file in this process it's incremented with + mi_mark_file_change(). (We have a write lock on the file in this case) + - In mi_close() it's decremented by _mi_decrement_open_count() if it + was incremented in the same process. + + This mean that if we are the only process using the file, the open_count + tells us if the MYISAM file wasn't properly closed. (This is true if + my_disable_locking is set). +*/ + #include "myisamdef.h" @@ -32,12 +45,17 @@ int mi_lock_database(MI_INFO *info, int lock_type) MYISAM_SHARE *share=info->s; uint flag; DBUG_ENTER("mi_lock_database"); - DBUG_PRINT("info",("lock_type: %d", lock_type)); + DBUG_PRINT("enter",("lock_type: %d old lock %d r_locks: %u w_locks: %u " + "global_changed: %d open_count: %u name: '%s'", + lock_type, info->lock_type, share->r_locks, + share->w_locks, + share->global_changed, share->state.open_count, + share->index_file_name)); if (share->options & HA_OPTION_READ_ONLY_DATA || info->lock_type == lock_type) DBUG_RETURN(0); - if (lock_type == F_EXTRA_LCK) + if (lock_type == F_EXTRA_LCK) /* Used by TMP tables */ { ++share->w_locks; ++share->tot_locks; @@ -51,7 +69,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) { switch (lock_type) { case F_UNLCK: - DBUG_PRINT("info", ("old lock: %d", info->lock_type)); if (info->lock_type == F_RDLCK) count= --share->r_locks; else @@ -81,7 +98,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) share->state.process= share->last_process=share->this_process; share->state.unique= info->last_unique= info->this_unique; share->state.update_count= info->last_loop= ++info->this_loop; - if (mi_state_info_write(share->kfile, &share->state, 1)) + if (mi_state_info_write(share->kfile, &share->state, 1)) error=my_errno; share->changed=0; if (myisam_flush) @@ -119,11 +136,17 @@ int mi_lock_database(MI_INFO *info, int lock_type) break; case F_RDLCK: if (info->lock_type == F_WRLCK) - { /* Change RW to READONLY */ + { + /* + Change RW to READONLY + + mysqld does not turn write locks to read locks, + so we're never here in mysqld. + */ if (share->w_locks == 1) { flag=1; - if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, + if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, MYF(MY_SEEK_NOT_DONE))) { error=my_errno; @@ -346,9 +369,10 @@ int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer) } /* _mi_readinfo */ - /* Every isam-function that uppdates the isam-database must! end */ - /* with this request */ - /* ARGSUSED */ +/* + Every isam-function that uppdates the isam-database MUST end with this + request +*/ int _mi_writeinfo(register MI_INFO *info, uint operation) { @@ -421,6 +445,8 @@ int _mi_mark_file_changed(MI_INFO *info) { char buff[3]; register MYISAM_SHARE *share=info->s; + DBUG_ENTER("_mi_mark_file_changed"); + if (!(share->state.changed & STATE_CHANGED) || ! share->global_changed) { share->state.changed|=(STATE_CHANGED | STATE_NOT_ANALYZED | @@ -434,12 +460,12 @@ int _mi_mark_file_changed(MI_INFO *info) { mi_int2store(buff,share->state.open_count); buff[2]=1; /* Mark that it's changed */ - return (my_pwrite(share->kfile,buff,sizeof(buff), - sizeof(share->state.header), - MYF(MY_NABP))); + DBUG_RETURN(my_pwrite(share->kfile,buff,sizeof(buff), + sizeof(share->state.header), + MYF(MY_NABP))); } } - return 0; + DBUG_RETURN(0); } diff --git a/myisam/myisampack.c b/myisam/myisampack.c index de4bd80805a..0bbf2721cb3 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -2044,7 +2044,11 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->state.split=(ha_rows) mrg->records; share->state.version=(ulong) time((time_t*) 0); share->state.key_map=0; - share->state.state.key_file_length=share->base.keystart; + /* + Don't save key_file_length here, keep key_file_length of original file + so "myisamchk -rq" can use this value (this is necessary because index + size cannot be easily calculated for fulltext keys) + */ for (key=0 ; key < share->base.keys ; key++) share->state.key_root[key]= HA_OFFSET_ERROR; for (key=0 ; key < share->state.header.max_block_size ; key++) diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result index c500019042f..50af5464f54 100644 --- a/mysql-test/r/ctype_latin1_de.result +++ b/mysql-test/r/ctype_latin1_de.result @@ -280,6 +280,20 @@ word word2 ß ß drop table t1; CREATE TABLE t1 ( +autor varchar(80) NOT NULL default '', +PRIMARY KEY (autor) +); +INSERT INTO t1 VALUES ('Powell, B.'),('Powell, Bud.'),('Powell, L. H.'),('Power, H.'), +('Poynter, M. A. L. Lane'),('Poynting, J. H. und J. J. Thomson.'),('Pozzi, S(amuel-Jean).'), +('Pozzi, Samuel-Jean.'),('Pozzo, A.'),('Pozzoli, Serge.'); +SELECT * FROM t1 WHERE autor LIKE 'Poz%' ORDER BY autor; +autor +Pozzi, S(amuel-Jean). +Pozzi, Samuel-Jean. +Pozzo, A. +Pozzoli, Serge. +DROP TABLE t1; +CREATE TABLE t1 ( s1 CHAR(5) CHARACTER SET latin1 COLLATE latin1_german2_ci ); show create table t1; diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index c6b7a40214d..48cfa47b75c 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -130,3 +130,14 @@ select * from t1; a b 7 7 drop table t1; +create table t1 (a int not null auto_increment primary key, b char(32)); +insert into t1 (b) values ('apple'), ('apple'); +select * from t1; +a b +1 apple +2 apple +delete t1 from t1, t1 as t2 where t1.b = t2.b and t1.a > t2.a; +select * from t1; +a b +1 apple +drop table t1; diff --git a/mysql-test/r/flush_table.result b/mysql-test/r/flush_table.result index 257f69fa6d9..7d2e9ab0b8d 100644 --- a/mysql-test/r/flush_table.result +++ b/mysql-test/r/flush_table.result @@ -30,14 +30,23 @@ test.t2 flush tables; handler a1 read first limit 9; -ERROR 42S02: Unknown table 'a1' in HANDLER +table_id +test.t1 + handler a2 read first limit 9; -ERROR 42S02: Unknown table 'a2' in HANDLER +table_id +test.t1 + handler t2 read first limit 9; -ERROR 42S02: Unknown table 't2' in HANDLER +table_id +test.t2 + handler t1 open as a1; +Not unique table/alias: 'a1' handler t1 open as a2; +Not unique table/alias: 'a2' handler t2 open; +Not unique table/alias: 't2' handler a1 read first limit 9; table_id test.t1 @@ -52,9 +61,13 @@ test.t2 flush table t1; handler a1 read first limit 9; -ERROR 42S02: Unknown table 'a1' in HANDLER +table_id +test.t1 + handler a2 read first limit 9; -ERROR 42S02: Unknown table 'a2' in HANDLER +table_id +test.t1 + handler t2 read first limit 9; table_id test.t2 @@ -64,3 +77,28 @@ handler t2 close; ERROR 42S02: Unknown table 't2' in HANDLER drop table t1; drop table t2; +create table t1(table_id char(20) primary key); +insert into t1 values ('Record-01'); +insert into t1 values ('Record-02'); +insert into t1 values ('Record-03'); +insert into t1 values ('Record-04'); +insert into t1 values ('Record-05'); +handler t1 open; +handler t1 read first limit 1; +table_id +Record-01 +handler t1 read next limit 1; +table_id +Record-02 +handler t1 read next limit 1; +table_id +Record-03 +flush table t1; +handler t1 read next limit 1; +table_id +Record-01 +handler t1 read next limit 1; +table_id +Record-02 +handler t1 close; +drop table t1; diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index dd916d06372..508a50caf02 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -83,3 +83,6 @@ select if(1>2,a,avg(a)) from t1; if(1>2,a,avg(a)) 1.5000 drop table t1; +SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL; +NULLIF(5,5) IS NULL NULLIF(5,5) IS NOT NULL +1 0 diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 7b2fc4b21a5..ab99b2dcbdd 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -316,6 +316,11 @@ NULL NULL 1 1 n two 'two' 0 0 'two' four 'four' 0 0 'four' drop table t1; +select trim(trailing 'foo' from 'foo'); +trim(trailing 'foo' from 'foo') + +select trim(leading 'foo' from 'foo'); +trim(leading 'foo' from 'foo') select 1=_latin1'1'; 1=_latin1'1' 1 diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index f66e9f1759d..dcbf558ac3f 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -205,3 +205,247 @@ handler t1 read a=(1) where b=1; a b handler t1 close; drop table t1; +drop database if exists test_test; +create database test_test; +use test_test; +create table t1(table_id char(20) primary key); +insert into t1 values ('test_test.t1'); +insert into t1 values (''); +handler t1 open; +handler t1 read first limit 9; +table_id +test_test.t1 + +create table t2(table_id char(20) primary key); +insert into t2 values ('test_test.t2'); +insert into t2 values (''); +handler t2 open; +handler t2 read first limit 9; +table_id +test_test.t2 + +use test; +drop table if exists t1; +create table t1(table_id char(20) primary key); +insert into t1 values ('test.t1'); +insert into t1 values (''); +handler t1 open; +Not unique table/alias: 't1' +use test; +handler test.t1 read first limit 9; +Unknown table 'test.t1' in HANDLER +handler test_test.t1 read first limit 9; +table_id +test_test.t1 + +handler t1 read first limit 9; +table_id +test_test.t1 + +handler test_test.t2 read first limit 9; +table_id +test_test.t2 + +handler t2 read first limit 9; +table_id +test_test.t2 + +handler test_test.t1 close; +handler t1 close; +Unknown table 't1' in HANDLER +drop table test_test.t1; +handler test_test.t2 close; +handler t2 close; +Unknown table 't2' in HANDLER +drop table test_test.t2; +drop database test_test; +use test; +handler test.t1 close; +Unknown table 'test.t1' in HANDLER +handler t1 close; +Unknown table 't1' in HANDLER +drop table test.t1; +drop database if exists test_test; +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +create database test_test; +use test_test; +create table t1 (c1 char(20)); +insert into t1 values ('test_test.t1'); +create table t3 (c1 char(20)); +insert into t3 values ('test_test.t3'); +handler t1 open; +handler t1 read first limit 9; +c1 +test_test.t1 +handler t1 open h1; +handler h1 read first limit 9; +c1 +test_test.t1 +use test; +create table t1 (c1 char(20)); +create table t2 (c1 char(20)); +create table t3 (c1 char(20)); +insert into t1 values ('t1'); +insert into t2 values ('t2'); +insert into t3 values ('t3'); +handler t1 open; +Not unique table/alias: 't1' +handler t2 open t1; +Not unique table/alias: 't1' +handler t3 open t1; +Not unique table/alias: 't1' +handler t1 read first limit 9; +c1 +test_test.t1 +handler test.t1 close; +Unknown table 'test.t1' in HANDLER +handler test.t1 open h1; +Not unique table/alias: 'h1' +handler test_test.t1 open h1; +Not unique table/alias: 'h1' +handler test_test.t3 open h3; +handler test.t1 open h2; +handler t1 read first limit 9; +c1 +test_test.t1 +handler h1 read first limit 9; +c1 +test_test.t1 +handler h2 read first limit 9; +c1 +t1 +handler h3 read first limit 9; +c1 +test_test.t3 +handler test.h2 read first limit 9; +c1 +t1 +handler test.h1 close; +Unknown table 'test.h1' in HANDLER +handler test_test.t1 close; +handler test_test.h1 close; +handler h2 close; +handler t1 read first limit 9; +Unknown table 't1' in HANDLER +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +Unknown table 'h2' in HANDLER +handler h3 read first limit 9; +c1 +test_test.t3 +handler test_test.h3 read first limit 9; +c1 +test_test.t3 +use test_test; +handler h3 read first limit 9; +c1 +test_test.t3 +handler test.h3 read first limit 9; +Unknown table 'test.h3' in HANDLER +handler test_test.h3 close; +use test; +drop table t3; +drop table t2; +drop table t1; +drop database test_test; +create table t1 (c1 char(20)); +insert into t1 values ("t1"); +handler t1 open as h1; +handler h1 read first limit 9; +c1 +t1 +create table t2 (c1 char(20)); +insert into t2 values ("t2"); +handler t2 open as h2; +handler h2 read first limit 9; +c1 +t2 +create table t3 (c1 char(20)); +insert into t3 values ("t3"); +handler t3 open as h3; +handler h3 read first limit 9; +c1 +t3 +create table t4 (c1 char(20)); +insert into t4 values ("t4"); +handler t4 open as h4; +handler h4 read first limit 9; +c1 +t4 +create table t5 (c1 char(20)); +insert into t5 values ("t5"); +handler t5 open as h5; +handler h5 read first limit 9; +c1 +t5 +alter table t1 engine=MyISAM; +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +c1 +t2 +handler h3 read first limit 9; +c1 +t3 +handler h4 read first limit 9; +c1 +t4 +handler h5 read first limit 9; +c1 +t5 +alter table t5 engine=MyISAM; +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +c1 +t2 +handler h3 read first limit 9; +c1 +t3 +handler h4 read first limit 9; +c1 +t4 +handler h5 read first limit 9; +Unknown table 'h5' in HANDLER +alter table t3 engine=MyISAM; +handler h1 read first limit 9; +Unknown table 'h1' in HANDLER +handler h2 read first limit 9; +c1 +t2 +handler h3 read first limit 9; +Unknown table 'h3' in HANDLER +handler h4 read first limit 9; +c1 +t4 +handler h5 read first limit 9; +Unknown table 'h5' in HANDLER +handler h2 close; +handler h4 close; +handler t1 open as h1_1; +handler t1 open as h1_2; +handler t1 open as h1_3; +handler h1_1 read first limit 9; +c1 +t1 +handler h1_2 read first limit 9; +c1 +t1 +handler h1_3 read first limit 9; +c1 +t1 +alter table t1 engine=MyISAM; +handler h1_1 read first limit 9; +Unknown table 'h1_1' in HANDLER +handler h1_2 read first limit 9; +Unknown table 'h1_2' in HANDLER +handler h1_3 read first limit 9; +Unknown table 'h1_3' in HANDLER +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index a0efce727d3..9eedbf50064 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -17,6 +17,18 @@ unlock tables; n 1 drop table t1; +create table t1 (a int, b int); +create table t2 (c int, d int); +insert into t1 values(1,1); +insert into t1 values(2,2); +insert into t2 values(1,2); +lock table t1 read; + update t1,t2 set c=a where b=d; +select c from t2; +c +2 +drop table t1; +drop table t2; create table t1 (a int); create table t2 (a int); lock table t1 write, t2 write; diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 6a7cecdd460..4dd94b26a73 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -92,9 +92,6 @@ date date_time time_stamp 2005-01-01 2005-01-01 00:00:00 2005-01-01 00:00:00 2030-01-01 2030-01-01 00:00:00 2030-01-01 00:00:00 drop table t1; -show variables like 'new'; -Variable_name Value -new OFF create table t1 (t2 timestamp(2), t4 timestamp(4), t6 timestamp(6), t8 timestamp(8), t10 timestamp(10), t12 timestamp(12), t14 timestamp(14)); @@ -106,7 +103,6 @@ select * from t1; t2 t4 t6 t8 t10 t12 t14 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 -set new=1; select * from t1; t2 t4 t6 t8 t10 t12 t14 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 @@ -421,3 +417,11 @@ select * from t1; ts 2001-09-09 04:46:40 drop table t1; +create table t1 (a char(2), t timestamp); +insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'), +('b', '2004-02-01 00:00:00'); +select max(t) from t1 group by a; +max(t) +2004-01-01 01:00:00 +2004-02-01 00:00:00 +drop table t1; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 0037fb9ea95..6d2e623a6fb 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -169,3 +169,40 @@ F1 F2 F3 cnt groupid 2 0 1 2 4 2 2 0 1 7 drop table t1; +CREATE TABLE t1 ( +`colA` int(10) unsigned NOT NULL auto_increment, +`colB` int(11) NOT NULL default '0', +PRIMARY KEY (`colA`) +); +INSERT INTO t1 VALUES (4433,5424); +CREATE TABLE t2 ( +`colC` int(10) unsigned NOT NULL default '0', +`colA` int(10) unsigned NOT NULL default '0', +`colD` int(10) unsigned NOT NULL default '0', +`colE` int(10) unsigned NOT NULL default '0', +`colF` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`colC`,`colA`,`colD`,`colE`) +); +INSERT INTO t2 VALUES (3,4433,10005,495,500); +INSERT INTO t2 VALUES (3,4433,10005,496,500); +INSERT INTO t2 VALUES (3,4433,10009,494,500); +INSERT INTO t2 VALUES (3,4433,10011,494,500); +INSERT INTO t2 VALUES (3,4433,10005,497,500); +INSERT INTO t2 VALUES (3,4433,10013,489,500); +INSERT INTO t2 VALUES (3,4433,10005,494,500); +INSERT INTO t2 VALUES (3,4433,10005,493,500); +INSERT INTO t2 VALUES (3,4433,10005,492,500); +UPDATE IGNORE t2,t1 set t2.colE = t2.colE + 1,colF=0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +SELECT * FROM t2; +colC colA colD colE colF +3 4433 10005 495 500 +3 4433 10005 496 500 +3 4433 10009 495 0 +3 4433 10011 495 0 +3 4433 10005 498 0 +3 4433 10013 490 0 +3 4433 10005 494 500 +3 4433 10005 493 500 +3 4433 10005 492 500 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test index e29e43496af..472a3db648e 100644 --- a/mysql-test/t/ctype_latin1_de.test +++ b/mysql-test/t/ctype_latin1_de.test @@ -86,6 +86,24 @@ select * from t1 where word like binary 0xDF; select * from t1 where word like CAST(0xDF as CHAR); drop table t1; +# +# Bug #5447 Select does not find records +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( + autor varchar(80) NOT NULL default '', + PRIMARY KEY (autor) +); +INSERT INTO t1 VALUES ('Powell, B.'),('Powell, Bud.'),('Powell, L. H.'),('Power, H.'), +('Poynter, M. A. L. Lane'),('Poynting, J. H. und J. J. Thomson.'),('Pozzi, S(amuel-Jean).'), +('Pozzi, Samuel-Jean.'),('Pozzo, A.'),('Pozzoli, Serge.'); +SELECT * FROM t1 WHERE autor LIKE 'Poz%' ORDER BY autor; +DROP TABLE t1; + +# +# Test of special character in german collation +# + CREATE TABLE t1 ( s1 CHAR(5) CHARACTER SET latin1 COLLATE latin1_german2_ci ); diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 56c8ce77627..5f60445d765 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -71,6 +71,16 @@ delete from t1 where 3 > 2; select count(*) from t1; drop table t1; +# +# Bug #5733: Table handler error with self-join multi-table DELETE +# + +create table t1 (a int not null auto_increment primary key, b char(32)); +insert into t1 (b) values ('apple'), ('apple'); +select * from t1; +delete t1 from t1, t1 as t2 where t1.b = t2.b and t1.a > t2.a; +select * from t1; +drop table t1; # # IGNORE option diff --git a/mysql-test/t/flush_table.test b/mysql-test/t/flush_table.test index 8bee94cf21f..afb30d21da7 100644 --- a/mysql-test/t/flush_table.test +++ b/mysql-test/t/flush_table.test @@ -16,7 +16,8 @@ drop table t1; # # In the following test FLUSH TABLES produces a deadlock -# (hang forever) if the fix for bug#3565 is missing. +# (hang forever) if the fix for BUG #3565 is missing. +# And it shows that handler tables are re-opened after flush (BUG #4286). # create table t1(table_id char(20) primary key); create table t2(table_id char(20) primary key); @@ -31,28 +32,43 @@ handler a1 read first limit 9; handler a2 read first limit 9; handler t2 read first limit 9; flush tables; ---error 1109; handler a1 read first limit 9; ---error 1109; handler a2 read first limit 9; ---error 1109; handler t2 read first limit 9; # +--error 1066 handler t1 open as a1; +--error 1066 handler t1 open as a2; +--error 1066 handler t2 open; handler a1 read first limit 9; handler a2 read first limit 9; handler t2 read first limit 9; flush table t1; ---error 1109; handler a1 read first limit 9; ---error 1109; handler a2 read first limit 9; handler t2 read first limit 9; flush table t2; ---error 1109; handler t2 close; drop table t1; drop table t2; +# +# The fix for BUG #4286 cannot restore the position after a flush. +# +create table t1(table_id char(20) primary key); +insert into t1 values ('Record-01'); +insert into t1 values ('Record-02'); +insert into t1 values ('Record-03'); +insert into t1 values ('Record-04'); +insert into t1 values ('Record-05'); +handler t1 open; +handler t1 read first limit 1; +handler t1 read next limit 1; +handler t1 read next limit 1; +flush table t1; +handler t1 read next limit 1; +handler t1 read next limit 1; +handler t1 close; +drop table t1; diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test index 7048d188604..693773b18c8 100644 --- a/mysql-test/t/func_if.test +++ b/mysql-test/t/func_if.test @@ -56,3 +56,7 @@ insert t1 values (1),(2); select if(1>2,a,avg(a)) from t1; drop table t1; +# +# Bug #5595 NULLIF() IS NULL returns false if NULLIF() returns NULL +# +SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL; diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index e7852df40b3..3eab694ee05 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -182,6 +182,13 @@ select a, quote(a), isnull(quote(a)), quote(a) is null, ifnull(quote(a), 'n') fr drop table t1; # +# Bug #5498: TRIM fails with LEADING or TRAILING if remstr = str +# + +select trim(trailing 'foo' from 'foo'); +select trim(leading 'foo' from 'foo'); + +# # Test collation and coercibility # diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 685f438712c..b7fe5d10297 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -138,3 +138,207 @@ handler t1 read a=(1) where b=1; handler t1 close; drop table t1; +# +# Check if two database names beginning the same are seen as different. +# +# This database begins like the usual 'test' database. +# +--disable_warnings +drop database if exists test_test; +--enable_warnings +create database test_test; +use test_test; +create table t1(table_id char(20) primary key); +insert into t1 values ('test_test.t1'); +insert into t1 values (''); +handler t1 open; +handler t1 read first limit 9; +create table t2(table_id char(20) primary key); +insert into t2 values ('test_test.t2'); +insert into t2 values (''); +handler t2 open; +handler t2 read first limit 9; +# +# This is the usual 'test' database. +# +use test; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1(table_id char(20) primary key); +insert into t1 values ('test.t1'); +insert into t1 values (''); +--error 1066 +handler t1 open; +# +# Check accesibility of all the tables. +# +use test; +--error 1109; +handler test.t1 read first limit 9; +handler test_test.t1 read first limit 9; +handler t1 read first limit 9; +handler test_test.t2 read first limit 9; +handler t2 read first limit 9; +# +# Cleanup. +# + +handler test_test.t1 close; +--error 1109; +handler t1 close; +drop table test_test.t1; +handler test_test.t2 close; +--error 1109; +handler t2 close; +drop table test_test.t2; +drop database test_test; +# +use test; +--error 1109; +handler test.t1 close; +--error 1109; +handler t1 close; +drop table test.t1; + +# +# BUG#4335 +# +--disable_warnings +drop database if exists test_test; +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +--enable_warnings +create database test_test; +use test_test; +create table t1 (c1 char(20)); +insert into t1 values ('test_test.t1'); +create table t3 (c1 char(20)); +insert into t3 values ('test_test.t3'); +handler t1 open; +handler t1 read first limit 9; +handler t1 open h1; +handler h1 read first limit 9; +use test; +create table t1 (c1 char(20)); +create table t2 (c1 char(20)); +create table t3 (c1 char(20)); +insert into t1 values ('t1'); +insert into t2 values ('t2'); +insert into t3 values ('t3'); +--error 1066 +handler t1 open; +--error 1066 +handler t2 open t1; +--error 1066 +handler t3 open t1; +handler t1 read first limit 9; +--error 1109 +handler test.t1 close; +--error 1066 +handler test.t1 open h1; +--error 1066 +handler test_test.t1 open h1; +handler test_test.t3 open h3; +handler test.t1 open h2; +handler t1 read first limit 9; +handler h1 read first limit 9; +handler h2 read first limit 9; +handler h3 read first limit 9; +handler test.h2 read first limit 9; +--error 1109 +handler test.h1 close; +handler test_test.t1 close; +handler test_test.h1 close; +handler h2 close; +--error 1109 +handler t1 read first limit 9; +--error 1109 +handler h1 read first limit 9; +--error 1109 +handler h2 read first limit 9; +handler h3 read first limit 9; +handler test_test.h3 read first limit 9; +use test_test; +handler h3 read first limit 9; +--error 1109 +handler test.h3 read first limit 9; +handler test_test.h3 close; +use test; +drop table t3; +drop table t2; +drop table t1; +drop database test_test; + +# +# Test if fix for BUG#4286 correctly closes handler tables. +# +create table t1 (c1 char(20)); +insert into t1 values ("t1"); +handler t1 open as h1; +handler h1 read first limit 9; +create table t2 (c1 char(20)); +insert into t2 values ("t2"); +handler t2 open as h2; +handler h2 read first limit 9; +create table t3 (c1 char(20)); +insert into t3 values ("t3"); +handler t3 open as h3; +handler h3 read first limit 9; +create table t4 (c1 char(20)); +insert into t4 values ("t4"); +handler t4 open as h4; +handler h4 read first limit 9; +create table t5 (c1 char(20)); +insert into t5 values ("t5"); +handler t5 open as h5; +handler h5 read first limit 9; +# close first +alter table t1 engine=MyISAM; +--error 1109; +handler h1 read first limit 9; +handler h2 read first limit 9; +handler h3 read first limit 9; +handler h4 read first limit 9; +handler h5 read first limit 9; +# close last +alter table t5 engine=MyISAM; +--error 1109; +handler h1 read first limit 9; +handler h2 read first limit 9; +handler h3 read first limit 9; +handler h4 read first limit 9; +--error 1109; +handler h5 read first limit 9; +# close middle +alter table t3 engine=MyISAM; +--error 1109; +handler h1 read first limit 9; +handler h2 read first limit 9; +--error 1109; +handler h3 read first limit 9; +handler h4 read first limit 9; +--error 1109; +handler h5 read first limit 9; +handler h2 close; +handler h4 close; +# close all depending handler tables +handler t1 open as h1_1; +handler t1 open as h1_2; +handler t1 open as h1_3; +handler h1_1 read first limit 9; +handler h1_2 read first limit 9; +handler h1_3 read first limit 9; +alter table t1 engine=MyISAM; +--error 1109; +handler h1_1 read first limit 9; +--error 1109; +handler h1_2 read first limit 9; +--error 1109; +handler h1_3 read first limit 9; +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index fa095275182..cbda47ac864 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -53,6 +53,30 @@ reap; drop table t1; # +# Test problem when using locks with multi-updates +# It should not block when multi-update is reading on a read-locked table +# + +connection locker; +create table t1 (a int, b int); +create table t2 (c int, d int); +insert into t1 values(1,1); +insert into t1 values(2,2); +insert into t2 values(1,2); +lock table t1 read; +connection writer; +--sleep 2 +send update t1,t2 set c=a where b=d; +connection reader; +--sleep 2 +select c from t2; +connection writer; +reap; +connection locker; +drop table t1; +drop table t2; + +# # Test problem when using locks on many tables and droping a table that # is to-be-locked by another thread # diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 40e742679f8..e56636bd2ba 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -154,8 +154,6 @@ LOCK TABLES t1 write, t2 read; DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n; --error 1099 UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; -# The following should be fixed to not give an error ---error 1099 UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; unlock tables; LOCK TABLES t1 write, t2 write; diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 3f0b41d7221..d3bda858b8b 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -62,19 +62,6 @@ INSERT INTO t1 VALUES ("2030-01-01","2030-01-01 00:00:00",20300101000000); SELECT * FROM t1; drop table t1; -show variables like 'new'; -create table t1 (t2 timestamp(2), t4 timestamp(4), t6 timestamp(6), - t8 timestamp(8), t10 timestamp(10), t12 timestamp(12), - t14 timestamp(14)); -insert t1 values (0,0,0,0,0,0,0), -("1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", -"1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", -"1997-12-31 23:47:59"); -select * from t1; -set new=1; -select * from t1; -drop table t1; - # # Let us check if we properly treat wrong datetimes and produce proper warnings # (for both strings and numbers) @@ -258,6 +245,9 @@ select * from t1; drop table t1; # It is also OK to specify NULL as default explicitly for such fields. +# This is also a test for bug #2464, DEFAULT keyword in INSERT statement +# should return default value for column. + create table t1 (a timestamp null default null, b timestamp null default '2003-01-01 00:00:00'); show create table t1; insert into t1 values (NULL, NULL); @@ -275,3 +265,14 @@ set TIMESTAMP=1000000000; insert into t1 values (); select * from t1; drop table t1; + +# +# Test for bug #4131, TIMESTAMP columns missing minutes and seconds when +# using GROUP BY in @@new=1 mode. +# +set new=1; +create table t1 (a char(2), t timestamp); +insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'), + ('b', '2004-02-01 00:00:00'); +select max(t) from t1 group by a; +drop table t1; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 6ca75cf0c26..aeefa3c33f5 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -128,3 +128,36 @@ insert into t1 (F1,F2,F3,cnt,groupid) values ('0','0','0',1,6), delete from m1 using t1 m1,t1 m2 where m1.groupid=m2.groupid and (m1.cnt < m2.cnt or m1.cnt=m2.cnt and m1.F3>m2.F3); select * from t1; drop table t1; + +# +# Bug#5553 - Multi table UPDATE IGNORE fails on duplicate keys +# + +CREATE TABLE t1 ( + `colA` int(10) unsigned NOT NULL auto_increment, + `colB` int(11) NOT NULL default '0', + PRIMARY KEY (`colA`) +); +INSERT INTO t1 VALUES (4433,5424); +CREATE TABLE t2 ( + `colC` int(10) unsigned NOT NULL default '0', + `colA` int(10) unsigned NOT NULL default '0', + `colD` int(10) unsigned NOT NULL default '0', + `colE` int(10) unsigned NOT NULL default '0', + `colF` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`colC`,`colA`,`colD`,`colE`) +); +INSERT INTO t2 VALUES (3,4433,10005,495,500); +INSERT INTO t2 VALUES (3,4433,10005,496,500); +INSERT INTO t2 VALUES (3,4433,10009,494,500); +INSERT INTO t2 VALUES (3,4433,10011,494,500); +INSERT INTO t2 VALUES (3,4433,10005,497,500); +INSERT INTO t2 VALUES (3,4433,10013,489,500); +INSERT INTO t2 VALUES (3,4433,10005,494,500); +INSERT INTO t2 VALUES (3,4433,10005,493,500); +INSERT INTO t2 VALUES (3,4433,10005,492,500); +UPDATE IGNORE t2,t1 set t2.colE = t2.colE + 1,colF=0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +SELECT * FROM t2; +DROP TABLE t1; +DROP TABLE t2; + diff --git a/mysys/errors.c b/mysys/errors.c index 255b6893c73..5401c2b3cc6 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -41,7 +41,7 @@ const char * NEAR globerrs[GLOBERRS]= "Can't change dir to '%s' (Errcode: %d)", "Warning: '%s' had %d links", "%d files and %d streams is left open\n", - "Disk is full writing '%s'. Waiting for someone to free space...", + "Disk is full writing '%s' (Errcode: %d). Waiting for someone to free space... Retry in %d secs", "Can't create directory '%s' (Errcode: %d)", "Character set '%s' is not a compiled character set and is not specified in the '%s' file", "Out of resources when opening file '%s' (Errcode: %d)", diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c index 00fe5c7a009..5b17e3ff51c 100644 --- a/mysys/my_fstream.c +++ b/mysys/my_fstream.c @@ -114,13 +114,15 @@ uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags) if (my_thread_var->abort) MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */ #endif - if (errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL)) + if ((errno == ENOSPC || errno == EDQUOT) && + (MyFlags & MY_WAIT_IF_FULL)) { - if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) - my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH)); - sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC); - VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0))); - continue; + if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) + my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH), + "[stream]",my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC); + VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); + VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0))); + continue; } #endif if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP))) diff --git a/mysys/my_pread.c b/mysys/my_pread.c index 6a55a3cd8de..3d02e368720 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -115,11 +115,12 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, if (my_thread_var->abort) MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */ #endif - if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL)) + if ((my_errno == ENOSPC || my_errno == EDQUOT) && + (MyFlags & MY_WAIT_IF_FULL)) { if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH), - my_filename(Filedes)); + my_filename(Filedes),my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC); VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } @@ -131,7 +132,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, { if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { - my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG), + my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG), my_filename(Filedes),my_errno); } DBUG_RETURN(MY_FILE_ERROR); /* Error on read */ @@ -142,4 +143,4 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, if (MyFlags & (MY_NABP | MY_FNABP)) DBUG_RETURN(0); /* Want only errors */ DBUG_RETURN(writenbytes+written); /* purecov: inspected */ -} /* my_write */ +} /* my_pwrite */ diff --git a/mysys/my_write.c b/mysys/my_write.c index 37d885f04cd..2df3a31e774 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -48,12 +48,13 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) if (my_thread_var->abort) MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */ #endif - if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL) && + if ((my_errno == ENOSPC || my_errno == EDQUOT) && + (MyFlags & MY_WAIT_IF_FULL) && (uint) writenbytes != (uint) -1) { if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE)) my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH), - my_filename(Filedes)); + my_filename(Filedes),my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC); VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index 6abadd48aeb..89a6d8aa2a7 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -34,3 +34,10 @@ extern pthread_mutex_t THR_LOCK_charset; #include <my_no_pthread.h> #endif +/* + EDQUOT is used only in 3 C files only in mysys/. If it does not exist on + system, we set it to some value which can never happen. +*/ +#ifndef EDQUOT +#define EDQUOT (-1) +#endif diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index fe93aa5a1bc..b8494727975 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -77,7 +77,7 @@ Usage: $0 db_name[./table_regex/] [new_db_name | directory] --record_log_pos=# record slave and master status in specified db.table --chroot=# base directory of chroot jail in which mysqld operates - Try \'perldoc $0 for more complete documentation\' + Try \'perldoc $0\' for more complete documentation _OPTIONS sub usage { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index f5da82a8a8c..8ddf00a7568 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -812,6 +812,7 @@ ha_innobase::init_table_handle_for_HANDLER(void) if the trx isolation level would have been specified as SERIALIZABLE */ prebuilt->select_lock_type = LOCK_NONE; + prebuilt->stored_select_lock_type = LOCK_NONE; /* Always fetch all columns in the index record */ @@ -3171,7 +3172,7 @@ ha_innobase::index_last( { int error; - DBUG_ENTER("index_first"); + DBUG_ENTER("index_last"); statistic_increment(ha_read_last_count, &LOCK_status); error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY); @@ -4255,7 +4256,7 @@ ha_innobase::info( if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { - return; + DBUG_VOID_RETURN; } /* We do not know if MySQL can call this function before calling @@ -4816,6 +4817,7 @@ ha_innobase::external_lock( /* If this is a SELECT, then it is in UPDATE TABLE ... or SELECT ... FOR UPDATE */ prebuilt->select_lock_type = LOCK_X; + prebuilt->stored_select_lock_type = LOCK_X; } if (lock_type != F_UNLCK) { @@ -5067,14 +5069,22 @@ ha_innobase::store_lock( { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - if (lock_type == TL_READ_WITH_SHARED_LOCKS || + if ((lock_type == TL_READ && thd->in_lock_tables) || + (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) || + lock_type == TL_READ_WITH_SHARED_LOCKS || lock_type == TL_READ_NO_INSERT) { - /* This is a SELECT ... IN SHARE MODE, or - we are doing a complex SQL statement like + /* The OR cases above are in this order: + 1) MySQL is doing LOCK TABLES ... READ LOCAL, or + 2) (we do not know when TL_READ_HIGH_PRIORITY is used), or + 3) this is a SELECT ... IN SHARE MODE, or + 4) we are doing a complex SQL statement like INSERT INTO ... SELECT ... and the logical logging (MySQL - binlog) requires the use of a locking read */ + binlog) requires the use of a locking read, or + MySQL is doing LOCK TABLES ... READ. */ prebuilt->select_lock_type = LOCK_S; + prebuilt->stored_select_lock_type = LOCK_S; + } else if (lock_type != TL_IGNORE) { /* In ha_berkeley.cc there is a comment that MySQL @@ -5085,6 +5095,7 @@ ha_innobase::store_lock( here even if this would be SELECT ... FOR UPDATE */ prebuilt->select_lock_type = LOCK_NONE; + prebuilt->stored_select_lock_type = LOCK_NONE; } if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 729ec4c27eb..0b993ebe793 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1280,6 +1280,7 @@ int ha_myisam::delete_table(const char *name) return mi_delete_table(name); } + int ha_myisam::external_lock(THD *thd, int lock_type) { return mi_lock_database(file, !table->tmp_table ? @@ -1287,7 +1288,6 @@ int ha_myisam::external_lock(THD *thd, int lock_type) F_UNLCK : F_EXTRA_LCK)); } - THR_LOCK_DATA **ha_myisam::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) diff --git a/sql/handler.cc b/sql/handler.cc index 23b4fbe4835..e59358d44bf 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -483,7 +483,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) if (trans == &thd->transaction.all && mysql_bin_log.is_open() && my_b_tell(&thd->transaction.trans_log)) { - if (error= wait_if_global_read_lock(thd, 0, 0)) + if ((error= wait_if_global_read_lock(thd, 0, 0))) { /* Note that ROLLBACK [TO SAVEPOINT] does not have this test; it's diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index bb1ea09d6bc..5b6484f5017 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1162,6 +1162,15 @@ Item_func_nullif::val_str(String *str) return res; } + +bool +Item_func_nullif::is_null() +{ + if (!(this->*cmp_func)()) + return null_value=1; + return 0; +} + /* CASE expression Return the matching ITEM or NULL if all compares (including else) failed diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index f1a2b11aaa8..ad2b929c19e 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -444,6 +444,7 @@ public: const char *func_name() const { return "nullif"; } void print(String *str) { Item_func::print(str); } table_map not_null_tables() const { return 0; } + bool is_null(); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 131bd55dc81..78acaafc486 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1245,7 +1245,7 @@ String *Item_func_ltrim::val_str(String *str) { const char *r_ptr=remove_str->ptr(); end-=remove_length; - while (ptr < end && !memcmp(ptr,r_ptr,remove_length)) + while (ptr <= end && !memcmp(ptr, r_ptr, remove_length)) ptr+=remove_length; end+=remove_length; } @@ -1317,8 +1317,8 @@ String *Item_func_rtrim::val_str(String *str) else #endif /* USE_MB */ { - while (ptr + remove_length < end && - !memcmp(end-remove_length,r_ptr,remove_length)) + while (ptr + remove_length <= end && + !memcmp(end-remove_length, r_ptr, remove_length)) end-=remove_length; } } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5d04d145563..8a81c0690b8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -677,12 +677,15 @@ void mysql_reset_errors(THD *thd); my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show); /* sql_handler.cc */ -int mysql_ha_open(THD *thd, TABLE_LIST *tables); -int mysql_ha_close(THD *thd, TABLE_LIST *tables, - bool dont_send_ok=0, bool dont_lock=0, bool no_alias=0); -int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed=0); +int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen= 0); +int mysql_ha_close(THD *thd, TABLE_LIST *tables); int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, int mode_flags); +/* mysql_ha_flush mode_flags bits */ +#define MYSQL_HA_CLOSE_FINAL 0x00 +#define MYSQL_HA_REOPEN_ON_USAGE 0x01 +#define MYSQL_HA_FLUSH_ALL 0x02 /* sql_base.cc */ void set_item_name(Item *item,char *pos,uint length); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5e40398574b..b9fc5477449 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2118,8 +2118,7 @@ static void check_data_home(const char *path) /* ARGSUSED */ -extern "C" int my_message_sql(uint error, const char *str, - myf MyFlags __attribute__((unused))) +! extern "C" int my_message_sql(uint error, const char *str, myf MyFlags) { THD *thd; DBUG_ENTER("my_message_sql"); @@ -2147,7 +2146,7 @@ extern "C" int my_message_sql(uint error, const char *str, } } } - else + if (!thd || MyFlags & ME_NOREFRESH) sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */ DBUG_RETURN(0); } diff --git a/sql/protocol.cc b/sql/protocol.cc index da2a285fffc..c2d9117b062 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -209,6 +209,10 @@ net_printf(THD *thd, uint errcode, ...) format,args); va_end(args); + /* Replication slave relies on net->last_* to see if there was error */ + net->last_errno= errcode; + strmake(net->last_error, text_pos, sizeof(net->last_error)-1); + #ifndef EMBEDDED_LIBRARY if (net->vio == 0) { diff --git a/sql/records.cc b/sql/records.cc index 5a969ef9c20..e5a0d102b10 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -156,17 +156,26 @@ void end_read_record(READ_RECORD *info) static int rr_quick(READ_RECORD *info) { - int tmp=info->select->quick->get_next(); - if (tmp) + int tmp; + while ((tmp= info->select->quick->get_next())) { - if (tmp == HA_ERR_END_OF_FILE) - tmp= -1; - else + if (info->thd->killed) { - if (info->print_error) - info->file->print_error(tmp,MYF(0)); - if (tmp < 0) // Fix negative BDB errno - tmp=1; + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + return 1; + } + if (tmp != HA_ERR_RECORD_DELETED) + { + if (tmp == HA_ERR_END_OF_FILE) + tmp= -1; + else + { + if (info->print_error) + info->file->print_error(tmp,MYF(0)); + if (tmp < 0) // Fix negative BDB errno + tmp=1; + } + break; } } return tmp; @@ -330,9 +339,10 @@ static int init_rr_cache(READ_RECORD *info) rec_cache_size=info->cache_records*info->reclength; info->rec_cache_size=info->cache_records*info->ref_length; + // We have to allocate one more byte to use uint3korr (see comments for it) if (info->cache_records <= 2 || !(info->cache=(byte*) my_malloc_lock(rec_cache_size+info->cache_records* - info->struct_length, + info->struct_length+1, MYF(0)))) DBUG_RETURN(1); #ifdef HAVE_purify diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index d7b70fe122c..66c6e7c508d 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -14,8 +14,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// Sasha Pachev <sasha@mysql.com> is currently in charge of this file - #include "mysql_priv.h" #ifdef HAVE_REPLICATION diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h index a9c504330ab..ad0219bb735 100644 --- a/sql/repl_failsafe.h +++ b/sql/repl_failsafe.h @@ -1,6 +1,20 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifdef HAVE_REPLICATION -#ifndef REPL_FAILSAFE_H -#define REPL_FAILSAFE_H #include "mysql.h" #include "my_sys.h" @@ -35,5 +49,4 @@ void end_slave_list(); int register_slave(THD* thd, uchar* packet, uint packet_length); void unregister_slave(THD* thd, bool only_mine, bool need_mutex); -#endif #endif /* HAVE_REPLICATION */ diff --git a/sql/slave.h b/sql/slave.h index 384436fdfcc..20167094453 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -1,3 +1,19 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifdef HAVE_REPLICATION #ifndef SLAVE_H diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2770d93bf26..a91371b4248 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -300,7 +300,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_close_list(thd, tables); + mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", @@ -852,7 +852,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, } /* close handler tables which are marked for flush */ - mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; @@ -936,6 +936,31 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, for (uint i=0 ; i < table->fields ; i++) table->field[i]->table_name=table->table_name; } +#if MYSQL_VERSION_ID < 40100 + /* + If per-connection "new" variable (represented by variables.new_mode) + is set then we should pretend that the length of TIMESTAMP field is 19. + The cheapest (from perfomance viewpoint) way to achieve that is to set + field_length of all Field_timestamp objects in a table after opening + it (to 19 if new_mode is true or to original field length otherwise). + We save value of new_mode variable in TABLE::timestamp_mode to + not perform this setup if new_mode value is the same between sequential + table opens. + */ + my_bool new_mode= thd->variables.new_mode; + if (table->timestamp_mode != new_mode) + { + for (uint i=0 ; i < table->fields ; i++) + { + Field *field= table->field[i]; + + if (field->type() == FIELD_TYPE_TIMESTAMP) + field->field_length= new_mode ? 19 : + ((Field_timestamp *)(field))->orig_field_length; + } + table->timestamp_mode= new_mode; + } +#endif /* These variables are also set in reopen_table() */ table->tablenr=thd->current_tablenr++; table->used_fields=0; @@ -1224,7 +1249,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index f69fb3085d3..7aa0ef83238 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1945,7 +1945,6 @@ inline ulong Query_cache::get_min_append_result_data_size() /* Allocate one or more blocks to hold data */ - my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, ulong data_len, Query_cache_block *query_block, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 6cf01896b03..e061340b0e0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -172,6 +172,7 @@ THD::THD() query_error= tmp_table_used= 0; next_insert_id=last_insert_id=0; open_tables= temporary_tables= handler_tables= derived_tables= 0; + hash_clear(&handler_tables_hash); tmp_table=0; lock=locked_tables=0; used_tables=0; @@ -346,11 +347,9 @@ void THD::cleanup(void) lock=locked_tables; locked_tables=0; close_thread_tables(this); } - if (handler_tables) - { - open_tables=handler_tables; handler_tables=0; - close_thread_tables(this); - } + mysql_ha_flush(this, (TABLE_LIST*) 0, + MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); + hash_free(&handler_tables_hash); close_temporary_tables(this); my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); diff --git a/sql/sql_class.h b/sql/sql_class.h index fbbb7fc7383..8896b7b658f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -750,6 +750,7 @@ public: */ MYSQL_LOCK *lock; /* Current locks */ MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */ + HASH handler_tables_hash; /* One thread can hold up to one named user-level lock. This variable points to a lock object if the lock is present. See item_func.cc and diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5965732d2ce..09893970803 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -338,6 +338,8 @@ multi_delete::initialize_tables(JOIN *join) walk=walk->next; /* Don't use KEYREAD optimization on this table */ tbl->no_keyread=1; + /* Don't use record cache */ + tbl->no_cache= 1; tbl->used_keys.clear_all(); if (tbl->file->has_transactions()) log_delayed= transactional_tables= 1; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 56c1b0a1b51..1e50e1e571e 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -1,5 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB - +/* Copyright (C) 2000-2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -17,9 +16,6 @@ /* HANDLER ... commands - direct access to ISAM */ -#include "mysql_priv.h" -#include "sql_select.h" - /* TODO: HANDLER blabla OPEN [ AS foobar ] [ (column-list) ] @@ -37,190 +33,410 @@ all the sql_alloc'ed memory. It's harder to work around... */ +/* + There are two containers holding information about open handler tables. + The first is 'thd->handler_tables'. It is a linked list of TABLE objects. + It is used like 'thd->open_tables' in the table cache. The trick is to + exchange these two lists during open and lock of tables. Thus the normal + table cache code can be used. + The second container is a HASH. It holds objects of the type TABLE_LIST. + Despite its name, no lists of tables but only single structs are hashed + (the 'next' pointer is always NULL). The reason for theis second container + is, that we want handler tables to survive FLUSH TABLE commands. A table + affected by FLUSH TABLE must be closed so that other threads are not + blocked by handler tables still in use. Since we use the normal table cache + functions with 'thd->handler_tables', the closed tables are removed from + this list. Hence we need the original open information for the handler + table in the case that it is used again. This information is handed over + to mysql_ha_open() as a TABLE_LIST. So we store this information in the + second container, where it is not affected by FLUSH TABLE. The second + container is implemented as a hash for performance reasons. Consequently, + we use it not only for re-opening a handler table, but also for the + HANDLER ... READ commands. For this purpose, we store a pointer to the + TABLE structure (in the first container) in the TBALE_LIST object in the + second container. When the table is flushed, the pointer is cleared. +*/ + +#include "mysql_priv.h" +#include "sql_select.h" +#include <assert.h> + +#define HANDLER_TABLES_HASH_SIZE 120 + +static enum enum_ha_read_modes rkey_to_rnext[]= + { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV }; + #define HANDLER_TABLES_HACK(thd) { \ TABLE *tmp=thd->open_tables; \ thd->open_tables=thd->handler_tables; \ thd->handler_tables=tmp; } -static TABLE **find_table_ptr_by_name(THD *thd,const char *db, - const char *table_name, - bool is_alias, bool dont_lock, - bool *was_flushed); +static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, int mode_flags); + + +/* + Get hash key and hash key length. + + SYNOPSIS + mysql_ha_hash_get_key() + tables Pointer to the hash object. + key_len_p (out) Pointer to the result for key length. + first Unused. + + DESCRIPTION + The hash object is an TABLE_LIST struct. + The hash key is the alias name. + The hash key length is the alias name length plus one for the + terminateing NUL character. + + RETURN + Pointer to the TABLE_LIST struct. +*/ -int mysql_ha_open(THD *thd, TABLE_LIST *tables) +static char *mysql_ha_hash_get_key(TABLE_LIST *tables, uint *key_len_p, + my_bool first __attribute__((unused))) { - HANDLER_TABLES_HACK(thd); - uint counter; - int err=open_tables(thd, tables, &counter); - HANDLER_TABLES_HACK(thd); - if (err) - return -1; + *key_len_p= strlen(tables->alias) + 1 ; /* include '\0' in comparisons */ + return tables->alias; +} - // there can be only one table in *tables - if (!(tables->table->file->table_flags() & HA_CAN_SQL_HANDLER)) - { - my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias); - mysql_ha_close(thd, tables,1); - return -1; - } - send_ok(thd); - return 0; +/* + Free an hash object. + + SYNOPSIS + mysql_ha_hash_free() + tables Pointer to the hash object. + + DESCRIPTION + The hash object is an TABLE_LIST struct. + + RETURN + Nothing +*/ + +static void mysql_ha_hash_free(TABLE_LIST *tables) +{ + my_free((char*) tables, MYF(0)); } /* - Close a HANDLER table. + Open a HANDLER table. SYNOPSIS - mysql_ha_close() + mysql_ha_open() thd Thread identifier. - tables A list of tables with the first entry to close. - dont_send_ok Suppresses the commands' ok message and - error message and error return. - dont_lock Suppresses the normal locking of LOCK_open. + tables A list of tables with the first entry to open. + reopen Re-open a previously opened handler table. DESCRIPTION Though this function takes a list of tables, only the first list entry - will be closed. Broadcasts a COND_refresh condition. - If mysql_ha_close() is not called from the parser, 'dont_send_ok' - must be set. - If the caller did already lock LOCK_open, it must set 'dont_lock'. - - IMPLEMENTATION - find_table_ptr_by_name() closes the table, if a FLUSH TABLE is outstanding. - It returns a NULL pointer in this case, but flags the situation in - 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages - is suppressed. + will be opened. + 'reopen' is set when a handler table is to be re-opened. In this case, + 'tables' is the pointer to the hashed TABLE_LIST object which has been + saved on the original open. + 'reopen' is also used to suppress the sending of an 'ok' message or + error messages. RETURN - 0 ok - -1 error + 0 ok + != 0 error */ -int mysql_ha_close(THD *thd, TABLE_LIST *tables, - bool dont_send_ok, bool dont_lock, bool no_alias) +int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) { - TABLE **table_ptr; - bool was_flushed; - - table_ptr= find_table_ptr_by_name(thd, tables->db, tables->alias, - !no_alias, dont_lock, &was_flushed); - if (*table_ptr) + TABLE_LIST *hash_tables; + char *db, *name, *alias; + uint dblen, namelen, aliaslen, counter; + int err; + DBUG_ENTER("mysql_ha_open"); + DBUG_PRINT("enter",("mysql_ha_open: '%s'.'%s' as '%s' reopen %d", + tables->db, tables->real_name, tables->alias, reopen)); + + if (! hash_inited(&thd->handler_tables_hash)) + { + /* + HASH entries are of type TABLE_LIST. + */ + if (hash_init(&thd->handler_tables_hash, HANDLER_TABLES_HASH_SIZE, 0, 0, + (hash_get_key) mysql_ha_hash_get_key, + (hash_free_key) mysql_ha_hash_free, 0)) + goto err; + } + else if (! reopen) /* Otherwise we have 'tables' already. */ { - (*table_ptr)->file->ha_index_or_rnd_end(); - if (!dont_lock) - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, table_ptr)) + if (hash_search(&thd->handler_tables_hash, (byte*) tables->alias, + strlen(tables->alias) + 1)) { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); + DBUG_PRINT("info",("mysql_ha_open: duplicate '%s'", tables->alias)); + if (! reopen) + my_printf_error(ER_NONUNIQ_TABLE, ER(ER_NONUNIQ_TABLE), + MYF(0), tables->alias); + goto err; } - if (!dont_lock) - VOID(pthread_mutex_unlock(&LOCK_open)); } - else if (!was_flushed && !dont_send_ok) + + /* + open_tables() will set 'tables->table' if successful. + It must be NULL for a real open when calling open_tables(). + */ + DBUG_ASSERT(! tables->table); + HANDLER_TABLES_HACK(thd); + err=open_tables(thd, tables, &counter); + HANDLER_TABLES_HACK(thd); + if (err) + goto err; + + /* There can be only one table in '*tables'. */ + if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER)) + { + if (! reopen) + my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias); + mysql_ha_close(thd, tables); + goto err; + } + + if (! reopen) { - my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), - tables->alias, "HANDLER"); - return -1; + /* copy the TABLE_LIST struct */ + dblen= strlen(tables->db) + 1; + namelen= strlen(tables->real_name) + 1; + aliaslen= strlen(tables->alias) + 1; + if (!(my_multi_malloc(MYF(MY_WME), + &hash_tables, sizeof(*hash_tables), + &db, dblen, + &name, namelen, + &alias, aliaslen, + NullS))) + { + DBUG_PRINT("exit",("mysql_ha_open: malloc ERROR")); + goto err; + } + /* structure copy */ + *hash_tables= *tables; + hash_tables->db= db; + hash_tables->real_name= name; + hash_tables->alias= alias; + memcpy(hash_tables->db, tables->db, dblen); + memcpy(hash_tables->real_name, tables->real_name, namelen); + memcpy(hash_tables->alias, tables->alias, aliaslen); + + /* add to hash */ + if (hash_insert(&thd->handler_tables_hash, (byte*) hash_tables)) + { + mysql_ha_close(thd, tables); + goto err; + } } - if (!dont_send_ok) + + if (! reopen) send_ok(thd); - return 0; + DBUG_PRINT("exit",("mysql_ha_open: OK")); + DBUG_RETURN(0); + +err: + DBUG_PRINT("exit",("mysql_ha_open: ERROR")); + DBUG_RETURN(-1); } /* - Close a list of HANDLER tables. + Close a HANDLER table. SYNOPSIS - mysql_ha_close_list() + mysql_ha_close() thd Thread identifier. - tables The list of tables to close. If NULL, - close all HANDLER tables. - flushed Close only tables which are marked flushed. - Used only if tables is NULL. + tables A list of tables with the first entry to close. DESCRIPTION - The list of HANDLER tables may be NULL, in which case all HANDLER - tables are closed. Broadcasts a COND_refresh condition, for - every table closed. If 'tables' is NULL and 'flushed' is set, - all HANDLER tables marked for flush are closed. - The caller must lock LOCK_open. - - IMPLEMENTATION - find_table_ptr_by_name() closes the table, if it is marked for flush. - It returns a NULL pointer in this case, but flags the situation in - 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages - is suppressed. + Though this function takes a list of tables, only the first list entry + will be closed. Broadcasts a COND_refresh condition. RETURN - 0 ok + 0 ok + != 0 error */ -int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed) +int mysql_ha_close(THD *thd, TABLE_LIST *tables) { - TABLE_LIST *tl_item; + TABLE_LIST *hash_tables; TABLE **table_ptr; - - if (tables) + bool was_flushed= FALSE; + bool not_opened; + DBUG_ENTER("mysql_ha_close"); + DBUG_PRINT("enter",("mysql_ha_close: '%s'.'%s' as '%s'", + tables->db, tables->real_name, tables->alias)); + + if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, + (byte*) tables->alias, + strlen(tables->alias) + 1))) { - for (tl_item= tables ; tl_item; tl_item= tl_item->next) + /* + Though we could take the table pointer from hash_tables->table, + we must follow the thd->handler_tables chain anyway, as we need the + address of the 'next' pointer referencing this table + for close_thread_table(). + */ + for (table_ptr= &(thd->handler_tables); + *table_ptr && (*table_ptr != hash_tables->table); + table_ptr= &(*table_ptr)->next); + +#if MYSQL_VERSION_ID < 40100 + if (*tables->db && strcmp(hash_tables->db, tables->db)) { - mysql_ha_close(thd, tl_item, /*dont_send_ok*/ 1, - /*dont_lock*/ 1, /*no_alias*/ 1); + DBUG_PRINT("info",("mysql_ha_close: wrong db")); + hash_tables= NULL; } - } - else - { - table_ptr= &(thd->handler_tables); - while (*table_ptr) + else +#endif { - if (! flushed || ((*table_ptr)->version != refresh_version)) + if (*table_ptr) { - (*table_ptr)->file->ha_index_or_rnd_end(); + table_ptr->file->ha_index_or_rnd_end(); + VOID(pthread_mutex_lock(&LOCK_open)); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ VOID(pthread_cond_broadcast(&COND_refresh)); } - continue; + VOID(pthread_mutex_unlock(&LOCK_open)); } - table_ptr= &((*table_ptr)->next); + + hash_delete(&thd->handler_tables_hash, (byte*) hash_tables); } } - return 0; + + if (! hash_tables) + { +#if MYSQL_VERSION_ID < 40100 + char buff[MAX_DBKEY_LENGTH]; + if (*tables->db) + strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS); + else + strncpy(buff, tables->alias, sizeof(buff)); + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + buff, "HANDLER"); +#else + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + tables->alias, "HANDLER"); +#endif + DBUG_PRINT("exit",("mysql_ha_close: ERROR")); + DBUG_RETURN(-1); + } + + send_ok(thd); + DBUG_PRINT("exit",("mysql_ha_close: OK")); + DBUG_RETURN(0); } -static enum enum_ha_read_modes rkey_to_rnext[]= - { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV }; +/* + Read from a HANDLER table. + + SYNOPSIS + mysql_ha_read() + thd Thread identifier. + tables A list of tables with the first entry to read. + mode + keyname + key_expr + ha_rkey_mode + cond + select_limit + offset_limit + RETURN + 0 ok + != 0 error +*/ + int mysql_ha_read(THD *thd, TABLE_LIST *tables, enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr, enum ha_rkey_function ha_rkey_mode, Item *cond, ha_rows select_limit,ha_rows offset_limit) { - int err, keyno=-1; - bool was_flushed; - TABLE *table= *find_table_ptr_by_name(thd, tables->db, tables->alias, - /*is_alias*/ 1, /*dont_lock*/ 0, - &was_flushed); + TABLE_LIST *hash_tables; + TABLE *table; + MYSQL_LOCK *lock; + List<Item> list; + Protocol *protocol= thd->protocol; + char buff[MAX_FIELD_WIDTH]; + String buffer(buff, sizeof(buff), system_charset_info); + int err, keyno= -1; + uint num_rows; + byte *key; + uint key_len; + bool was_flushed; + DBUG_ENTER("mysql_ha_read"); + DBUG_PRINT("enter",("mysql_ha_read: '%s'.'%s' as '%s'", + tables->db, tables->real_name, tables->alias)); + + LINT_INIT(key); + LINT_INIT(key_len); + + list.push_front(new Item_field(NULL,NULL,"*")); + List_iterator<Item> it(list); + it++; + + if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, + (byte*) tables->alias, + strlen(tables->alias) + 1))) + { + table= hash_tables->table; + DBUG_PRINT("info",("mysql_ha_read: found in hash '%s'.'%s' as '%s' tab %p", + hash_tables->db, hash_tables->real_name, + hash_tables->alias, table)); + if (!table) + { + /* + The handler table has been closed. Re-open it. + */ + if (mysql_ha_open(thd, hash_tables, 1)) + { + DBUG_PRINT("exit",("mysql_ha_read: reopen failed")); + goto err0; + } + + table= hash_tables->table; + DBUG_PRINT("info",("mysql_ha_read: re-opened '%s'.'%s' as '%s' tab %p", + hash_tables->db, hash_tables->real_name, + hash_tables->alias, table)); + } + +#if MYSQL_VERSION_ID < 40100 + if (*tables->db && strcmp(table->table_cache_key, tables->db)) + { + DBUG_PRINT("info",("mysql_ha_read: wrong db")); + table= NULL; + } +#endif + } + else + table= NULL; + if (!table) { - my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0), - tables->alias,"HANDLER"); - return -1; +#if MYSQL_VERSION_ID < 40100 + char buff[MAX_DBKEY_LENGTH]; + if (*tables->db) + strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS); + else + strncpy(buff, tables->alias, sizeof(buff)); + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + buff, "HANDLER"); +#else + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + tables->alias, "HANDLER"); +#endif + goto err0; } tables->table=table; if (cond && (cond->fix_fields(thd, tables, &cond) || cond->check_cols(1))) - return -1; - - /* InnoDB needs to know that this table handle is used in the HANDLER */ + goto err0; - table->file->init_table_handle_for_HANDLER(); + table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it if (keyname) { @@ -228,34 +444,22 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, { my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0), keyname,tables->alias); - return -1; + goto err0; } table->file->ha_index_or_rnd_end(); table->file->ha_index_init(keyno); } - List<Item> list; - list.push_front(new Item_field(NULL,NULL,"*")); - List_iterator<Item> it(list); - Protocol *protocol= thd->protocol; - char buff[MAX_FIELD_WIDTH]; - String buffer(buff, sizeof(buff), system_charset_info); - uint num_rows; - byte *key; - uint key_len; - LINT_INIT(key); - LINT_INIT(key_len); - - it++; // Skip first NULL field - - insert_fields(thd,tables,tables->db,tables->alias,&it); + if (insert_fields(thd,tables,tables->db,tables->alias,&it)) + goto err0; select_limit+=offset_limit; protocol->send_fields(&list,1); HANDLER_TABLES_HACK(thd); - MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1); + lock= mysql_lock_tables(thd, &tables->table, 1); HANDLER_TABLES_HACK(thd); + if (!lock) goto err0; // mysql_lock_tables() printed error message already @@ -378,84 +582,156 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } ok: mysql_unlock_tables(thd,lock); - send_eof(thd); - return 0; + send_eof(&thd->net); + DBUG_PRINT("exit",("mysql_ha_read: OK")); + DBUG_RETURN(0); err: mysql_unlock_tables(thd,lock); err0: - return -1; + DBUG_PRINT("exit",("mysql_ha_read: ERROR")); + DBUG_RETURN(-1); } /* - Find a HANDLER table by name. + Flush (close) a list of HANDLER tables. SYNOPSIS - find_table_ptr_by_name() + mysql_ha_flush() thd Thread identifier. - db Database (schema) name. - table_name Table name ;-). - is_alias Table name may be an alias name. - dont_lock Suppresses the normal locking of LOCK_open. + tables The list of tables to close. If NULL, + close all HANDLER tables [marked as flushed]. + mode_flags MYSQL_HA_CLOSE_FINAL finally close the table. + MYSQL_HA_REOPEN_ON_USAGE mark for reopen. + MYSQL_HA_FLUSH_ALL flush all tables, not only + those marked for flush. DESCRIPTION - Find the table 'db'.'table_name' in the list of HANDLER tables of the - thread 'thd'. If the table has been marked by FLUSH TABLE(S), close it, - flag this situation in '*was_flushed' and broadcast a COND_refresh - condition. - An empty database (schema) name matches all database (schema) names. - If the caller did already lock LOCK_open, it must set 'dont_lock'. - - IMPLEMENTATION - Just in case that the table is twice in 'thd->handler_tables' (!?!), - the loop does not break when the table was flushed. If another table - by that name was found and not flushed, '*was_flushed' is cleared again, - since a pointer to an open HANDLER table is returned. + The list of HANDLER tables may be NULL, in which case all HANDLER + tables are closed (if MYSQL_HA_FLUSH_ALL) is set. + If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set, + all HANDLER tables marked for flush are closed. + Broadcasts a COND_refresh condition, for every table closed. + The caller must lock LOCK_open. + + NOTE + Since mysql_ha_flush() is called when the base table has to be closed, + we compare real table names, not aliases. Hence, database names matter. RETURN - *was_flushed Table has been closed due to FLUSH TABLE. - NULL A HANDLER Table by that name does not exist (any more). - != NULL Pointer to the TABLE structure. + 0 ok */ -static TABLE **find_table_ptr_by_name(THD *thd, const char *db, - const char *table_name, - bool is_alias, bool dont_lock, - bool *was_flushed) +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, int mode_flags) { - int dblen; - TABLE **table_ptr; - - DBUG_ASSERT(db); - dblen= strlen(db); - table_ptr= &(thd->handler_tables); - *was_flushed= FALSE; + TABLE_LIST **tmp_tables_p; + TABLE_LIST *tmp_tables; + TABLE **table_ptr; + bool was_flushed; + DBUG_ENTER("mysql_ha_flush"); + DBUG_PRINT("enter",("mysql_ha_flush: tables %p mode_flags 0x%02x", + tables, mode_flags)); - for (TABLE *table= *table_ptr; table ; table= *table_ptr) + if (tables) { - if ((db == any_db || !memcmp(table->table_cache_key, db, dblen)) && - !my_strcasecmp(system_charset_info, - (is_alias ? table->table_name : table->real_name), - table_name)) + /* Close all tables in the list. */ + for (tmp_tables= tables ; tmp_tables; tmp_tables= tmp_tables->next) { - if (table->version != refresh_version) + DBUG_PRINT("info",("mysql_ha_flush: in tables list '%s'.'%s' as '%s'", + tmp_tables->db, tmp_tables->real_name, + tmp_tables->alias)); + /* Close all currently open handler tables with the same base table. */ + table_ptr= &(thd->handler_tables); + while (*table_ptr) { - if (!dont_lock) - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, table_ptr)) + if ((! *tmp_tables->db || + ! my_strcasecmp((*table_ptr)->table_cache_key, tmp_tables->db)) && + ! my_strcasecmp((*table_ptr)->real_name, tmp_tables->real_name)) { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); + DBUG_PRINT("info",("mysql_ha_flush: *table_ptr '%s'.'%s' as '%s'", + (*table_ptr)->table_cache_key, + (*table_ptr)->real_name, + (*table_ptr)->table_name)); + mysql_ha_flush_table(thd, table_ptr, mode_flags); + continue; } - if (!dont_lock) - VOID(pthread_mutex_unlock(&LOCK_open)); - *was_flushed= TRUE; + table_ptr= &(*table_ptr)->next; + } + /* end of handler_tables list */ + } + /* end of flush tables list */ + } + else + { + /* Close all currently open tables [which are marked for flush]. */ + table_ptr= &(thd->handler_tables); + while (*table_ptr) + { + if ((mode_flags & MYSQL_HA_FLUSH_ALL) || + ((*table_ptr)->version != refresh_version)) + { + mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } - *was_flushed= FALSE; - break; + table_ptr= &(*table_ptr)->next; + } + } + + DBUG_PRINT("exit",("mysql_ha_flush: OK")); + DBUG_RETURN(0); +} + +/* + Flush (close) a table. + + SYNOPSIS + mysql_ha_flush_table() + thd Thread identifier. + table The table to close. + mode_flags MYSQL_HA_CLOSE_FINAL finally close the table. + MYSQL_HA_REOPEN_ON_USAGE mark for reopen. + + DESCRIPTION + Broadcasts a COND_refresh condition, for every table closed. + The caller must lock LOCK_open. + + RETURN + 0 ok +*/ + +static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, int mode_flags) +{ + TABLE_LIST *hash_tables; + TABLE *table= *table_ptr; + bool was_flushed; + DBUG_ENTER("mysql_ha_flush_table"); + DBUG_PRINT("info",("mysql_ha_flush_table: '%s'.'%s' as '%s' flags 0x%02x", + table->table_cache_key, table->real_name, + table->table_name, mode_flags)); + + if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, + (*table_ptr)->table_name, + strlen((*table_ptr)->table_name) + 1))) + { + if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) + { + /* This is a final close. Remove from hash. */ + hash_delete(&thd->handler_tables_hash, (byte*) hash_tables); + } + else + { + /* Mark table as closed, ready for re-open. */ + hash_tables->table= NULL; } - table_ptr= &(table->next); + } + + table_ptr->file->ha_index_or_rnd_end(); + if (close_thread_table(thd, table_ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); } - return table_ptr; + + DBUG_PRINT("exit",("mysql_ha_flush_table: OK")); + DBUG_RETURN(0); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index f71d5a311ab..a84b63c270b 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -14,8 +14,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// Sasha Pachev <sasha@mysql.com> is currently in charge of this file - #include "mysql_priv.h" #ifdef HAVE_REPLICATION diff --git a/sql/sql_repl.h b/sql/sql_repl.h index e7001c1fe1e..3c17540b664 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -1,3 +1,19 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifdef HAVE_REPLICATION #include "slave.h" diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bd145a1de59..44bc2a9efc9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,5 @@ /* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -387,27 +388,23 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, { /* Return databases */ #ifdef USE_SYMDIR char *ext; + char buff[FN_REFLEN]; if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym")) { /* Only show the sym file if it points to a directory */ - char buff[FN_REFLEN], *end; - MY_STAT status; + char *end; *ext=0; /* Remove extension */ unpack_dirname(buff, file->name); end= strend(buff); if (end != buff && end[-1] == FN_LIBCHAR) end[-1]= 0; // Remove end FN_LIBCHAR - if (!my_stat(buff, &status, MYF(0)) || - !MY_S_ISDIR(status.st_mode)) - continue; - } - else + if (!my_stat(buff, file->mystat, MYF(0))) + continue; + } #endif - { if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) || (wild && wild_compare(file->name,wild,0))) continue; - } } else { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3d5aaf0c2ec..5cb328f530b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -197,7 +197,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, for (table=tables ; table ; table=table->next) { char *db=table->db; - mysql_ha_close(thd, table, /*dont_send_ok*/ 1, /*dont_lock*/ 1); + mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); if (!close_temporary_table(thd, db, table->real_name)) { tmp_table_deleted=1; @@ -1762,7 +1762,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); - mysql_ha_close(thd, tables, /*dont_send_ok*/ 1, /*dont_lock*/ 1); + mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL); for (table = tables; table; table = table->next) { char table_name[NAME_LEN*2+2]; @@ -2567,8 +2567,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, new_db= db; used_fields=create_info->used_fields; - mysql_ha_close(thd, table_list, /*dont_send_ok*/ 1, /*dont_lock*/ 1); - + mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL); /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, @@ -3307,7 +3306,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (!(copy= new Copy_field[to->fields])) DBUG_RETURN(-1); /* purecov: inspected */ - to->file->external_lock(thd,F_WRLCK); + if (to->file->external_lock(thd, F_WRLCK)) + DBUG_RETURN(-1); from->file->info(HA_STATUS_VARIABLE); to->file->start_bulk_insert(from->file->records); @@ -3434,12 +3434,13 @@ copy_data_between_tables(TABLE *from,TABLE *to, error=1; if (ha_commit(thd)) error=1; - if (to->file->external_lock(thd,F_UNLCK)) - error=1; + err: free_io_cache(from); *copied= found_count; *deleted=delete_count; + if (to->file->external_lock(thd,F_UNLCK)) + error=1; DBUG_RETURN(error > 0 ? -1 : 0); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 1e8c6576dec..b46cfc05538 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -346,6 +346,7 @@ int st_select_lex_unit::exec() SELECT_LEX *lex_select_save= thd->lex->current_select; SELECT_LEX *select_cursor=first_select_in_union(); ulonglong add_rows=0; + ha_rows examined_rows= 0; DBUG_ENTER("st_select_lex_unit::exec"); if (executed && !uncacheable && !describe) @@ -426,6 +427,7 @@ int st_select_lex_unit::exec() offset_limit_cnt= sl->offset_limit; if (!res && union_result->flush()) { + examined_rows+= thd->examined_row_count; thd->lex->current_select= lex_select_save; DBUG_RETURN(1); } @@ -502,7 +504,10 @@ int st_select_lex_unit::exec() fake_select_lex->table_list.empty(); if (!res) + { thd->limit_found_rows = (ulonglong)table->file->records + add_rows; + thd->examined_row_count+= examined_rows; + } /* Mark for slow query log if any of the union parts didn't use indexes efficiently diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c6fb3d6e415..25d94d6d039 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -449,6 +449,24 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list, ***************************************************************************/ /* + Get table map for list of Item_field +*/ + +static table_map get_table_map(List<Item> *items) +{ + List_iterator_fast<Item> item_it(*items); + Item_field *item; + table_map map= 0; + + while ((item= (Item_field *) item_it++)) + map|= item->used_tables(); + DBUG_PRINT("info",("table_map: 0x%08x", map)); + return map; +} + + + +/* Setup multi-update handling and call SELECT to do the join */ @@ -465,107 +483,163 @@ int mysql_multi_update(THD *thd, multi_update *result; TABLE_LIST *tl; TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first; - table_map item_tables= 0, derived_tables= 0; + List<Item> total_list; DBUG_ENTER("mysql_multi_update"); - if ((res=open_and_lock_tables(thd,table_list))) - DBUG_RETURN(res); - select_lex->select_limit= HA_POS_ERROR; /* - Ensure that we have update privilege for all tables and columns in the - SET part + The following loop is here to to ensure that we only lock tables + that we are going to update with a write lock */ - for (tl= update_list; tl; tl= tl->next) + for (;;) { - TABLE *table= tl->table; + table_map update_tables, derived_tables=0; + uint tnr, counter; + + if ((res=open_tables(thd,table_list, &counter))) + DBUG_RETURN(res); + + /* Only need to call lock_tables if we are not using LOCK TABLES */ + if (!using_lock_tables && ((res= lock_tables(thd, table_list)))) + DBUG_RETURN(res); + /* - Update of derived tables is checked later - We don't check privileges here, becasue then we would get error - "UPDATE command denided .. for column N" instead of - "Target table ... is not updatable" + Ensure that we have update privilege for all tables and columns in the + SET part + While we are here, initialize the table->map field to check which + tables are updated and updatability of derived tables */ - if (!tl->derived) - table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); - } + for (tl= update_list, tnr=0 ; tl ; tl=tl->next) + { + TABLE *table= tl->table; + /* + Update of derived tables is checked later + We don't check privileges here, becasue then we would get error + "UPDATE command denided .. for column N" instead of + "Target table ... is not updatable" + */ + if (!tl->derived) + table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); + table->map= (table_map) 1 << (tnr++); + } - /* Assign table map values to check updatability of derived tables */ - { - uint tablenr=0; - for (TABLE_LIST *table_list= update_list; - table_list; - table_list= table_list->next, tablenr++) + if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0)) + DBUG_RETURN(-1); + + update_tables= get_table_map(fields); + + /* Unlock the tables in preparation for relocking */ + if (!using_lock_tables) + { + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; + } + + /* + Count tables and setup timestamp handling + Set also the table locking strategy according to the update map + */ + for (tl= update_list; tl; tl= tl->next) { - table_list->table->map= (table_map) 1 << tablenr; + TABLE *table= tl->table; + /* if table will be updated then check that it is unique */ + if (table->map & update_tables) + { + /* + Multi-update can't be constructed over-union => we always have + single SELECT on top and have to check underlaying SELECTs of it + */ + if (select_lex->check_updateable_in_subqueries(tl->db, + tl->real_name)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), + tl->real_name); + DBUG_RETURN(-1); + } + DBUG_PRINT("info",("setting table `%s` for update", tl->alias)); + tl->lock_type= thd->lex.lock_option; + tl->updating= 1; + } + else + { + DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias)); + tl->lock_type= TL_READ; + tl->updating= 0; + } + if (tl->derived) + derived_tables|= table->map; } - } - if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0)) - DBUG_RETURN(-1); + if (thd->lex->derived_tables && (update_tables & derived_tables)) + { + // find derived table which cause error + for (tl= update_list; tl; tl= tl->next) + { + if (tl->derived && (update_tables & tl->table->map)) + { + my_printf_error(ER_NON_UPDATABLE_TABLE, ER(ER_NON_UPDATABLE_TABLE), + MYF(0), tl->alias, "UPDATE"); + DBUG_RETURN(-1); + } + } + } - /* Find tables used in items */ - { - List_iterator_fast<Item> it(*fields); - Item *item; - while ((item= it++)) + /* Relock the tables with the correct modes */ + res= lock_tables(thd,table_list); + if (using_lock_tables) { - item_tables|= item->used_tables(); + if (res) + DBUG_RETURN(res); + break; // Don't have to do setup_field() } + + /* + We must setup fields again as the file may have been reopened + during lock_tables + */ + { + List_iterator_fast<Item> field_it(*fields); + Item_field *item; + + while ((item= (Item_field *) field_it++)) + { + item->field->query_id= 0; + item->cleanup(); + } + } + if (setup_fields(thd, table_list, *fields, 1, 0, 0)) + DBUG_RETURN(-1); + /* + If lock succeded and the table map didn't change since the above lock + we can continue. + */ + if (!res && update_tables == get_table_map(fields)) + break; + + /* + There was some very unexpected changes in the table definition between + open tables and lock tables. Close tables and try again. + */ + close_thread_tables(thd); } /* - Count tables and setup timestamp handling + Setup timestamp handling */ for (tl= update_list; tl; tl= tl->next) { TABLE *table= tl->table; - - /* We only need SELECT privilege for columns in the values list */ - table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); - // Only set timestamp column if this is not modified + /* Only set timestamp column if this is not modified */ if (table->timestamp_field && table->timestamp_field->query_id == thd->query_id) table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; - - /* if table will be updated then check that it is unique */ - if (table->map & item_tables) - { - /* - Multi-update can't be constructed over-union => we always have - single SELECT on top and have to check underlaying SELECTs of it - */ - if (select_lex->check_updateable_in_subqueries(tl->db, - tl->real_name)) - { - my_error(ER_UPDATE_TABLE_USED, MYF(0), - tl->real_name); - DBUG_RETURN(-1); - } - } - - if (tl->derived) - derived_tables|= table->map; - } - if (thd->lex->derived_tables && (item_tables & derived_tables)) - { - // find derived table which cause error - for (tl= update_list; tl; tl= tl->next) - { - if (tl->derived && (item_tables & tl->table->map)) - { - my_printf_error(ER_NON_UPDATABLE_TABLE, ER(ER_NON_UPDATABLE_TABLE), - MYF(0), tl->alias, "UPDATE"); - DBUG_RETURN(-1); - } - } } if (!(result=new multi_update(thd, update_list, fields, values, handle_duplicates))) DBUG_RETURN(-1); - List<Item> total_list; res= mysql_select(thd, &select_lex->ref_pointer_array, select_lex->get_table_list(), select_lex->with_wild, total_list, @@ -597,7 +671,7 @@ int multi_update::prepare(List<Item> ¬_used_values, { TABLE_LIST *table_ref; SQL_LIST update; - table_map tables_to_update= 0; + table_map tables_to_update; Item_field *item; List_iterator_fast<Item> field_it(*fields); List_iterator_fast<Item> value_it(*values); @@ -608,8 +682,7 @@ int multi_update::prepare(List<Item> ¬_used_values, thd->cuted_fields=0L; thd->proc_info="updating main table"; - while ((item= (Item_field *) field_it++)) - tables_to_update|= item->used_tables(); + tables_to_update= get_table_map(fields); if (!tables_to_update) { @@ -672,7 +745,6 @@ int multi_update::prepare(List<Item> ¬_used_values, /* Split fields into fields_for_table[] and values_by_table[] */ - field_it.rewind(); while ((item= (Item_field *) field_it++)) { Item *value= value_it++; @@ -918,9 +990,13 @@ bool multi_update::send_data(List<Item> ¬_used_values) if ((error=table->file->update_row(table->record[1], table->record[0]))) { - table->file->print_error(error,MYF(0)); updated--; - DBUG_RETURN(1); + if (handle_duplicates != DUP_IGNORE || + error != HA_ERR_FOUND_DUPP_KEY) + { + table->file->print_error(error,MYF(0)); + DBUG_RETURN(1); + } } } } @@ -986,7 +1062,6 @@ int multi_update::do_updates(bool from_send_error) TABLE *table, *tmp_table; DBUG_ENTER("do_updates"); - do_update= 0; // Don't retry this function if (!found) DBUG_RETURN(0); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0c81c172cf7..7982b501ac4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4163,12 +4163,14 @@ update: lex->lock_option= TL_UNLOCK; /* Will be set later */ } opt_low_priority opt_ignore join_table_list - SET update_list where_clause opt_order_clause delete_limit_clause + SET update_list { LEX *lex= Lex; - Select->set_lock_for_tables($3); if (lex->select_lex.table_list.elements > 1) + { lex->sql_command= SQLCOM_UPDATE_MULTI; + lex->lock_option= $3; + } else if (lex->select_lex.get_table_list()->derived) { /* it is single table update and it is update of derived table */ @@ -4176,7 +4178,10 @@ update: lex->select_lex.get_table_list()->alias, "UPDATE"); YYABORT; } + else + Select->set_lock_for_tables($3); } + where_clause opt_order_clause delete_limit_clause {} ; update_list: diff --git a/sql/stacktrace.c b/sql/stacktrace.c index d0478052fb1..322d647e741 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -197,7 +197,7 @@ terribly wrong...\n"); fprintf(stderr, "Stack trace seems successful - bottom reached\n"); end: - fprintf(stderr, "Please read http://www.mysql.com/doc/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\ + fprintf(stderr, "Please read http://dev.mysql.com/doc/mysql/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\ stack trace is much more helpful in diagnosing the problem, so please do \n\ resolve it\n"); } diff --git a/sql/table.h b/sql/table.h index 904038ad029..f25b172a0d9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -150,6 +150,14 @@ struct st_table { *found_next_number_field, /* Set on open */ *rowid_field; Field_timestamp *timestamp_field; +#if MYSQL_VERSION_ID < 40100 + /* + Indicates whenever we have to set field_length members of all TIMESTAMP + fields to 19 (to honour 'new_mode' variable) or to original + field_length values. + */ + my_bool timestamp_mode; +#endif my_string comment; /* Comment about table */ CHARSET_INFO *table_charset; /* Default charset of string fields */ REGINFO reginfo; /* field connections */ |