Merge with 4.0.13

This commit is contained in:
monty@narttu.mysql.fi 2003-05-19 16:35:49 +03:00
commit dd2b7918cd
317 changed files with 6662 additions and 3466 deletions

View File

@ -38,7 +38,11 @@ COPYING.LIB
Docs/#manual.texi# Docs/#manual.texi#
Docs/INSTALL-BINARY Docs/INSTALL-BINARY
Docs/include.texi Docs/include.texi
Docs/internals.html
Docs/internals.info Docs/internals.info
Docs/internals.pdf
Docs/internals.txt
Docs/internals_toc.html
Docs/manual.aux Docs/manual.aux
Docs/manual.cp Docs/manual.cp
Docs/manual.cps Docs/manual.cps
@ -239,6 +243,7 @@ client/select_test
client/ssl_test client/ssl_test
client/thimble client/thimble
client/thread_test client/thread_test
client_test
cmd-line-utils/libedit/common.h cmd-line-utils/libedit/common.h
comon.h comon.h
config.cache config.cache
@ -287,6 +292,7 @@ innobase/conftest.subs
innobase/ib_config.h innobase/ib_config.h
innobase/ib_config.h.in innobase/ib_config.h.in
innobase/stamp-h1 innobase/stamp-h1
insert_test
isam/isamchk isam/isamchk
isam/isamlog isam/isamlog
isam/pack_isam isam/pack_isam
@ -513,6 +519,7 @@ scripts/mysqld_safe
scripts/mysqldumpslow scripts/mysqldumpslow
scripts/mysqlhotcopy scripts/mysqlhotcopy
scripts/safe_mysqld scripts/safe_mysqld
select_test
sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686 sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686
sql-bench/bench-count-distinct sql-bench/bench-count-distinct
sql-bench/bench-init.pl sql-bench/bench-init.pl
@ -578,6 +585,7 @@ strings/ctype_autoconf.c
strings/ctype_extra_sources.c strings/ctype_extra_sources.c
support-files/MacOSX/Description.plist support-files/MacOSX/Description.plist
support-files/MacOSX/Info.plist support-files/MacOSX/Info.plist
support-files/MacOSX/ReadMe.txt
support-files/MacOSX/StartupParameters.plist support-files/MacOSX/StartupParameters.plist
support-files/MacOSX/postinstall support-files/MacOSX/postinstall
support-files/MacOSX/preinstall support-files/MacOSX/preinstall
@ -597,6 +605,7 @@ support-files/mysql.spec
tags tags
test_xml test_xml
tests/client_test tests/client_test
thread_test
tmp/* tmp/*
tools/my_vsnprintf.c tools/my_vsnprintf.c
tools/mysqlmanager tools/mysqlmanager
@ -607,7 +616,3 @@ vio/test-ssl
vio/test-sslclient vio/test-sslclient
vio/test-sslserver vio/test-sslserver
vio/viotest-ssl vio/viotest-ssl
client_test
thread_test
select_test
insert_test

View File

@ -71,4 +71,6 @@ else
make=make make=make
fi fi
CXX=gcc if test -z $CXX ; then
CXX=gcc
fi

View File

@ -51,6 +51,7 @@ miguel@hegel.br
miguel@hegel.local miguel@hegel.local
miguel@light. miguel@light.
miguel@light.local miguel@light.local
mmatthew@markslaptop.
monty@bitch.mysql.fi monty@bitch.mysql.fi
monty@butch. monty@butch.
monty@donna.mysql.fi monty@donna.mysql.fi
@ -67,6 +68,7 @@ mwagner@cash.mwagner.org
mwagner@evoq.mwagner.org mwagner@evoq.mwagner.org
mwagner@work.mysql.com mwagner@work.mysql.com
mysql@home.(none) mysql@home.(none)
mysqldev@build.mysql2.com
nick@mysql.com nick@mysql.com
nick@nick.leippe.com nick@nick.leippe.com
papa@gbichot.local papa@gbichot.local
@ -75,6 +77,7 @@ paul@teton.kitebird.com
pem@mysql.com pem@mysql.com
peter@linux.local peter@linux.local
peter@mysql.com peter@mysql.com
peterg@mysql.com
pgulutzan@linux.local pgulutzan@linux.local
ram@gw.udmsearch.izhnet.ru ram@gw.udmsearch.izhnet.ru
ram@mysql.r18.ru ram@mysql.r18.ru

View File

@ -276,7 +276,11 @@ if ($opt_stage <= 3)
my $flags= ""; my $flags= "";
log_timestamp(); log_timestamp();
log_system("rm -fr mysql-3* mysql-4* $pwd/$host/*.tar.gz"); log_system("rm -fr mysql-3* mysql-4* $pwd/$host/*.tar.gz");
log_system("nm -n sql/mysqld | gzip -9 -v 2>&1 > sql/mysqld.sym.gz | cat"); # No need to add the debug symbols, if the binaries are not stripped (saves space)
unless ($opt_with_debug || $opt_no_strip)
{
log_system("nm -n sql/mysqld | gzip -9 -v 2>&1 > sql/mysqld.sym.gz | cat");
}
$flags.= "--no-strip" if ($opt_no_strip || $opt_with_debug); $flags.= "--no-strip" if ($opt_no_strip || $opt_with_debug);
check_system("scripts/make_binary_distribution --tmp=$opt_tmp --suffix=$opt_suffix $flags",".tar.gz created"); check_system("scripts/make_binary_distribution --tmp=$opt_tmp --suffix=$opt_suffix $flags",".tar.gz created");

View File

@ -27,7 +27,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) $(BUILT_SOURCES) mysqld_error.txt \
all: $(targets) txt_files all: $(targets) txt_files
txt_files: ../INSTALL-SOURCE ../COPYING ../COPYING.LIB \ txt_files: ../INSTALL-SOURCE ../COPYING ../COPYING.LIB \
INSTALL-BINARY INSTALL-BINARY ../support-files/MacOSX/ReadMe.txt
CLEAN_FILES: $(BUILD_SOURCES) CLEAN_FILES: $(BUILD_SOURCES)
touch $(BUILD_SOURCES) touch $(BUILD_SOURCES)
@ -254,5 +254,8 @@ INSTALL-BINARY: mysql.info $(GT)
../COPYING.LIB: mysql.info $(GT) ../COPYING.LIB: mysql.info $(GT)
perl -w $(GT) mysql.info "LGPL license" "Function Index" > $@ perl -w $(GT) mysql.info "LGPL license" "Function Index" > $@
../support-files/MacOSX/ReadMe.txt: mysql.info $(GT)
perl -w $(GT) mysql.info "Mac OS X installation" "Netware installation" > $@
# Don't update the files from bitkeeper # Don't update the files from bitkeeper
%::SCCS/s.% %::SCCS/s.%

File diff suppressed because it is too large Load Diff

9
Docs/manual_toc.html Normal file
View File

@ -0,0 +1,9 @@
<html>
<head>
<title>Place holder for manual_toc.html</title>
</head>
<body>
This is just a place holder for the autogenerated manual_toc.html
to make "make dist" happy.
</body>
</html>

View File

@ -1 +0,0 @@
logo_nusphere_b.tif

View File

@ -25,7 +25,7 @@ CFG=libmysql - Win32 Debug
# PROP AllowPerConfigDependencies 0 # PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "" # PROP Scc_ProjName ""
# PROP Scc_LocalPath "" # PROP Scc_LocalPath ""
CPP=cl.exe CPP=xicl6.exe
MTL=midl.exe MTL=midl.exe
RSC=rc.exe RSC=rc.exe
@ -52,7 +52,7 @@ RSC=rc.exe
BSC32=bscmake.exe BSC32=bscmake.exe
# ADD BASE BSC32 /nologo # ADD BASE BSC32 /nologo
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=xilink6.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /def:"libmysql.def" /out:"..\lib_release\libmysql.dll" /libpath:"." /libpath:"..\lib_release" # ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /def:"libmysql.def" /out:"..\lib_release\libmysql.dll" /libpath:"." /libpath:"..\lib_release"
# SUBTRACT LINK32 /pdb:none # SUBTRACT LINK32 /pdb:none
@ -85,7 +85,7 @@ PostBuild_Cmds=xcopy release\libmysql.lib ..\lib_release /y
BSC32=bscmake.exe BSC32=bscmake.exe
# ADD BASE BSC32 /nologo # ADD BASE BSC32 /nologo
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=xilink6.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 zlib.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /def:"libmysql.def" /out:"..\lib_debug\libmysql.dll" /pdbtype:sept /libpath:"." /libpath:"..\lib_debug" # ADD LINK32 zlib.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /def:"libmysql.def" /out:"..\lib_debug\libmysql.dll" /pdbtype:sept /libpath:"." /libpath:"..\lib_debug"
# SUBTRACT LINK32 /pdb:none # SUBTRACT LINK32 /pdb:none
@ -251,6 +251,10 @@ SOURCE=..\mysys\mf_pack.c
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\mysys\mf_path.c
# End Source File
# Begin Source File
SOURCE=..\mysys\mf_unixpath.c SOURCE=..\mysys\mf_unixpath.c
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -605,6 +605,9 @@ Package=<5>
Package=<4> Package=<4>
{{{ {{{
Begin Project Dependency
Project_Dep_Name strings
End Project Dependency
}}} }}}
############################################################################### ###############################################################################

View File

@ -78,7 +78,7 @@ AC_LANG_SAVE
AC_LANG_CPLUSPLUS AC_LANG_CPLUSPLUS
if test "$ac_cv_prog_gxx" = "yes" if test "$ac_cv_prog_gxx" = "yes"
then then
CXXFLAGS="$CXXFLAGS -Werror" CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'`
fi fi
mysql_cv_btype_last_arg_accept=none mysql_cv_btype_last_arg_accept=none
[AC_TRY_COMPILE([#if defined(inline) [AC_TRY_COMPILE([#if defined(inline)

View File

@ -1091,7 +1091,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
{ // Add found char to buffer { // Add found char to buffer
if (inchar == *in_string) if (inchar == *in_string)
*in_string=0; *in_string=0;
else if (!*in_string && (inchar == '\'' || inchar == '"')) else if (!*in_string && (inchar == '\'' || inchar == '"' || inchar == '`'))
*in_string=(char) inchar; *in_string=(char) inchar;
if (!(*ml_comment)) if (!(*ml_comment))
*out++ = (char) inchar; *out++ = (char) inchar;
@ -2709,31 +2709,32 @@ select_limit, max_join_size);
static int static int
put_info(const char *str,INFO_TYPE info_type,uint error) put_info(const char *str,INFO_TYPE info_type,uint error)
{ {
FILE *file= (info_type == INFO_ERROR ? stderr : stdout);
static int inited=0; static int inited=0;
if (status.batch) if (status.batch)
{ {
if (info_type == INFO_ERROR) if (info_type == INFO_ERROR)
{ {
(void) fflush(stdout); (void) fflush(file);
fprintf(stderr,"ERROR"); fprintf(file,"ERROR");
if (error) if (error)
(void) fprintf(stderr," %d",error); (void) fprintf(file," %d",error);
if (status.query_start_line && line_numbers) if (status.query_start_line && line_numbers)
{ {
(void) fprintf(stderr," at line %lu",status.query_start_line); (void) fprintf(file," at line %lu",status.query_start_line);
if (status.file_name) if (status.file_name)
(void) fprintf(stderr," in file: '%s'", status.file_name); (void) fprintf(file," in file: '%s'", status.file_name);
} }
(void) fprintf(stderr,": %s\n",str); (void) fprintf(file,": %s\n",str);
(void) fflush(stderr); (void) fflush(file);
if (!ignore_errors) if (!ignore_errors)
return 1; return 1;
} }
else if (info_type == INFO_RESULT && verbose > 1) else if (info_type == INFO_RESULT && verbose > 1)
tee_puts(str, stdout); tee_puts(str, file);
if (unbuffered) if (unbuffered)
fflush(stdout); fflush(file);
return info_type == INFO_ERROR ? -1 : 0; return info_type == INFO_ERROR ? -1 : 0;
} }
if (!opt_silent || info_type == INFO_ERROR) if (!opt_silent || info_type == INFO_ERROR)
@ -2751,17 +2752,17 @@ put_info(const char *str,INFO_TYPE info_type,uint error)
putchar('\007'); /* This should make a bell */ putchar('\007'); /* This should make a bell */
vidattr(A_STANDOUT); vidattr(A_STANDOUT);
if (error) if (error)
(void) tee_fprintf(stderr, "ERROR %d: ", error); (void) tee_fprintf(file, "ERROR %d: ", error);
else else
tee_puts("ERROR: ", stdout); tee_puts("ERROR: ", file);
} }
else else
vidattr(A_BOLD); vidattr(A_BOLD);
(void) tee_puts(str, stdout); (void) tee_puts(str, file);
vidattr(A_NORMAL); vidattr(A_NORMAL);
} }
if (unbuffered) if (unbuffered)
fflush(stdout); fflush(file);
return info_type == INFO_ERROR ? -1 : 0; return info_type == INFO_ERROR ? -1 : 0;
} }

View File

@ -44,6 +44,7 @@ static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
void sql_print_error(const char *format, ...); void sql_print_error(const char *format, ...);
static bool one_database = 0; static bool one_database = 0;
static bool force_opt= 0;
static const char* database; static const char* database;
static bool short_form = 0; static bool short_form = 0;
static ulonglong offset = 0; static ulonglong offset = 0;
@ -199,6 +200,9 @@ static struct my_option my_long_options[] =
{"database", 'd', "List entries for just this database (local log only)", {"database", 'd', "List entries for just this database (local log only)",
(gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, (gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG,
0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0, 0},
{"force-read", 'f', "Force reading unknown binlog events",
(gptr*) &force_opt, (gptr*) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"help", '?', "Display this help and exit", {"help", '?', "Display this help and exit",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Get the binlog from server", (gptr*) &host, (gptr*) &host, {"host", 'h', "Get the binlog from server", (gptr*) &host, (gptr*) &host,

View File

@ -1613,7 +1613,7 @@ int main(int argc, char **argv)
else else
{ {
row = mysql_fetch_row(master); row = mysql_fetch_row(master);
if (row[0] && row[1]) if (row && row[0] && row[1])
{ {
fprintf(md_result_file, fprintf(md_result_file,
"\n--\n-- Position to start replication from\n--\n\n"); "\n--\n-- Position to start replication from\n--\n\n");

View File

@ -1005,8 +1005,9 @@ case $SYSTEM_TYPE in
*darwin5*) *darwin5*)
if test "$ac_cv_prog_gcc" = "yes" if test "$ac_cv_prog_gcc" = "yes"
then then
CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE" FLAGS="-traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE"
CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DFN_NO_CASE_SENCE" CFLAGS="$CFLAGS $FLAGS"
CXXFLAGS="$CXXFLAGS $FLAGS"
MAX_C_OPTIMIZE="-O" MAX_C_OPTIMIZE="-O"
with_named_curses="" with_named_curses=""
fi fi
@ -1014,8 +1015,9 @@ case $SYSTEM_TYPE in
*darwin6*) *darwin6*)
if test "$ac_cv_prog_gcc" = "yes" if test "$ac_cv_prog_gcc" = "yes"
then then
CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE" FLAGS="-traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE"
CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DFN_NO_CASE_SENCE" CFLAGS="$CFLAGS $FLAGS"
CXXFLAGS="$CXXFLAGS $FLAGS"
MAX_C_OPTIMIZE="-O" MAX_C_OPTIMIZE="-O"
fi fi
;; ;;
@ -1365,10 +1367,8 @@ then
with_named_thread="-Kthread -lsocket -lnsl" with_named_thread="-Kthread -lsocket -lnsl"
if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null
then then
# AC_DEFINE(HAVE_OpenUNIX8_THREADS)
AC_DEFINE(HAVE_UNIXWARE7_THREADS) AC_DEFINE(HAVE_UNIXWARE7_THREADS)
else else
# AC_DEFINE(HAVE_OpenUNIX8_POSIX)
AC_DEFINE(HAVE_UNIXWARE7_POSIX) AC_DEFINE(HAVE_UNIXWARE7_POSIX)
fi fi
# We must have cc # We must have cc
@ -1377,10 +1377,8 @@ then
then then
{ echo "configure: error: On OpenUNIX8 and UnixWare7 MySQL must be compiled with cc. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; { echo "configure: error: On OpenUNIX8 and UnixWare7 MySQL must be compiled with cc. See the Installation chapter in the Reference Manual." 1>&2; exit 1; };
else else
# CC="$CC -Kthread -DOpenUNIX8"; CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK";
# CXX="$CXX -Kthread -DOpenUNIX8"; CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK";
CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK";
CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"
fi fi
AC_MSG_RESULT("yes") AC_MSG_RESULT("yes")
else else
@ -1877,7 +1875,7 @@ AC_LANG_SAVE
AC_LANG_CPLUSPLUS AC_LANG_CPLUSPLUS
if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no" if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no"
then then
CXXFLAGS="$CXXFLAGS -Werror" CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed 's/-fbranch-probabilities//'`
fi fi
AC_TRY_COMPILE( AC_TRY_COMPILE(
[#undef inline [#undef inline
@ -1909,7 +1907,7 @@ AC_LANG_SAVE
AC_LANG_CPLUSPLUS AC_LANG_CPLUSPLUS
if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no" if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no"
then then
CXXFLAGS="$CXXFLAGS -Werror" CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed 's/-fbranch-probabilities//'`
fi fi
AC_TRY_COMPILE( AC_TRY_COMPILE(
[#undef inline [#undef inline

View File

@ -35,7 +35,7 @@ noinst_HEADERS = config-win.h config-os2.h config-netware.h \
SUPERCLEANFILES = mysql_version.h my_config.h SUPERCLEANFILES = mysql_version.h my_config.h
# Some include files that may be moved and patched by configure # Some include files that may be moved and patched by configure
DISTCLEANFILES = sched.h DISTCLEANFILES = sched.h $(SUPERCLEANFILES)
clean: clean:
$(RM) -f readline/* $(RM) -f readline/*

View File

@ -153,6 +153,9 @@ typedef uint rf_SetTimer;
#define USE_MB_IDENT 1 #define USE_MB_IDENT 1
#define USE_STRCOLL 1 #define USE_STRCOLL 1
/* If LOAD DATA LOCAL INFILE should be enabled by default */
#define ENABLED_LOCAL_INFILE 1
/* Convert some simple functions to Posix */ /* Convert some simple functions to Posix */
#define sigset(A,B) signal((A),(B)) #define sigset(A,B) signal((A),(B))

View File

@ -225,6 +225,7 @@ enum ha_base_keytype {
/* Errorcodes given by functions */ /* Errorcodes given by functions */
/* opt_sum_query() assumes these codes are > 1 */
#define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */ #define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */
#define HA_ERR_FOUND_DUPP_KEY 121 /* Dupplicate key on write */ #define HA_ERR_FOUND_DUPP_KEY 121 /* Dupplicate key on write */
#define HA_ERR_RECORD_CHANGED 123 /* Uppdate with is recoverable */ #define HA_ERR_RECORD_CHANGED 123 /* Uppdate with is recoverable */

View File

@ -287,6 +287,10 @@ C_MODE_END
#include <asm/atomic.h> #include <asm/atomic.h>
#endif #endif
#include <errno.h> /* Recommended by debian */ #include <errno.h> /* Recommended by debian */
/* We need the following to go around a problem with openssl on solaris */
#if defined(HAVE_CRYPT_H)
#include <crypt.h>
#endif
/* Go around some bugs in different OS and compilers */ /* Go around some bugs in different OS and compilers */
#if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H) #if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H)
@ -306,9 +310,7 @@ C_MODE_END
/* This has to be after include limits.h */ /* This has to be after include limits.h */
#define HAVE_ERRNO_AS_DEFINE #define HAVE_ERRNO_AS_DEFINE
#define HAVE_FCNTL_LOCK #define HAVE_FCNTL_LOCK
#undef HAVE_SYS_UN_H
#undef HAVE_FINITE #undef HAVE_FINITE
#undef HAVE_RINT
#undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */ #undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */
#undef LONGLONG_MAX /* standard system library 'limits.h' */ #undef LONGLONG_MAX /* standard system library 'limits.h' */
#endif #endif
@ -377,7 +379,7 @@ typedef unsigned short ushort;
#define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1)) #define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1))
#define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) #define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0])))
#ifndef HAVE_RINT #ifndef HAVE_RINT
#define rint(A) floor((A)+0.5) #define rint(A) floor((A)+(((A) < 0)? -0.5 : 0.5))
#endif #endif
/* Define some general constants */ /* Define some general constants */

View File

@ -248,6 +248,11 @@ extern int my_sigwait(const sigset_t *set,int *sig);
#error Requires at least rev 2 of EMX pthreads library. #error Requires at least rev 2 of EMX pthreads library.
#endif #endif
#ifdef __NETWARE__
void my_pthread_exit(void *status);
#define pthread_exit(A) my_pthread_exit(A)
#endif
extern int my_pthread_getprio(pthread_t thread_id); extern int my_pthread_getprio(pthread_t thread_id);
#define pthread_key(T,V) pthread_key_t V #define pthread_key(T,V) pthread_key_t V

View File

@ -31,6 +31,8 @@
#ifndef _my_semaphore_h_ #ifndef _my_semaphore_h_
#define _my_semaphore_h_ #define _my_semaphore_h_
#ifdef THREAD
C_MODE_START C_MODE_START
#ifdef HAVE_SEMAPHORE_H #ifdef HAVE_SEMAPHORE_H
#include <semaphore.h> #include <semaphore.h>
@ -56,4 +58,7 @@ int sem_getvalue(sem_t * sem, unsigned int * sval);
#endif /* !__bsdi__ */ #endif /* !__bsdi__ */
C_MODE_END C_MODE_END
#endif /* THREAD */
#endif /* !_my_semaphore_h_ */ #endif /* !_my_semaphore_h_ */

View File

@ -744,6 +744,7 @@ extern my_bool my_uncompress(byte *, ulong *, ulong *);
extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen); extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen);
extern ulong checksum(const byte *mem, uint count); extern ulong checksum(const byte *mem, uint count);
extern uint my_bit_log2(ulong value); extern uint my_bit_log2(ulong value);
uint my_count_bits(ulonglong v);
extern void my_sleep(ulong m_seconds); extern void my_sleep(ulong m_seconds);
#ifdef __WIN__ #ifdef __WIN__

View File

@ -165,7 +165,7 @@ my_bool vio_ssl_should_retry(Vio* vio);
int vio_ssl_close(Vio* vio); int vio_ssl_close(Vio* vio);
/* Return last error number */ /* Return last error number */
int vio_ssl_errno(Vio *vio); int vio_ssl_errno(Vio *vio);
my_bool vio_ssl_peer_addr(Vio* vio, char *buf); my_bool vio_ssl_peer_addr(Vio* vio, char *buf, uint16 *port);
void vio_ssl_in_addr(Vio *vio, struct in_addr *in); void vio_ssl_in_addr(Vio *vio, struct in_addr *in);
int vio_ssl_blocking(Vio * vio, my_bool set_blocking_mode, my_bool *old_mode); int vio_ssl_blocking(Vio * vio, my_bool set_blocking_mode, my_bool *old_mode);
@ -242,7 +242,7 @@ struct st_vio
my_bool (*is_blocking)(Vio*); my_bool (*is_blocking)(Vio*);
int (*viokeepalive)(Vio*, my_bool); int (*viokeepalive)(Vio*, my_bool);
int (*fastsend)(Vio*); int (*fastsend)(Vio*);
my_bool (*peer_addr)(Vio*, gptr, uint16*); my_bool (*peer_addr)(Vio*, char *, uint16*);
void (*in_addr)(Vio*, struct in_addr*); void (*in_addr)(Vio*, struct in_addr*);
my_bool (*should_retry)(Vio*); my_bool (*should_retry)(Vio*);
int (*vioclose)(Vio*); int (*vioclose)(Vio*);

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libbtr.a noinst_LIBRARIES = libbtr.a
libbtr_a_SOURCES = btr0btr.c btr0cur.c btr0pcur.c btr0sea.c libbtr_a_SOURCES = btr0btr.c btr0cur.c btr0pcur.c btr0sea.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libbuf.a noinst_LIBRARIES = libbuf.a
libbuf_a_SOURCES = buf0buf.c buf0flu.c buf0lru.c buf0rea.c libbuf_a_SOURCES = buf0buf.c buf0flu.c buf0lru.c buf0rea.c

View File

@ -597,8 +597,9 @@ buf_pool_init(
/* Wipe contents of frame to eliminate a Purify /* Wipe contents of frame to eliminate a Purify
warning */ warning */
#ifdef HAVE_purify
memset(block->frame, '\0', UNIV_PAGE_SIZE); memset(block->frame, '\0', UNIV_PAGE_SIZE);
#endif
if (srv_use_awe) { if (srv_use_awe) {
/* Add to the list of blocks mapped to /* Add to the list of blocks mapped to
frames */ frames */
@ -1837,7 +1838,7 @@ buf_pool_invalidate(void)
freed = TRUE; freed = TRUE;
while (freed) { while (freed) {
freed = buf_LRU_search_and_free_block(0); freed = buf_LRU_search_and_free_block(100);
} }
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
@ -2056,6 +2057,29 @@ buf_get_n_pending_ios(void)
+ buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
} }
/*************************************************************************
Returns the ratio in percents of modified pages in the buffer pool /
database pages in the buffer pool. */
ulint
buf_get_modified_ratio_pct(void)
/*============================*/
{
ulint ratio;
mutex_enter(&(buf_pool->mutex));
ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list))
/ (1 + UT_LIST_GET_LEN(buf_pool->LRU)
+ UT_LIST_GET_LEN(buf_pool->free));
/* 1 + is there to avoid division by zero */
mutex_exit(&(buf_pool->mutex));
return(ratio);
}
/************************************************************************* /*************************************************************************
Prints info of the buffer i/o. */ Prints info of the buffer i/o. */
@ -2109,8 +2133,10 @@ buf_print_io(
buf += sprintf(buf, buf += sprintf(buf,
"Pending writes: LRU %lu, flush list %lu, single page %lu\n", "Pending writes: LRU %lu, flush list %lu, single page %lu\n",
buf_pool->n_flush[BUF_FLUSH_LRU], buf_pool->n_flush[BUF_FLUSH_LRU]
buf_pool->n_flush[BUF_FLUSH_LIST], + buf_pool->init_flush[BUF_FLUSH_LRU],
buf_pool->n_flush[BUF_FLUSH_LIST]
+ buf_pool->init_flush[BUF_FLUSH_LIST],
buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
current_time = time(NULL); current_time = time(NULL);
@ -2144,7 +2170,7 @@ buf_print_io(
/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old))); / (buf_pool->n_page_gets - buf_pool->n_page_gets_old)));
} else { } else {
buf += sprintf(buf, buf += sprintf(buf,
"No buffer pool activity since the last printout\n"); "No buffer pool page gets since the last printout\n");
} }
buf_pool->n_page_gets_old = buf_pool->n_page_gets; buf_pool->n_page_gets_old = buf_pool->n_page_gets;

View File

@ -107,7 +107,7 @@ buf_flush_ready_for_replace(
BUF_BLOCK_FILE_PAGE and in the LRU list */ BUF_BLOCK_FILE_PAGE and in the LRU list */
{ {
ut_ad(mutex_own(&(buf_pool->mutex))); ut_ad(mutex_own(&(buf_pool->mutex)));
ut_ad(block->state == BUF_BLOCK_FILE_PAGE); ut_a(block->state == BUF_BLOCK_FILE_PAGE);
if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0) if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
|| (block->buf_fix_count != 0) || (block->buf_fix_count != 0)
@ -227,7 +227,9 @@ buf_flush_buffered_writes(void)
} }
for (i = 0; i < trx_doublewrite->first_free; i++) { for (i = 0; i < trx_doublewrite->first_free; i++) {
block = trx_doublewrite->buf_block_arr[i]; block = trx_doublewrite->buf_block_arr[i];
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
if (block->check_index_page_at_flush if (block->check_index_page_at_flush
&& !page_simple_validate(block->frame)) { && !page_simple_validate(block->frame)) {
@ -236,10 +238,12 @@ buf_flush_buffered_writes(void)
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
" InnoDB: Apparent corruption of an index page\n" " InnoDB: Apparent corruption of an index page n:o %lu in space %lu\n"
"InnoDB: to be written to data file. We intentionally crash server\n" "InnoDB: to be written to data file. We intentionally crash server\n"
"InnoDB: to prevent corrupt data from ending up in data\n" "InnoDB: to prevent corrupt data from ending up in data\n"
"InnoDB: files.\n"); "InnoDB: files.\n",
block->offset, block->space);
ut_a(0); ut_a(0);
} }
} }
@ -394,7 +398,7 @@ buf_flush_write_block_low(
"Warning: cannot force log to disk in the log debug version!\n"); "Warning: cannot force log to disk in the log debug version!\n");
#else #else
/* Force the log to the disk before writing the modified block */ /* Force the log to the disk before writing the modified block */
log_flush_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS); log_write_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE);
#endif #endif
buf_flush_init_for_writing(block->frame, block->newest_modification, buf_flush_init_for_writing(block->frame, block->newest_modification,
block->space, block->offset); block->space, block->offset);
@ -432,6 +436,8 @@ buf_flush_try_page(
block = buf_page_hash_get(space, offset); block = buf_page_hash_get(space, offset);
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
if (flush_type == BUF_FLUSH_LIST if (flush_type == BUF_FLUSH_LIST
&& block && buf_flush_ready_for_flush(block, flush_type)) { && block && buf_flush_ready_for_flush(block, flush_type)) {
@ -567,7 +573,8 @@ buf_flush_try_page(
rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE); rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE);
if (buf_debug_prints) { if (buf_debug_prints) {
printf("Flushing single page space %lu, page no %lu \n", printf(
"Flushing single page space %lu, page no %lu \n",
block->space, block->offset); block->space, block->offset);
} }
@ -606,14 +613,6 @@ buf_flush_try_neighbors(
/* If there is little space, it is better not to flush any /* If there is little space, it is better not to flush any
block except from the end of the LRU list */ block except from the end of the LRU list */
low = offset;
high = offset + 1;
} else if (flush_type == BUF_FLUSH_LIST) {
/* Since semaphore waits require us to flush the
doublewrite buffer to disk, it is best that the
search area is just the page itself, to minimize
chances for semaphore waits */
low = offset; low = offset;
high = offset + 1; high = offset + 1;
} }
@ -633,13 +632,20 @@ buf_flush_try_neighbors(
if (block && flush_type == BUF_FLUSH_LRU && i != offset if (block && flush_type == BUF_FLUSH_LRU && i != offset
&& !block->old) { && !block->old) {
/* We avoid flushing 'non-old' blocks in an LRU flush, /* We avoid flushing 'non-old' blocks in an LRU flush,
because the flushed blocks are soon freed */ because the flushed blocks are soon freed */
continue; continue;
} }
if (block && buf_flush_ready_for_flush(block, flush_type)) { if (block && buf_flush_ready_for_flush(block, flush_type)
&& (i == offset || block->buf_fix_count == 0)) {
/* We only try to flush those neighbors != offset
where the buf fix count is zero, as we then know that
we probably can latch the page without a semaphore
wait. Semaphore waits are expensive because we must
flush the doublewrite buffer before we start
waiting. */
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
@ -758,7 +764,6 @@ buf_flush_batch(
page_count += page_count +=
buf_flush_try_neighbors(space, offset, buf_flush_try_neighbors(space, offset,
flush_type); flush_type);
/* printf( /* printf(
"Flush type %lu, page no %lu, neighb %lu\n", "Flush type %lu, page no %lu, neighb %lu\n",
flush_type, offset, flush_type, offset,
@ -884,11 +889,19 @@ buf_flush_free_margin(void)
/*=======================*/ /*=======================*/
{ {
ulint n_to_flush; ulint n_to_flush;
ulint n_flushed;
n_to_flush = buf_flush_LRU_recommendation(); n_to_flush = buf_flush_LRU_recommendation();
if (n_to_flush > 0) { if (n_to_flush > 0) {
buf_flush_batch(BUF_FLUSH_LRU, n_to_flush, ut_dulint_zero); n_flushed = buf_flush_batch(BUF_FLUSH_LRU, n_to_flush,
ut_dulint_zero);
if (n_flushed == ULINT_UNDEFINED) {
/* There was an LRU type flush batch already running;
let us wait for it to end */
buf_flush_wait_batch_end(BUF_FLUSH_LRU);
}
} }
} }

View File

@ -104,12 +104,15 @@ ibool
buf_LRU_search_and_free_block( buf_LRU_search_and_free_block(
/*==========================*/ /*==========================*/
/* out: TRUE if freed */ /* out: TRUE if freed */
ulint n_iterations __attribute__((unused))) /* in: how many times ulint n_iterations) /* in: how many times this has been called
this has been called repeatedly without repeatedly without result: a high value means
result: a high value means that we should that we should search farther; if value is
search farther */ k < 10, then we only search k/10 * [number
of pages in the buffer pool] from the end
of the LRU list */
{ {
buf_block_t* block; buf_block_t* block;
ulint distance = 0;
ibool freed; ibool freed;
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
@ -152,6 +155,18 @@ buf_LRU_search_and_free_block(
} }
block = UT_LIST_GET_PREV(LRU, block); block = UT_LIST_GET_PREV(LRU, block);
distance++;
if (!freed && n_iterations <= 10
&& distance > 100 + (n_iterations * buf_pool->curr_size)
/ 10) {
buf_pool->LRU_flush_ended = 0;
mutex_exit(&(buf_pool->mutex));
return(FALSE);
}
} }
if (buf_pool->LRU_flush_ended > 0) { if (buf_pool->LRU_flush_ended > 0) {
@ -186,7 +201,7 @@ buf_LRU_try_free_flushed_blocks(void)
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
buf_LRU_search_and_free_block(0); buf_LRU_search_and_free_block(1);
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
} }
@ -208,7 +223,7 @@ buf_LRU_get_free_block(void)
{ {
buf_block_t* block = NULL; buf_block_t* block = NULL;
ibool freed; ibool freed;
ulint n_iterations = 0; ulint n_iterations = 1;
ibool mon_value_was = 0; /* remove bug */ ibool mon_value_was = 0; /* remove bug */
ibool started_monitor = FALSE; ibool started_monitor = FALSE;
loop: loop:
@ -236,9 +251,12 @@ loop:
fprintf(stderr, fprintf(stderr,
" InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n" " InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n"
"InnoDB: lock heaps or the adaptive hash index! Check that your\n" "InnoDB: lock heaps or the adaptive hash index! Check that your\n"
"InnoDB: transactions do not set too many row locks. Starting InnoDB\n" "InnoDB: transactions do not set too many row locks.\n"
"InnoDB: Monitor to print diagnostics, including lock heap and hash index\n" "InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n"
"InnoDB: sizes.\n"); "InnoDB: the buffer pool bigger?\n"
"InnoDB: Starting the InnoDB Monitor to print diagnostics, including\n"
"InnoDB: lock heap and hash index sizes.\n",
buf_pool->curr_size / (1024 * 1024 / UNIV_PAGE_SIZE));
srv_print_innodb_monitor = TRUE; srv_print_innodb_monitor = TRUE;
@ -252,14 +270,6 @@ loop:
srv_print_innodb_monitor = FALSE; srv_print_innodb_monitor = FALSE;
} }
if (buf_pool->LRU_flush_ended > 0) {
mutex_exit(&(buf_pool->mutex));
buf_LRU_try_free_flushed_blocks();
mutex_enter(&(buf_pool->mutex));
}
/* If there is a block in the free list, take it */ /* If there is a block in the free list, take it */
if (UT_LIST_GET_LEN(buf_pool->free) > 0) { if (UT_LIST_GET_LEN(buf_pool->free) > 0) {
@ -340,6 +350,20 @@ loop:
os_aio_simulated_wake_handler_threads(); os_aio_simulated_wake_handler_threads();
mutex_enter(&(buf_pool->mutex));
if (buf_pool->LRU_flush_ended > 0) {
/* We have written pages in an LRU flush. To make the insert
buffer more efficient, we try to move these pages to the free
list. */
mutex_exit(&(buf_pool->mutex));
buf_LRU_try_free_flushed_blocks();
} else {
mutex_exit(&(buf_pool->mutex));
}
if (n_iterations > 10) { if (n_iterations > 10) {
os_thread_sleep(500000); os_thread_sleep(500000);

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libcom.a noinst_LIBRARIES = libcom.a
libcom_a_SOURCES = com0com.c com0shm.c libcom_a_SOURCES = com0com.c com0shm.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libdata.a noinst_LIBRARIES = libdata.a
libdata_a_SOURCES = data0data.c data0type.c libdata_a_SOURCES = data0data.c data0type.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libdict.a noinst_LIBRARIES = libdict.a
libdict_a_SOURCES = dict0boot.c dict0crea.c dict0dict.c dict0load.c\ libdict_a_SOURCES = dict0boot.c dict0crea.c dict0dict.c dict0load.c\
dict0mem.c dict0mem.c

View File

@ -1173,6 +1173,7 @@ dict_create_add_foreigns_to_dictionary(
if (NULL == dict_table_get_low((char *) "SYS_FOREIGN")) { if (NULL == dict_table_get_low((char *) "SYS_FOREIGN")) {
fprintf(stderr, fprintf(stderr,
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); "InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
return(DB_ERROR); return(DB_ERROR);
} }
@ -1259,6 +1260,13 @@ loop:
"InnoDB: at http://www.innodb.com/ibman.html\n"); "InnoDB: at http://www.innodb.com/ibman.html\n");
} }
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Internal error in foreign key constraint creation for table %.500s.\n"
"See the MySQL .err log in the datadir for more information.\n", table->name);
mutex_exit(&dict_foreign_err_mutex);
return(error); return(error);
} }

View File

@ -185,6 +185,14 @@ dict_foreign_free(
/*==============*/ /*==============*/
dict_foreign_t* foreign); /* in, own: foreign key struct */ dict_foreign_t* foreign); /* in, own: foreign key struct */
/* Buffers for storing detailed information about the latest foreign key
and unique key errors */
char* dict_foreign_err_buf = NULL;
char* dict_unique_err_buf = NULL;
mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign
and unique error buffers */
/************************************************************************ /************************************************************************
Checks if the database name in two table names is the same. */ Checks if the database name in two table names is the same. */
static static
@ -573,6 +581,13 @@ dict_init(void)
rw_lock_create(&dict_operation_lock); rw_lock_create(&dict_operation_lock);
rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION); rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION);
dict_foreign_err_buf = mem_alloc(DICT_FOREIGN_ERR_BUF_LEN);
dict_foreign_err_buf[0] = '\0';
dict_unique_err_buf = mem_alloc(DICT_FOREIGN_ERR_BUF_LEN);
dict_unique_err_buf[0] = '\0';
mutex_create(&dict_foreign_err_mutex);
mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
} }
/************************************************************************** /**************************************************************************
@ -1818,6 +1833,7 @@ dict_foreign_add_to_cache(
dict_foreign_t* for_in_cache = NULL; dict_foreign_t* for_in_cache = NULL;
dict_index_t* index; dict_index_t* index;
ibool added_to_referenced_list = FALSE; ibool added_to_referenced_list = FALSE;
char* buf = dict_foreign_err_buf;
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
@ -1850,9 +1866,29 @@ dict_foreign_add_to_cache(
for_in_cache->foreign_index); for_in_cache->foreign_index);
if (index == NULL) { if (index == NULL) {
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s:\n"
"there is no index in referenced table which would contain\n"
"the columns as the first columns, or the data types in the\n"
"referenced table do not match to the ones in table. Constraint:\n",
for_in_cache->foreign_table_name);
dict_print_info_on_foreign_key_in_create_format(
for_in_cache, buf + strlen(buf));
if (for_in_cache->foreign_index) {
sprintf(buf + strlen(buf),
"\nThe index in the foreign key in table is %.500s\n"
"See http://www.innodb.com/ibman.html about correct foreign key definition.\n",
for_in_cache->foreign_index->name);
}
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
if (for_in_cache == foreign) { if (for_in_cache == foreign) {
mem_heap_free(foreign->heap); mem_heap_free(foreign->heap);
} }
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -1871,6 +1907,25 @@ dict_foreign_add_to_cache(
for_in_cache->referenced_index); for_in_cache->referenced_index);
if (index == NULL) { if (index == NULL) {
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s:\n"
"there is no index in the table which would contain\n"
"the columns as the first columns, or the data types in the\n"
"table do not match to the ones in the referenced table. Constraint:\n",
for_in_cache->foreign_table_name);
dict_print_info_on_foreign_key_in_create_format(
for_in_cache, buf + strlen(buf));
if (for_in_cache->foreign_index) {
sprintf(buf + strlen(buf),
"\nIndex of the foreign key in the referenced table is %.500s\n"
"See http://www.innodb.com/ibman.html about correct foreign key definition.\n",
for_in_cache->referenced_index->name);
}
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
if (for_in_cache == foreign) { if (for_in_cache == foreign) {
if (added_to_referenced_list) { if (added_to_referenced_list) {
UT_LIST_REMOVE(referenced_list, UT_LIST_REMOVE(referenced_list,
@ -2141,18 +2196,21 @@ dict_scan_table_name(
} }
/************************************************************************* /*************************************************************************
Skips one 'word', like an id. For the lexical definition of 'word', see the Scans an id. For the lexical definition of an 'id', see the code below.
code below. */ Strips backquotes from around the id. */
static static
char* char*
dict_skip_word( dict_scan_id(
/*===========*/ /*=========*/
/* out: scanned to */ /* out: scanned to */
char* ptr, /* in: scanned to */ char* ptr, /* in: scanned to */
ibool* success)/* out: TRUE if success, FALSE if just spaces left in char** start, /* out: start of the id; NULL if no id was
string */ scannable */
ulint* len) /* out: length of the id */
{ {
*success = FALSE; ibool scanned_backquote = FALSE;
*start = NULL;
while (isspace(*ptr)) { while (isspace(*ptr)) {
ptr++; ptr++;
@ -2164,24 +2222,61 @@ dict_skip_word(
} }
if (*ptr == '`') { if (*ptr == '`') {
scanned_backquote = TRUE;
ptr++; ptr++;
} }
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != '`' *start = ptr;
&& *ptr != '\0') {
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != ')'
&& *ptr != '\0' && *ptr != '`') {
ptr++; ptr++;
} }
*success = TRUE; *len = (ulint) (ptr - *start);
if (scanned_backquote) {
if (*ptr == '`') {
ptr++;
} else {
/* Syntax error */
*start = NULL;
}
}
return(ptr); return(ptr);
} }
/*************************************************************************
Skips one id. */
static
char*
dict_skip_word(
/*===========*/
/* out: scanned to */
char* ptr, /* in: scanned to */
ibool* success)/* out: TRUE if success, FALSE if just spaces left in
string or a syntax error */
{
char* start;
ulint len;
*success = FALSE;
ptr = dict_scan_id(ptr, &start, &len);
if (start) {
*success = TRUE;
}
return(ptr);
}
#ifdef currentlynotused
/************************************************************************* /*************************************************************************
Returns the number of opening brackets '(' subtracted by the number Returns the number of opening brackets '(' subtracted by the number
of closing brackets ')' between string and ptr. */ of closing brackets ')' between string and ptr. */
#ifdef NOT_USED
static static
int int
dict_bracket_count( dict_bracket_count(
@ -2206,16 +2301,116 @@ dict_bracket_count(
return(count); return(count);
} }
#endif #endif
/*************************************************************************
Removes MySQL comments from an SQL string. A comment is either
(a) '#' to the end of the line,
(b) '--<space>' to the end of the line, or
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
C comment syntax). */
static
char*
dict_strip_comments(
/*================*/
/* out, own: SQL string stripped from
comments; the caller must free this
with mem_free()! */
char* sql_string) /* in: SQL string */
{
char* str;
char* sptr;
char* ptr;
str = mem_alloc(strlen(sql_string) + 1);
sptr = sql_string;
ptr = str;
for (;;) {
if (*sptr == '\0') {
*ptr = '\0';
return(str);
}
if (*sptr == '#'
|| (strlen(sptr) >= 3 && 0 == memcmp("-- ", sptr, 3))) {
for (;;) {
/* In Unix a newline is 0x0D while in Windows
it is 0x0A followed by 0x0D */
if (*sptr == (char)0x0A
|| *sptr == (char)0x0D
|| *sptr == '\0') {
break;
}
sptr++;
}
}
if (strlen(sptr) >= 2 && *sptr == '/' && *(sptr + 1) == '*') {
for (;;) {
if (strlen(sptr) >= 2
&& *sptr == '*' && *(sptr + 1) == '/') {
sptr += 2;
break;
}
if (*sptr == '\0') {
break;
}
sptr++;
}
}
*ptr = *sptr;
ptr++;
sptr++;
}
}
/*************************************************************************
Reports a simple foreign key create clause syntax error. */
static
void
dict_foreign_report_syntax_err(
/*===========================*/
char* name, /* in: table name */
char* start_of_latest_foreign,/* in: start of the foreign key clause
in the SQL string */
char* ptr) /* in: place of the syntax error */
{
char* buf = dict_foreign_err_buf;
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
"Syntax error close to:\n%.500s\n", name, start_of_latest_foreign, ptr);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
}
/************************************************************************* /*************************************************************************
Scans a table create SQL string and adds to the data dictionary the foreign Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must the indexes for a table have been created. Each foreign key constraint must
be accompanied with indexes in both participating tables. The indexes are be accompanied with indexes in both participating tables. The indexes are
allowed to contain more fields than mentioned in the constraint. */ allowed to contain more fields than mentioned in the constraint. */
static
ulint ulint
dict_create_foreign_constraints( dict_create_foreign_constraints_low(
/*============================*/ /*================================*/
/* out: error code or DB_SUCCESS */ /* out: error code or DB_SUCCESS */
trx_t* trx, /* in: transaction */ trx_t* trx, /* in: transaction */
char* sql_string, /* in: table create or ALTER TABLE char* sql_string, /* in: table create or ALTER TABLE
@ -2231,7 +2426,9 @@ dict_create_foreign_constraints(
dict_table_t* referenced_table; dict_table_t* referenced_table;
dict_index_t* index; dict_index_t* index;
dict_foreign_t* foreign; dict_foreign_t* foreign;
char* ptr = sql_string; char* ptr = sql_string;
char* start_of_latest_foreign = sql_string;
char* buf = dict_foreign_err_buf;
ibool success; ibool success;
ulint error; ulint error;
ulint i; ulint i;
@ -2249,6 +2446,15 @@ dict_create_foreign_constraints(
table = dict_table_get_low(name); table = dict_table_get_low(name);
if (table == NULL) { if (table == NULL) {
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s.\n"
"Cannot find the table from the internal data dictionary of InnoDB.\n"
"Create table statement:\n%.2000\n", name, sql_string);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_ERROR); return(DB_ERROR);
} }
loop: loop:
@ -2264,6 +2470,8 @@ loop:
return(error); return(error);
} }
start_of_latest_foreign = ptr;
ptr = dict_accept(ptr, (char *) "FOREIGN", &success); ptr = dict_accept(ptr, (char *) "FOREIGN", &success);
if (!isspace(*ptr)) { if (!isspace(*ptr)) {
@ -2284,13 +2492,19 @@ loop:
ptr = dict_skip_word(ptr, &success); ptr = dict_skip_word(ptr, &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err(name,
start_of_latest_foreign, ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
ptr = dict_accept(ptr, (char *) "(", &success); ptr = dict_accept(ptr, (char *) "(", &success);
if (!success) { if (!success) {
return(DB_CANNOT_ADD_CONSTRAINT); /* We do not flag a syntax error here because in an
ALTER TABLE we may also have DROP FOREIGN KEY abc */
goto loop;
} }
} }
@ -2301,6 +2515,15 @@ col_loop1:
ptr = dict_scan_col(ptr, &success, table, columns + i, ptr = dict_scan_col(ptr, &success, table, columns + i,
column_names + i, column_name_lens + i); column_names + i, column_name_lens + i);
if (!success) { if (!success) {
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
"Cannot resolve column name close to:\n%.500s\n", name,
start_of_latest_foreign, ptr);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2315,6 +2538,8 @@ col_loop1:
ptr = dict_accept(ptr, (char *) ")", &success); ptr = dict_accept(ptr, (char *) ")", &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2324,12 +2549,24 @@ col_loop1:
index = dict_foreign_find_index(table, column_names, i, NULL); index = dict_foreign_find_index(table, column_names, i, NULL);
if (!index) { if (!index) {
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s:\n"
"There is no index in the table %.500s where the columns appear\n"
"as the first columns. Constraint:\n%.500s\n"
"See http://www.innodb.com/ibman.html for correct foreign key definition.\n",
name, name, start_of_latest_foreign);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
ptr = dict_accept(ptr, (char *) "REFERENCES", &success); ptr = dict_accept(ptr, (char *) "REFERENCES", &success);
if (!success || !isspace(*ptr)) { if (!success || !isspace(*ptr)) {
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2359,6 +2596,15 @@ col_loop1:
if (!success || (!referenced_table && trx->check_foreigns)) { if (!success || (!referenced_table && trx->check_foreigns)) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
"Cannot resolve table name close to:\n"
"%.500s\n", name, start_of_latest_foreign, ptr);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2366,7 +2612,8 @@ col_loop1:
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2381,6 +2628,15 @@ col_loop2:
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s,\n%.500s\n"
"Cannot resolve column name close to:\n"
"%.500s\n", name, start_of_latest_foreign, ptr);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2395,6 +2651,8 @@ col_loop2:
if (!success || foreign->n_fields != i) { if (!success || foreign->n_fields != i) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2417,9 +2675,10 @@ scan_on_conditions:
ptr = dict_accept(ptr, "UPDATE", &success); ptr = dict_accept(ptr, "UPDATE", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name,
start_of_latest_foreign, ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2455,6 +2714,8 @@ scan_on_conditions:
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name,
start_of_latest_foreign, ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2472,7 +2733,8 @@ scan_on_conditions:
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2480,7 +2742,8 @@ scan_on_conditions:
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2494,6 +2757,15 @@ scan_on_conditions:
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
"You have defined a SET NULL condition though some of the\n"
"columns is defined as NOT NULL.\n", name, start_of_latest_foreign);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
} }
@ -2512,6 +2784,15 @@ try_find_index:
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
"You have twice an ON DELETE clause or twice an ON UPDATE clause.\n",
name, start_of_latest_foreign);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@ -2525,6 +2806,18 @@ try_find_index:
foreign->foreign_index); foreign->foreign_index);
if (!index) { if (!index) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s:\n"
"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%.500s\n"
"See http://www.innodb.com/ibman.html for correct foreign key definition.\n",
name, start_of_latest_foreign);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
} else { } else {
@ -2565,6 +2858,165 @@ try_find_index:
goto loop; goto loop;
} }
/*************************************************************************
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must
be accompanied with indexes in both participating tables. The indexes are
allowed to contain more fields than mentioned in the constraint. */
ulint
dict_create_foreign_constraints(
/*============================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in: transaction */
char* sql_string, /* in: table create or ALTER TABLE
statement where foreign keys are declared like:
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the database
name before it: test.table2; the default
database id the database of parameter name */
char* name) /* in: table full name in the normalized form
database_name/table_name */
{
char* str;
ulint err;
str = dict_strip_comments(sql_string);
err = dict_create_foreign_constraints_low(trx, str, name);
mem_free(str);
return(err);
}
/**************************************************************************
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
ulint
dict_foreign_parse_drop_constraints(
/*================================*/
/* out: DB_SUCCESS or
DB_CANNOT_DROP_CONSTRAINT if
syntax error or the constraint
id does not match */
mem_heap_t* heap, /* in: heap from which we can
allocate memory */
trx_t* trx, /* in: transaction */
dict_table_t* table, /* in: table */
ulint* n, /* out: number of constraints
to drop */
char*** constraints_to_drop) /* out: id's of the
constraints to drop */
{
dict_foreign_t* foreign;
ibool success;
char* str;
char* ptr;
char* buf = dict_foreign_err_buf;
char* start;
char* id;
ulint len;
*n = 0;
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
str = dict_strip_comments(*(trx->mysql_query_str));
ptr = str;
ut_ad(mutex_own(&(dict_sys->mutex)));
loop:
ptr = dict_scan_to(ptr, (char *) "DROP");
if (*ptr == '\0') {
ut_a(*n < 1000);
mem_free(str);
return(DB_SUCCESS);
}
ptr = dict_accept(ptr, (char *) "DROP", &success);
if (!isspace(*ptr)) {
goto loop;
}
ptr = dict_accept(ptr, (char *) "FOREIGN", &success);
if (!success) {
goto loop;
}
ptr = dict_accept(ptr, (char *) "KEY", &success);
if (!success) {
goto syntax_error;
}
ptr = dict_scan_id(ptr, &start, &len);
if (start == NULL) {
goto syntax_error;
}
id = mem_heap_alloc(heap, len + 1);
ut_memcpy(id, start, len);
id[len] = '\0';
(*constraints_to_drop)[*n] = id;
(*n)++;
/* Look for the given constraint id */
foreign = UT_LIST_GET_FIRST(table->foreign_list);
while (foreign != NULL) {
if (0 == ut_strcmp(foreign->id, id)) {
/* Found */
break;
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
if (foreign == NULL) {
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Error in dropping of a foreign key constraint of table %.500s,\n"
"just before:\n%s\n in SQL command\n%s\nCannot find a constraint with the\n"
"given id %s.\n", table->name, ptr, str, id);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
mem_free(str);
return(DB_CANNOT_DROP_CONSTRAINT);
}
goto loop;
syntax_error:
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf),
" Syntax error in dropping of a foreign key constraint of table %.500s,\n"
"close to:\n%s\n in SQL command\n%s\n", table->name, ptr, str);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
mem_free(str);
return(DB_CANNOT_DROP_CONSTRAINT);
}
/*==================== END OF FOREIGN KEY PROCESSING ====================*/ /*==================== END OF FOREIGN KEY PROCESSING ====================*/
/************************************************************************** /**************************************************************************
@ -3286,7 +3738,6 @@ dict_index_print_low(
n_vals = index->stat_n_diff_key_vals[1]; n_vals = index->stat_n_diff_key_vals[1];
} }
printf( printf(
" INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n", " INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n",
index->name, index->table_name, index->name, index->table_name,
@ -3327,6 +3778,99 @@ dict_field_print_low(
printf(" %s", field->name); printf(" %s", field->name);
} }
/**************************************************************************
Sprintfs to a string info on a foreign key of a table in a format suitable
for CREATE TABLE. */
char*
dict_print_info_on_foreign_key_in_create_format(
/*============================================*/
/* out: how far in buf we printed */
dict_foreign_t* foreign,/* in: foreign key constraint */
char* buf) /* in: buffer of at least 5000 bytes */
{
char* buf2 = buf;
ulint i;
buf2 += sprintf(buf2, ",\n CONSTRAINT `%s` FOREIGN KEY (",
foreign->id);
for (i = 0; i < foreign->n_fields; i++) {
if ((ulint)(buf2 - buf) >= 4000) {
goto no_space;
}
buf2 += sprintf(buf2, "`%.250s`",
foreign->foreign_col_names[i]);
if (i + 1 < foreign->n_fields) {
buf2 += sprintf(buf2, ", ");
}
}
if (dict_tables_have_same_db(foreign->foreign_table_name,
foreign->referenced_table_name)) {
/* Do not print the database name of the referenced
table */
buf2 += sprintf(buf2, ") REFERENCES `%.500s` (",
dict_remove_db_name(
foreign->referenced_table_name));
} else {
buf2 += sprintf(buf2, ") REFERENCES `%.500s` (",
foreign->referenced_table_name);
/* Change the '/' in the table name to '.' */
for (i = ut_strlen(buf); i > 0; i--) {
if (buf[i] == '/') {
buf[i] = '.';
break;
}
}
}
for (i = 0; i < foreign->n_fields; i++) {
if ((ulint)(buf2 - buf) >= 4000) {
goto no_space;
}
buf2 += sprintf(buf2, "`%.250s`",
foreign->referenced_col_names[i]);
if (i + 1 < foreign->n_fields) {
buf2 += sprintf(buf2, ", ");
}
}
buf2 += sprintf(buf2, ")");
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
buf2 += sprintf(buf2, " ON DELETE CASCADE");
}
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
buf2 += sprintf(buf2, " ON DELETE SET NULL");
}
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
buf2 += sprintf(buf2, " ON DELETE NO ACTION");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
buf2 += sprintf(buf2, " ON UPDATE CASCADE");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
buf2 += sprintf(buf2, " ON UPDATE SET NULL");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
}
no_space:
return(buf2);
}
/************************************************************************** /**************************************************************************
Sprintfs to a string info on foreign keys of a table in a format suitable Sprintfs to a string info on foreign keys of a table in a format suitable
for CREATE TABLE. */ for CREATE TABLE. */
@ -3336,13 +3880,12 @@ dict_print_info_on_foreign_keys_in_create_format(
/*=============================================*/ /*=============================================*/
char* buf, /* in: auxiliary buffer */ char* buf, /* in: auxiliary buffer */
char* str, /* in/out: pointer to a string */ char* str, /* in/out: pointer to a string */
ulint len, /* in: str has to be a buffer at least ulint len, /* in: buf has to be a buffer of at least
len + 5000 bytes */ len + 5000 bytes; str must have at least
len + 1 bytes */
dict_table_t* table) /* in: table */ dict_table_t* table) /* in: table */
{ {
dict_foreign_t* foreign; dict_foreign_t* foreign;
ulint i;
char* buf2; char* buf2;
buf2 = buf; buf2 = buf;
@ -3358,78 +3901,12 @@ dict_print_info_on_foreign_keys_in_create_format(
} }
while (foreign != NULL) { while (foreign != NULL) {
buf2 += sprintf(buf2, ",\n FOREIGN KEY ("); if ((ulint)(buf2 - buf) >= len) {
goto no_space;
}
for (i = 0; i < foreign->n_fields; i++) { buf2 = dict_print_info_on_foreign_key_in_create_format(
if ((ulint)(buf2 - buf) >= len) { foreign, buf2);
goto no_space;
}
buf2 += sprintf(buf2, "`%s`",
foreign->foreign_col_names[i]);
if (i + 1 < foreign->n_fields) {
buf2 += sprintf(buf2, ", ");
}
}
if (dict_tables_have_same_db(table->name,
foreign->referenced_table_name)) {
/* Do not print the database name of the referenced
table */
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
dict_remove_db_name(
foreign->referenced_table_name));
} else {
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
foreign->referenced_table_name);
/* Change the '/' in the table name to '.' */
for (i = ut_strlen(buf); i > 0; i--) {
if (buf[i] == '/') {
buf[i] = '.';
break;
}
}
}
for (i = 0; i < foreign->n_fields; i++) {
if ((ulint)(buf2 - buf) >= len) {
goto no_space;
}
buf2 += sprintf(buf2, "`%s`",
foreign->referenced_col_names[i]);
if (i + 1 < foreign->n_fields) {
buf2 += sprintf(buf2, ", ");
}
}
buf2 += sprintf(buf2, ")");
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
buf2 += sprintf(buf2, " ON DELETE CASCADE");
}
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
buf2 += sprintf(buf2, " ON DELETE SET NULL");
}
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
buf2 += sprintf(buf2, " ON DELETE NO ACTION");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
buf2 += sprintf(buf2, " ON UPDATE CASCADE");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
buf2 += sprintf(buf2, " ON UPDATE SET NULL");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
} }
@ -3490,7 +3967,7 @@ dict_print_info_on_foreign_keys(
goto no_space; goto no_space;
} }
buf2 += sprintf(buf2, "%s", buf2 += sprintf(buf2, "%.500s",
foreign->foreign_col_names[i]); foreign->foreign_col_names[i]);
if (i + 1 < foreign->n_fields) { if (i + 1 < foreign->n_fields) {
@ -3498,14 +3975,14 @@ dict_print_info_on_foreign_keys(
} }
} }
buf2 += sprintf(buf2, ") REFER %s(", buf2 += sprintf(buf2, ") REFER %.500s(",
foreign->referenced_table_name); foreign->referenced_table_name);
for (i = 0; i < foreign->n_fields; i++) { for (i = 0; i < foreign->n_fields; i++) {
if ((ulint)(buf2 - buf) >= len) { if ((ulint)(buf2 - buf) >= len) {
goto no_space; goto no_space;
} }
buf2 += sprintf(buf2, "%s", buf2 += sprintf(buf2, "%.500s",
foreign->referenced_col_names[i]); foreign->referenced_col_names[i]);
if (i + 1 < foreign->n_fields) { if (i + 1 < foreign->n_fields) {
buf2 += sprintf(buf2, " "); buf2 += sprintf(buf2, " ");

View File

@ -456,7 +456,7 @@ dict_load_indexes(
ut_ad(len == 8); ut_ad(len == 8);
id = mach_read_from_8(field); id = mach_read_from_8(field);
ut_a(0 == ut_strcmp((void*) "NAME", ut_a(0 == ut_strcmp((char*) "NAME",
dict_field_get_col( dict_field_get_col(
dict_index_get_nth_field( dict_index_get_nth_field(
dict_table_get_first_index(sys_indexes), 4))->name)); dict_table_get_first_index(sys_indexes), 4))->name));
@ -515,7 +515,7 @@ dict_load_indexes(
&& ((type & DICT_CLUSTERED) && ((type & DICT_CLUSTERED)
|| ((table == dict_sys->sys_tables) || ((table == dict_sys->sys_tables)
&& (name_len == ut_strlen("ID_IND")) && (name_len == ut_strlen("ID_IND"))
&& (0 == ut_memcmp(name_buf, (void*) "ID_IND", && (0 == ut_memcmp(name_buf, (char*) "ID_IND",
name_len))))) { name_len))))) {
/* The index was created in memory already in /* The index was created in memory already in
@ -566,6 +566,7 @@ dict_load_table(
char* buf; char* buf;
ulint space; ulint space;
ulint n_cols; ulint n_cols;
ulint err;
mtr_t mtr; mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
@ -674,8 +675,25 @@ dict_load_table(
dict_load_indexes(table, heap); dict_load_indexes(table, heap);
ut_a(DB_SUCCESS == dict_load_foreigns(table->name)); err = dict_load_foreigns(table->name);
/*
if (err != DB_SUCCESS) {
mutex_enter(&dict_foreign_err_mutex);
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: could not make a foreign key definition to match\n"
"InnoDB: the foreign key table or the referenced table!\n"
"InnoDB: The data dictionary of InnoDB is corrupt. You may need to drop\n"
"InnoDB: and recreate the foreign key table or the referenced table.\n"
"InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n"
"InnoDB: Latest foreign key error printout:\n%s\n", dict_foreign_err_buf);
mutex_exit(&dict_foreign_err_mutex);
}
*/
mem_heap_free(heap); mem_heap_free(heap);
return(table); return(table);
@ -978,8 +996,8 @@ dict_load_foreign(
field = rec_get_nth_field(rec, 4, &len); field = rec_get_nth_field(rec, 4, &len);
foreign->referenced_table_name = mem_heap_alloc(foreign->heap, 1 + len); foreign->referenced_table_name = mem_heap_alloc(foreign->heap,
1 + len);
ut_memcpy(foreign->referenced_table_name, field, len); ut_memcpy(foreign->referenced_table_name, field, len);
foreign->referenced_table_name[len] = '\0'; foreign->referenced_table_name[len] = '\0';
@ -988,10 +1006,19 @@ dict_load_foreign(
dict_load_foreign_cols(id, foreign); dict_load_foreign_cols(id, foreign);
/* If the foreign table is not yet in the dictionary cache, we
have to load it so that we are able to make type comparisons
in the next function call. */
dict_table_get_low(foreign->foreign_table_name);
/* Note that there may already be a foreign constraint object in /* Note that there may already be a foreign constraint object in
the dictionary cache for this constraint: then the following the dictionary cache for this constraint: then the following
call only sets the pointers in it to point to the appropriate table call only sets the pointers in it to point to the appropriate table
and index objects and frees the newly created object foreign. */ and index objects and frees the newly created object foreign.
Adding to the cache should always succeed since we are not creating
a new foreign key constraint but loading one from the data
dictionary. */
err = dict_foreign_add_to_cache(foreign); err = dict_foreign_add_to_cache(foreign);

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libdyn.a noinst_LIBRARIES = libdyn.a
libdyn_a_SOURCES = dyn0dyn.c libdyn_a_SOURCES = dyn0dyn.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libeval.a noinst_LIBRARIES = libeval.a
libeval_a_SOURCES = eval0eval.c eval0proc.c libeval_a_SOURCES = eval0eval.c eval0proc.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libfil.a noinst_LIBRARIES = libfil.a
libfil_a_SOURCES = fil0fil.c libfil_a_SOURCES = fil0fil.c

View File

@ -18,7 +18,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libfsp.a noinst_LIBRARIES = libfsp.a
libfsp_a_SOURCES = fsp0fsp.c libfsp_a_SOURCES = fsp0fsp.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libfut.a noinst_LIBRARIES = libfut.a
libfut_a_SOURCES = fut0fut.c fut0lst.c libfut_a_SOURCES = fut0fut.c fut0lst.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libha.a noinst_LIBRARIES = libha.a
libha_a_SOURCES = ha0ha.c hash0hash.c libha_a_SOURCES = ha0ha.c hash0hash.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libibuf.a noinst_LIBRARIES = libibuf.a
libibuf_a_SOURCES = ibuf0ibuf.c libibuf_a_SOURCES = ibuf0ibuf.c

View File

@ -2420,17 +2420,22 @@ ibuf_delete_rec(
fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n"); fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n");
fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n", fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n",
page_no); page_no);
fflush(stderr);
rec_print(btr_pcur_get_rec(pcur)); rec_print(btr_pcur_get_rec(pcur));
rec_print(pcur->old_rec); rec_print(pcur->old_rec);
dtuple_print(search_tuple); dtuple_print(search_tuple);
rec_print(page_rec_get_next(btr_pcur_get_rec(pcur))); rec_print(page_rec_get_next(btr_pcur_get_rec(pcur)));
fflush(stdout);
mtr_commit(mtr); mtr_commit(mtr);
fprintf(stderr, "InnoDB: Validating insert buffer tree:\n"); fprintf(stderr, "InnoDB: Validating insert buffer tree:\n");
ut_a(btr_validate_tree(ibuf_data->index->tree)); ut_a(btr_validate_tree(ibuf_data->index->tree));
fprintf(stderr, "InnoDB: Ibuf tree ok\n");
fprintf(stderr, "InnoDB: ibuf tree ok\n");
fflush(stderr);
} }
ut_a(success); ut_a(success);

View File

@ -1,7 +1,5 @@
# Makefile included in Makefile.am in every subdirectory # Makefile included in Makefile.am in every subdirectory
libsdir = ../libs
INCLUDES = -I$(srcdir)/../include -I$(srcdir)/../../include -I../../include INCLUDES = -I$(srcdir)/../include -I$(srcdir)/../../include -I../../include
# Don't update the files from bitkeeper # Don't update the files from bitkeeper

View File

@ -496,6 +496,13 @@ buf_print_io(
/*=========*/ /*=========*/
char* buf, /* in/out: buffer where to print */ char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */ char* buf_end);/* in: buffer end */
/*************************************************************************
Returns the ratio in percents of modified pages in the buffer pool /
database pages in the buffer pool. */
ulint
buf_get_modified_ratio_pct(void);
/*============================*/
/************************************************************************** /**************************************************************************
Refreshes the statistics used to print per-second averages. */ Refreshes the statistics used to print per-second averages. */

View File

@ -46,6 +46,20 @@ buf_LRU_get_recent_limit(void);
/*==========================*/ /*==========================*/
/* out: the limit; zero if could not determine it */ /* out: the limit; zero if could not determine it */
/********************************************************************** /**********************************************************************
Look for a replaceable block from the end of the LRU list and put it to
the free list if found. */
ibool
buf_LRU_search_and_free_block(
/*==========================*/
/* out: TRUE if freed */
ulint n_iterations); /* in: how many times this has been called
repeatedly without result: a high value means
that we should search farther; if value is
k < 10, then we only search k/10 * number
of pages in the buffer pool from the end
of the LRU list */
/**********************************************************************
Returns a free block from the buf_pool. The block is taken off the Returns a free block from the buf_pool. The block is taken off the
free list. If it is empty, blocks are moved from the end of the free list. If it is empty, blocks are moved from the end of the
LRU list to the free list. */ LRU list to the free list. */
@ -88,17 +102,6 @@ void
buf_LRU_make_block_old( buf_LRU_make_block_old(
/*===================*/ /*===================*/
buf_block_t* block); /* in: control block */ buf_block_t* block); /* in: control block */
/**********************************************************************
Look for a replaceable block from the end of the LRU list and put it to
the free list if found. */
ibool
buf_LRU_search_and_free_block(
/*==========================*/
/* out: TRUE if freed */
ulint n_iterations); /* in: how many times this has been called
repeatedly without result: a high value
means that we should search farther */
/************************************************************************** /**************************************************************************
Validates the LRU list. */ Validates the LRU list. */

View File

@ -44,6 +44,8 @@ Created 5/24/1996 Heikki Tuuri
#define DB_CORRUPTION 39 /* data structure corruption noticed */ #define DB_CORRUPTION 39 /* data structure corruption noticed */
#define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index #define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index
where same column appears twice */ where same column appears twice */
#define DB_CANNOT_DROP_CONSTRAINT 40 /* dropping a foreign key constraint
from a table failed */
/* The following are partial failure codes */ /* The following are partial failure codes */
#define DB_FAIL 1000 #define DB_FAIL 1000

View File

@ -219,6 +219,24 @@ dict_create_foreign_constraints(
char* name); /* in: table full name in the normalized form char* name); /* in: table full name in the normalized form
database_name/table_name */ database_name/table_name */
/************************************************************************** /**************************************************************************
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
ulint
dict_foreign_parse_drop_constraints(
/*================================*/
/* out: DB_SUCCESS or
DB_CANNOT_DROP_CONSTRAINT if
syntax error or the constraint
id does not match */
mem_heap_t* heap, /* in: heap from which we can
allocate memory */
trx_t* trx, /* in: transaction */
dict_table_t* table, /* in: table */
ulint* n, /* out: number of constraints
to drop */
char*** constraints_to_drop); /* out: id's of the
constraints to drop */
/**************************************************************************
Returns a table object and memoryfixes it. NOTE! This is a high-level Returns a table object and memoryfixes it. NOTE! This is a high-level
function to be used mainly from outside the 'dict' directory. Inside this function to be used mainly from outside the 'dict' directory. Inside this
directory dict_table_get_low is usually the appropriate function. */ directory dict_table_get_low is usually the appropriate function. */
@ -333,6 +351,16 @@ dict_print_info_on_foreign_keys(
char* str, /* in/out: pointer to a string */ char* str, /* in/out: pointer to a string */
ulint len, /* in: space in str available for info */ ulint len, /* in: space in str available for info */
dict_table_t* table); /* in: table */ dict_table_t* table); /* in: table */
/**************************************************************************
Sprintfs to a string info on a foreign key of a table in a format suitable
for CREATE TABLE. */
char*
dict_print_info_on_foreign_key_in_create_format(
/*============================================*/
/* out: how far in buf we printed */
dict_foreign_t* foreign,/* in: foreign key constraint */
char* buf); /* in: buffer of at least 5000 bytes */
/************************************************************************ /************************************************************************
Gets the first index on the table (the clustered index). */ Gets the first index on the table (the clustered index). */
UNIV_INLINE UNIV_INLINE
@ -808,6 +836,14 @@ void
dict_mutex_exit_for_mysql(void); dict_mutex_exit_for_mysql(void);
/*===========================*/ /*===========================*/
/* The following len must be at least 10000 bytes! */
#define DICT_FOREIGN_ERR_BUF_LEN 10000
/* Buffers for storing detailed information about the latest foreign key
and unique key errors */
extern char* dict_foreign_err_buf;
extern char* dict_unique_err_buf;
extern mutex_t dict_foreign_err_mutex; /* mutex protecting the buffers */
extern dict_sys_t* dict_sys; /* the dictionary system */ extern dict_sys_t* dict_sys; /* the dictionary system */
extern rw_lock_t dict_operation_lock; extern rw_lock_t dict_operation_lock;

View File

@ -20,7 +20,7 @@ typedef struct log_group_struct log_group_t;
extern ibool log_do_write; extern ibool log_do_write;
extern ibool log_debug_writes; extern ibool log_debug_writes;
/* Wait modes for log_flush_up_to */ /* Wait modes for log_write_up_to */
#define LOG_NO_WAIT 91 #define LOG_NO_WAIT 91
#define LOG_WAIT_ONE_GROUP 92 #define LOG_WAIT_ONE_GROUP 92
#define LOG_WAIT_ALL_GROUPS 93 #define LOG_WAIT_ALL_GROUPS 93
@ -157,26 +157,21 @@ log_io_complete(
/*============*/ /*============*/
log_group_t* group); /* in: log group */ log_group_t* group); /* in: log group */
/********************************************************** /**********************************************************
Flushes the log files to the disk, using, for example, the Unix fsync.
This function does the flush even if the user has set
srv_flush_log_at_trx_commit = FALSE. */
void
log_flush_to_disk(void);
/*===================*/
/**********************************************************
This function is called, e.g., when a transaction wants to commit. It checks This function is called, e.g., when a transaction wants to commit. It checks
that the log has been flushed to disk up to the last log entry written by the that the log has been written to the log file up to the last log entry written
transaction. If there is a flush running, it waits and checks if the flush by the transaction. If there is a flush running, it waits and checks if the
flushed enough. If not, starts a new flush. */ flush flushed enough. If not, starts a new flush. */
void void
log_flush_up_to( log_write_up_to(
/*============*/ /*============*/
dulint lsn, /* in: log sequence number up to which the log should dulint lsn, /* in: log sequence number up to which the log should
be flushed, ut_dulint_max if not specified */ be written, ut_dulint_max if not specified */
ulint wait); /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, ulint wait, /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP,
or LOG_WAIT_ALL_GROUPS */ or LOG_WAIT_ALL_GROUPS */
ibool flush_to_disk);
/* in: TRUE if we want the written log also to be
flushed to disk */
/******************************************************************** /********************************************************************
Advances the smallest lsn for which there are unflushed dirty blocks in the Advances the smallest lsn for which there are unflushed dirty blocks in the
buffer pool and also may make a new checkpoint. NOTE: this function may only buffer pool and also may make a new checkpoint. NOTE: this function may only
@ -741,27 +736,37 @@ struct log_struct{
be advanced, it is enough that the be advanced, it is enough that the
write i/o has been completed for all write i/o has been completed for all
log groups */ log groups */
dulint flush_lsn; /* end lsn for the current flush */ dulint write_lsn; /* end lsn for the current running
ulint flush_end_offset;/* the data in buffer has been flushed write */
ulint write_end_offset;/* the data in buffer has been written
up to this offset when the current up to this offset when the current
flush ends: this field will then write ends: this field will then
be copied to buf_next_to_write */ be copied to buf_next_to_write */
ulint n_pending_writes;/* number of currently pending flush dulint current_flush_lsn;/* end lsn for the current running
writes */ write + flush operation */
dulint flushed_to_disk_lsn;
/* how far we have written the log
AND flushed to disk */
ulint n_pending_writes;/* number of currently pending flushes
or writes */
/* NOTE on the 'flush' in names of the fields below: starting from
4.0.14, we separate the write of the log file and the actual fsync()
or other method to flush it to disk. The names below shhould really
be 'flush_or_write'! */
os_event_t no_flush_event; /* this event is in the reset state os_event_t no_flush_event; /* this event is in the reset state
when a flush is running; a thread when a flush or a write is running;
should wait for this without owning a thread should wait for this without
the log mutex, but NOTE that to set or owning the log mutex, but NOTE that
reset this event, the thread MUST own to set or reset this event, the
the log mutex! */ thread MUST own the log mutex! */
ibool one_flushed; /* during a flush, this is first FALSE ibool one_flushed; /* during a flush, this is first FALSE
and becomes TRUE when one log group and becomes TRUE when one log group
has been flushed */ has been written or flushed */
os_event_t one_flushed_event;/* this event is reset when the os_event_t one_flushed_event;/* this event is reset when the
flush has not yet completed for any flush or write has not yet completed
log group; e.g., this means that a for any log group; e.g., this means
transaction has been committed when that a transaction has been committed
this is set; a thread should wait when this is set; a thread should wait
for this without owning the log mutex, for this without owning the log mutex,
but NOTE that to set or reset this but NOTE that to set or reset this
event, the thread MUST own the log event, the thread MUST own the log

View File

@ -35,7 +35,6 @@ row_ins_check_foreign_constraint(
dictionary cache if they exist at all */ dictionary cache if they exist at all */
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
table, else the referenced table */ table, else the referenced table */
dict_index_t* index, /* in: index in table */
dtuple_t* entry, /* in: index entry for index */ dtuple_t* entry, /* in: index entry for index */
que_thr_t* thr); /* in: query thread */ que_thr_t* thr); /* in: query thread */
/************************************************************************* /*************************************************************************

View File

@ -427,13 +427,21 @@ struct row_prebuilt_struct {
index where the ordering column is index where the ordering column is
the row id: in this case this flag the row id: in this case this flag
is set to TRUE */ is set to TRUE */
dict_index_t* index; /* current index for a search, if any */ dict_index_t* index; /* current index for a search, if
any */
ulint read_just_key; /* set to 1 when MySQL calls ulint read_just_key; /* set to 1 when MySQL calls
ha_innobase::extra with the ha_innobase::extra with the
argument HA_EXTRA_KEYREAD; it is enough argument HA_EXTRA_KEYREAD; it is enough
to read just columns defined in to read just columns defined in
the index (i.e., no read of the the index (i.e., no read of the
clustered index record necessary) */ clustered index record necessary) */
ibool used_in_HANDLER;/* TRUE if we have been using this
handle in a MySQL HANDLER low level
index cursor command: then we must
store the pcur position even in a
unique search from a clustered index,
because HANDLER allows NEXT and PREV
in such a situation */
ulint template_type; /* ROW_MYSQL_WHOLE_ROW, ulint template_type; /* ROW_MYSQL_WHOLE_ROW,
ROW_MYSQL_REC_FIELDS, ROW_MYSQL_REC_FIELDS,
ROW_MYSQL_DUMMY_TEMPLATE, or ROW_MYSQL_DUMMY_TEMPLATE, or

View File

@ -75,6 +75,9 @@ extern ulint srv_lock_wait_timeout;
extern char* srv_file_flush_method_str; extern char* srv_file_flush_method_str;
extern ulint srv_unix_file_flush_method; extern ulint srv_unix_file_flush_method;
extern ulint srv_win_file_flush_method; extern ulint srv_win_file_flush_method;
extern ulint srv_max_dirty_pages_pct;
extern ulint srv_force_recovery; extern ulint srv_force_recovery;
extern ulint srv_thread_concurrency; extern ulint srv_thread_concurrency;

View File

@ -157,6 +157,15 @@ trx_commit_for_mysql(
/* out: 0 or error number */ /* out: 0 or error number */
trx_t* trx); /* in: trx handle */ trx_t* trx); /* in: trx handle */
/************************************************************************** /**************************************************************************
If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE. */
ulint
trx_commit_complete_for_mysql(
/*==========================*/
/* out: 0 or error number */
trx_t* trx); /* in: trx handle */
/**************************************************************************
Marks the latest SQL statement ended. */ Marks the latest SQL statement ended. */
void void
@ -343,6 +352,11 @@ struct trx_struct{
dulint no; /* transaction serialization number == dulint no; /* transaction serialization number ==
max trx id when the transaction is max trx id when the transaction is
moved to COMMITTED_IN_MEMORY state */ moved to COMMITTED_IN_MEMORY state */
ibool flush_log_later;/* when we commit the transaction
in MySQL's binlog write, we will
flush the log to disk later in
a separate call */
dulint commit_lsn; /* lsn at the time of the commit */
ibool dict_operation; /* TRUE if the trx is used to create ibool dict_operation; /* TRUE if the trx is used to create
a table, create an index, or drop a a table, create an index, or drop a
table */ table */
@ -418,10 +432,6 @@ struct trx_struct{
lock_t* auto_inc_lock; /* possible auto-inc lock reserved by lock_t* auto_inc_lock; /* possible auto-inc lock reserved by
the transaction; note that it is also the transaction; note that it is also
in the lock list trx_locks */ in the lock list trx_locks */
ibool ignore_duplicates_in_insert;
/* in an insert roll back only insert
of the latest row in case
of a duplicate key error */
UT_LIST_NODE_T(trx_t) UT_LIST_NODE_T(trx_t)
trx_list; /* list of transactions */ trx_list; /* list of transactions */
UT_LIST_NODE_T(trx_t) UT_LIST_NODE_T(trx_t)

View File

@ -100,6 +100,15 @@ memory is read outside the allocated blocks. */
#define YYDEBUG 1 #define YYDEBUG 1
#ifdef HAVE_purify
/* The following sets all new allocated memory to zero before use:
this can be used to eliminate unnecessary Purify warnings, but note that
it also masks many bugs Purify could detect. For detailed Purify analysis it
is best to remove the define below and look through the warnings one
by one. */
#define UNIV_SET_MEM_TO_ZERO
#endif
/* /*
#define UNIV_SQL_DEBUG #define UNIV_SQL_DEBUG
#define UNIV_LOG_DEBUG #define UNIV_LOG_DEBUG

View File

@ -20,7 +20,6 @@ extern ibool ut_dbg_stop_threads;
extern ulint* ut_dbg_null_ptr; extern ulint* ut_dbg_null_ptr;
#define ut_a(EXPR)\ #define ut_a(EXPR)\
{\ {\
ulint dbg_i;\ ulint dbg_i;\
@ -31,8 +30,10 @@ extern ulint* ut_dbg_null_ptr;
" InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\
os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\ os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\
(ulint)__LINE__);\ (ulint)__LINE__);\
fprintf(stderr,\
"InnoDB: Failing assertion: " #EXPR);\
fprintf(stderr,\ fprintf(stderr,\
"InnoDB: We intentionally generate a memory trap.\n");\ "\nInnoDB: We intentionally generate a memory trap.\n");\
fprintf(stderr,\ fprintf(stderr,\
"InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\ "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\
ut_dbg_stop_threads = TRUE;\ ut_dbg_stop_threads = TRUE;\

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = liblock.a noinst_LIBRARIES = liblock.a
liblock_a_SOURCES = lock0lock.c liblock_a_SOURCES = lock0lock.c

View File

@ -3092,8 +3092,7 @@ lock_deadlock_recursive(
err_buf += strlen(err_buf); err_buf += strlen(err_buf);
err_buf += sprintf(err_buf, err_buf += sprintf(err_buf,
" LATEST DETECTED DEADLOCK:\n" "\n*** (1) TRANSACTION:\n");
"*** (1) TRANSACTION:\n");
trx_print(err_buf, wait_lock->trx); trx_print(err_buf, wait_lock->trx);
err_buf += strlen(err_buf); err_buf += strlen(err_buf);
@ -3936,24 +3935,15 @@ lock_print_info(
return; return;
} }
buf += sprintf(buf, "Trx id counter %lu %lu\n",
ut_dulint_get_high(trx_sys->max_trx_id),
ut_dulint_get_low(trx_sys->max_trx_id));
buf += sprintf(buf,
"Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n",
ut_dulint_get_high(purge_sys->purge_trx_no),
ut_dulint_get_low(purge_sys->purge_trx_no),
ut_dulint_get_high(purge_sys->purge_undo_no),
ut_dulint_get_low(purge_sys->purge_undo_no));
lock_mutex_enter_kernel(); lock_mutex_enter_kernel();
buf += sprintf(buf,
"Total number of lock structs in row lock hash table %lu\n",
lock_get_n_rec_locks());
if (lock_deadlock_found) { if (lock_deadlock_found) {
buf += sprintf(buf,
"------------------------\n"
"LATEST DETECTED DEADLOCK\n"
"------------------------\n");
if ((ulint)(buf_end - buf) if ((ulint)(buf_end - buf)
< 100 + strlen(lock_latest_err_buf)) { < 100 + strlen(lock_latest_err_buf)) {
@ -3973,6 +3963,26 @@ lock_print_info(
return; return;
} }
buf += sprintf(buf,
"------------\n"
"TRANSACTIONS\n"
"------------\n");
buf += sprintf(buf, "Trx id counter %lu %lu\n",
ut_dulint_get_high(trx_sys->max_trx_id),
ut_dulint_get_low(trx_sys->max_trx_id));
buf += sprintf(buf,
"Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n",
ut_dulint_get_high(purge_sys->purge_trx_no),
ut_dulint_get_low(purge_sys->purge_trx_no),
ut_dulint_get_high(purge_sys->purge_undo_no),
ut_dulint_get_low(purge_sys->purge_undo_no));
buf += sprintf(buf,
"Total number of lock structs in row lock hash table %lu\n",
lock_get_n_rec_locks());
buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n");
/* First print info on non-active transactions */ /* First print info on non-active transactions */

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = liblog.a noinst_LIBRARIES = liblog.a
liblog_a_SOURCES = log0log.c log0recv.c liblog_a_SOURCES = log0log.c log0recv.c

View File

@ -178,7 +178,7 @@ loop:
/* Not enough free space, do a syncronous flush of the log /* Not enough free space, do a syncronous flush of the log
buffer */ buffer */
log_flush_up_to(ut_dulint_max, LOG_WAIT_ALL_GROUPS); log_write_up_to(ut_dulint_max, LOG_WAIT_ALL_GROUPS, TRUE);
count++; count++;
@ -675,7 +675,9 @@ log_init(void)
log_sys->buf_next_to_write = 0; log_sys->buf_next_to_write = 0;
log_sys->flush_lsn = ut_dulint_zero; log_sys->write_lsn = ut_dulint_zero;
log_sys->current_flush_lsn = ut_dulint_zero;
log_sys->flushed_to_disk_lsn = ut_dulint_zero;
log_sys->written_to_some_lsn = log_sys->lsn; log_sys->written_to_some_lsn = log_sys->lsn;
log_sys->written_to_all_lsn = log_sys->lsn; log_sys->written_to_all_lsn = log_sys->lsn;
@ -867,7 +869,7 @@ log_group_check_flush_completion(
printf("Log flushed first to group %lu\n", group->id); printf("Log flushed first to group %lu\n", group->id);
} }
log_sys->written_to_some_lsn = log_sys->flush_lsn; log_sys->written_to_some_lsn = log_sys->write_lsn;
log_sys->one_flushed = TRUE; log_sys->one_flushed = TRUE;
return(LOG_UNLOCK_NONE_FLUSHED_LOCK); return(LOG_UNLOCK_NONE_FLUSHED_LOCK);
@ -896,15 +898,15 @@ log_sys_check_flush_completion(void)
if (log_sys->n_pending_writes == 0) { if (log_sys->n_pending_writes == 0) {
log_sys->written_to_all_lsn = log_sys->flush_lsn; log_sys->written_to_all_lsn = log_sys->write_lsn;
log_sys->buf_next_to_write = log_sys->flush_end_offset; log_sys->buf_next_to_write = log_sys->write_end_offset;
if (log_sys->flush_end_offset > log_sys->max_buf_free / 2) { if (log_sys->write_end_offset > log_sys->max_buf_free / 2) {
/* Move the log buffer content to the start of the /* Move the log buffer content to the start of the
buffer */ buffer */
move_start = ut_calc_align_down( move_start = ut_calc_align_down(
log_sys->flush_end_offset, log_sys->write_end_offset,
OS_FILE_LOG_BLOCK_SIZE); OS_FILE_LOG_BLOCK_SIZE);
move_end = ut_calc_align(log_sys->buf_free, move_end = ut_calc_align(log_sys->buf_free,
OS_FILE_LOG_BLOCK_SIZE); OS_FILE_LOG_BLOCK_SIZE);
@ -981,57 +983,6 @@ log_io_complete(
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
} }
/**********************************************************
Flushes the log files to the disk, using, for example, the Unix fsync.
This function does the flush even if the user has set
srv_flush_log_at_trx_commit = FALSE. */
void
log_flush_to_disk(void)
/*===================*/
{
log_group_t* group;
loop:
mutex_enter(&(log_sys->mutex));
if (log_sys->n_pending_writes > 0) {
/* A log file write is running */
mutex_exit(&(log_sys->mutex));
/* Wait for the log file write to complete and try again */
os_event_wait(log_sys->no_flush_event);
goto loop;
}
group = UT_LIST_GET_FIRST(log_sys->log_groups);
log_sys->n_pending_writes++;
group->n_pending_writes++;
os_event_reset(log_sys->no_flush_event);
os_event_reset(log_sys->one_flushed_event);
mutex_exit(&(log_sys->mutex));
fil_flush(group->space_id);
mutex_enter(&(log_sys->mutex));
ut_a(group->n_pending_writes == 1);
ut_a(log_sys->n_pending_writes == 1);
group->n_pending_writes--;
log_sys->n_pending_writes--;
os_event_set(log_sys->no_flush_event);
os_event_set(log_sys->one_flushed_event);
mutex_exit(&(log_sys->mutex));
}
/********************************************************** /**********************************************************
Writes a log file header to a log file space. */ Writes a log file header to a log file space. */
static static
@ -1205,12 +1156,15 @@ by the transaction. If there is a flush running, it waits and checks if the
flush flushed enough. If not, starts a new flush. */ flush flushed enough. If not, starts a new flush. */
void void
log_flush_up_to( log_write_up_to(
/*============*/ /*============*/
dulint lsn, /* in: log sequence number up to which the log should dulint lsn, /* in: log sequence number up to which the log should
be written, ut_dulint_max if not specified */ be written, ut_dulint_max if not specified */
ulint wait) /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, ulint wait, /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP,
or LOG_WAIT_ALL_GROUPS */ or LOG_WAIT_ALL_GROUPS */
ibool flush_to_disk)
/* in: TRUE if we want the written log also to be
flushed to disk */
{ {
log_group_t* group; log_group_t* group;
ulint start_offset; ulint start_offset;
@ -1239,9 +1193,18 @@ loop:
mutex_enter(&(log_sys->mutex)); mutex_enter(&(log_sys->mutex));
if ((ut_dulint_cmp(log_sys->written_to_all_lsn, lsn) >= 0) if (flush_to_disk
|| ((ut_dulint_cmp(log_sys->written_to_some_lsn, lsn) >= 0) && ut_dulint_cmp(log_sys->flushed_to_disk_lsn, lsn) >= 0) {
&& (wait != LOG_WAIT_ALL_GROUPS))) {
mutex_exit(&(log_sys->mutex));
return;
}
if (!flush_to_disk
&& (ut_dulint_cmp(log_sys->written_to_all_lsn, lsn) >= 0
|| (ut_dulint_cmp(log_sys->written_to_some_lsn, lsn) >= 0
&& wait != LOG_WAIT_ALL_GROUPS))) {
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
@ -1249,10 +1212,19 @@ loop:
} }
if (log_sys->n_pending_writes > 0) { if (log_sys->n_pending_writes > 0) {
/* A flush is running */ /* A write (+ possibly flush to disk) is running */
if (ut_dulint_cmp(log_sys->flush_lsn, lsn) >= 0) { if (flush_to_disk
/* The flush will flush enough: wait for it to && ut_dulint_cmp(log_sys->current_flush_lsn, lsn) >= 0) {
/* The write + flush will write enough: wait for it to
complete */
goto do_waits;
}
if (!flush_to_disk
&& ut_dulint_cmp(log_sys->write_lsn, lsn) >= 0) {
/* The write will write enough: wait for it to
complete */ complete */
goto do_waits; goto do_waits;
@ -1260,16 +1232,17 @@ loop:
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
/* Wait for the flush to complete and try to start a new /* Wait for the write to complete and try to start a new
flush */ write */
os_event_wait(log_sys->no_flush_event); os_event_wait(log_sys->no_flush_event);
goto loop; goto loop;
} }
if (log_sys->buf_free == log_sys->buf_next_to_write) { if (!flush_to_disk
/* Nothing to flush */ && log_sys->buf_free == log_sys->buf_next_to_write) {
/* Nothing to write and no flush to disk requested */
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
@ -1277,7 +1250,7 @@ loop:
} }
if (log_debug_writes) { if (log_debug_writes) {
printf("Flushing log from %lu %lu up to lsn %lu %lu\n", printf("Writing log from %lu %lu up to lsn %lu %lu\n",
ut_dulint_get_high(log_sys->written_to_all_lsn), ut_dulint_get_high(log_sys->written_to_all_lsn),
ut_dulint_get_low(log_sys->written_to_all_lsn), ut_dulint_get_low(log_sys->written_to_all_lsn),
ut_dulint_get_high(log_sys->lsn), ut_dulint_get_high(log_sys->lsn),
@ -1301,7 +1274,12 @@ loop:
ut_ad(area_end - area_start > 0); ut_ad(area_end - area_start > 0);
log_sys->flush_lsn = log_sys->lsn; log_sys->write_lsn = log_sys->lsn;
if (flush_to_disk) {
log_sys->current_flush_lsn = log_sys->lsn;
}
log_sys->one_flushed = FALSE; log_sys->one_flushed = FALSE;
log_block_set_flush_bit(log_sys->buf + area_start, TRUE); log_block_set_flush_bit(log_sys->buf + area_start, TRUE);
@ -1318,10 +1296,12 @@ loop:
OS_FILE_LOG_BLOCK_SIZE); OS_FILE_LOG_BLOCK_SIZE);
log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE; log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE;
log_sys->flush_end_offset = log_sys->buf_free; log_sys->write_end_offset = log_sys->buf_free;
group = UT_LIST_GET_FIRST(log_sys->log_groups); group = UT_LIST_GET_FIRST(log_sys->log_groups);
/* Do the write to the log files */
while (group) { while (group) {
log_group_write_buf(LOG_FLUSH, group, log_group_write_buf(LOG_FLUSH, group,
log_sys->buf + area_start, log_sys->buf + area_start,
@ -1330,20 +1310,25 @@ loop:
OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE),
start_offset - area_start); start_offset - area_start);
log_group_set_fields(group, log_sys->flush_lsn); log_group_set_fields(group, log_sys->write_lsn);
group = UT_LIST_GET_NEXT(log_groups, group); group = UT_LIST_GET_NEXT(log_groups, group);
} }
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) {
&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC /* O_DSYNC means the OS did not buffer the log file at all:
&& srv_flush_log_at_trx_commit != 2) { so we have also flushed to disk what we have written */
log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
} else if (flush_to_disk) {
group = UT_LIST_GET_FIRST(log_sys->log_groups); group = UT_LIST_GET_FIRST(log_sys->log_groups);
fil_flush(group->space_id); fil_flush(group->space_id);
log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
} }
mutex_enter(&(log_sys->mutex)); mutex_enter(&(log_sys->mutex));
@ -1403,7 +1388,7 @@ log_flush_margin(void)
mutex_exit(&(log->mutex)); mutex_exit(&(log->mutex));
if (do_flush) { if (do_flush) {
log_flush_up_to(ut_dulint_max, LOG_NO_WAIT); log_write_up_to(ut_dulint_max, LOG_NO_WAIT, FALSE);
} }
} }
@ -1555,7 +1540,8 @@ log_group_checkpoint(
buf = group->checkpoint_buf; buf = group->checkpoint_buf;
mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no); mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no);
mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn); mach_write_to_8(buf + LOG_CHECKPOINT_LSN,
log_sys->next_checkpoint_lsn);
mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET, mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET,
log_group_calc_lsn_offset( log_group_calc_lsn_offset(
@ -1664,8 +1650,10 @@ log_reset_first_header_and_checkpoint(
lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE); lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE);
/* Write the label of ibbackup --restore */ /* Write the label of ibbackup --restore */
sprintf((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup "); sprintf((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
ut_sprintf_timestamp((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP "ibbackup ");
ut_sprintf_timestamp(
(char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
+ strlen("ibbackup ")); + strlen("ibbackup "));
buf = hdr_buf + LOG_CHECKPOINT_1; buf = hdr_buf + LOG_CHECKPOINT_1;
@ -1773,7 +1761,7 @@ log_checkpoint(
write-ahead-logging algorithm ensures that the log has been flushed write-ahead-logging algorithm ensures that the log has been flushed
up to oldest_lsn. */ up to oldest_lsn. */
log_flush_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS); log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
mutex_enter(&(log_sys->mutex)); mutex_enter(&(log_sys->mutex));
@ -2466,7 +2454,7 @@ loop:
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
log_flush_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS); log_write_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
calc_new_limit = FALSE; calc_new_limit = FALSE;
@ -3104,8 +3092,8 @@ log_print(
"Last checkpoint at %lu %lu\n", "Last checkpoint at %lu %lu\n",
ut_dulint_get_high(log_sys->lsn), ut_dulint_get_high(log_sys->lsn),
ut_dulint_get_low(log_sys->lsn), ut_dulint_get_low(log_sys->lsn),
ut_dulint_get_high(log_sys->written_to_some_lsn), ut_dulint_get_high(log_sys->flushed_to_disk_lsn),
ut_dulint_get_low(log_sys->written_to_some_lsn), ut_dulint_get_low(log_sys->flushed_to_disk_lsn),
ut_dulint_get_high(log_sys->last_checkpoint_lsn), ut_dulint_get_high(log_sys->last_checkpoint_lsn),
ut_dulint_get_low(log_sys->last_checkpoint_lsn)); ut_dulint_get_low(log_sys->last_checkpoint_lsn));

View File

@ -1833,7 +1833,12 @@ recv_report_corrupt_log(
"InnoDB: WARNING: the log file may have been corrupt and it\n" "InnoDB: WARNING: the log file may have been corrupt and it\n"
"InnoDB: is possible that the log scan did not proceed\n" "InnoDB: is possible that the log scan did not proceed\n"
"InnoDB: far enough in recovery! Please run CHECK TABLE\n" "InnoDB: far enough in recovery! Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\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.html\n"
"InnoDB: about forcing recovery.\n");
fflush(stderr);
} }
/*********************************************************** /***********************************************************
@ -2470,7 +2475,7 @@ recv_recovery_from_checkpoint_start(
log_hdr_buf, max_cp_group); log_hdr_buf, max_cp_group);
if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
"ibbackup", ut_strlen("ibbackup"))) { (byte*)"ibbackup", ut_strlen((char*)"ibbackup"))) {
/* This log file was created by ibbackup --restore: print /* This log file was created by ibbackup --restore: print
a note to the user about it */ a note to the user about it */
@ -2481,7 +2486,7 @@ recv_recovery_from_checkpoint_start(
/* Wipe over the label now */ /* Wipe over the label now */
ut_memcpy(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, ut_memcpy(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
" ", 4); (char*)" ", 4);
/* Write to the log file to wipe over the label */ /* Write to the log file to wipe over the label */
fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE,
max_cp_group->space_id, max_cp_group->space_id,

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libmach.a noinst_LIBRARIES = libmach.a
libmach_a_SOURCES = mach0data.c libmach_a_SOURCES = mach0data.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libmem.a noinst_LIBRARIES = libmem.a
libmem_a_SOURCES = mem0mem.c mem0pool.c libmem_a_SOURCES = mem0mem.c mem0pool.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libmtr.a noinst_LIBRARIES = libmtr.a
libmtr_a_SOURCES = mtr0mtr.c mtr0log.c libmtr_a_SOURCES = mtr0mtr.c mtr0log.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libodbc.a noinst_LIBRARIES = libodbc.a
libodbc_a_SOURCES = odbc0odbc.c libodbc_a_SOURCES = odbc0odbc.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libos.a noinst_LIBRARIES = libos.a
libos_a_SOURCES = os0proc.c os0shm.c os0sync.c os0thread.c os0file.c libos_a_SOURCES = os0proc.c os0shm.c os0sync.c os0thread.c os0file.c

View File

@ -214,9 +214,14 @@ os_file_get_last_error(void)
"InnoDB: the directory. It may also be you have created a subdirectory\n" "InnoDB: the directory. It may also be you have created a subdirectory\n"
"InnoDB: of the same name as a data file.\n"); "InnoDB: of the same name as a data file.\n");
} else { } else {
fprintf(stderr, if (strerror((int)err) != NULL) {
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n" fprintf(stderr,
"InnoDB: what the error number means.\n"); "InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err));
}
fprintf(stderr,
"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: about operating system error numbers.\n");
} }
} }
@ -252,9 +257,14 @@ os_file_get_last_error(void)
"InnoDB: The error means mysqld does not have the access rights to\n" "InnoDB: The error means mysqld does not have the access rights to\n"
"InnoDB: the directory.\n"); "InnoDB: the directory.\n");
} else { } else {
fprintf(stderr, if (strerror((int)err) != NULL) {
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n" fprintf(stderr,
"InnoDB: what the error number means or use the perror program of MySQL.\n"); "InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err));
}
fprintf(stderr,
"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: about operating system error numbers.\n");
} }
} }
@ -511,10 +521,11 @@ try_again:
} }
#endif #endif
#ifdef UNIV_NON_BUFFERED_IO #ifdef UNIV_NON_BUFFERED_IO
if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { if (type == OS_LOG_FILE) {
/* Do not use unbuffered i/o to log files because /* Do not use unbuffered i/o to log files because
value 2 denotes that we do not flush the log at every to allow group commit to work when MySQL binlogging
commit, but only once per second */ is used we must separate log file write and log
file flush to disk. */
} else { } else {
if (srv_win_file_flush_method == if (srv_win_file_flush_method ==
SRV_WIN_IO_UNBUFFERED) { SRV_WIN_IO_UNBUFFERED) {
@ -742,6 +753,11 @@ os_file_set_size(
offset = 0; offset = 0;
low = (ib_longlong)size + (((ib_longlong)size_high) << 32); low = (ib_longlong)size + (((ib_longlong)size_high) << 32);
if (low >= (ib_longlong)(100 * 1024 * 1024)) {
fprintf(stderr, "InnoDB: Progress in MB:");
}
while (offset < low) { while (offset < low) {
if (low - offset < UNIV_PAGE_SIZE * 512) { if (low - offset < UNIV_PAGE_SIZE * 512) {
n_bytes = (ulint)(low - offset); n_bytes = (ulint)(low - offset);
@ -757,9 +773,24 @@ os_file_set_size(
ut_free(buf2); ut_free(buf2);
goto error_handling; goto error_handling;
} }
/* Print about progress for each 100 MB written */
if ((offset + n_bytes) / (ib_longlong)(100 * 1024 * 1024)
!= offset / (ib_longlong)(100 * 1024 * 1024)) {
fprintf(stderr, " %lu00",
(ulint)((offset + n_bytes)
/ (ib_longlong)(100 * 1024 * 1024)));
}
offset += n_bytes; offset += n_bytes;
} }
if (low >= (ib_longlong)(100 * 1024 * 1024)) {
fprintf(stderr, "\n");
}
ut_free(buf2); ut_free(buf2);
ret = os_file_flush(file); ret = os_file_flush(file);

View File

@ -68,9 +68,10 @@ os_event_create(
os_fast_mutex_init(&(event->os_mutex)); os_fast_mutex_init(&(event->os_mutex));
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
pthread_cond_init(&(event->cond_var), pthread_condattr_default); ut_a(0 == pthread_cond_init(&(event->cond_var),
pthread_condattr_default));
#else #else
pthread_cond_init(&(event->cond_var), NULL); ut_a(0 == pthread_cond_init(&(event->cond_var), NULL));
#endif #endif
event->is_set = FALSE; event->is_set = FALSE;
@ -130,7 +131,7 @@ os_event_set(
/* Do nothing */ /* Do nothing */
} else { } else {
event->is_set = TRUE; event->is_set = TRUE;
pthread_cond_broadcast(&(event->cond_var)); ut_a(0 == pthread_cond_broadcast(&(event->cond_var)));
} }
os_fast_mutex_unlock(&(event->os_mutex)); os_fast_mutex_unlock(&(event->os_mutex));
@ -182,7 +183,7 @@ os_event_free(
ut_a(event); ut_a(event);
os_fast_mutex_free(&(event->os_mutex)); os_fast_mutex_free(&(event->os_mutex));
pthread_cond_destroy(&(event->cond_var)); ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
ut_free(event); ut_free(event);
#endif #endif
@ -446,9 +447,9 @@ os_fast_mutex_init(
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex); InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
#else #else
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
pthread_mutex_init(fast_mutex, pthread_mutexattr_default); ut_a(0 == pthread_mutex_init(fast_mutex, pthread_mutexattr_default));
#else #else
pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST); ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST));
#endif #endif
#endif #endif
} }
@ -495,10 +496,7 @@ os_fast_mutex_free(
ut_a(fast_mutex); ut_a(fast_mutex);
DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
#elif defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
pthread_mutex_destroy(fast_mutex);
#else #else
UT_NOT_USED(fast_mutex); ut_a(0 == pthread_mutex_destroy(fast_mutex));
#endif #endif
} }

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libpage.a noinst_LIBRARIES = libpage.a
libpage_a_SOURCES = page0page.c page0cur.c libpage_a_SOURCES = page0page.c page0cur.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libpars.a noinst_LIBRARIES = libpars.a
noinst_HEADERS = pars0grm.h noinst_HEADERS = pars0grm.h

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libque.a noinst_LIBRARIES = libque.a
libque_a_SOURCES = que0que.c libque_a_SOURCES = que0que.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libread.a noinst_LIBRARIES = libread.a
libread_a_SOURCES = read0read.c libread_a_SOURCES = read0read.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = librem.a noinst_LIBRARIES = librem.a
librem_a_SOURCES = rem0rec.c rem0cmp.c librem_a_SOURCES = rem0rec.c rem0cmp.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = librow.a noinst_LIBRARIES = librow.a
librow_a_SOURCES = row0ins.c row0mysql.c row0purge.c row0row.c row0sel.c\ librow_a_SOURCES = row0ins.c row0mysql.c row0purge.c row0row.c row0sel.c\
row0uins.c row0umod.c row0undo.c row0upd.c row0vers.c row0uins.c row0umod.c row0undo.c row0upd.c row0vers.c

View File

@ -323,7 +323,7 @@ row_ins_clust_index_entry_by_modify(
/************************************************************************* /*************************************************************************
Returns TRUE if in a cascaded update/delete an ancestor node of node Returns TRUE if in a cascaded update/delete an ancestor node of node
updates table. */ updates (not DELETE, but UPDATE) table. */
static static
ibool ibool
row_ins_cascade_ancestor_updates_table( row_ins_cascade_ancestor_updates_table(
@ -341,7 +341,7 @@ row_ins_cascade_ancestor_updates_table(
upd_node = parent; upd_node = parent;
if (upd_node->table == table) { if (upd_node->table == table && upd_node->is_delete == FALSE) {
return(TRUE); return(TRUE);
} }
@ -437,6 +437,111 @@ row_ins_cascade_calc_update_vec(
return(n_fields_updated); return(n_fields_updated);
} }
/*************************************************************************
Reports a foreign key error associated with an update or a delete of a
parent table index entry. */
static
void
row_ins_foreign_report_err(
/*=======================*/
char* errstr, /* in: error string from the viewpoint
of the parent table */
que_thr_t* thr, /* in: query thread whose run_node
is an update node */
dict_foreign_t* foreign, /* in: foreign key constraint */
rec_t* rec, /* in: a matching index record in the
child table */
dtuple_t* entry) /* in: index entry in the parent
table */
{
char* buf = dict_foreign_err_buf;
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf), " Transaction:\n");
trx_print(buf + strlen(buf), thr_get_trx(thr));
sprintf(buf + strlen(buf),
"Foreign key constraint fails for table %.500s:\n",
foreign->foreign_table_name);
dict_print_info_on_foreign_key_in_create_format(
foreign, buf + strlen(buf));
sprintf(buf + strlen(buf), "\n%s", errstr);
sprintf(buf + strlen(buf),
" in parent table, in index %.500s tuple:\n",
foreign->referenced_index->name);
if (entry) {
dtuple_sprintf(buf + strlen(buf), 1000, entry);
}
sprintf(buf + strlen(buf),
"\nBut in child table %.500s, in index %.500s, there is a record:\n",
foreign->foreign_table_name, foreign->foreign_index->name);
if (rec) {
rec_sprintf(buf + strlen(buf), 1000, rec);
}
sprintf(buf + strlen(buf), "\n");
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
}
/*************************************************************************
Reports a foreign key error to dict_foreign_err_buf when we are trying
to add an index entry to a child table. Note that the adding may be the result
of an update, too. */
static
void
row_ins_foreign_report_add_err(
/*===========================*/
que_thr_t* thr, /* in: query thread whose run_node
is an insert node */
dict_foreign_t* foreign, /* in: foreign key constraint */
rec_t* rec, /* in: a record in the parent table:
it does not match entry because we
have an error! */
dtuple_t* entry) /* in: index entry to insert in the
child table */
{
char* buf = dict_foreign_err_buf;
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf), " Transaction:\n");
trx_print(buf + strlen(buf), thr_get_trx(thr));
sprintf(buf + strlen(buf),
"Foreign key constraint fails for table %.500s:\n",
foreign->foreign_table_name);
dict_print_info_on_foreign_key_in_create_format(
foreign, buf + strlen(buf));
sprintf(buf + strlen(buf),
"\nTrying to add in child table, in index %.500s tuple:\n",
foreign->foreign_index->name);
if (entry) {
dtuple_sprintf(buf + strlen(buf), 1000, entry);
}
sprintf(buf + strlen(buf),
"\nBut in parent table %.500s, in index %.500s,\n"
"the closest match we can find is record:\n",
foreign->referenced_table_name,
foreign->referenced_index->name);
if (rec && page_rec_is_supremum(rec)) {
/* If the cursor ended on a supremum record, it is better
to report the previous record in the error message, so that
the user gets a more descriptive error message. */
rec = page_rec_get_prev(rec);
}
if (rec) {
rec_sprintf(buf + strlen(buf), 1000, rec);
}
sprintf(buf + strlen(buf), "\n");
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
}
/************************************************************************* /*************************************************************************
Perform referential actions or checks when a parent row is deleted or updated Perform referential actions or checks when a parent row is deleted or updated
and the constraint had an ON DELETE or ON UPDATE condition which was not and the constraint had an ON DELETE or ON UPDATE condition which was not
@ -453,6 +558,8 @@ row_ins_foreign_check_on_constraint(
type is != 0 */ type is != 0 */
btr_pcur_t* pcur, /* in: cursor placed on a matching btr_pcur_t* pcur, /* in: cursor placed on a matching
index record in the child table */ index record in the child table */
dtuple_t* entry, /* in: index entry in the parent
table */
mtr_t* mtr) /* in: mtr holding the latch of pcur mtr_t* mtr) /* in: mtr holding the latch of pcur
page */ page */
{ {
@ -506,6 +613,10 @@ row_ins_foreign_check_on_constraint(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
row_ins_foreign_report_err((char*)"Trying to delete",
thr, foreign,
btr_pcur_get_rec(pcur), entry);
return(DB_ROW_IS_REFERENCED); return(DB_ROW_IS_REFERENCED);
} }
@ -523,6 +634,10 @@ row_ins_foreign_check_on_constraint(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
row_ins_foreign_report_err((char*)"Trying to update",
thr, foreign,
btr_pcur_get_rec(pcur), entry);
return(DB_ROW_IS_REFERENCED); return(DB_ROW_IS_REFERENCED);
} }
@ -563,14 +678,13 @@ row_ins_foreign_check_on_constraint(
} }
} }
/* We do not allow cyclic cascaded updating of the same /* We do not allow cyclic cascaded updating (DELETE is allowed,
table. Check that we are not updating the same table which but not UPDATE) of the same table, as this can lead to an infinite
is already being modified in this cascade chain. We have to cycle. Check that we are not updating the same table which is
check this because the modification of the indexes of a already being modified in this cascade chain. We have to check
'parent' table may still be incomplete, and we must avoid this also because the modification of the indexes of a 'parent'
seeing the indexes of the parent table in an inconsistent table may still be incomplete, and we must avoid seeing the indexes
state! In this way we also prevent possible infinite of the parent table in an inconsistent state! */
update loops caused by cyclic cascaded updates. */
if (!cascade->is_delete if (!cascade->is_delete
&& row_ins_cascade_ancestor_updates_table(cascade, table)) { && row_ins_cascade_ancestor_updates_table(cascade, table)) {
@ -580,6 +694,10 @@ row_ins_foreign_check_on_constraint(
err = DB_ROW_IS_REFERENCED; err = DB_ROW_IS_REFERENCED;
row_ins_foreign_report_err(
(char*)"Trying an update, possibly causing a cyclic cascaded update\n"
"in the child table,", thr, foreign, btr_pcur_get_rec(pcur), entry);
goto nonstandard_exit_func; goto nonstandard_exit_func;
} }
@ -809,11 +927,10 @@ row_ins_check_foreign_constraint(
dictionary cache if they exist at all */ dictionary cache if they exist at all */
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
table, else the referenced table */ table, else the referenced table */
dict_index_t* index __attribute__((unused)),/* in: index in table */
dtuple_t* entry, /* in: index entry for index */ dtuple_t* entry, /* in: index entry for index */
que_thr_t* thr) /* in: query thread */ que_thr_t* thr) /* in: query thread */
{ {
upd_node_t* upd_node; upd_node_t* upd_node;
dict_table_t* check_table; dict_table_t* check_table;
dict_index_t* check_index; dict_index_t* check_index;
ulint n_fields_cmp; ulint n_fields_cmp;
@ -824,6 +941,7 @@ row_ins_check_foreign_constraint(
int cmp; int cmp;
ulint err; ulint err;
ulint i; ulint i;
char* buf = dict_foreign_err_buf;
mtr_t mtr; mtr_t mtr;
run_again: run_again:
@ -884,6 +1002,25 @@ run_again:
if (check_table == NULL) { if (check_table == NULL) {
if (check_ref) { if (check_ref) {
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf), " Transaction:\n");
trx_print(buf + strlen(buf), thr_get_trx(thr));
sprintf(buf + strlen(buf),
"Foreign key constraint fails for table %.500s:\n",
foreign->foreign_table_name);
dict_print_info_on_foreign_key_in_create_format(
foreign, buf + strlen(buf));
sprintf(buf + strlen(buf),
"\nTrying to add to index %.500s tuple:\n", foreign->foreign_index->name);
dtuple_sprintf(buf + strlen(buf), 1000, entry);
sprintf(buf + strlen(buf),
"\nBut the parent table %.500s does not currently exist!\n",
foreign->referenced_table_name);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
return(DB_NO_REFERENCED_ROW); return(DB_NO_REFERENCED_ROW);
} }
@ -949,7 +1086,8 @@ run_again:
if (cmp == 0) { if (cmp == 0) {
if (rec_get_deleted_flag(rec)) { if (rec_get_deleted_flag(rec)) {
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, err = row_ins_set_shared_rec_lock(
LOCK_ORDINARY,
rec, check_index, thr); rec, check_index, thr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -989,13 +1127,17 @@ run_again:
err = err =
row_ins_foreign_check_on_constraint( row_ins_foreign_check_on_constraint(
thr, foreign, &pcur, &mtr); thr, foreign, &pcur, entry,
&mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
break; break;
} }
} else { } else {
row_ins_foreign_report_err(
(char*)"Trying to delete or update",
thr, foreign, rec, entry);
err = DB_ROW_IS_REFERENCED; err = DB_ROW_IS_REFERENCED;
break; break;
} }
@ -1012,6 +1154,8 @@ run_again:
if (check_ref) { if (check_ref) {
err = DB_NO_REFERENCED_ROW; err = DB_NO_REFERENCED_ROW;
row_ins_foreign_report_add_err(
thr, foreign, rec, entry);
} else { } else {
err = DB_SUCCESS; err = DB_SUCCESS;
} }
@ -1025,6 +1169,9 @@ next_rec:
if (!moved) { if (!moved) {
if (check_ref) { if (check_ref) {
rec = btr_pcur_get_rec(&pcur);
row_ins_foreign_report_add_err(
thr, foreign, rec, entry);
err = DB_NO_REFERENCED_ROW; err = DB_NO_REFERENCED_ROW;
} else { } else {
err = DB_SUCCESS; err = DB_SUCCESS;
@ -1100,7 +1247,7 @@ row_ins_check_foreign_constraints(
} }
err = row_ins_check_foreign_constraint(TRUE, foreign, err = row_ins_check_foreign_constraint(TRUE, foreign,
table, index, entry, thr); table, entry, thr);
if (got_s_lock) { if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx); row_mysql_unfreeze_data_dictionary(trx);
} }
@ -1116,6 +1263,48 @@ row_ins_check_foreign_constraints(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/*************************************************************************
Reports a UNIQUE key error to dict_unique_err_buf so that SHOW INNODB
STATUS can print it. */
static
void
row_ins_unique_report_err(
/*======================*/
que_thr_t* thr, /* in: query thread */
rec_t* rec, /* in: a record in the index */
dtuple_t* entry, /* in: index entry to insert in the index */
dict_index_t* index) /* in: index */
{
char* buf = dict_unique_err_buf;
/* The foreign err mutex protects also dict_unique_err_buf */
mutex_enter(&dict_foreign_err_mutex);
ut_sprintf_timestamp(buf);
sprintf(buf + strlen(buf), " Transaction:\n");
trx_print(buf + strlen(buf), thr_get_trx(thr));
sprintf(buf + strlen(buf),
"Unique key constraint fails for table %.500s.\n", index->table_name);
sprintf(buf + strlen(buf),
"Trying to add in index %.500s (%lu fields unique) tuple:\n", index->name,
dict_index_get_n_unique(index));
dtuple_sprintf(buf + strlen(buf), 1000, entry);
sprintf(buf + strlen(buf),
"\nBut there is already a record:\n");
rec_sprintf(buf + strlen(buf), 1000, rec);
sprintf(buf + strlen(buf), "\n");
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
}
/******************************************************************* /*******************************************************************
Checks if a unique key violation to rec would occur at the index entry Checks if a unique key violation to rec would occur at the index entry
insert. */ insert. */
@ -1246,10 +1435,8 @@ row_ins_scan_sec_index_for_duplicate(
if (cmp == 0) { if (cmp == 0) {
if (row_ins_dupl_error_with_rec(rec, entry, index)) { if (row_ins_dupl_error_with_rec(rec, entry, index)) {
/* printf("Duplicate key in index %s\n", row_ins_unique_report_err(thr, rec, entry,
index->name); index);
dtuple_print(entry); */
err = DB_DUPLICATE_KEY; err = DB_DUPLICATE_KEY;
thr_get_trx(thr)->error_info = index; thr_get_trx(thr)->error_info = index;
@ -1344,7 +1531,8 @@ row_ins_duplicate_error_in_clust(
if (row_ins_dupl_error_with_rec(rec, entry, if (row_ins_dupl_error_with_rec(rec, entry,
cursor->index)) { cursor->index)) {
trx->error_info = cursor->index; trx->error_info = cursor->index;
row_ins_unique_report_err(thr, rec, entry,
cursor->index);
return(DB_DUPLICATE_KEY); return(DB_DUPLICATE_KEY);
} }
} }
@ -1368,6 +1556,8 @@ row_ins_duplicate_error_in_clust(
cursor->index)) { cursor->index)) {
trx->error_info = cursor->index; trx->error_info = cursor->index;
row_ins_unique_report_err(thr, rec, entry,
cursor->index);
return(DB_DUPLICATE_KEY); return(DB_DUPLICATE_KEY);
} }
} }

View File

@ -289,6 +289,17 @@ handle_new_error:
"InnoDB: my.cnf and restart the database.\n"); "InnoDB: my.cnf and restart the database.\n");
exit(1); exit(1);
} else if (err == DB_CORRUPTION) {
fprintf(stderr,
"InnoDB: We detected index corruption in an InnoDB type table.\n"
"InnoDB: You have to dump + drop + reimport the table or, in\n"
"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");
} else { } else {
fprintf(stderr, "InnoDB: unknown error code %lu\n", err); fprintf(stderr, "InnoDB: unknown error code %lu\n", err);
ut_a(0); ut_a(0);
@ -337,6 +348,9 @@ row_create_prebuilt(
prebuilt->mysql_has_locked = FALSE; prebuilt->mysql_has_locked = FALSE;
prebuilt->index = NULL; prebuilt->index = NULL;
prebuilt->used_in_HANDLER = FALSE;
prebuilt->n_template = 0; prebuilt->n_template = 0;
prebuilt->mysql_template = NULL; prebuilt->mysql_template = NULL;
@ -1169,7 +1183,7 @@ row_mysql_recover_tmp_table(
return(DB_ERROR); return(DB_ERROR);
} }
if (0 == ut_memcmp(ptr, "/rsql", 5)) { if (0 == ut_memcmp(ptr, (char*)"/rsql", 5)) {
ptr++; ptr++;
*ptr = '#'; *ptr = '#';
@ -1294,9 +1308,9 @@ row_create_table_for_mysql(
trx->op_info = (char *) "creating table"; trx->op_info = (char *) "creating table";
if (0 == ut_strcmp(table->name, "mysql/host") if (0 == ut_strcmp(table->name, (char*)"mysql/host")
|| 0 == ut_strcmp(table->name, "mysql/user") || 0 == ut_strcmp(table->name, (char*)"mysql/user")
|| 0 == ut_strcmp(table->name, "mysql/db")) { || 0 == ut_strcmp(table->name, (char*)"mysql/db")) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n" "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n"
@ -1316,7 +1330,7 @@ row_create_table_for_mysql(
if (namelen >= keywordlen if (namelen >= keywordlen
&& 0 == ut_memcmp(table->name + namelen - keywordlen, && 0 == ut_memcmp(table->name + namelen - keywordlen,
"_recover_innodb_tmp_table", keywordlen)) { (char*)"_recover_innodb_tmp_table", keywordlen)) {
/* MySQL prevents accessing of tables whose name begins /* MySQL prevents accessing of tables whose name begins
with #sql, that is temporary tables. If mysqld crashes in with #sql, that is temporary tables. If mysqld crashes in
@ -1384,7 +1398,7 @@ row_create_table_for_mysql(
if (namelen >= keywordlen if (namelen >= keywordlen
&& 0 == ut_memcmp(table->name + namelen - keywordlen, && 0 == ut_memcmp(table->name + namelen - keywordlen,
"innodb_mem_validate", keywordlen)) { (char*)"innodb_mem_validate", keywordlen)) {
/* We define here a debugging feature intended for /* We define here a debugging feature intended for
developers */ developers */
@ -1494,7 +1508,7 @@ row_create_index_for_mysql(
if (namelen >= keywordlen if (namelen >= keywordlen
&& 0 == ut_memcmp( && 0 == ut_memcmp(
index->table_name + namelen - keywordlen, index->table_name + namelen - keywordlen,
"_recover_innodb_tmp_table", keywordlen)) { (char*)"_recover_innodb_tmp_table", keywordlen)) {
return(DB_SUCCESS); return(DB_SUCCESS);
} }
@ -1599,7 +1613,7 @@ row_table_add_foreign_constraints(
if (namelen >= keywordlen if (namelen >= keywordlen
&& 0 == ut_memcmp( && 0 == ut_memcmp(
name + namelen - keywordlen, name + namelen - keywordlen,
"_recover_innodb_tmp_table", keywordlen)) { (char*)"_recover_innodb_tmp_table", keywordlen)) {
return(DB_SUCCESS); return(DB_SUCCESS);
} }
@ -1663,7 +1677,7 @@ row_drop_table_for_mysql_in_background(
the InnoDB data dictionary get out-of-sync if the user runs the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */ with innodb_flush_log_at_trx_commit = 0 */
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
@ -1821,7 +1835,6 @@ row_drop_table_for_mysql(
ulint len; ulint len;
ulint namelen; ulint namelen;
ulint keywordlen; ulint keywordlen;
ulint rounds = 0;
ibool locked_dictionary = FALSE; ibool locked_dictionary = FALSE;
char buf[10000]; char buf[10000];
@ -2168,7 +2181,7 @@ row_is_mysql_tmp_table_name(
ulint i; ulint i;
for (i = 0; i <= ut_strlen(name) - 5; i++) { for (i = 0; i <= ut_strlen(name) - 5; i++) {
if (ut_memcmp(name + i, "/#sql", 5) == 0) { if (ut_memcmp(name + i, (char*)"/#sql", 5) == 0) {
return(TRUE); return(TRUE);
} }
@ -2190,12 +2203,16 @@ row_rename_table_for_mysql(
{ {
dict_table_t* table; dict_table_t* table;
que_thr_t* thr; que_thr_t* thr;
que_t* graph; que_t* graph = NULL;
ulint err; ulint err;
char* str1; char* str1;
char* str2; char* str2;
char* str3; char* str3;
mem_heap_t* heap = NULL;
char** constraints_to_drop = NULL;
ulint n_constraints_to_drop = 0;
ulint len; ulint len;
ulint i;
char buf[10000]; char buf[10000];
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
@ -2214,9 +2231,9 @@ row_rename_table_for_mysql(
return(DB_ERROR); return(DB_ERROR);
} }
if (0 == ut_strcmp(new_name, "mysql/host") if (0 == ut_strcmp(new_name, (char*)"mysql/host")
|| 0 == ut_strcmp(new_name, "mysql/user") || 0 == ut_strcmp(new_name, (char*)"mysql/user")
|| 0 == ut_strcmp(new_name, "mysql/db")) { || 0 == ut_strcmp(new_name, (char*)"mysql/db")) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n" "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n"
@ -2230,6 +2247,19 @@ row_rename_table_for_mysql(
trx->op_info = (char *) "renaming table"; trx->op_info = (char *) "renaming table";
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
row_mysql_lock_data_dictionary(trx);
table = dict_table_get_low(old_name);
if (!table) {
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
}
str1 = (char *) str1 = (char *)
"PROCEDURE RENAME_TABLE_PROC () IS\n" "PROCEDURE RENAME_TABLE_PROC () IS\n"
"new_table_name CHAR;\n" "new_table_name CHAR;\n"
@ -2242,14 +2272,43 @@ row_rename_table_for_mysql(
if (row_is_mysql_tmp_table_name(new_name)) { if (row_is_mysql_tmp_table_name(new_name)) {
/* We want to preserve the original foreign key /* MySQL is doing an ALTER TABLE command and it renames the
constraint definitions despite the name change */ original table to a temporary table name. We want to preserve
the original foreign key constraint definitions despite the
name change. An exception is those constraints for which
the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
str3 = (char*) heap = mem_heap_create(100);
"';\n"
"UPDATE SYS_TABLES SET NAME = new_table_name\n" err = dict_foreign_parse_drop_constraints(heap, trx,
"WHERE NAME = old_table_name;\n" table,
"END;\n"; &n_constraints_to_drop,
&constraints_to_drop);
if (err != DB_SUCCESS) {
goto funct_exit;
}
str3 = mem_heap_alloc(heap,
1000 + 500 * n_constraints_to_drop);
*str3 = '\0';
sprintf(str3,
"';\n"
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
"WHERE NAME = old_table_name;\n");
for (i = 0; i < n_constraints_to_drop; i++) {
sprintf(str3 + strlen(str3),
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s';\n"
"DELETE FROM SYS_FOREIGN WHERE ID = '%s';\n",
constraints_to_drop[i],
constraints_to_drop[i]);
}
sprintf(str3 + strlen(str3),
"END;\n");
ut_a(strlen(str3) < 1000 + 500 * n_constraints_to_drop);
} else { } else {
str3 = (char*) str3 = (char*)
"';\n" "';\n"
@ -2280,13 +2339,6 @@ row_rename_table_for_mysql(
ut_memcpy(buf + len, str3, ut_strlen(str3) + 1); ut_memcpy(buf + len, str3, ut_strlen(str3) + 1);
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
row_mysql_lock_data_dictionary(trx);
table = dict_table_get_low(old_name);
graph = pars_sql(buf); graph = pars_sql(buf);
ut_a(graph); ut_a(graph);
@ -2296,12 +2348,6 @@ row_rename_table_for_mysql(
graph->fork_type = QUE_FORK_MYSQL_INTERFACE; graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
if (!table) {
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
}
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0)); ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
que_run_threads(thr); que_run_threads(thr);
@ -2342,6 +2388,13 @@ row_rename_table_for_mysql(
if (row_is_mysql_tmp_table_name(old_name)) { if (row_is_mysql_tmp_table_name(old_name)) {
/* MySQL is doing an ALTER TABLE command and it
renames the created temporary table to the name
of the original table. In the ALTER TABLE we maybe
created some FOREIGN KEY constraints for the temporary
table. But we want to load also the foreign key
constraint definitions for the original table name. */
err = dict_load_foreigns(new_name); err = dict_load_foreigns(new_name);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -2367,7 +2420,13 @@ row_rename_table_for_mysql(
funct_exit: funct_exit:
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
que_graph_free(graph); if (graph) {
que_graph_free(graph);
}
if (heap) {
mem_heap_free(heap);
}
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);

View File

@ -2619,6 +2619,24 @@ row_search_for_mysql(
printf("N tables locked %lu\n", trx->mysql_n_tables_locked); printf("N tables locked %lu\n", trx->mysql_n_tables_locked);
*/ */
/*-------------------------------------------------------------*/
/* PHASE 0: Release a possible s-latch we are holding on the
adaptive hash index latch if there is someone waiting behind */
if (trx->has_search_latch
&& btr_search_latch.writer != RW_LOCK_NOT_LOCKED) {
/* There is an x-latch request on the adaptive hash index:
release the s-latch to reduce starvation and wait for
BTR_SEA_TIMEOUT rounds before trying to keep it again over
calls from MySQL */
rw_lock_s_unlock(&btr_search_latch);
trx->has_search_latch = FALSE;
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
}
/*-------------------------------------------------------------*/ /*-------------------------------------------------------------*/
/* PHASE 1: Try to pop the row from the prefetch cache */ /* PHASE 1: Try to pop the row from the prefetch cache */
@ -2685,16 +2703,31 @@ row_search_for_mysql(
mode = pcur->search_mode; mode = pcur->search_mode;
} }
if ((direction == ROW_SEL_NEXT || direction == ROW_SEL_PREV)
&& pcur->old_stored != BTR_PCUR_OLD_STORED) {
/* MySQL sometimes seems to do fetch next or fetch prev even
if the search condition is unique; this can, for example,
happen with the HANDLER commands; we do not always store the
pcur position in this case, so we cannot restore cursor
position, and must return immediately */
/* printf("%s record not found 1\n", index->name); */
trx->op_info = (char *) "";
return(DB_RECORD_NOT_FOUND);
}
mtr_start(&mtr); mtr_start(&mtr);
/* In a search where at most one record in the index may match, we /* In a search where at most one record in the index may match, we
can use a LOCK_REC_NOT_GAP type record lock when locking a non-delete can use a LOCK_REC_NOT_GAP type record lock when locking a non-delete-
marked matching record. marked matching record.
Note that in a unique secondary index there may be different delete Note that in a unique secondary index there may be different delete-
marked versions of a record where only the primary key values differ: marked versions of a record where only the primary key values differ:
thus in a secondary index we must use next-key locks when locking thus in a secondary index we must use next-key locks when locking
delete marked records. */ delete-marked records. */
if (match_mode == ROW_SEL_EXACT if (match_mode == ROW_SEL_EXACT
&& index->type & DICT_UNIQUE && index->type & DICT_UNIQUE
@ -2715,25 +2748,9 @@ row_search_for_mysql(
if (unique_search if (unique_search
&& index->type & DICT_CLUSTERED && index->type & DICT_CLUSTERED
&& !prebuilt->templ_contains_blob && !prebuilt->templ_contains_blob
&& !prebuilt->used_in_HANDLER
&& (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) { && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) {
if (direction == ROW_SEL_NEXT) {
/* MySQL sometimes seems to do fetch next even
if the search condition is unique; we do not store
pcur position in this case, so we cannot
restore cursor position, and must return
immediately */
mtr_commit(&mtr);
/* printf("%s record not found 1\n", index->name); */
trx->op_info = (char *) "";
return(DB_RECORD_NOT_FOUND);
}
ut_a(direction == 0); /* We cannot do fetch prev, as we have
not stored the cursor position */
mode = PAGE_CUR_GE; mode = PAGE_CUR_GE;
unique_search_from_clust_index = TRUE; unique_search_from_clust_index = TRUE;
@ -2755,22 +2772,6 @@ row_search_for_mysql(
and if we try that, we can deadlock on the adaptive and if we try that, we can deadlock on the adaptive
hash index semaphore! */ hash index semaphore! */
if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED) {
/* There is an x-latch request: release
a possible s-latch to reduce starvation
and wait for BTR_SEA_TIMEOUT rounds before
trying to keep it again over calls from
MySQL */
if (trx->has_search_latch) {
rw_lock_s_unlock(&btr_search_latch);
trx->has_search_latch = FALSE;
}
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
goto no_shortcut;
}
#ifndef UNIV_SEARCH_DEBUG #ifndef UNIV_SEARCH_DEBUG
if (!trx->has_search_latch) { if (!trx->has_search_latch) {
rw_lock_s_lock(&btr_search_latch); rw_lock_s_lock(&btr_search_latch);
@ -2806,6 +2807,10 @@ row_search_for_mysql(
} }
trx->op_info = (char *) ""; trx->op_info = (char *) "";
/* NOTE that we do NOT store the cursor
position */
return(DB_SUCCESS); return(DB_SUCCESS);
} else if (shortcut == SEL_EXHAUSTED) { } else if (shortcut == SEL_EXHAUSTED) {
@ -2825,6 +2830,10 @@ row_search_for_mysql(
} }
trx->op_info = (char *) ""; trx->op_info = (char *) "";
/* NOTE that we do NOT store the cursor
position */
return(DB_RECORD_NOT_FOUND); return(DB_RECORD_NOT_FOUND);
} }
@ -2833,7 +2842,6 @@ row_search_for_mysql(
} }
} }
no_shortcut:
/*-------------------------------------------------------------*/ /*-------------------------------------------------------------*/
/* PHASE 3: Open or restore index cursor position */ /* PHASE 3: Open or restore index cursor position */
@ -3206,6 +3214,7 @@ rec_loop:
&& prebuilt->select_lock_type == LOCK_NONE && prebuilt->select_lock_type == LOCK_NONE
&& !prebuilt->templ_contains_blob && !prebuilt->templ_contains_blob
&& !prebuilt->clust_index_was_generated && !prebuilt->clust_index_was_generated
&& !prebuilt->used_in_HANDLER
&& prebuilt->template_type && prebuilt->template_type
!= ROW_MYSQL_DUMMY_TEMPLATE) { != ROW_MYSQL_DUMMY_TEMPLATE) {
@ -3214,7 +3223,9 @@ rec_loop:
update, that is why we require ...lock_type == LOCK_NONE. update, that is why we require ...lock_type == LOCK_NONE.
Since we keep space in prebuilt only for the BLOBs of Since we keep space in prebuilt only for the BLOBs of
a single row, we cannot cache rows in the case there a single row, we cannot cache rows in the case there
are BLOBs in the fields to be fetched. */ are BLOBs in the fields to be fetched. In HANDLER we do
not cache rows because there the cursor is a scrollable
cursor. */
row_sel_push_cache_row_for_mysql(prebuilt, rec); row_sel_push_cache_row_for_mysql(prebuilt, rec);
@ -3243,11 +3254,16 @@ rec_loop:
} }
} }
got_row: got_row:
/* TODO: should we in every case store the cursor position, even /* We have an optimization to save CPU time: if this is a consistent
if this is just a join, for example? */ read on a unique condition on the clustered index, then we do not
store the pcur position, because any fetch next or prev will anyway
return 'end of file'. An exception is the MySQL HANDLER command
where the user can move the cursor with PREV or NEXT even after
a unique search. */
if (!unique_search_from_clust_index if (!unique_search_from_clust_index
|| prebuilt->select_lock_type == LOCK_X) { || prebuilt->select_lock_type == LOCK_X
|| prebuilt->used_in_HANDLER) {
/* Inside an update always store the cursor position */ /* Inside an update always store the cursor position */

View File

@ -218,7 +218,7 @@ row_upd_check_references_constraints(
being dropped while the check is running. */ being dropped while the check is running. */
err = row_ins_check_foreign_constraint(FALSE, foreign, err = row_ins_check_foreign_constraint(FALSE, foreign,
table, index, entry, thr); table, entry, thr);
if (foreign->foreign_table) { if (foreign->foreign_table) {
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libsrv.a noinst_LIBRARIES = libsrv.a
libsrv_a_SOURCES = srv0srv.c srv0que.c srv0start.c libsrv_a_SOURCES = srv0srv.c srv0que.c srv0start.c

View File

@ -162,6 +162,13 @@ char* srv_file_flush_method_str = NULL;
ulint srv_unix_file_flush_method = SRV_UNIX_FDATASYNC; ulint srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
ulint srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; ulint srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
/* The InnoDB main thread tries to keep the ratio of modified pages
in the buffer pool to all database pages in the buffer pool smaller than
the following number. But it is not guaranteed that the value stays below
that during a time of heavy update/insert activity. */
ulint srv_max_buf_pool_modified_pct = 90;
/* If the following is != 0 we do not allow inserts etc. This protects /* If the following is != 0 we do not allow inserts etc. This protects
the user from forgetting the innodb_force_recovery keyword to my.cnf */ the user from forgetting the innodb_force_recovery keyword to my.cnf */
@ -1881,11 +1888,11 @@ retry:
/* Go to wait for the event; when a thread leaves InnoDB it will /* Go to wait for the event; when a thread leaves InnoDB it will
release this thread */ release this thread */
trx->op_info = "waiting in InnoDB queue"; trx->op_info = (char*)"waiting in InnoDB queue";
os_event_wait(slot->event); os_event_wait(slot->event);
trx->op_info = ""; trx->op_info = (char*)"";
os_fast_mutex_lock(&srv_conc_mutex); os_fast_mutex_lock(&srv_conc_mutex);
@ -2368,9 +2375,32 @@ srv_sprintf_innodb_monitor(
buf = buf + strlen(buf); buf = buf + strlen(buf);
ut_a(buf < buf_end + 1500); ut_a(buf < buf_end + 1500);
buf += sprintf(buf, "------------\n" if (*dict_foreign_err_buf != '\0') {
"TRANSACTIONS\n" buf += sprintf(buf,
"------------\n"); "------------------------\n"
"LATEST FOREIGN KEY ERROR\n"
"------------------------\n");
if (buf_end - buf > 6000) {
buf+= sprintf(buf, "%.4000s", dict_foreign_err_buf);
}
}
ut_a(buf < buf_end + 1500);
if (*dict_unique_err_buf != '\0') {
buf += sprintf(buf,
"---------------------------------------------------------------\n"
"LATEST UNIQUE KEY ERROR (is masked in REPLACE or INSERT IGNORE)\n"
"---------------------------------------------------------------\n");
if (buf_end - buf > 6000) {
buf+= sprintf(buf, "%.4000s", dict_unique_err_buf);
}
}
ut_a(buf < buf_end + 1500);
lock_print_info(buf, buf_end); lock_print_info(buf, buf_end);
buf = buf + strlen(buf); buf = buf + strlen(buf);
@ -2777,6 +2807,7 @@ srv_master_thread(
ulint n_ios_old; ulint n_ios_old;
ulint n_ios_very_old; ulint n_ios_very_old;
ulint n_pend_ios; ulint n_pend_ios;
ibool skip_sleep = FALSE;
ulint i; ulint i;
UT_NOT_USED(arg); UT_NOT_USED(arg);
@ -2794,24 +2825,42 @@ srv_master_thread(
os_event_set(srv_sys->operational); os_event_set(srv_sys->operational);
loop: loop:
/*****************************************************************/
/* ---- When there is database activity by users, we cycle in this
loop */
srv_main_thread_op_info = (char*) "reserving kernel mutex"; srv_main_thread_op_info = (char*) "reserving kernel mutex";
n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written; + buf_pool->n_pages_written;
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
/* Store the user activity counter at the start of this loop */
old_activity_count = srv_activity_count; old_activity_count = srv_activity_count;
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
/* We run purge and a batch of ibuf_contract every 10 seconds, even if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
if the server were active: */
goto suspend_thread;
}
/* ---- We run the following loop approximately once per second
when there is database activity */
skip_sleep = FALSE;
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written; + buf_pool->n_pages_written;
srv_main_thread_op_info = (char*)"sleeping"; srv_main_thread_op_info = (char*)"sleeping";
os_thread_sleep(1000000);
if (!skip_sleep) {
os_thread_sleep(1000000);
}
skip_sleep = FALSE;
/* ALTER TABLE in MySQL requires on Unix that the table handler /* ALTER TABLE in MySQL requires on Unix that the table handler
can drop tables lazily after there no longer are SELECT can drop tables lazily after there no longer are SELECT
@ -2824,9 +2873,9 @@ loop:
srv_main_thread_op_info = (char*)""; srv_main_thread_op_info = (char*)"";
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) { if (srv_fast_shutdown && srv_shutdown_state > 0) {
goto suspend_thread; goto background_loop;
} }
/* We flush the log once in a second even if no commit /* We flush the log once in a second even if no commit
@ -2834,10 +2883,9 @@ loop:
at transaction commit */ at transaction commit */
srv_main_thread_op_info = (char*)"flushing log"; srv_main_thread_op_info = (char*)"flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
log_flush_to_disk();
/* If there were less than 10 i/os during the /* If there were less than 5 i/os during the
one second sleep, we assume that there is free one second sleep, we assume that there is free
disk i/o capacity available, and it makes sense to disk i/o capacity available, and it makes sense to
do an insert buffer merge. */ do an insert buffer merge. */
@ -2846,35 +2894,45 @@ loop:
+ log_sys->n_pending_writes; + log_sys->n_pending_writes;
n_ios = log_sys->n_log_ios + buf_pool->n_pages_read n_ios = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written; + buf_pool->n_pages_written;
if (n_pend_ios < 3 && (n_ios - n_ios_old < 10)) { if (n_pend_ios < 3 && (n_ios - n_ios_old < 5)) {
srv_main_thread_op_info = srv_main_thread_op_info =
(char*)"doing insert buffer merge"; (char*)"doing insert buffer merge";
ibuf_contract_for_n_pages(TRUE, 5); ibuf_contract_for_n_pages(TRUE, 5);
srv_main_thread_op_info = srv_main_thread_op_info =
(char*)"flushing log"; (char*)"flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP,
log_flush_to_disk(); TRUE);
} }
if (srv_fast_shutdown && srv_shutdown_state > 0) { if (buf_get_modified_ratio_pct() >
srv_max_buf_pool_modified_pct) {
goto background_loop; /* Try to keep the number of modified pages in the
buffer pool under the limit wished by the user */
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100,
ut_dulint_max);
/* If we had to do the flush, it may have taken
even more than 1 second, and also, there may be more
to flush. Do not sleep 1 second during the next
iteration of this loop. */
skip_sleep = TRUE;
} }
if (srv_activity_count == old_activity_count) { if (srv_activity_count == old_activity_count) {
if (srv_print_thread_releases) { /* There is no user activity at the moment, go to
printf("Master thread wakes up!\n"); the background loop */
}
goto background_loop; goto background_loop;
} }
} }
if (srv_print_thread_releases) { /* ---- We perform the following code approximately once per
printf("Master thread wakes up!\n"); 10 seconds when there is database activity */
}
#ifdef MEM_PERIODIC_CHECK #ifdef MEM_PERIODIC_CHECK
/* Check magic numbers of every allocated mem block once in 10 /* Check magic numbers of every allocated mem block once in 10
@ -2883,7 +2941,7 @@ loop:
#endif #endif
/* If there were less than 200 i/os during the 10 second period, /* If there were less than 200 i/os during the 10 second period,
we assume that there is free disk i/o capacity available, and it we assume that there is free disk i/o capacity available, and it
makes sense to do a buffer pool flush. */ makes sense to flush 100 pages. */
n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes;
n_ios = log_sys->n_log_ios + buf_pool->n_pages_read n_ios = log_sys->n_log_ios + buf_pool->n_pages_read
@ -2891,11 +2949,10 @@ loop:
if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) { if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) {
srv_main_thread_op_info = (char*) "flushing buffer pool pages"; srv_main_thread_op_info = (char*) "flushing buffer pool pages";
buf_flush_batch(BUF_FLUSH_LIST, 50, ut_dulint_max); buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
srv_main_thread_op_info = (char*) "flushing log"; srv_main_thread_op_info = (char*) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
log_flush_to_disk();
} }
/* We run a batch of insert buffer merge every 10 seconds, /* We run a batch of insert buffer merge every 10 seconds,
@ -2905,8 +2962,7 @@ loop:
ibuf_contract_for_n_pages(TRUE, 5); ibuf_contract_for_n_pages(TRUE, 5);
srv_main_thread_op_info = (char*)"flushing log"; srv_main_thread_op_info = (char*)"flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
log_flush_to_disk();
/* We run a full purge every 10 seconds, even if the server /* We run a full purge every 10 seconds, even if the server
were active */ were active */
@ -2930,27 +2986,32 @@ loop:
if (difftime(current_time, last_flush_time) > 1) { if (difftime(current_time, last_flush_time) > 1) {
srv_main_thread_op_info = (char*) "flushing log"; srv_main_thread_op_info = (char*) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP,
log_flush_to_disk(); TRUE);
last_flush_time = current_time; last_flush_time = current_time;
} }
} }
background_loop:
/* In this loop we run background operations when the server
is quiet and we also come here about once in 10 seconds */
srv_main_thread_op_info = (char*)"doing background drop tables";
n_tables_to_drop = row_drop_tables_for_mysql_in_background();
srv_main_thread_op_info = (char*)"";
srv_main_thread_op_info = (char*)"flushing buffer pool pages"; srv_main_thread_op_info = (char*)"flushing buffer pool pages";
/* Flush a few oldest pages to make the checkpoint younger */ /* Flush a few oldest pages to make a new checkpoint younger */
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 10, ut_dulint_max); if (buf_get_modified_ratio_pct() > 70) {
/* If there are lots of modified pages in the buffer pool
(> 70 %), we assume we can afford reserving the disk(s) for
the time it requires to flush 100 pages */
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100,
ut_dulint_max);
} else {
/* Otherwise, we only flush a small number of pages so that
we do not unnecessarily use much disk i/o capacity from
other work */
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 10,
ut_dulint_max);
}
srv_main_thread_op_info = (char*)"making checkpoint"; srv_main_thread_op_info = (char*)"making checkpoint";
@ -2961,16 +3022,31 @@ background_loop:
srv_main_thread_op_info = (char*)"reserving kernel mutex"; srv_main_thread_op_info = (char*)"reserving kernel mutex";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
/* ---- When there is database activity, we jump from here back to
the start of loop */
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
goto loop; goto loop;
} }
old_activity_count = srv_activity_count;
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
/* If the database is quiet, we enter the background loop */
/*****************************************************************/
background_loop:
/* ---- In this loop we run background operations when the server
is quiet from user activity */
/* The server has been quiet for a while: start running background /* The server has been quiet for a while: start running background
operations */ operations */
srv_main_thread_op_info = (char*)"doing background drop tables";
n_tables_to_drop = row_drop_tables_for_mysql_in_background();
srv_main_thread_op_info = (char*)"purging"; srv_main_thread_op_info = (char*)"purging";
if (srv_fast_shutdown && srv_shutdown_state > 0) { if (srv_fast_shutdown && srv_shutdown_state > 0) {
@ -3005,6 +3081,7 @@ background_loop:
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
flush_loop:
srv_main_thread_op_info = (char*)"flushing buffer pool pages"; srv_main_thread_op_info = (char*)"flushing buffer pool pages";
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
@ -3017,13 +3094,22 @@ background_loop:
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
srv_main_thread_op_info = (char*) "waiting for buffer pool flush to end"; srv_main_thread_op_info =
(char*) "waiting for buffer pool flush to end";
buf_flush_wait_batch_end(BUF_FLUSH_LIST); buf_flush_wait_batch_end(BUF_FLUSH_LIST);
srv_main_thread_op_info = (char*)"making checkpoint"; srv_main_thread_op_info = (char*)"making checkpoint";
log_checkpoint(TRUE, FALSE); log_checkpoint(TRUE, FALSE);
if (buf_get_modified_ratio_pct() > srv_max_buf_pool_modified_pct) {
/* Try to keep the number of modified pages in the
buffer pool under the limit wished by the user */
goto flush_loop;
}
srv_main_thread_op_info = (char*)"reserving kernel mutex"; srv_main_thread_op_info = (char*)"reserving kernel mutex";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
@ -3038,15 +3124,24 @@ background_loop:
log_archive_do(FALSE, &n_bytes_archived); log_archive_do(FALSE, &n_bytes_archived);
/* Keep looping in the background loop if still work to do */
if (srv_fast_shutdown && srv_shutdown_state > 0) { if (srv_fast_shutdown && srv_shutdown_state > 0) {
if (n_tables_to_drop + n_pages_flushed if (n_tables_to_drop + n_pages_flushed
+ n_bytes_archived != 0) { + n_bytes_archived != 0) {
/* If we are doing a fast shutdown (= the default)
we do not do purge or insert buffer merge. But we
flush the buffer pool completely to disk. */
goto background_loop; goto background_loop;
} }
} else if (n_tables_to_drop + } else if (n_tables_to_drop +
n_pages_purged + n_bytes_merged + n_pages_flushed n_pages_purged + n_bytes_merged + n_pages_flushed
+ n_bytes_archived != 0) { + n_bytes_archived != 0) {
/* In a 'slow' shutdown we run purge and the insert buffer
merge to completion */
goto background_loop; goto background_loop;
} }
@ -3078,6 +3173,9 @@ suspend_thread:
os_event_wait(event); os_event_wait(event);
/* When there is user activity, InnoDB will set the event and the main
thread goes back to loop: */
goto loop; goto loop;
#ifndef __WIN__ #ifndef __WIN__

View File

@ -161,13 +161,13 @@ srv_parse_data_file_paths_and_sizes(
} }
if (strlen(str) >= ut_strlen(":autoextend") if (strlen(str) >= ut_strlen(":autoextend")
&& 0 == ut_memcmp(str, ":autoextend", && 0 == ut_memcmp(str, (char*)":autoextend",
ut_strlen(":autoextend"))) { ut_strlen(":autoextend"))) {
str += ut_strlen(":autoextend"); str += ut_strlen(":autoextend");
if (strlen(str) >= ut_strlen(":max:") if (strlen(str) >= ut_strlen(":max:")
&& 0 == ut_memcmp(str, ":max:", && 0 == ut_memcmp(str, (char*)":max:",
ut_strlen(":max:"))) { ut_strlen(":max:"))) {
str += ut_strlen(":max:"); str += ut_strlen(":max:");
@ -265,7 +265,7 @@ srv_parse_data_file_paths_and_sizes(
(*data_file_sizes)[i] = size; (*data_file_sizes)[i] = size;
if (strlen(str) >= ut_strlen(":autoextend") if (strlen(str) >= ut_strlen(":autoextend")
&& 0 == ut_memcmp(str, ":autoextend", && 0 == ut_memcmp(str, (char*)":autoextend",
ut_strlen(":autoextend"))) { ut_strlen(":autoextend"))) {
*is_auto_extending = TRUE; *is_auto_extending = TRUE;
@ -273,7 +273,7 @@ srv_parse_data_file_paths_and_sizes(
str += ut_strlen(":autoextend"); str += ut_strlen(":autoextend");
if (strlen(str) >= ut_strlen(":max:") if (strlen(str) >= ut_strlen(":max:")
&& 0 == ut_memcmp(str, ":max:", && 0 == ut_memcmp(str, (char*)":max:",
ut_strlen(":max:"))) { ut_strlen(":max:"))) {
str += ut_strlen(":max:"); str += ut_strlen(":max:");
@ -864,6 +864,7 @@ open_or_create_data_files(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
#ifdef notdefined
/********************************************************************* /*********************************************************************
This thread is used to measure contention of latches. */ This thread is used to measure contention of latches. */
static static
@ -935,6 +936,7 @@ test_measure_cont(
return(0); return(0);
} }
#endif
/******************************************************************** /********************************************************************
Starts InnoDB and creates a new database if database files Starts InnoDB and creates a new database if database files
@ -1053,20 +1055,24 @@ innobase_start_or_create_for_mysql(void)
srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
#ifndef __WIN__ #ifndef __WIN__
} else if (0 == ut_strcmp(srv_file_flush_method_str, "fdatasync")) { } else if (0 == ut_strcmp(srv_file_flush_method_str,
(char*)"fdatasync")) {
srv_unix_file_flush_method = SRV_UNIX_FDATASYNC; srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
} else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DSYNC")) { } else if (0 == ut_strcmp(srv_file_flush_method_str,
(char*)"O_DSYNC")) {
srv_unix_file_flush_method = SRV_UNIX_O_DSYNC; srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;
} else if (0 == ut_strcmp(srv_file_flush_method_str, } else if (0 == ut_strcmp(srv_file_flush_method_str,
"littlesync")) { (char*)"littlesync")) {
srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC; srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
} else if (0 == ut_strcmp(srv_file_flush_method_str, "nosync")) { } else if (0 == ut_strcmp(srv_file_flush_method_str,
(char*)"nosync")) {
srv_unix_file_flush_method = SRV_UNIX_NOSYNC; srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
#else #else
} else if (0 == ut_strcmp(srv_file_flush_method_str, "normal")) { } else if (0 == ut_strcmp(srv_file_flush_method_str,
(char*)"normal")) {
srv_win_file_flush_method = SRV_WIN_IO_NORMAL; srv_win_file_flush_method = SRV_WIN_IO_NORMAL;
os_aio_use_native_aio = FALSE; os_aio_use_native_aio = FALSE;
@ -1196,7 +1202,14 @@ innobase_start_or_create_for_mysql(void)
&max_flushed_lsn, &max_arch_log_no, &max_flushed_lsn, &max_arch_log_no,
&sum_of_new_sizes); &sum_of_new_sizes);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
fprintf(stderr, "InnoDB: Could not open data files\n"); fprintf(stderr,
"InnoDB: Could not open or create data files.\n"
"InnoDB: If you tried to add new data files, and it failed here,\n"
"InnoDB: you should now edit innodb_data_file_path in my.cnf back\n"
"InnoDB: to what it was, and remove the new ibdata files InnoDB created\n"
"InnoDB: in this failed attempt. InnoDB only wrote those files full of\n"
"InnoDB: zeros, but did not yet use them in any way. But be careful: do not\n"
"InnoDB: remove old data files which contain your precious data!\n");
return((int) err); return((int) err);
} }
@ -1207,7 +1220,10 @@ innobase_start_or_create_for_mysql(void)
and restore them from the doublewrite buffer if and restore them from the doublewrite buffer if
possible */ possible */
trx_sys_doublewrite_restore_corrupt_pages(); if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
trx_sys_doublewrite_restore_corrupt_pages();
}
} }
srv_normalize_path_for_win(srv_arch_dir); srv_normalize_path_for_win(srv_arch_dir);
@ -1480,6 +1496,8 @@ innobase_start_or_create_for_mysql(void)
srv_force_recovery); srv_force_recovery);
} }
fflush(stderr);
return((int) DB_SUCCESS); return((int) DB_SUCCESS);
} }

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libsync.a noinst_LIBRARIES = libsync.a
libsync_a_SOURCES = sync0arr.c sync0ipm.c sync0rw.c sync0sync.c libsync_a_SOURCES = sync0arr.c sync0ipm.c sync0rw.c sync0sync.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libthr.a noinst_LIBRARIES = libthr.a
libthr_a_SOURCES = thr0loc.c libthr_a_SOURCES = thr0loc.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libtrx.a noinst_LIBRARIES = libtrx.a
libtrx_a_SOURCES = trx0purge.c trx0rec.c trx0roll.c trx0rseg.c\ libtrx_a_SOURCES = trx0purge.c trx0rec.c trx0roll.c trx0rseg.c\
trx0sys.c trx0trx.c trx0undo.c trx0sys.c trx0trx.c trx0undo.c

View File

@ -340,7 +340,6 @@ trx_sys_doublewrite_restore_corrupt_pages(void)
/* It is an unwritten doublewrite buffer page: /* It is an unwritten doublewrite buffer page:
do nothing */ do nothing */
} else { } else {
/* Read in the actual page from the data files */ /* Read in the actual page from the data files */
@ -357,9 +356,19 @@ trx_sys_doublewrite_restore_corrupt_pages(void)
"InnoDB: Trying to recover it from the doublewrite buffer.\n"); "InnoDB: Trying to recover it from the doublewrite buffer.\n");
if (buf_page_is_corrupted(page)) { if (buf_page_is_corrupted(page)) {
fprintf(stderr,
"InnoDB: Dump of the page:\n");
buf_page_print(read_buf);
fprintf(stderr,
"InnoDB: Dump of corresponding page in doublewrite buffer:\n");
buf_page_print(page);
fprintf(stderr, fprintf(stderr,
"InnoDB: Also the page in the doublewrite buffer is corrupt.\n" "InnoDB: Also the page in the doublewrite buffer is corrupt.\n"
"InnoDB: Cannot continue operation.\n"); "InnoDB: Cannot continue operation.\n"
"InnoDB: You can try to recover the database with the my.cnf\n"
"InnoDB: option:\n"
"InnoDB: set-variable=innodb_force_recovery=6\n");
exit(1); exit(1);
} }

View File

@ -89,6 +89,8 @@ trx_create(
trx->check_foreigns = TRUE; trx->check_foreigns = TRUE;
trx->check_unique_secondary = TRUE; trx->check_unique_secondary = TRUE;
trx->flush_log_later = FALSE;
trx->dict_operation = FALSE; trx->dict_operation = FALSE;
trx->mysql_thd = NULL; trx->mysql_thd = NULL;
@ -102,8 +104,6 @@ trx_create(
trx->mysql_master_log_file_name = ""; trx->mysql_master_log_file_name = "";
trx->mysql_master_log_pos = 0; trx->mysql_master_log_pos = 0;
trx->ignore_duplicates_in_insert = FALSE;
mutex_create(&(trx->undo_mutex)); mutex_create(&(trx->undo_mutex));
mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO); mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO);
@ -782,13 +782,26 @@ trx_commit_off_kernel(
/*-------------------------------------*/ /*-------------------------------------*/
/* Most MySQL users run with srv_flush_.. set to FALSE: */ /* Most MySQL users run with srv_flush_.. set to 0: */
if (srv_flush_log_at_trx_commit) { if (srv_flush_log_at_trx_commit != 0) {
if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC
&& srv_flush_log_at_trx_commit != 2
&& !trx->flush_log_later) {
log_flush_up_to(lsn, LOG_WAIT_ONE_GROUP); /* Write the log to the log files AND flush
them to disk */
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
} else {
/* Write the log but do not flush it to disk */
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
}
} }
trx->commit_lsn = lsn;
/*-------------------------------------*/ /*-------------------------------------*/
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
@ -1469,6 +1482,33 @@ trx_commit_for_mysql(
return(0); return(0);
} }
/**************************************************************************
If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE. */
ulint
trx_commit_complete_for_mysql(
/*==========================*/
/* out: 0 or error number */
trx_t* trx) /* in: trx handle */
{
ut_a(trx);
if (srv_flush_log_at_trx_commit == 1
&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
trx->op_info = (char *) "flushing log";
/* Flush the log files to disk */
log_write_up_to(trx->commit_lsn, LOG_WAIT_ONE_GROUP, TRUE);
trx->op_info = (char *) "";
}
return(0);
}
/************************************************************************** /**************************************************************************
Marks the latest SQL statement ended. */ Marks the latest SQL statement ended. */

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libusr.a noinst_LIBRARIES = libusr.a
libusr_a_SOURCES = usr0sess.c libusr_a_SOURCES = usr0sess.c

View File

@ -17,7 +17,7 @@
include ../include/Makefile.i include ../include/Makefile.i
libs_LIBRARIES = libut.a noinst_LIBRARIES = libut.a
libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c

View File

@ -206,7 +206,7 @@ ut_get_year_month_day(
cal_tm_ptr = localtime(&tm); cal_tm_ptr = localtime(&tm);
*year = (ulint)cal_tm_ptr->tm_year; *year = (ulint)cal_tm_ptr->tm_year + 1900;
*month = (ulint)cal_tm_ptr->tm_mon + 1; *month = (ulint)cal_tm_ptr->tm_mon + 1;
*day = (ulint)cal_tm_ptr->tm_mday; *day = (ulint)cal_tm_ptr->tm_mday;
#endif #endif

View File

@ -124,12 +124,7 @@ EXPORTS
mysql_autocommit mysql_autocommit
load_defaults load_defaults
free_defaults free_defaults
my_path

View File

@ -66,7 +66,7 @@ TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib)-1,"",
#define closesocket(A) close(A) #define closesocket(A) close(A)
#endif #endif
void mysql_once_init(void); void mysqld_once_init(void);
static void end_server(MYSQL *mysql); static void end_server(MYSQL *mysql);
static void append_wild(char *to,char *end,const char *wild); static void append_wild(char *to,char *end,const char *wild);
static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
@ -373,7 +373,7 @@ static void mysql_read_default_options(struct st_mysql_options *options,
MYSQL * STDCALL MYSQL * STDCALL
mysql_init(MYSQL *mysql) mysql_init(MYSQL *mysql)
{ {
mysql_once_init(); mysqld_once_init();
if (!mysql) if (!mysql)
{ {
if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL)))) if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
@ -386,7 +386,7 @@ mysql_init(MYSQL *mysql)
} }
void mysql_once_init() void mysqld_once_init()
{ {
if (!mysql_client_init) if (!mysql_client_init)
{ {

View File

@ -19,7 +19,7 @@
man_MANS = mysql.1 isamchk.1 isamlog.1 mysql_zap.1 mysqlaccess.1 \ man_MANS = mysql.1 isamchk.1 isamlog.1 mysql_zap.1 mysqlaccess.1 \
mysqladmin.1 mysqld.1 mysqld_multi.1 mysqldump.1 mysqlshow.1 \ mysqladmin.1 mysqld.1 mysqld_multi.1 mysqldump.1 mysqlshow.1 \
perror.1 replace.1 mysqld_safe.1 perror.1 replace.1 mysqld_safe.1 mysql_fix_privilege_tables.1
EXTRA_DIST = $(man_MANS) EXTRA_DIST = $(man_MANS)

View File

@ -1,4 +1,4 @@
.TH isamchk 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH isamchk 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
.BR isamchk .BR isamchk
\- Description, check and repair of ISAM tables. \- Description, check and repair of ISAM tables.

View File

@ -1,4 +1,4 @@
.TH isamlog 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH isamlog 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
isamlog - Write info about whats in a nisam log file. isamlog - Write info about whats in a nisam log file.
.SH USAGE .SH USAGE

View File

@ -1,4 +1,4 @@
.TH mysql 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH mysql 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
mysql \- text-based client for mysqld, a SQL-based relational database daemon mysql \- text-based client for mysqld, a SQL-based relational database daemon
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -0,0 +1,23 @@
.TH mysql 1 "17 March 2003" "MySQL 4.0" "MySQL database"
.SH NAME
mysql_fix_privilege_tables \- Fixes MySQL privilege tables.
.SH SYNOPSIS
mysql_fix_privilege_tables [options]
.SH DESCRIPTION
This scripts updates the mysql.user, mysql.db, mysql.host and the
mysql.func tables to MySQL 3.22.14 and above.
This is needed if you want to use the new GRANT functions,
CREATE AGGREGATE FUNCTION or want to use the more secure passwords in 3.23
If you get 'Access denied' errors, you should run this script again
and give the MySQL root user password as an argument!
For more information start the program with '--help'.
.SH "SEE ALSO"
mysql (1), mysqld (1)
.SH AUTHOR
This manpage was written by Christian Hammers <ch@debian.org>.
MySQL is available at http://www.mysql.com/.
.\" end of man page

View File

@ -1,4 +1,4 @@
.TH zap 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH zap 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
zap - a perl script used to kill processes zap - a perl script used to kill processes
.SH USAGE .SH USAGE

View File

@ -1,4 +1,4 @@
.TH mysqlaccess 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH mysqlaccess 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
.BR mysqlaccess .BR mysqlaccess
\- Create new users to mysql. \- Create new users to mysql.

View File

@ -1,4 +1,4 @@
.TH mysqladmin 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH mysqladmin 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
mysqladmin [OPTIONS] command command.... \- A utility for performing administrative operations mysqladmin [OPTIONS] command command.... \- A utility for performing administrative operations
.SH OPTION SYNOPSIS .SH OPTION SYNOPSIS

View File

@ -1,4 +1,4 @@
.TH mysqld 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH mysqld 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
.BR mysqld .BR mysqld
\- Starts the MySQL server demon \- Starts the MySQL server demon

View File

@ -1,4 +1,4 @@
.TH mysqld_multi 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH mysqld_multi 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
mysqld_multi - is meant for managing several mysqld processes running in different UNIX sockets and TCP/IP ports. mysqld_multi - is meant for managing several mysqld processes running in different UNIX sockets and TCP/IP ports.
.SH USAGE .SH USAGE

View File

@ -1,4 +1,4 @@
.TH safe_mysqld 1 "19 December 2000" "MySQL 3.23" "MySQL database" .TH safe_mysqld 1 "19 December 2000" "MySQL 4.0" "MySQL database"
.SH NAME .SH NAME
mysqld_safe \- start the mysqld daemon on Unix. mysqld_safe \- start the mysqld daemon on Unix.
.SH SYNOPSIS .SH SYNOPSIS

Some files were not shown because too many files have changed in this diff Show More