diff options
author | unknown <ramil@mysql.com> | 2005-10-24 11:36:29 +0500 |
---|---|---|
committer | unknown <ramil@mysql.com> | 2005-10-24 11:36:29 +0500 |
commit | 39af58dbd46636bf4d5bcdda56a090905f740ad7 (patch) | |
tree | 619517758503f7aaf39c2b8b7a147627ef05ce4a | |
parent | 811c6d216ec224a019dad5a99e356720677b6d22 (diff) | |
parent | d29ecd5e91adf6eaeb4f2afef0db30648fe08065 (diff) | |
download | mariadb-git-39af58dbd46636bf4d5bcdda56a090905f740ad7.tar.gz |
Merge rkalimullin@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/usr/home/ram/work/5.0.b10303
mysql-test/r/query_cache.result:
Auto merged
mysql-test/t/query_cache.test:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_select.cc:
Auto merged
882 files changed, 36794 insertions, 13598 deletions
diff --git a/.bzrignore b/.bzrignore index 10bfea9154d..388dcac2ca6 100644 --- a/.bzrignore +++ b/.bzrignore @@ -312,6 +312,7 @@ emacs.h extra/charset2html extra/comp_err extra/created_include_files +extra/innochecksum extra/my_print_defaults extra/mysql_install extra/mysql_tzinfo_to_sql @@ -477,6 +478,8 @@ libmysqld/sql_cache.cc libmysqld/sql_class.cc libmysqld/sql_command libmysqld/sql_crypt.cc +libmysqld/sql_cursor.cc +libmysqld/sql_cursor.h libmysqld/sql_db.cc libmysqld/sql_delete.cc libmysqld/sql_derived.cc @@ -858,6 +861,7 @@ ndb/test/ndbapi/testNodeRestart ndb/test/ndbapi/testOIBasic ndb/test/ndbapi/testOperations ndb/test/ndbapi/testRestartGci +ndb/test/ndbapi/testSRBank ndb/test/ndbapi/testScan ndb/test/ndbapi/testScan.dsp ndb/test/ndbapi/testScanInterpreter diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh index 8cd78bf4165..2fc8015ea28 100644 --- a/BUILD/FINISH.sh +++ b/BUILD/FINISH.sh @@ -14,7 +14,7 @@ path=`dirname $0` if [ -z "$just_clean" ] then commands="$commands -CFLAGS=\"$cflags\" CXX=\"$CXX\" CXXFLAGS=\"$cxxflags\" CXXLDFLAGS=\"$CXXLDFLAGS\" \ +CC=\"$CC\" CFLAGS=\"$cflags\" CXX=\"$CXX\" CXXFLAGS=\"$cxxflags\" CXXLDFLAGS=\"$CXXLDFLAGS\" \ $configure" fi diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 1603cfadbed..96ec5803b63 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -10,6 +10,11 @@ prefix_configs="--prefix=/usr/local/mysql" just_print= just_configure= full_debug= +if test -n "$MYSQL_BUILD_PREFIX" +then + prefix_configs="--prefix=$MYSQL_BUILD_PREFIX" +fi + while test $# -gt 0 do case "$1" in @@ -47,10 +52,11 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch #debug_extra_warnings="-Wuninitialized" c_warnings="$global_warnings -Wunused" cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor" - -base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine" -max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-openssl --with-embedded-server --with-big-tables" +base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine --with-csv-storage-engine" +base_max_no_ndb_configs="--with-innodb --with-berkeley-db --without-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine --with-csv-storage-engine" +max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-csv-storage-engine --with-openssl --with-embedded-server --with-big-tables" max_configs="$base_max_configs --with-embedded-server" +max_no_ndb_configs="$base_max_no_ndb_configs --with-embedded-server" path=`dirname $0` . "$path/check-cpu" @@ -98,6 +104,10 @@ else make=make fi +if test -z "$CC" ; then + CC=gcc +fi + if test -z "$CXX" ; then CXX=gcc fi diff --git a/BUILD/autorun.sh b/BUILD/autorun.sh index 47a80a709a8..f5986720b48 100755 --- a/BUILD/autorun.sh +++ b/BUILD/autorun.sh @@ -7,7 +7,7 @@ aclocal || die "Can't execute aclocal" autoheader || die "Can't execute autoheader" # --force means overwrite ltmain.sh script if it already exists # Added glibtoolize reference to make native OSX autotools work -if [ -f /usr/bin/glibtoolize ] ; then +if test -f /usr/bin/glibtoolize ; then glibtoolize --automake --force || die "Can't execute glibtoolize" else libtoolize --automake --force || die "Can't execute libtoolize" diff --git a/BUILD/compile-pentium-debug-max-no-ndb b/BUILD/compile-pentium-debug-max-no-ndb new file mode 100755 index 00000000000..26ec7eacc9d --- /dev/null +++ b/BUILD/compile-pentium-debug-max-no-ndb @@ -0,0 +1,11 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" $@ --with-debug=full + +extra_flags="$pentium_cflags $debug_cflags $max_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs $max_no_ndb_configs" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-icc b/BUILD/compile-pentium-icc index eee8b6c9d90..bf550a4b574 100755 --- a/BUILD/compile-pentium-icc +++ b/BUILD/compile-pentium-icc @@ -8,29 +8,16 @@ path=`dirname $0` CC=icc CXX=icpc CXXLD="$CXX -static-libcxa" -export CC CXX - - -extra_flags="$pentium_cflags $debug_cflags $max_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify -DMYSQL_SERVER_SUFFIX=-valgrind-max" - -# Disable following warnings as these are generated by header files: -# 161 unrecognized pragma -# 444 destructor for base class xxx is not virtual -# 279 controlling expression is constant -# 810 conversion from ulonglong to ulong with cast -# 981 operands are evaluated in unspecified order -# 1292 warning for unknown 'attribute' options -# 1469 "xxx" clobber ignored -# 1572 floating-point equality and inequality comparisons are unreliable - -# In C++ -# 869 parameter "xxx" was never referenced -# (Problem with virtual functions) -# 874 support for placement delete is disabled +export CC CXX CXXLD c_warnings="" cxx_warnings="" -extra_flags="-O3 -unroll2 -ip -mp -no-gcc -restrict" +extra_flags="$fast_cflags -unroll2 -ip -mp -restrict" + +# Use -no-ipo if you get this error +# IPO link: can not find "-lstdc++_shared" +# icpc: error: problem during multi-file optimization compilation (code 1) +extra_flags="$extra_flags -no-ipo" base_cxxflags="-fno-exceptions -fno-rtti" extra_configs="$pentium_configs $static_link" diff --git a/BUILD/compile-pentium-icc-yassl b/BUILD/compile-pentium-icc-yassl new file mode 100644 index 00000000000..53b191e4db3 --- /dev/null +++ b/BUILD/compile-pentium-icc-yassl @@ -0,0 +1,24 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +# Note that we can't use ccache with icc as the generated .deps file will +# then contain wrong information +CC=icc +CXX=icpc +CXXLD="$CXX -static-libcxa" +export CC CXX CXXLD + +c_warnings="" +cxx_warnings="" +extra_flags="$fast_cflags -unroll2 -ip -mp -restrict" + +# Use -no-ipo if you get this error +# IPO link: can not find "-lstdc++_shared" +# icpc: error: problem during multi-file optimization compilation (code 1) +extra_flags="$extra_flags -no-ipo" +base_cxxflags="-fno-exceptions -fno-rtti" +extra_configs="$pentium_configs $static_link --with-yassl" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-valgrind-max b/BUILD/compile-pentium64-valgrind-max index 2e4ff8e0082..2e4ff8e0082 100644..100755 --- a/BUILD/compile-pentium64-valgrind-max +++ b/BUILD/compile-pentium64-valgrind-max diff --git a/BUILD/compile-ppc-debug-max-no-ndb b/BUILD/compile-ppc-debug-max-no-ndb new file mode 100755 index 00000000000..a5b922a1ec9 --- /dev/null +++ b/BUILD/compile-ppc-debug-max-no-ndb @@ -0,0 +1,11 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$ppc_cflags $debug_cflags $max_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$debug_configs $max_no_ndb_configs" + +. "$path/FINISH.sh" diff --git a/BitKeeper/etc/RESYNC_TREE b/BitKeeper/etc/RESYNC_TREE new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/BitKeeper/etc/RESYNC_TREE diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config index 81e867e514f..b68810b77ac 100644 --- a/BitKeeper/etc/config +++ b/BitKeeper/etc/config @@ -73,5 +73,6 @@ hours: [nick:]checkout:get [jonas:]checkout:get [tomas:]checkout:get +[guilhem:]checkout:get checkout:edit eoln:unix diff --git a/Makefile.am b/Makefile.am index 353a05eeb14..403a4ba2137 100644 --- a/Makefile.am +++ b/Makefile.am @@ -97,12 +97,6 @@ tags: support-files/build-tags .PHONY: init-db bin-dist -# Test installation - -test: - cd mysql-test; \ - ./mysql-test-run && ./mysql-test-run --ps-protocol - # Test installation. Ports are configurable from the environment. MYSQL_TEST_MANAGER_PORT = 9305 @@ -113,15 +107,26 @@ MYSQL_TEST_RUN_ARGS = --manager-port=$(MYSQL_TEST_MANAGER_PORT) \ --master_port=$(MYSQL_TEST_MASTER_PORT) \ --slave_port=$(MYSQL_TEST_SLAVE_PORT) \ --ndbcluster_port=$(MYSQL_TEST_NDB_PORT) + test: cd mysql-test ; \ - ./mysql-test-run.pl $(MYSQL_TEST_RUN_ARGS) && \ - ./mysql-test-run.pl --ps-protocol $(MYSQL_TEST_RUN_ARGS) + ./mysql-test-run $(MYSQL_TEST_RUN_ARGS) && \ + ./mysql-test-run $(MYSQL_TEST_RUN_ARGS) --ps-protocol test-force: cd mysql-test ; \ - ./mysql-test-run --force $(MYSQL_TEST_RUN_ARGS) ; \ - ./mysql-test-run --ps-protocol --force $(MYSQL_TEST_RUN_ARGS) + ./mysql-test-run $(MYSQL_TEST_RUN_ARGS) --force ; \ + ./mysql-test-run $(MYSQL_TEST_RUN_ARGS) --ps-protocol --force + +test-pl: + cd mysql-test ; \ + ./mysql-test-run.pl $(MYSQL_TEST_RUN_ARGS) && \ + ./mysql-test-run.pl $(MYSQL_TEST_RUN_ARGS) --ps-protocol + +test-force-pl: + cd mysql-test ; \ + ./mysql-test-run.pl $(MYSQL_TEST_RUN_ARGS) --force ; \ + ./mysql-test-run.pl $(MYSQL_TEST_RUN_ARGS) --ps-protocol --force # Don't update the files from bitkeeper %::SCCS/s.% @@ -1,52 +1,35 @@ -This is a release of MySQL, a GPL (free) SQL database server (more -licence information in the PUBLIC file and in the reference manual). +This is a release of MySQL, a dual-license SQL database server. +MySQL is brought to you by the MySQL team at MySQL AB. -Please read the "Upgrading from..." section in the manual first, if you are -migrating from older versions of MySQL! +License information can be found in these files: +- For GPL (free) distributions, see the COPYING file. +- For commercial distributions, see the MySQLEULA.txt file. -The latest information about MySQL can be found at: -http://www.mysql.com -To see what it can do take a look at the features section in the -manual. +For further information about MySQL or additional documentation, see: +- The latest information about MySQL: http://www.mysql.com +- The current MySQL documentation: http:/dev.mysql.com/doc -For installation instructions see the Installation chapter in the -manual. +Some manual sections of special interest: -For future plans see the TODO appendix in the manual. +- If you are migrating from an older version of MySQL, please read the + "Upgrading from..." section first! +- To see what MySQL can do, take a look at the features section. +- For installation instructions, see the Installation chapter. +- For future plans, see the TODO appendix. +- For the new features/bugfix history, see the News appendix. +- For the currently known bugs/misfeatures (known errors) see the problems + appendix. +- For a list of developers and other contributors, see the Credits + appendix. -New features/bug fixes history is in the news appendix in the manual. - -For the currently known bugs/misfeatures (known errors) see the bugs -appendix in the manual. - -For examples of SQL and benchmarking information see the bench -directory. - -The manual mentioned above can be found in the Docs directory. The -manual is available in the following formats: as plain ASCII text in -Docs/manual.txt, in HTML format in Docs/manual_toc.html, as GNU Info in -Docs/mysql.info and as PostScript in Docs/manual.ps. - -MySQL is brought to you by the MySQL team at MySQL AB - -For a list of developers and other contributors, see the Credits appendix -in the manual. +A local copy of the MySQL Reference Manual can be found in the Docs +directory in GNU Info format. You can also browse the manual online or +download it in any of several formats at the URL given earlier in this +file. ************************************************************ IMPORTANT: -Send bug (error) reports, questions and comments to the mailing list -at mysql@lists.mysql.com - -Please use the 'mysqlbug' script when posting bug reports or questions -about MySQL. mysqlbug will gather some information about your system -and start your editor with a form in which you can describe your -problem. Bug reports might be silently ignored by the MySQL -maintainers if there is not a good reason included in the report as to -why mysqlbug has not been used. A report that says 'MySQL does not -work for me. Why?' is not considered a valid bug report. - -The mysqlbug script can be found in the 'scripts' directory of the -distribution, that is '<where-you-installed-mysql>/scripts'. +Bug or error reports should be sent to http://bugs.mysql.com. diff --git a/VC++Files/bdb/bdb.vcproj b/VC++Files/bdb/bdb.vcproj index 6258da3cb3a..6258da3cb3a 100755..100644 --- a/VC++Files/bdb/bdb.vcproj +++ b/VC++Files/bdb/bdb.vcproj diff --git a/VC++Files/client/mysql.vcproj b/VC++Files/client/mysql.vcproj index 72cc4ba6b89..72cc4ba6b89 100755..100644 --- a/VC++Files/client/mysql.vcproj +++ b/VC++Files/client/mysql.vcproj diff --git a/VC++Files/client/mysqladmin.vcproj b/VC++Files/client/mysqladmin.vcproj index 188bf61dff7..188bf61dff7 100755..100644 --- a/VC++Files/client/mysqladmin.vcproj +++ b/VC++Files/client/mysqladmin.vcproj diff --git a/VC++Files/client/mysqlclient.vcproj b/VC++Files/client/mysqlclient.vcproj index eebba9ebe0e..eebba9ebe0e 100755..100644 --- a/VC++Files/client/mysqlclient.vcproj +++ b/VC++Files/client/mysqlclient.vcproj diff --git a/VC++Files/client/mysqldump.vcproj b/VC++Files/client/mysqldump.vcproj index b6a33596083..b6a33596083 100755..100644 --- a/VC++Files/client/mysqldump.vcproj +++ b/VC++Files/client/mysqldump.vcproj diff --git a/VC++Files/client/mysqlimport.vcproj b/VC++Files/client/mysqlimport.vcproj index ef440c2fe5a..ef440c2fe5a 100755..100644 --- a/VC++Files/client/mysqlimport.vcproj +++ b/VC++Files/client/mysqlimport.vcproj diff --git a/VC++Files/client/mysqlshow.vcproj b/VC++Files/client/mysqlshow.vcproj index a0707680728..a0707680728 100755..100644 --- a/VC++Files/client/mysqlshow.vcproj +++ b/VC++Files/client/mysqlshow.vcproj diff --git a/VC++Files/client/mysqltest.vcproj b/VC++Files/client/mysqltest.vcproj index 5c075740fbd..5c075740fbd 100755..100644 --- a/VC++Files/client/mysqltest.vcproj +++ b/VC++Files/client/mysqltest.vcproj diff --git a/VC++Files/comp_err/comp_err.vcproj b/VC++Files/comp_err/comp_err.vcproj index b12ef8b0af1..b12ef8b0af1 100755..100644 --- a/VC++Files/comp_err/comp_err.vcproj +++ b/VC++Files/comp_err/comp_err.vcproj diff --git a/VC++Files/dbug/dbug.vcproj b/VC++Files/dbug/dbug.vcproj index 57257451aea..57257451aea 100755..100644 --- a/VC++Files/dbug/dbug.vcproj +++ b/VC++Files/dbug/dbug.vcproj diff --git a/VC++Files/heap/heap.vcproj b/VC++Files/heap/heap.vcproj index b2afd752acf..b2afd752acf 100755..100644 --- a/VC++Files/heap/heap.vcproj +++ b/VC++Files/heap/heap.vcproj diff --git a/VC++Files/innobase/innobase.vcproj b/VC++Files/innobase/innobase.vcproj index 9d972366440..9d972366440 100755..100644 --- a/VC++Files/innobase/innobase.vcproj +++ b/VC++Files/innobase/innobase.vcproj diff --git a/VC++Files/isam/isam.dsp b/VC++Files/isam/isam.dsp deleted file mode 100644 index 759a1b6ee03..00000000000 --- a/VC++Files/isam/isam.dsp +++ /dev/null @@ -1,260 +0,0 @@ -# Microsoft Developer Studio Project File - Name="isam" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - -CFG=isam - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "isam.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "isam.mak" CFG="isam - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "isam - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "isam - Win32 Debug" (based on "Win32 (x86) Static Library") -!MESSAGE "isam - Win32 TLS_DEBUG" (based on "Win32 (x86) Static Library") -!MESSAGE "isam - Win32 TLS" (based on "Win32 (x86) Static Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=xicl6.exe -RSC=rc.exe - -!IF "$(CFG)" == "isam - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "release" -# PROP Intermediate_Dir "release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "DBUG_OFF" /D "_WINDOWS" /D "NDEBUG" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=xilink6.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"..\lib_release\isam.lib" - -!ELSEIF "$(CFG)" == "isam - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "debug" -# PROP Intermediate_Dir "debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=xilink6.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"..\lib_Debug\isam.lib" - -!ELSEIF "$(CFG)" == "isam - Win32 TLS_DEBUG" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "isam___Win32_TLS_DEBUG" -# PROP BASE Intermediate_Dir "isam___Win32_TLS_DEBUG" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "isam___Win32_TLS_DEBUG" -# PROP Intermediate_Dir "isam___Win32_TLS_DEBUG" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c -# SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /D "USE_TLS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:"..\lib_Debug\isam_tls.lib" -# ADD LIB32 /nologo /out:"..\lib_Debug\isam_tls.lib" - -!ELSEIF "$(CFG)" == "isam - Win32 TLS" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "isam___Win32_TLS" -# PROP BASE Intermediate_Dir "isam___Win32_TLS" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "isam___Win32_TLS" -# PROP Intermediate_Dir "isam___Win32_TLS" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "DBUG_OFF" /D "_WINDOWS" /D "NDEBUG" /FD /c -# SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "DBUG_OFF" /D "_WINDOWS" /D "NDEBUG" /D "USE_TLS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:"..\lib_release\isam_tls.lib" -# ADD LIB32 /nologo /out:"..\lib_release\isam_tls.lib" - -!ENDIF - -# Begin Target - -# Name "isam - Win32 Release" -# Name "isam - Win32 Debug" -# Name "isam - Win32 TLS_DEBUG" -# Name "isam - Win32 TLS" -# Begin Source File - -SOURCE=.\_cache.c -# End Source File -# Begin Source File - -SOURCE=.\_dbug.c -# End Source File -# Begin Source File - -SOURCE=.\_dynrec.c -# End Source File -# Begin Source File - -SOURCE=.\_key.c -# End Source File -# Begin Source File - -SOURCE=.\_locking.c -# End Source File -# Begin Source File - -SOURCE=.\_packrec.c -# End Source File -# Begin Source File - -SOURCE=.\_page.c -# End Source File -# Begin Source File - -SOURCE=.\_search.c -# End Source File -# Begin Source File - -SOURCE=.\_statrec.c -# End Source File -# Begin Source File - -SOURCE=.\changed.c -# End Source File -# Begin Source File - -SOURCE=.\close.c -# End Source File -# Begin Source File - -SOURCE=.\create.c -# End Source File -# Begin Source File - -SOURCE=.\delete.c -# End Source File -# Begin Source File - -SOURCE=.\extra.c -# End Source File -# Begin Source File - -SOURCE=.\info.c -# End Source File -# Begin Source File - -SOURCE=.\log.c -# End Source File -# Begin Source File - -SOURCE=.\open.c -# End Source File -# Begin Source File - -SOURCE=.\panic.c -# End Source File -# Begin Source File - -SOURCE=.\range.c -# End Source File -# Begin Source File - -SOURCE=.\rfirst.c -# End Source File -# Begin Source File - -SOURCE=.\rkey.c -# End Source File -# Begin Source File - -SOURCE=.\rlast.c -# End Source File -# Begin Source File - -SOURCE=.\rnext.c -# End Source File -# Begin Source File - -SOURCE=.\rprev.c -# End Source File -# Begin Source File - -SOURCE=.\rrnd.c -# End Source File -# Begin Source File - -SOURCE=.\rsame.c -# End Source File -# Begin Source File - -SOURCE=.\rsamepos.c -# End Source File -# Begin Source File - -SOURCE=.\static.c -# End Source File -# Begin Source File - -SOURCE=.\update.c -# End Source File -# Begin Source File - -SOURCE=.\write.c -# End Source File -# End Target -# End Project diff --git a/VC++Files/isam/isam.dsw b/VC++Files/isam/isam.dsw deleted file mode 100644 index c18224a6d73..00000000000 --- a/VC++Files/isam/isam.dsw +++ /dev/null @@ -1,28 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 5.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "isam"=".\isam.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### diff --git a/VC++Files/isam/isam_ia64.dsp b/VC++Files/isam/isam_ia64.dsp deleted file mode 100644 index f9dce0bed4a..00000000000 --- a/VC++Files/isam/isam_ia64.dsp +++ /dev/null @@ -1,260 +0,0 @@ -# Microsoft Developer Studio Project File - Name="isam" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - -CFG=isam - WinIA64 TLS -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "isam.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "isam.mak" CFG="isam - WinIA64 TLS" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "isam - WinIA64 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "isam - WinIA64 Debug" (based on "Win32 (x86) Static Library") -!MESSAGE "isam - WinIA64 TLS_DEBUG" (based on "Win32 (x86) Static Library") -!MESSAGE "isam - WinIA64 TLS" (based on "Win32 (x86) Static Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "isam - WinIA64 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "release" -# PROP Intermediate_Dir "release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN64" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../include" /D "DBUG_OFF" /D "_WINDOWS" /D "NDEBUG" /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"..\lib_release\isam.lib" - -!ELSEIF "$(CFG)" == "isam - WinIA64 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "debug" -# PROP Intermediate_Dir "debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN64" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MTd /W3 /Zi /Od /GF /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"..\lib_Debug\isam.lib" - -!ELSEIF "$(CFG)" == "isam - WinIA64 TLS_DEBUG" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "isam___WinIA64_TLS_DEBUG" -# PROP BASE Intermediate_Dir "isam___WinIA64_TLS_DEBUG" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "isam___WinIA64_TLS_DEBUG" -# PROP Intermediate_Dir "isam___WinIA64_TLS_DEBUG" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /G6 /MTd /W3 /Z7 /Od /GF /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c -# SUBTRACT BASE CPP /YX -# ADD CPP /nologo /MTd /W3 /Zi /O2 /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /D "USE_TLS" /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:"..\lib_Debug\isam_tls.lib" -# ADD LIB32 /nologo /out:"..\lib_Debug\isam_tls.lib" - -!ELSEIF "$(CFG)" == "isam - WinIA64 TLS" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "isam___WinIA64_TLS" -# PROP BASE Intermediate_Dir "isam___WinIA64_TLS" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "isam___WinIA64_TLS" -# PROP Intermediate_Dir "isam___WinIA64_TLS" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "DBUG_OFF" /D "_WINDOWS" /D "NDEBUG" /FD /c -# SUBTRACT BASE CPP /YX -# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../include" /D "DBUG_OFF" /D "_WINDOWS" /D "NDEBUG" /D "USE_TLS" /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 -# ADD RSC /l 0x409 -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:"..\lib_release\isam_tls.lib" -# ADD LIB32 /nologo /out:"..\lib_release\isam_tls.lib" - -!ENDIF - -# Begin Target - -# Name "isam - WinIA64 Release" -# Name "isam - WinIA64 Debug" -# Name "isam - WinIA64 TLS_DEBUG" -# Name "isam - WinIA64 TLS" -# Begin Source File - -SOURCE=.\_cache.c -# End Source File -# Begin Source File - -SOURCE=.\_dbug.c -# End Source File -# Begin Source File - -SOURCE=.\_dynrec.c -# End Source File -# Begin Source File - -SOURCE=.\_key.c -# End Source File -# Begin Source File - -SOURCE=.\_locking.c -# End Source File -# Begin Source File - -SOURCE=.\_packrec.c -# End Source File -# Begin Source File - -SOURCE=.\_page.c -# End Source File -# Begin Source File - -SOURCE=.\_search.c -# End Source File -# Begin Source File - -SOURCE=.\_statrec.c -# End Source File -# Begin Source File - -SOURCE=.\changed.c -# End Source File -# Begin Source File - -SOURCE=.\close.c -# End Source File -# Begin Source File - -SOURCE=.\create.c -# End Source File -# Begin Source File - -SOURCE=.\delete.c -# End Source File -# Begin Source File - -SOURCE=.\extra.c -# End Source File -# Begin Source File - -SOURCE=.\info.c -# End Source File -# Begin Source File - -SOURCE=.\log.c -# End Source File -# Begin Source File - -SOURCE=.\open.c -# End Source File -# Begin Source File - -SOURCE=.\panic.c -# End Source File -# Begin Source File - -SOURCE=.\range.c -# End Source File -# Begin Source File - -SOURCE=.\rfirst.c -# End Source File -# Begin Source File - -SOURCE=.\rkey.c -# End Source File -# Begin Source File - -SOURCE=.\rlast.c -# End Source File -# Begin Source File - -SOURCE=.\rnext.c -# End Source File -# Begin Source File - -SOURCE=.\rprev.c -# End Source File -# Begin Source File - -SOURCE=.\rrnd.c -# End Source File -# Begin Source File - -SOURCE=.\rsame.c -# End Source File -# Begin Source File - -SOURCE=.\rsamepos.c -# End Source File -# Begin Source File - -SOURCE=.\static.c -# End Source File -# Begin Source File - -SOURCE=.\update.c -# End Source File -# Begin Source File - -SOURCE=.\write.c -# End Source File -# End Target -# End Project diff --git a/VC++Files/isamchk/isamchk.dsp b/VC++Files/isamchk/isamchk.dsp deleted file mode 100644 index 2026be94ea0..00000000000 --- a/VC++Files/isamchk/isamchk.dsp +++ /dev/null @@ -1,129 +0,0 @@ -# Microsoft Developer Studio Project File - Name="isamchk" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=isamchk - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "isamchk.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "isamchk.mak" CFG="isamchk - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "isamchk - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "isamchk - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE "isamchk - Win32 classic" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=xicl6.exe -RSC=rc.exe - -!IF "$(CFG)" == "isamchk - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "release" -# PROP Intermediate_Dir "release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x41d /d "NDEBUG" -# ADD RSC /l 0x41d /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -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:console /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 setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/isamchk.exe" -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "isamchk - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "isamchk_" -# PROP BASE Intermediate_Dir "isamchk_" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "debug" -# PROP Intermediate_Dir "debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../include" /I "../isam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /Fr /YX -# ADD BASE RSC /l 0x41d /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -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:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/isamchk.exe" /pdbtype:sept -# SUBTRACT LINK32 /verbose /pdb:none - -!ELSEIF "$(CFG)" == "isamchk - Win32 classic" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "isamchk___Win32_classic" -# PROP BASE Intermediate_Dir "isamchk___Win32_classic" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "classic" -# PROP Intermediate_Dir "classic" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /FD /c -# SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "_CONSOLE" /D "_WINDOWS" /D "DBUG_OFF" /D "_MBCS" /D "NDEBUG" /D LICENSE=Commercial /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x41d /d "NDEBUG" -# ADD RSC /l 0x41d /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=xilink6.exe -# ADD BASE 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 setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/isamchk.exe" -# SUBTRACT BASE LINK32 /pdb:none -# 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 setargv.obj ..\lib_release\isam.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib /nologo /subsystem:console /machine:I386 /out:"../client_classic/isamchk.exe" /libpath:"..\lib_release\\" -# SUBTRACT LINK32 /pdb:none - -!ENDIF - -# Begin Target - -# Name "isamchk - Win32 Release" -# Name "isamchk - Win32 Debug" -# Name "isamchk - Win32 classic" -# Begin Source File - -SOURCE=..\isam\isamchk.c -# End Source File -# Begin Source File - -SOURCE=..\isam\sort.c -# End Source File -# End Target -# End Project diff --git a/VC++Files/isamchk/isamchk_ia64.dsp b/VC++Files/isamchk/isamchk_ia64.dsp deleted file mode 100644 index 61eab230e1f..00000000000 --- a/VC++Files/isamchk/isamchk_ia64.dsp +++ /dev/null @@ -1,100 +0,0 @@ -# Microsoft Developer Studio Project File - Name="isamchk" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=isamchk - WinIA64 classic -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "isamchk_ia64.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "isamchk_ia64.mak" CFG="isamchk - WinIA64 classic" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "isamchk - WinIA64 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "isamchk - WinIA64 classic" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "isamchk - WinIA64 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "release" -# PROP Intermediate_Dir "release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -MTL=midl.exe -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN64" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x41d /d "NDEBUG" -# ADD RSC /l 0x41d /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.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:console /machine:IA64 -# 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 setargv.obj bufferoverflowU.lib ..\lib_release\isam.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib /nologo /subsystem:console /out:"../client_release/isamchk.exe" /machine:IA64 - -!ELSEIF "$(CFG)" == "isamchk - WinIA64 classic" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "isamchk___WinIA64_classic" -# PROP BASE Intermediate_Dir "isamchk___WinIA64_classic" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "classic" -# PROP Intermediate_Dir "classic" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -MTL=midl.exe -# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /FD /c -# SUBTRACT BASE CPP /YX -# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../include" /I "../isam" /D "_CONSOLE" /D "_WINDOWS" /D "DBUG_OFF" /D "_MBCS" /D "NDEBUG" /D LICENSE=Commercial /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x41d /d "NDEBUG" -# ADD RSC /l 0x41d /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE 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 setargv.obj /nologo /subsystem:console /out:"../client_release/isamchk.exe" /machine:IA64 -# ADD LINK32 ..\lib_release\isam.lib ..\lib_release\mysys.lib ..\lib_release\strings.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 setargv.obj bufferoverflowU.lib /nologo /subsystem:console /out:"../client_classic/isamchk.exe" /libpath:"..\lib_release\\" /machine:IA64 - -!ENDIF - -# Begin Target - -# Name "isamchk - WinIA64 Release" -# Name "isamchk - WinIA64 classic" -# Begin Source File - -SOURCE=..\isam\isamchk.c -# End Source File -# Begin Source File - -SOURCE=..\isam\sort.c -# End Source File -# End Target -# End Project diff --git a/VC++Files/libmysql/libmysql.vcproj b/VC++Files/libmysql/libmysql.vcproj index 9ba877e0520..9ba877e0520 100755..100644 --- a/VC++Files/libmysql/libmysql.vcproj +++ b/VC++Files/libmysql/libmysql.vcproj diff --git a/VC++Files/libmysqld/examples/test_libmysqld.vcproj b/VC++Files/libmysqld/examples/test_libmysqld.vcproj index bf26fbd6588..bf26fbd6588 100755..100644 --- a/VC++Files/libmysqld/examples/test_libmysqld.vcproj +++ b/VC++Files/libmysqld/examples/test_libmysqld.vcproj diff --git a/VC++Files/libmysqld/libmysqld.dsp b/VC++Files/libmysqld/libmysqld.dsp index 0fb3a645a48..87a88333a2a 100644 --- a/VC++Files/libmysqld/libmysqld.dsp +++ b/VC++Files/libmysqld/libmysqld.dsp @@ -396,10 +396,6 @@ SOURCE=..\sql\protocol.cpp # End Source File # Begin Source File -SOURCE=..\sql\protocol_cursor.cpp -# End Source File -# Begin Source File - SOURCE=..\sql\records.cpp
# End Source File
# Begin Source File
@@ -556,6 +552,10 @@ SOURCE=..\sql\sql_trigger.cpp # End Source File # Begin Source File +SOURCE=..\sql\sql_cursor.cpp +# End Source File +# Begin Source File + SOURCE=..\sql\sql_udf.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/libmysqld/libmysqld.vcproj b/VC++Files/libmysqld/libmysqld.vcproj index 187a63ece38..eb411f79362 100755..100644 --- a/VC++Files/libmysqld/libmysqld.vcproj +++ b/VC++Files/libmysqld/libmysqld.vcproj @@ -24,7 +24,7 @@ AdditionalIncludeDirectories="../include,../libmysqld,../sql,../regex,../extra/yassl/include,../bdb/build_win32,../zlib" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;SAFEMALLOC;HAVE_BERKELEY_DB;USE_SYMDIR;SIGNAL_WITH_VIO_CLOSE;HAVE_DLOPEN;EMBEDDED_LIBRARY;HAVE_INNOBASE_DB;USE_TLS;__WIN__" BasicRuntimeChecks="3" - RuntimeLibrary="0" + RuntimeLibrary="1" PrecompiledHeaderFile=".\debug/libmysqld.pch" AssemblerListingLocation=".\debug/" ObjectFile=".\debug/" @@ -37,11 +37,11 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" - AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug_tls.lib ..\lib_debug\mysys_tls.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap_tls.lib ..\lib_debug\innodb.lib ..\extra\yassl\Debug\yassl.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib" OutputFile="../lib_debug/libmysqld.dll" LinkIncremental="1" SuppressStartupBanner="TRUE" - IgnoreDefaultLibraryNames="LIBCMTD" + IgnoreDefaultLibraryNames="" ModuleDefinitionFile=".\libmysqld.def" GenerateDebugInformation="TRUE" ProgramDatabaseFile=".\debug/libmysqld.pdb" @@ -106,7 +106,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" - AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib ..\extra\yassl\Release\yassl.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib" OutputFile="../lib_pro/libmysqld.dll" LinkIncremental="1" SuppressStartupBanner="TRUE" @@ -172,7 +172,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" - AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib ..\lib_release\zlib.lib ..\extra\yassl\Release\yassl.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib" OutputFile="../lib_release/libmysqld.dll" LinkIncremental="1" SuppressStartupBanner="TRUE" @@ -238,7 +238,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" - AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\zlib.lib ..\extra\yassl\Release\yassl.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib" OutputFile="../lib_classic/libmysqld.dll" LinkIncremental="1" SuppressStartupBanner="TRUE" @@ -2299,7 +2299,7 @@ </FileConfiguration> </File> <File - RelativePath="..\sql\protocol_cursor.cpp"> + RelativePath="..\sql\sql_cursor.cpp"> <FileConfiguration Name="Debug|Win32"> <Tool diff --git a/VC++Files/libmysqltest/myTest.vcproj b/VC++Files/libmysqltest/myTest.vcproj index 06ce20bf021..afc44b482c9 100755..100644 --- a/VC++Files/libmysqltest/myTest.vcproj +++ b/VC++Files/libmysqltest/myTest.vcproj @@ -40,7 +40,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="libmysql.lib odbc32.lib odbccp32.lib" - OutputFile=".\release/myTest.exe" + OutputFile="..\client_release/myTest.exe" LinkIncremental="1" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="..\lib_release" @@ -74,7 +74,7 @@ </Configuration> <Configuration Name="Debug|Win32" - OutputDirectory=".\debug" + OutputDirectory="..\client_debug" IntermediateDirectory=".\debug" ConfigurationType="1" UseOfMFC="0" @@ -100,7 +100,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="libmysql.lib odbc32.lib odbccp32.lib" - OutputFile=".\debug/myTest.exe" + OutputFile="../client_debug/myTest.exe" LinkIncremental="1" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="..\lib_debug" diff --git a/VC++Files/my_print_defaults/my_print_defaults.vcproj b/VC++Files/my_print_defaults/my_print_defaults.vcproj index e49039b6a1e..e49039b6a1e 100755..100644 --- a/VC++Files/my_print_defaults/my_print_defaults.vcproj +++ b/VC++Files/my_print_defaults/my_print_defaults.vcproj diff --git a/VC++Files/myisam/myisam.vcproj b/VC++Files/myisam/myisam.vcproj index b63b7ffaccc..b63b7ffaccc 100755..100644 --- a/VC++Files/myisam/myisam.vcproj +++ b/VC++Files/myisam/myisam.vcproj diff --git a/VC++Files/myisam_ftdump/myisam_ftdump.vcproj b/VC++Files/myisam_ftdump/myisam_ftdump.vcproj index 4d1013775fa..4d1013775fa 100755..100644 --- a/VC++Files/myisam_ftdump/myisam_ftdump.vcproj +++ b/VC++Files/myisam_ftdump/myisam_ftdump.vcproj diff --git a/VC++Files/myisamchk/myisamchk.vcproj b/VC++Files/myisamchk/myisamchk.vcproj index ce2435bc34a..33f813024b5 100755..100644 --- a/VC++Files/myisamchk/myisamchk.vcproj +++ b/VC++Files/myisamchk/myisamchk.vcproj @@ -101,7 +101,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" - AdditionalDependencies="wsock32.lib setargv.obj ..\lib_release\myisam.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\zlib.lib" + AdditionalDependencies="wsock32.lib setargv.obj" OutputFile="../client_classic/myisamchk.exe" LinkIncremental="1" SuppressStartupBanner="TRUE" diff --git a/VC++Files/myisamlog/myisamlog.vcproj b/VC++Files/myisamlog/myisamlog.vcproj index 6189a54d33b..6189a54d33b 100755..100644 --- a/VC++Files/myisamlog/myisamlog.vcproj +++ b/VC++Files/myisamlog/myisamlog.vcproj diff --git a/VC++Files/myisammrg/myisammrg.vcproj b/VC++Files/myisammrg/myisammrg.vcproj index 3075f8ef9f6..3075f8ef9f6 100755..100644 --- a/VC++Files/myisammrg/myisammrg.vcproj +++ b/VC++Files/myisammrg/myisammrg.vcproj diff --git a/VC++Files/myisampack/myisampack.vcproj b/VC++Files/myisampack/myisampack.vcproj index 27a8653cc5a..27a8653cc5a 100755..100644 --- a/VC++Files/myisampack/myisampack.vcproj +++ b/VC++Files/myisampack/myisampack.vcproj diff --git a/VC++Files/mysql-test/mysql_test_run_new.vcproj b/VC++Files/mysql-test/mysql_test_run_new.vcproj index 12d502e5768..12d502e5768 100755..100644 --- a/VC++Files/mysql-test/mysql_test_run_new.vcproj +++ b/VC++Files/mysql-test/mysql_test_run_new.vcproj diff --git a/VC++Files/mysql.sln b/VC++Files/mysql.sln index fc75dc24723..e119fe8d8a3 100755..100644 --- a/VC++Files/mysql.sln +++ b/VC++Files/mysql.sln @@ -37,6 +37,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmysqld", "libmysqld\libm {13D37150-54D0-46C5-9519-03923243C7C7} = {13D37150-54D0-46C5-9519-03923243C7C7} {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB} = {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB} {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3} = {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3} + {DB28DE80-837F-4497-9AA9-CC0A20584C98} = {DB28DE80-837F-4497-9AA9-CC0A20584C98} {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0} = {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0} {262280A8-37D5-4037-BDFB-242468DFB3D2} = {262280A8-37D5-4037-BDFB-242468DFB3D2} {8762A9B8-72A9-462E-A9A2-F3265081F8AF} = {8762A9B8-72A9-462E-A9A2-F3265081F8AF} @@ -268,6 +269,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysqltest", "client\mysqlte EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql_client_test", "tests\mysql_client_test.vcproj", "{DA224DAB-5006-42BE-BB77-16E8BE5326D5}" ProjectSection(ProjectDependencies) = postProject + {26383276-4843-494B-8BE0-8936ED3EBAAB} = {26383276-4843-494B-8BE0-8936ED3EBAAB} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql_test_run_new", "mysql-test\mysql_test_run_new.vcproj", "{6189F838-21C6-42A1-B2D0-9146316573F7}" @@ -277,6 +279,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql_test_run_new", "mysql {D2B00DE0-F6E9-40AF-B90D-A257D014F098} = {D2B00DE0-F6E9-40AF-B90D-A257D014F098} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysqlmanager", "server-tools\instance-manager\mysqlmanager.vcproj", "{6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}" + ProjectSection(ProjectDependencies) = postProject + {EEC1300B-85A5-497C-B3E1-F708021DF859} = {EEC1300B-85A5-497C-B3E1-F708021DF859} + {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB} = {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB} + {DB28DE80-837F-4497-9AA9-CC0A20584C98} = {DB28DE80-837F-4497-9AA9-CC0A20584C98} + {8762A9B8-72A9-462E-A9A2-F3265081F8AF} = {8762A9B8-72A9-462E-A9A2-F3265081F8AF} + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B} = {F74653C4-8003-4A79-8F53-FC69E0AD7A9B} + {44D9C7DC-6636-4B82-BD01-6876C64017DF} = {44D9C7DC-6636-4B82-BD01-6876C64017DF} + {FC369DF4-AEB7-4531-BF34-A638C4363BFE} = {FC369DF4-AEB7-4531-BF34-A638C4363BFE} + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution classic = classic @@ -286,32 +299,43 @@ Global Embedded_Debug = Embedded_Debug Embedded_Pro = Embedded_Pro Embedded_Release = Embedded_Release + Embedded_ProGPL = Embedded_ProGPL Max = Max Max nt = Max nt nt = nt pro = pro pro nt = pro nt + pro gpl = pro gpl + pro gpl nt = pro gpl nt Release = Release EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic.ActiveCfg = Debug|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic nt.ActiveCfg = Debug|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic nt.ActiveCfg = Max|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Debug.ActiveCfg = Debug|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Debug.Build.0 = Debug|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Classic.ActiveCfg = Debug|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Classic.Build.0 = Debug|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Classic.ActiveCfg = Max|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Debug.ActiveCfg = Debug|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Debug.Build.0 = Debug|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Pro.ActiveCfg = Debug|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Pro.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_ProGPL.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_ProGPL.Build.0 = Max|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Release.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Release.Build.0 = Max|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max.ActiveCfg = Max|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max.Build.0 = Max|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max nt.ActiveCfg = Max|Win32 {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max nt.Build.0 = Max|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.nt.ActiveCfg = Debug|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro.ActiveCfg = Debug|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro nt.ActiveCfg = Debug|Win32 - {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Release.ActiveCfg = Debug|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.nt.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.nt.Build.0 = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro nt.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro gpl.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro gpl.Build.0 = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro gpl nt.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro gpl nt.Build.0 = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Release.ActiveCfg = Max|Win32 + {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Release.Build.0 = Max|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.classic.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.classic nt.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.classic nt.Build.0 = Release|Win32 @@ -319,6 +343,7 @@ Global {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Embedded_Classic.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Embedded_Debug.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Embedded_Pro.ActiveCfg = Release|Win32 + {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Embedded_ProGPL.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Embedded_Release.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Max.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Max.Build.0 = Release|Win32 @@ -330,6 +355,10 @@ Global {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.pro.Build.0 = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.pro nt.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.pro nt.Build.0 = Release|Win32 + {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.pro gpl.ActiveCfg = Release|Win32 + {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.pro gpl.Build.0 = Release|Win32 + {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.pro gpl nt.ActiveCfg = Release|Win32 + {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.pro gpl nt.Build.0 = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Release.ActiveCfg = Release|Win32 {1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.Release.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.classic.ActiveCfg = Release|Win32 @@ -338,11 +367,16 @@ Global {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.classic nt.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Debug.ActiveCfg = Debug|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Debug.Build.0 = Debug|Win32 - {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Classic.ActiveCfg = Debug|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Classic.ActiveCfg = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Classic.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Debug.ActiveCfg = TLS_DEBUG|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Debug.Build.0 = TLS_DEBUG|Win32 - {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Pro.ActiveCfg = Debug|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Pro.ActiveCfg = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Pro.Build.0 = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_ProGPL.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Release.ActiveCfg = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Release.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Max.ActiveCfg = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Max.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Max nt.ActiveCfg = Release|Win32 @@ -353,6 +387,10 @@ Global {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.pro.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.pro nt.ActiveCfg = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.pro nt.Build.0 = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.pro gpl.ActiveCfg = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.pro gpl.Build.0 = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.pro gpl nt.ActiveCfg = Release|Win32 + {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.pro gpl nt.Build.0 = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Release.ActiveCfg = Release|Win32 {FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Release.Build.0 = Release|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.classic.ActiveCfg = Release|Win32 @@ -367,6 +405,8 @@ Global {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Embedded_Debug.Build.0 = TLS_DEBUG|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Embedded_Pro.ActiveCfg = TLS|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Embedded_Pro.Build.0 = TLS|Win32 + {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Embedded_ProGPL.ActiveCfg = TLS|Win32 + {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Embedded_ProGPL.Build.0 = TLS|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Embedded_Release.ActiveCfg = TLS|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Embedded_Release.Build.0 = TLS|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Max.ActiveCfg = Release|Win32 @@ -379,17 +419,26 @@ Global {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro.Build.0 = Release|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro nt.ActiveCfg = Release|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro nt.Build.0 = Release|Win32 + {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro gpl.ActiveCfg = Release|Win32 + {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro gpl.Build.0 = Release|Win32 + {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro gpl nt.ActiveCfg = Release|Win32 + {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro gpl nt.Build.0 = Release|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Release.ActiveCfg = Release|Win32 {C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Release.Build.0 = Release|Win32 - {13D37150-54D0-46C5-9519-03923243C7C7}.classic.ActiveCfg = nt|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.classic.ActiveCfg = Release|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.classic.Build.0 = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.classic nt.ActiveCfg = nt|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.classic nt.Build.0 = nt|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Debug.ActiveCfg = Debug|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Debug.Build.0 = Debug|Win32 - {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Classic.ActiveCfg = nt|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Classic.ActiveCfg = Release|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Classic.Build.0 = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Debug.ActiveCfg = Debug|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Debug.Build.0 = Debug|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Pro.ActiveCfg = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Pro.Build.0 = Release|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_ProGPL.Build.0 = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Release.ActiveCfg = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Release.Build.0 = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Max.ActiveCfg = Release|Win32 @@ -402,6 +451,10 @@ Global {13D37150-54D0-46C5-9519-03923243C7C7}.pro.Build.0 = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.pro nt.ActiveCfg = nt|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.pro nt.Build.0 = nt|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.pro gpl.ActiveCfg = Release|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.pro gpl.Build.0 = Release|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.pro gpl nt.ActiveCfg = nt|Win32 + {13D37150-54D0-46C5-9519-03923243C7C7}.pro gpl nt.Build.0 = nt|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Release.ActiveCfg = Release|Win32 {13D37150-54D0-46C5-9519-03923243C7C7}.Release.Build.0 = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.classic.ActiveCfg = Release|Win32 @@ -413,6 +466,8 @@ Global {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Embedded_Classic.ActiveCfg = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Embedded_Debug.ActiveCfg = Debug|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Embedded_Pro.ActiveCfg = Release|Win32 + {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Embedded_ProGPL.ActiveCfg = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Embedded_Release.ActiveCfg = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Max.ActiveCfg = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Max.Build.0 = Release|Win32 @@ -424,6 +479,10 @@ Global {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.pro.Build.0 = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.pro nt.ActiveCfg = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.pro nt.Build.0 = Release|Win32 + {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.pro gpl.ActiveCfg = Release|Win32 + {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.pro gpl.Build.0 = Release|Win32 + {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.pro gpl nt.ActiveCfg = Release|Win32 + {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.pro gpl nt.Build.0 = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Release.ActiveCfg = Release|Win32 {1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}.Release.Build.0 = Release|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.classic.ActiveCfg = classic|Win32 @@ -435,6 +494,8 @@ Global {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Embedded_Debug.Build.0 = Debug|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Embedded_Pro.ActiveCfg = pro|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Embedded_Pro.Build.0 = pro|Win32 + {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Embedded_ProGPL.Build.0 = Release|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Embedded_Release.ActiveCfg = Release|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Embedded_Release.Build.0 = Release|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Max.ActiveCfg = classic|Win32 @@ -442,16 +503,19 @@ Global {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.nt.ActiveCfg = classic|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.pro.ActiveCfg = pro|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.pro nt.ActiveCfg = pro|Win32 + {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.pro gpl.ActiveCfg = Release|Win32 + {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.pro gpl nt.ActiveCfg = Release|Win32 {93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Release.ActiveCfg = Release|Win32 - {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.ActiveCfg = Debug|Win32 - {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.Build.0 = Debug|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.ActiveCfg = Release|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.Build.0 = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic nt.ActiveCfg = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic nt.Build.0 = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Debug.ActiveCfg = Debug|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Debug.Build.0 = Debug|Win32 - {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Embedded_Classic.ActiveCfg = Debug|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Embedded_Classic.ActiveCfg = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Embedded_Debug.ActiveCfg = Debug|Win32 - {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Embedded_Pro.ActiveCfg = Debug|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Embedded_Pro.ActiveCfg = Release|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Embedded_ProGPL.ActiveCfg = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Embedded_Release.ActiveCfg = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Max.ActiveCfg = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Max.Build.0 = Release|Win32 @@ -463,6 +527,10 @@ Global {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.pro.Build.0 = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.pro nt.ActiveCfg = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.pro nt.Build.0 = Release|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.pro gpl.ActiveCfg = Release|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.pro gpl.Build.0 = Release|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.pro gpl nt.ActiveCfg = Release|Win32 + {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.pro gpl nt.Build.0 = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Release.ActiveCfg = Release|Win32 {2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Release.Build.0 = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.classic.ActiveCfg = classic|Win32 @@ -471,9 +539,10 @@ Global {B0EC3594-CD67-4364-826E-BA75EF2050F8}.classic nt.Build.0 = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Debug.ActiveCfg = Debug|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Debug.Build.0 = Debug|Win32 - {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Embedded_Classic.ActiveCfg = Debug|Win32 + {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Embedded_Classic.ActiveCfg = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Embedded_Debug.ActiveCfg = Debug|Win32 - {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Embedded_Pro.ActiveCfg = Debug|Win32 + {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Embedded_Pro.ActiveCfg = Release|Win32 + {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Embedded_ProGPL.ActiveCfg = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Embedded_Release.ActiveCfg = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Max.ActiveCfg = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Max.Build.0 = Release|Win32 @@ -485,6 +554,10 @@ Global {B0EC3594-CD67-4364-826E-BA75EF2050F8}.pro.Build.0 = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.pro nt.ActiveCfg = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.pro nt.Build.0 = Release|Win32 + {B0EC3594-CD67-4364-826E-BA75EF2050F8}.pro gpl.ActiveCfg = Release|Win32 + {B0EC3594-CD67-4364-826E-BA75EF2050F8}.pro gpl.Build.0 = Release|Win32 + {B0EC3594-CD67-4364-826E-BA75EF2050F8}.pro gpl nt.ActiveCfg = Release|Win32 + {B0EC3594-CD67-4364-826E-BA75EF2050F8}.pro gpl nt.Build.0 = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Release.ActiveCfg = Release|Win32 {B0EC3594-CD67-4364-826E-BA75EF2050F8}.Release.Build.0 = Release|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.classic.ActiveCfg = Release|Win32 @@ -496,8 +569,11 @@ Global {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Classic.ActiveCfg = TLS|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Classic.Build.0 = TLS|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Debug.ActiveCfg = Debug|Win32 + {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Debug.Build.0 = Debug|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Pro.ActiveCfg = TLS|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Pro.Build.0 = TLS|Win32 + {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_ProGPL.ActiveCfg = TLS|Win32 + {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_ProGPL.Build.0 = TLS|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Release.ActiveCfg = TLS|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Release.Build.0 = TLS|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Max.ActiveCfg = Release|Win32 @@ -510,6 +586,10 @@ Global {262280A8-37D5-4037-BDFB-242468DFB3D2}.pro.Build.0 = Release|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.pro nt.ActiveCfg = Release|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.pro nt.Build.0 = Release|Win32 + {262280A8-37D5-4037-BDFB-242468DFB3D2}.pro gpl.ActiveCfg = Release|Win32 + {262280A8-37D5-4037-BDFB-242468DFB3D2}.pro gpl.Build.0 = Release|Win32 + {262280A8-37D5-4037-BDFB-242468DFB3D2}.pro gpl nt.ActiveCfg = Release|Win32 + {262280A8-37D5-4037-BDFB-242468DFB3D2}.pro gpl nt.Build.0 = Release|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Release.ActiveCfg = Release|Win32 {262280A8-37D5-4037-BDFB-242468DFB3D2}.Release.Build.0 = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.classic.ActiveCfg = Release|Win32 @@ -521,6 +601,7 @@ Global {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Embedded_Classic.ActiveCfg = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Embedded_Debug.ActiveCfg = Debug|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Embedded_Pro.ActiveCfg = Release|Win32 + {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Embedded_ProGPL.ActiveCfg = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Embedded_Release.ActiveCfg = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Max.ActiveCfg = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Max.Build.0 = Release|Win32 @@ -532,6 +613,10 @@ Global {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.pro.Build.0 = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.pro nt.ActiveCfg = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.pro nt.Build.0 = Release|Win32 + {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.pro gpl.ActiveCfg = Release|Win32 + {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.pro gpl.Build.0 = Release|Win32 + {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.pro gpl nt.ActiveCfg = Release|Win32 + {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.pro gpl nt.Build.0 = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Release.ActiveCfg = Release|Win32 {4C5D0EB1-B953-4BE9-A48B-4F3A874E6635}.Release.Build.0 = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.classic.ActiveCfg = classic|Win32 @@ -540,9 +625,10 @@ Global {87CD9881-D234-4306-BBC6-0668C6168C0F}.classic nt.Build.0 = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Debug.ActiveCfg = Debug|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Debug.Build.0 = Debug|Win32 - {87CD9881-D234-4306-BBC6-0668C6168C0F}.Embedded_Classic.ActiveCfg = Debug|Win32 + {87CD9881-D234-4306-BBC6-0668C6168C0F}.Embedded_Classic.ActiveCfg = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Embedded_Debug.ActiveCfg = Debug|Win32 - {87CD9881-D234-4306-BBC6-0668C6168C0F}.Embedded_Pro.ActiveCfg = Debug|Win32 + {87CD9881-D234-4306-BBC6-0668C6168C0F}.Embedded_Pro.ActiveCfg = Release|Win32 + {87CD9881-D234-4306-BBC6-0668C6168C0F}.Embedded_ProGPL.ActiveCfg = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Embedded_Release.ActiveCfg = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Max.ActiveCfg = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Max.Build.0 = Release|Win32 @@ -554,6 +640,10 @@ Global {87CD9881-D234-4306-BBC6-0668C6168C0F}.pro.Build.0 = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.pro nt.ActiveCfg = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.pro nt.Build.0 = Release|Win32 + {87CD9881-D234-4306-BBC6-0668C6168C0F}.pro gpl.ActiveCfg = Release|Win32 + {87CD9881-D234-4306-BBC6-0668C6168C0F}.pro gpl.Build.0 = Release|Win32 + {87CD9881-D234-4306-BBC6-0668C6168C0F}.pro gpl nt.ActiveCfg = Release|Win32 + {87CD9881-D234-4306-BBC6-0668C6168C0F}.pro gpl nt.Build.0 = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Release.ActiveCfg = Release|Win32 {87CD9881-D234-4306-BBC6-0668C6168C0F}.Release.Build.0 = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.classic.ActiveCfg = classic|Win32 @@ -565,6 +655,7 @@ Global {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Embedded_Classic.ActiveCfg = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Embedded_Debug.ActiveCfg = Debug|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Embedded_Pro.ActiveCfg = Release|Win32 + {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Embedded_ProGPL.ActiveCfg = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Embedded_Release.ActiveCfg = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Max.ActiveCfg = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Max.Build.0 = Release|Win32 @@ -576,10 +667,14 @@ Global {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro.Build.0 = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro nt.ActiveCfg = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro nt.Build.0 = Release|Win32 + {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro gpl.ActiveCfg = Release|Win32 + {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro gpl.Build.0 = Release|Win32 + {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro gpl nt.ActiveCfg = Release|Win32 + {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro gpl nt.Build.0 = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Release.ActiveCfg = Release|Win32 {194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Release.Build.0 = Release|Win32 - {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.ActiveCfg = Debug|Win32 - {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.Build.0 = Debug|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.ActiveCfg = Release|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.Build.0 = Release|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic nt.ActiveCfg = Release|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic nt.Build.0 = Release|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Debug.ActiveCfg = Debug|Win32 @@ -587,8 +682,11 @@ Global {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Classic.ActiveCfg = TLS|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Classic.Build.0 = TLS|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Debug.ActiveCfg = Debug|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Debug.Build.0 = Debug|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Pro.ActiveCfg = TLS|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Pro.Build.0 = TLS|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_ProGPL.ActiveCfg = TLS|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_ProGPL.Build.0 = TLS|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Release.ActiveCfg = TLS|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Release.Build.0 = TLS|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Max.ActiveCfg = Release|Win32 @@ -601,6 +699,10 @@ Global {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.pro.Build.0 = Release|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.pro nt.ActiveCfg = Release|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.pro nt.Build.0 = Release|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.pro gpl.ActiveCfg = Release|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.pro gpl.Build.0 = Release|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.pro gpl nt.ActiveCfg = Release|Win32 + {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.pro gpl nt.Build.0 = Release|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Release.ActiveCfg = Release|Win32 {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Release.Build.0 = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.classic.ActiveCfg = classic|Win32 @@ -612,6 +714,7 @@ Global {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Embedded_Classic.ActiveCfg = classic|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Embedded_Debug.ActiveCfg = Debug|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Embedded_Pro.ActiveCfg = classic|Win32 + {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Embedded_ProGPL.ActiveCfg = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Embedded_Release.ActiveCfg = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Max.ActiveCfg = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Max.Build.0 = Release|Win32 @@ -623,6 +726,10 @@ Global {EF833A1E-E358-4B6C-9C27-9489E85041CC}.pro.Build.0 = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.pro nt.ActiveCfg = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.pro nt.Build.0 = Release|Win32 + {EF833A1E-E358-4B6C-9C27-9489E85041CC}.pro gpl.ActiveCfg = Release|Win32 + {EF833A1E-E358-4B6C-9C27-9489E85041CC}.pro gpl.Build.0 = Release|Win32 + {EF833A1E-E358-4B6C-9C27-9489E85041CC}.pro gpl nt.ActiveCfg = Release|Win32 + {EF833A1E-E358-4B6C-9C27-9489E85041CC}.pro gpl nt.Build.0 = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Release.ActiveCfg = Release|Win32 {EF833A1E-E358-4B6C-9C27-9489E85041CC}.Release.Build.0 = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.classic.ActiveCfg = classic|Win32 @@ -633,7 +740,8 @@ Global {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Debug.Build.0 = Debug|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Embedded_Classic.ActiveCfg = Debug|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Embedded_Debug.ActiveCfg = Debug|Win32 - {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Embedded_Pro.ActiveCfg = Debug|Win32 + {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Embedded_Pro.ActiveCfg = Release|Win32 + {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Embedded_ProGPL.ActiveCfg = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Embedded_Release.ActiveCfg = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Max.ActiveCfg = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Max.Build.0 = Release|Win32 @@ -645,6 +753,10 @@ Global {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.pro.Build.0 = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.pro nt.ActiveCfg = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.pro nt.Build.0 = Release|Win32 + {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.pro gpl.ActiveCfg = Release|Win32 + {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.pro gpl.Build.0 = Release|Win32 + {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.pro gpl nt.ActiveCfg = Release|Win32 + {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.pro gpl nt.Build.0 = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Release.ActiveCfg = Release|Win32 {F9868FD3-7AE2-486D-BAB3-A299E11F6AC1}.Release.Build.0 = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.classic.ActiveCfg = classic|Win32 @@ -655,7 +767,8 @@ Global {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Debug.Build.0 = Debug|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Embedded_Classic.ActiveCfg = Debug|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Embedded_Debug.ActiveCfg = Debug|Win32 - {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Embedded_Pro.ActiveCfg = Debug|Win32 + {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Embedded_Pro.ActiveCfg = Release|Win32 + {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Embedded_ProGPL.ActiveCfg = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Embedded_Release.ActiveCfg = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Max.ActiveCfg = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Max.Build.0 = Release|Win32 @@ -667,6 +780,10 @@ Global {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.pro.Build.0 = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.pro nt.ActiveCfg = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.pro nt.Build.0 = Release|Win32 + {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.pro gpl.ActiveCfg = Release|Win32 + {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.pro gpl.Build.0 = Release|Win32 + {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.pro gpl nt.ActiveCfg = Release|Win32 + {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.pro gpl nt.Build.0 = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Release.ActiveCfg = Release|Win32 {D2B00DE0-F6E9-40AF-B90D-A257D014F098}.Release.Build.0 = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.classic.ActiveCfg = classic|Win32 @@ -678,6 +795,7 @@ Global {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Embedded_Classic.ActiveCfg = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Embedded_Debug.ActiveCfg = Debug|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Embedded_Pro.ActiveCfg = Release|Win32 + {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Embedded_ProGPL.ActiveCfg = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Embedded_Release.ActiveCfg = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Max.ActiveCfg = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Max.Build.0 = Release|Win32 @@ -689,6 +807,10 @@ Global {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.pro.Build.0 = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.pro nt.ActiveCfg = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.pro nt.Build.0 = Release|Win32 + {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.pro gpl.ActiveCfg = Release|Win32 + {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.pro gpl.Build.0 = Release|Win32 + {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.pro gpl nt.ActiveCfg = Release|Win32 + {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.pro gpl nt.Build.0 = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Release.ActiveCfg = Release|Win32 {DC3A4D26-B533-465B-A3C7-9DBBC06DC8BB}.Release.Build.0 = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.classic.ActiveCfg = classic|Win32 @@ -699,7 +821,8 @@ Global {67154F28-D076-419E-B149-819EF548E670}.Debug.Build.0 = Debug|Win32 {67154F28-D076-419E-B149-819EF548E670}.Embedded_Classic.ActiveCfg = Debug|Win32 {67154F28-D076-419E-B149-819EF548E670}.Embedded_Debug.ActiveCfg = Debug|Win32 - {67154F28-D076-419E-B149-819EF548E670}.Embedded_Pro.ActiveCfg = Debug|Win32 + {67154F28-D076-419E-B149-819EF548E670}.Embedded_Pro.ActiveCfg = Release|Win32 + {67154F28-D076-419E-B149-819EF548E670}.Embedded_ProGPL.ActiveCfg = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.Embedded_Release.ActiveCfg = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.Max.ActiveCfg = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.Max.Build.0 = Release|Win32 @@ -711,17 +834,22 @@ Global {67154F28-D076-419E-B149-819EF548E670}.pro.Build.0 = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.pro nt.ActiveCfg = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.pro nt.Build.0 = Release|Win32 + {67154F28-D076-419E-B149-819EF548E670}.pro gpl.ActiveCfg = Release|Win32 + {67154F28-D076-419E-B149-819EF548E670}.pro gpl.Build.0 = Release|Win32 + {67154F28-D076-419E-B149-819EF548E670}.pro gpl nt.ActiveCfg = Release|Win32 + {67154F28-D076-419E-B149-819EF548E670}.pro gpl nt.Build.0 = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.Release.ActiveCfg = Release|Win32 {67154F28-D076-419E-B149-819EF548E670}.Release.Build.0 = Release|Win32 - {26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.ActiveCfg = Debug|Win32 - {26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.Build.0 = Debug|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.ActiveCfg = Release|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.Build.0 = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.classic nt.ActiveCfg = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.classic nt.Build.0 = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Debug.ActiveCfg = Debug|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Debug.Build.0 = Debug|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Embedded_Classic.ActiveCfg = Debug|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Embedded_Debug.ActiveCfg = Debug|Win32 - {26383276-4843-494B-8BE0-8936ED3EBAAB}.Embedded_Pro.ActiveCfg = Debug|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.Embedded_Pro.ActiveCfg = Release|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.Embedded_ProGPL.ActiveCfg = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Embedded_Release.ActiveCfg = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Max.ActiveCfg = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Max.Build.0 = Release|Win32 @@ -733,6 +861,10 @@ Global {26383276-4843-494B-8BE0-8936ED3EBAAB}.pro.Build.0 = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.pro nt.ActiveCfg = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.pro nt.Build.0 = Release|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.pro gpl.ActiveCfg = Release|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.pro gpl.Build.0 = Release|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.pro gpl nt.ActiveCfg = Release|Win32 + {26383276-4843-494B-8BE0-8936ED3EBAAB}.pro gpl nt.Build.0 = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Release.ActiveCfg = Release|Win32 {26383276-4843-494B-8BE0-8936ED3EBAAB}.Release.Build.0 = Release|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.classic.ActiveCfg = classic|Win32 @@ -744,6 +876,7 @@ Global {62E85884-3ACF-4F4C-873B-60B878147890}.Embedded_Classic.ActiveCfg = Release|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.Embedded_Debug.ActiveCfg = Debug|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.Embedded_Pro.ActiveCfg = Release|Win32 + {62E85884-3ACF-4F4C-873B-60B878147890}.Embedded_ProGPL.ActiveCfg = Release|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.Embedded_Release.ActiveCfg = Release|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.Max.ActiveCfg = Max|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.Max.Build.0 = Max|Win32 @@ -755,6 +888,10 @@ Global {62E85884-3ACF-4F4C-873B-60B878147890}.pro.Build.0 = pro|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.pro nt.ActiveCfg = pro nt|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.pro nt.Build.0 = pro nt|Win32 + {62E85884-3ACF-4F4C-873B-60B878147890}.pro gpl.ActiveCfg = Release|Win32 + {62E85884-3ACF-4F4C-873B-60B878147890}.pro gpl.Build.0 = Release|Win32 + {62E85884-3ACF-4F4C-873B-60B878147890}.pro gpl nt.ActiveCfg = nt|Win32 + {62E85884-3ACF-4F4C-873B-60B878147890}.pro gpl nt.Build.0 = nt|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.Release.ActiveCfg = Release|Win32 {62E85884-3ACF-4F4C-873B-60B878147890}.Release.Build.0 = Release|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.classic.ActiveCfg = classic|Win32 @@ -766,6 +903,7 @@ Global {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Embedded_Classic.ActiveCfg = Release|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Embedded_Debug.ActiveCfg = Debug|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Embedded_Pro.ActiveCfg = Release|Win32 + {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Embedded_ProGPL.ActiveCfg = Release|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Embedded_Release.ActiveCfg = Release|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Max.ActiveCfg = Release|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Max.Build.0 = Release|Win32 @@ -777,6 +915,10 @@ Global {37D9BA79-302E-4582-A545-CB5FF7982EA3}.pro.Build.0 = pro|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.pro nt.ActiveCfg = pro|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.pro nt.Build.0 = pro|Win32 + {37D9BA79-302E-4582-A545-CB5FF7982EA3}.pro gpl.ActiveCfg = Release|Win32 + {37D9BA79-302E-4582-A545-CB5FF7982EA3}.pro gpl.Build.0 = Release|Win32 + {37D9BA79-302E-4582-A545-CB5FF7982EA3}.pro gpl nt.ActiveCfg = Release|Win32 + {37D9BA79-302E-4582-A545-CB5FF7982EA3}.pro gpl nt.Build.0 = Release|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Release.ActiveCfg = Release|Win32 {37D9BA79-302E-4582-A545-CB5FF7982EA3}.Release.Build.0 = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.classic.ActiveCfg = classic|Win32 @@ -788,6 +930,7 @@ Global {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Embedded_Classic.ActiveCfg = classic|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Embedded_Debug.ActiveCfg = Debug|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Embedded_Pro.ActiveCfg = classic|Win32 + {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Embedded_ProGPL.ActiveCfg = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Embedded_Release.ActiveCfg = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Max.ActiveCfg = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Max.Build.0 = Release|Win32 @@ -799,6 +942,10 @@ Global {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.pro.Build.0 = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.pro nt.ActiveCfg = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.pro nt.Build.0 = Release|Win32 + {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.pro gpl.ActiveCfg = Release|Win32 + {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.pro gpl.Build.0 = Release|Win32 + {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.pro gpl nt.ActiveCfg = Release|Win32 + {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.pro gpl nt.Build.0 = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Release.ActiveCfg = Release|Win32 {89F24ECE-9953-40EF-BDF4-B41F5631E92B}.Release.Build.0 = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.classic.ActiveCfg = classic|Win32 @@ -810,6 +957,7 @@ Global {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Embedded_Classic.ActiveCfg = classic|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Embedded_Debug.ActiveCfg = Debug|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Embedded_Pro.ActiveCfg = classic|Win32 + {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Embedded_ProGPL.ActiveCfg = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Embedded_Release.ActiveCfg = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Max.ActiveCfg = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Max.Build.0 = Release|Win32 @@ -821,6 +969,10 @@ Global {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.pro.Build.0 = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.pro nt.ActiveCfg = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.pro nt.Build.0 = Release|Win32 + {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.pro gpl.ActiveCfg = Release|Win32 + {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.pro gpl.Build.0 = Release|Win32 + {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.pro gpl nt.ActiveCfg = Release|Win32 + {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.pro gpl nt.Build.0 = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Release.ActiveCfg = Release|Win32 {AD95DAD3-6DB9-4F8B-A345-7A39A83AAD3D}.Release.Build.0 = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.classic.ActiveCfg = Release|Win32 @@ -832,6 +984,7 @@ Global {94B86159-C581-42CD-825D-C69CBC237E5C}.Embedded_Classic.ActiveCfg = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.Embedded_Debug.ActiveCfg = Debug|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.Embedded_Pro.ActiveCfg = Release|Win32 + {94B86159-C581-42CD-825D-C69CBC237E5C}.Embedded_ProGPL.ActiveCfg = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.Embedded_Release.ActiveCfg = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.Max.ActiveCfg = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.Max.Build.0 = Release|Win32 @@ -843,6 +996,10 @@ Global {94B86159-C581-42CD-825D-C69CBC237E5C}.pro.Build.0 = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.pro nt.ActiveCfg = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.pro nt.Build.0 = Release|Win32 + {94B86159-C581-42CD-825D-C69CBC237E5C}.pro gpl.ActiveCfg = Release|Win32 + {94B86159-C581-42CD-825D-C69CBC237E5C}.pro gpl.Build.0 = Release|Win32 + {94B86159-C581-42CD-825D-C69CBC237E5C}.pro gpl nt.ActiveCfg = Release|Win32 + {94B86159-C581-42CD-825D-C69CBC237E5C}.pro gpl nt.Build.0 = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.Release.ActiveCfg = Release|Win32 {94B86159-C581-42CD-825D-C69CBC237E5C}.Release.Build.0 = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.classic.ActiveCfg = classic|Win32 @@ -853,7 +1010,8 @@ Global {3737BFE2-EF25-464F-994D-BD28A9F84528}.Debug.Build.0 = Debug|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.Embedded_Classic.ActiveCfg = Debug|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.Embedded_Debug.ActiveCfg = Debug|Win32 - {3737BFE2-EF25-464F-994D-BD28A9F84528}.Embedded_Pro.ActiveCfg = Debug|Win32 + {3737BFE2-EF25-464F-994D-BD28A9F84528}.Embedded_Pro.ActiveCfg = Release|Win32 + {3737BFE2-EF25-464F-994D-BD28A9F84528}.Embedded_ProGPL.ActiveCfg = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.Embedded_Release.ActiveCfg = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.Max.ActiveCfg = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.Max.Build.0 = Release|Win32 @@ -865,6 +1023,10 @@ Global {3737BFE2-EF25-464F-994D-BD28A9F84528}.pro.Build.0 = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.pro nt.ActiveCfg = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.pro nt.Build.0 = Release|Win32 + {3737BFE2-EF25-464F-994D-BD28A9F84528}.pro gpl.ActiveCfg = Release|Win32 + {3737BFE2-EF25-464F-994D-BD28A9F84528}.pro gpl.Build.0 = Release|Win32 + {3737BFE2-EF25-464F-994D-BD28A9F84528}.pro gpl nt.ActiveCfg = Release|Win32 + {3737BFE2-EF25-464F-994D-BD28A9F84528}.pro gpl nt.Build.0 = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.Release.ActiveCfg = Release|Win32 {3737BFE2-EF25-464F-994D-BD28A9F84528}.Release.Build.0 = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.classic.ActiveCfg = Release|Win32 @@ -879,6 +1041,8 @@ Global {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Embedded_Debug.Build.0 = Debug|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Embedded_Pro.ActiveCfg = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Embedded_Pro.Build.0 = Release|Win32 + {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Embedded_ProGPL.Build.0 = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Embedded_Release.ActiveCfg = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Embedded_Release.Build.0 = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Max.ActiveCfg = Release|Win32 @@ -891,6 +1055,10 @@ Global {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.pro.Build.0 = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.pro nt.ActiveCfg = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.pro nt.Build.0 = Release|Win32 + {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.pro gpl.ActiveCfg = Release|Win32 + {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.pro gpl.Build.0 = Release|Win32 + {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.pro gpl nt.ActiveCfg = Release|Win32 + {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.pro gpl nt.Build.0 = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Release.ActiveCfg = Release|Win32 {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}.Release.Build.0 = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.classic.ActiveCfg = Release|Win32 @@ -900,9 +1068,15 @@ Global {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Debug.ActiveCfg = Debug|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Debug.Build.0 = Debug|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Classic.ActiveCfg = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Classic.Build.0 = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Debug.ActiveCfg = Debug|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Debug.Build.0 = Debug|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Pro.ActiveCfg = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Pro.Build.0 = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_ProGPL.Build.0 = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Release.ActiveCfg = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Release.Build.0 = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Max.ActiveCfg = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Max.Build.0 = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Max nt.ActiveCfg = Release|Win32 @@ -913,6 +1087,10 @@ Global {DB28DE80-837F-4497-9AA9-CC0A20584C98}.pro.Build.0 = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.pro nt.ActiveCfg = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.pro nt.Build.0 = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.pro gpl.ActiveCfg = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.pro gpl.Build.0 = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.pro gpl nt.ActiveCfg = Release|Win32 + {DB28DE80-837F-4497-9AA9-CC0A20584C98}.pro gpl nt.Build.0 = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Release.ActiveCfg = Release|Win32 {DB28DE80-837F-4497-9AA9-CC0A20584C98}.Release.Build.0 = Release|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.classic.ActiveCfg = TLS|Win32 @@ -927,6 +1105,8 @@ Global {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Embedded_Debug.Build.0 = TLS_DEBUG|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Embedded_Pro.ActiveCfg = TLS|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Embedded_Pro.Build.0 = TLS|Win32 + {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Embedded_ProGPL.ActiveCfg = TLS|Win32 + {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Embedded_ProGPL.Build.0 = TLS|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Embedded_Release.ActiveCfg = TLS|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Embedded_Release.Build.0 = TLS|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Max.ActiveCfg = Max|Win32 @@ -939,6 +1119,10 @@ Global {44D9C7DC-6636-4B82-BD01-6876C64017DF}.pro.Build.0 = Release|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.pro nt.ActiveCfg = Release|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.pro nt.Build.0 = Release|Win32 + {44D9C7DC-6636-4B82-BD01-6876C64017DF}.pro gpl.ActiveCfg = Release|Win32 + {44D9C7DC-6636-4B82-BD01-6876C64017DF}.pro gpl.Build.0 = Release|Win32 + {44D9C7DC-6636-4B82-BD01-6876C64017DF}.pro gpl nt.ActiveCfg = Release|Win32 + {44D9C7DC-6636-4B82-BD01-6876C64017DF}.pro gpl nt.Build.0 = Release|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Release.ActiveCfg = Release|Win32 {44D9C7DC-6636-4B82-BD01-6876C64017DF}.Release.Build.0 = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.classic.ActiveCfg = classic|Win32 @@ -949,7 +1133,8 @@ Global {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Debug.Build.0 = Debug|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Embedded_Classic.ActiveCfg = Debug|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Embedded_Debug.ActiveCfg = Debug|Win32 - {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Embedded_Pro.ActiveCfg = Debug|Win32 + {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Embedded_Pro.ActiveCfg = Release|Win32 + {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Embedded_ProGPL.ActiveCfg = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Embedded_Release.ActiveCfg = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Max.ActiveCfg = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Max.Build.0 = Release|Win32 @@ -961,6 +1146,10 @@ Global {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.pro.Build.0 = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.pro nt.ActiveCfg = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.pro nt.Build.0 = Release|Win32 + {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.pro gpl.ActiveCfg = Release|Win32 + {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.pro gpl.Build.0 = Release|Win32 + {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.pro gpl nt.ActiveCfg = Release|Win32 + {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.pro gpl nt.Build.0 = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Release.ActiveCfg = Release|Win32 {AC47623D-933C-4A80-83BB-B6AF7CB28B4B}.Release.Build.0 = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.classic.ActiveCfg = Release|Win32 @@ -975,6 +1164,8 @@ Global {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Embedded_Debug.Build.0 = Debug|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Embedded_Pro.ActiveCfg = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Embedded_Pro.Build.0 = Release|Win32 + {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Embedded_ProGPL.Build.0 = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Embedded_Release.ActiveCfg = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Embedded_Release.Build.0 = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Max.ActiveCfg = Release|Win32 @@ -987,6 +1178,10 @@ Global {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.pro.Build.0 = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.pro nt.ActiveCfg = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.pro nt.Build.0 = Release|Win32 + {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.pro gpl.ActiveCfg = Release|Win32 + {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.pro gpl.Build.0 = Release|Win32 + {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.pro gpl nt.ActiveCfg = Release|Win32 + {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.pro gpl nt.Build.0 = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Release.ActiveCfg = Release|Win32 {207E9014-C4D1-4F6D-B76F-BC7DD7E31113}.Release.Build.0 = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.classic.ActiveCfg = classic|Win32 @@ -998,6 +1193,7 @@ Global {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Embedded_Classic.ActiveCfg = classic|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Embedded_Debug.ActiveCfg = Debug|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Embedded_Pro.ActiveCfg = classic|Win32 + {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Embedded_ProGPL.ActiveCfg = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Embedded_Release.ActiveCfg = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Max.ActiveCfg = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Max.Build.0 = Release|Win32 @@ -1009,20 +1205,26 @@ Global {16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro.Build.0 = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro nt.ActiveCfg = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro nt.Build.0 = Release|Win32 + {16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro gpl.ActiveCfg = Release|Win32 + {16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro gpl.Build.0 = Release|Win32 + {16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro gpl nt.ActiveCfg = Release|Win32 + {16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro gpl nt.Build.0 = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Release.ActiveCfg = Release|Win32 {16699B52-ECC6-4A96-A99F-A043059BA2E7}.Release.Build.0 = Release|Win32 - {EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.ActiveCfg = Debug|Win32 - {EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.Build.0 = Debug|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.ActiveCfg = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.Build.0 = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.classic nt.ActiveCfg = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.classic nt.Build.0 = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Debug.ActiveCfg = Debug|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Debug.Build.0 = Debug|Win32 - {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.ActiveCfg = Debug|Win32 - {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.Build.0 = Debug|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.ActiveCfg = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.Build.0 = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Debug.ActiveCfg = Debug|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Debug.Build.0 = Debug|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Pro.ActiveCfg = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Pro.Build.0 = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_ProGPL.Build.0 = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Release.ActiveCfg = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Release.Build.0 = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Max.ActiveCfg = Release|Win32 @@ -1035,40 +1237,49 @@ Global {EEC1300B-85A5-497C-B3E1-F708021DF859}.pro.Build.0 = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.pro nt.ActiveCfg = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.pro nt.Build.0 = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.pro gpl.ActiveCfg = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.pro gpl.Build.0 = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.pro gpl nt.ActiveCfg = Release|Win32 + {EEC1300B-85A5-497C-B3E1-F708021DF859}.pro gpl nt.Build.0 = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Release.ActiveCfg = Release|Win32 {EEC1300B-85A5-497C-B3E1-F708021DF859}.Release.Build.0 = Release|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.ActiveCfg = Debug|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.Build.0 = Debug|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic nt.ActiveCfg = Debug|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.Build.0 = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic nt.ActiveCfg = Release|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Debug.ActiveCfg = Debug|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Debug.Build.0 = Debug|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Embedded_Classic.ActiveCfg = Debug|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Embedded_Debug.ActiveCfg = Debug|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Embedded_Pro.ActiveCfg = Debug|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Embedded_Pro.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Embedded_ProGPL.ActiveCfg = Release|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Embedded_Release.ActiveCfg = Release|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Max.ActiveCfg = Release|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Max nt.ActiveCfg = Debug|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.nt.ActiveCfg = Debug|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro.ActiveCfg = Debug|Win32 - {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro nt.ActiveCfg = Debug|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Max nt.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.nt.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro nt.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro gpl.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro gpl.Build.0 = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro gpl nt.ActiveCfg = Release|Win32 + {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.pro gpl nt.Build.0 = Release|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Release.ActiveCfg = Release|Win32 {8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Release.Build.0 = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.classic.ActiveCfg = Release|Win32 - {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.classic.Build.0 = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.classic nt.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Debug.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Embedded_Classic.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Embedded_Debug.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Embedded_Pro.ActiveCfg = Release|Win32 + {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Embedded_ProGPL.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Embedded_Release.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Max.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Max nt.ActiveCfg = Release|Win32 - {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Max nt.Build.0 = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.nt.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.pro.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.pro nt.ActiveCfg = Release|Win32 + {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.pro gpl.ActiveCfg = Release|Win32 + {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.pro gpl nt.ActiveCfg = Release|Win32 {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Release.ActiveCfg = Release|Win32 - {6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Release.Build.0 = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.classic.ActiveCfg = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.classic.Build.0 = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.classic nt.ActiveCfg = Release|Win32 @@ -1078,6 +1289,7 @@ Global {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Embedded_Classic.ActiveCfg = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Embedded_Debug.ActiveCfg = Debug|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Embedded_Pro.ActiveCfg = Release|Win32 + {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Embedded_ProGPL.ActiveCfg = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Embedded_Release.ActiveCfg = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Max.ActiveCfg = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Max.Build.0 = Release|Win32 @@ -1089,18 +1301,28 @@ Global {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro.Build.0 = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro nt.ActiveCfg = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro nt.Build.0 = Release|Win32 + {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro gpl.ActiveCfg = Release|Win32 + {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro gpl.Build.0 = Release|Win32 + {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro gpl nt.ActiveCfg = Release|Win32 + {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro gpl nt.Build.0 = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Release.ActiveCfg = Release|Win32 {7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Release.Build.0 = Release|Win32 - {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.ActiveCfg = Debug|Win32 - {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.Build.0 = Debug|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.ActiveCfg = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic nt.ActiveCfg = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic nt.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Debug.ActiveCfg = Debug|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Debug.Build.0 = Debug|Win32 - {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Classic.ActiveCfg = Debug|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Classic.ActiveCfg = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Classic.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Debug.ActiveCfg = Debug|Win32 - {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Pro.ActiveCfg = Debug|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Debug.Build.0 = Debug|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Pro.ActiveCfg = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Pro.Build.0 = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_ProGPL.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Release.ActiveCfg = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Release.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Max.ActiveCfg = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Max.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Max nt.ActiveCfg = Release|Win32 @@ -1111,6 +1333,10 @@ Global {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.pro.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.pro nt.ActiveCfg = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.pro nt.Build.0 = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.pro gpl.ActiveCfg = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.pro gpl.Build.0 = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.pro gpl nt.ActiveCfg = Release|Win32 + {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.pro gpl nt.Build.0 = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Release.ActiveCfg = Release|Win32 {F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Release.Build.0 = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.classic.ActiveCfg = Release|Win32 @@ -1122,8 +1348,11 @@ Global {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Classic.ActiveCfg = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Classic.Build.0 = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Debug.ActiveCfg = Debug|Win32 + {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Debug.Build.0 = Debug|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Pro.ActiveCfg = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Pro.Build.0 = Release|Win32 + {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_ProGPL.Build.0 = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Release.ActiveCfg = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Release.Build.0 = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Max.ActiveCfg = Release|Win32 @@ -1136,6 +1365,10 @@ Global {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.pro.Build.0 = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.pro nt.ActiveCfg = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.pro nt.Build.0 = Release|Win32 + {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.pro gpl.ActiveCfg = Release|Win32 + {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.pro gpl.Build.0 = Release|Win32 + {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.pro gpl nt.ActiveCfg = Release|Win32 + {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.pro gpl nt.Build.0 = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Release.ActiveCfg = Release|Win32 {8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Release.Build.0 = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.classic.ActiveCfg = classic|Win32 @@ -1146,7 +1379,8 @@ Global {8961F149-C68A-4154-A499-A2AB39E607E8}.Debug.Build.0 = Debug|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.Embedded_Classic.ActiveCfg = Debug|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.Embedded_Debug.ActiveCfg = Debug|Win32 - {8961F149-C68A-4154-A499-A2AB39E607E8}.Embedded_Pro.ActiveCfg = Debug|Win32 + {8961F149-C68A-4154-A499-A2AB39E607E8}.Embedded_Pro.ActiveCfg = Release|Win32 + {8961F149-C68A-4154-A499-A2AB39E607E8}.Embedded_ProGPL.ActiveCfg = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.Embedded_Release.ActiveCfg = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.Max.ActiveCfg = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.Max.Build.0 = Release|Win32 @@ -1158,28 +1392,36 @@ Global {8961F149-C68A-4154-A499-A2AB39E607E8}.pro.Build.0 = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.pro nt.ActiveCfg = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.pro nt.Build.0 = Release|Win32 + {8961F149-C68A-4154-A499-A2AB39E607E8}.pro gpl.ActiveCfg = Release|Win32 + {8961F149-C68A-4154-A499-A2AB39E607E8}.pro gpl.Build.0 = Release|Win32 + {8961F149-C68A-4154-A499-A2AB39E607E8}.pro gpl nt.ActiveCfg = Release|Win32 + {8961F149-C68A-4154-A499-A2AB39E607E8}.pro gpl nt.Build.0 = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.Release.ActiveCfg = Release|Win32 {8961F149-C68A-4154-A499-A2AB39E607E8}.Release.Build.0 = Release|Win32 - {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.ActiveCfg = Debug|Win32 - {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.Build.0 = Debug|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.ActiveCfg = Release|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.Build.0 = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic nt.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic nt.Build.0 = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Debug.ActiveCfg = Debug|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Debug.Build.0 = Debug|Win32 - {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Embedded_Classic.ActiveCfg = Debug|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Embedded_Classic.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Embedded_Debug.ActiveCfg = Debug|Win32 - {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Embedded_Pro.ActiveCfg = Debug|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Embedded_Pro.ActiveCfg = Release|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Embedded_ProGPL.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Embedded_Release.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max.Build.0 = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max nt.ActiveCfg = Release|Win32 - {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max nt.Build.0 = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.nt.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.nt.Build.0 = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro.Build.0 = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro nt.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro nt.Build.0 = Release|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro gpl.ActiveCfg = Release|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro gpl.Build.0 = Release|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro gpl nt.ActiveCfg = Release|Win32 + {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro gpl nt.Build.0 = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Release.ActiveCfg = Release|Win32 {DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Release.Build.0 = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.classic.ActiveCfg = Release|Win32 @@ -1191,6 +1433,7 @@ Global {6189F838-21C6-42A1-B2D0-9146316573F7}.Embedded_Classic.ActiveCfg = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.Embedded_Debug.ActiveCfg = Debug|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.Embedded_Pro.ActiveCfg = Release|Win32 + {6189F838-21C6-42A1-B2D0-9146316573F7}.Embedded_ProGPL.ActiveCfg = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.Embedded_Release.ActiveCfg = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.Max.ActiveCfg = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.Max.Build.0 = Release|Win32 @@ -1202,8 +1445,44 @@ Global {6189F838-21C6-42A1-B2D0-9146316573F7}.pro.Build.0 = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.pro nt.ActiveCfg = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.pro nt.Build.0 = Release|Win32 + {6189F838-21C6-42A1-B2D0-9146316573F7}.pro gpl.ActiveCfg = Release|Win32 + {6189F838-21C6-42A1-B2D0-9146316573F7}.pro gpl.Build.0 = Release|Win32 + {6189F838-21C6-42A1-B2D0-9146316573F7}.pro gpl nt.ActiveCfg = Release|Win32 + {6189F838-21C6-42A1-B2D0-9146316573F7}.pro gpl nt.Build.0 = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.Release.ActiveCfg = Release|Win32 {6189F838-21C6-42A1-B2D0-9146316573F7}.Release.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.classic.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.classic.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.classic nt.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.classic nt.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Debug.ActiveCfg = Debug|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Debug.Build.0 = Debug|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Classic.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Classic.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Debug.ActiveCfg = Debug|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Debug.Build.0 = Debug|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Pro.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Pro.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_ProGPL.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_ProGPL.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Release.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Embedded_Release.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Max.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Max.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Max nt.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Max nt.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.nt.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.nt.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro nt.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro nt.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro gpl.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro gpl.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro gpl nt.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.pro gpl nt.Build.0 = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Release.ActiveCfg = Release|Win32 + {6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/VC++Files/mysqlbinlog/mysqlbinlog.vcproj b/VC++Files/mysqlbinlog/mysqlbinlog.vcproj index 9d5d4db2565..9d5d4db2565 100755..100644 --- a/VC++Files/mysqlbinlog/mysqlbinlog.vcproj +++ b/VC++Files/mysqlbinlog/mysqlbinlog.vcproj diff --git a/VC++Files/mysqlcheck/mysqlcheck.vcproj b/VC++Files/mysqlcheck/mysqlcheck.vcproj index f47e171fd65..f47e171fd65 100755..100644 --- a/VC++Files/mysqlcheck/mysqlcheck.vcproj +++ b/VC++Files/mysqlcheck/mysqlcheck.vcproj diff --git a/VC++Files/mysqldemb/mysqldemb.vcproj b/VC++Files/mysqldemb/mysqldemb.vcproj index 52081adb214..52081adb214 100755..100644 --- a/VC++Files/mysqldemb/mysqldemb.vcproj +++ b/VC++Files/mysqldemb/mysqldemb.vcproj diff --git a/VC++Files/mysqlserver/dummy.cpp b/VC++Files/mysqlserver/dummy.cpp new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/VC++Files/mysqlserver/dummy.cpp diff --git a/VC++Files/mysqlserver/mysqlserver.vcproj b/VC++Files/mysqlserver/mysqlserver.vcproj index 2c587e0a2d7..43988b8489c 100755..100644 --- a/VC++Files/mysqlserver/mysqlserver.vcproj +++ b/VC++Files/mysqlserver/mysqlserver.vcproj @@ -12,7 +12,7 @@ <Configurations> <Configuration Name="Debug|Win32" - OutputDirectory=".\Debug" + OutputDirectory="..\lib_debug" IntermediateDirectory=".\Debug" ConfigurationType="4" UseOfMFC="0" @@ -38,7 +38,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLibrarianTool" - OutputFile=".\Debug\mysqlserver.lib" + OutputFile="$(OutDir)\mysqlserver.lib" SuppressStartupBanner="TRUE"/> <Tool Name="VCMIDLTool"/> @@ -63,7 +63,7 @@ </Configuration> <Configuration Name="Release|Win32" - OutputDirectory=".\release" + OutputDirectory="..\lib_release" IntermediateDirectory=".\release" ConfigurationType="4" UseOfMFC="0" @@ -90,7 +90,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLibrarianTool" - OutputFile=".\release\mysqlserver.lib" + OutputFile="$(OutDir)\mysqlserver.lib" SuppressStartupBanner="TRUE"/> <Tool Name="VCMIDLTool"/> @@ -117,6 +117,9 @@ <References> </References> <Files> + <File + RelativePath=".\dummy.cpp"> + </File> </Files> <Globals> </Globals> diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp index 230c2221b6e..935f1411530 100644 --- a/VC++Files/mysys/mysys.dsp +++ b/VC++Files/mysys/mysys.dsp @@ -369,6 +369,10 @@ SOURCE=.\my_compress.c # End Source File # Begin Source File +SOURCE=.\my_conio.c +# End Source File +# Begin Source File + SOURCE=.\my_copy.c # End Source File # Begin Source File diff --git a/VC++Files/mysys/mysys.vcproj b/VC++Files/mysys/mysys.vcproj index 3d53fd3923c..6ec9ca6d564 100755..100644 --- a/VC++Files/mysys/mysys.vcproj +++ b/VC++Files/mysys/mysys.vcproj @@ -1639,6 +1639,9 @@ </FileConfiguration> </File> <File + RelativePath=".\mf_unixpath.c"> + </File> + <File RelativePath="mf_wcomp.c"> <FileConfiguration Name="Debug|Win32"> @@ -2198,6 +2201,49 @@ </FileConfiguration> </File> <File + RelativePath="my_conio.c"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Max|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="TLS_DEBUG|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="TLS|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File RelativePath="my_copy.c"> <FileConfiguration Name="Debug|Win32"> diff --git a/VC++Files/mysys/mysys_ia64.dsp b/VC++Files/mysys/mysys_ia64.dsp index b0ce2b4c579..10d6ca7960a 100644 --- a/VC++Files/mysys/mysys_ia64.dsp +++ b/VC++Files/mysys/mysys_ia64.dsp @@ -362,6 +362,10 @@ SOURCE=.\my_compress.c # End Source File # Begin Source File +SOURCE=.\my_conio.c +# End Source File +# Begin Source File + SOURCE=.\my_copy.c # End Source File # Begin Source File diff --git a/VC++Files/pack_isam/pack_isam.dsp b/VC++Files/pack_isam/pack_isam.dsp deleted file mode 100644 index f5f8f0bcd7a..00000000000 --- a/VC++Files/pack_isam/pack_isam.dsp +++ /dev/null @@ -1,130 +0,0 @@ -# Microsoft Developer Studio Project File - Name="pack_isam" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=pack_isam - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "pack_isam.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "pack_isam.mak" CFG="pack_isam - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "pack_isam - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "pack_isam - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE "pack_isam - Win32 classic" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=xicl6.exe -RSC=rc.exe - -!IF "$(CFG)" == "pack_isam - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "release" -# PROP Intermediate_Dir "release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -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 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:console /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 setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/pack_isam.exe" - -!ELSEIF "$(CFG)" == "pack_isam - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "debug" -# PROP Intermediate_Dir "debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../include" /I "../isam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /Fr -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -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 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:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /debug /machine:I386 /out:"../client_debug/pack_isam.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "pack_isam - Win32 classic" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "pack_isam___Win32_classic" -# PROP BASE Intermediate_Dir "pack_isam___Win32_classic" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "classic" -# PROP Intermediate_Dir "classic" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "_CONSOLE" /D "_WINDOWS" /D LICENSE=Commercial /D "DBUG_OFF" /D "_MBCS" /D "NDEBUG" /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=xilink6.exe -# ADD BASE 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 setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/pack_isam.exe" -# 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 setargv.obj ..\lib_release\isam.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib /nologo /subsystem:console /machine:I386 /out:"../client_classic/pack_isam.exe" /libpath:"..\lib_release\\" - -!ENDIF - -# Begin Target - -# Name "pack_isam - Win32 Release" -# Name "pack_isam - Win32 Debug" -# Name "pack_isam - Win32 classic" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\isam\pack_isam.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/VC++Files/pack_isam/pack_isam_ia64.dsp b/VC++Files/pack_isam/pack_isam_ia64.dsp deleted file mode 100644 index 58b88f02f08..00000000000 --- a/VC++Files/pack_isam/pack_isam_ia64.dsp +++ /dev/null @@ -1,133 +0,0 @@ -# Microsoft Developer Studio Project File - Name="pack_isam" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=pack_isam - WinIA64 classic -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "pack_isam_ia64.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "pack_isam_ia64.mak" CFG="pack_isam - WinIA64 classic" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "pack_isam - WinIA64 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "pack_isam - WinIA64 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE "pack_isam - WinIA64 classic" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "pack_isam - WinIA64 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "release" -# PROP Intermediate_Dir "release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -MTL=midl.exe -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WinIA64" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /D "_IA64_" /D "WinIA64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.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 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:console /machine:IA64 -# ADD LINK32 ..\lib_release\isam.lib ..\lib_release\mysys.lib ..\lib_release\strings.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 setargv.obj bufferoverflowU.lib /nologo /subsystem:console /out:"../client_release/pack_isam.exe" /machine:IA64 - -!ELSEIF "$(CFG)" == "pack_isam - WinIA64 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "debug" -# PROP Intermediate_Dir "debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -MTL=midl.exe -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WinIA64" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Zi /Od /I "../include" /I "../isam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "_IA64_" /D "WinIA64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# SUBTRACT CPP /Fr -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.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 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:console /debug /machine:IA64 -# ADD LINK32 ..\lib_debug\dbug.lib ..\lib_debug\isam.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.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 setargv.obj bufferoverflowU.lib /nologo /subsystem:console /incremental:no /debug /out:"../client_debug/pack_isam.exe" /machine:IA64 - -!ELSEIF "$(CFG)" == "pack_isam - WinIA64 classic" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "pack_isam___WinIA64 _classic" -# PROP BASE Intermediate_Dir "pack_isam___WinIA64 _classic" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "classic" -# PROP Intermediate_Dir "classic" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -MTL=midl.exe -# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "NDEBUG" /FD /c -# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../include" /I "../isam" /D "_CONSOLE" /D "_WINDOWS" /D LICENSE=Commercial /D "DBUG_OFF" /D "_MBCS" /D "NDEBUG" /D "_IA64_" /D "WinIA64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE 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 setargv.obj /nologo /subsystem:console /out:"../client_release/pack_isam.exe" /machine:IA64 -# ADD LINK32 ..\lib_release\isam.lib ..\lib_release\mysys.lib ..\lib_release\strings.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 setargv.obj bufferoverflowU.lib /nologo /subsystem:console /out:"../client_classic/pack_isam.exe" /libpath:"..\lib_release\\" /machine:IA64 - -!ENDIF - -# Begin Target - -# Name "pack_isam - WinIA64 Release" -# Name "pack_isam - WinIA64 Debug" -# Name "pack_isam - WinIA64 classic" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\isam\pack_isam.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/VC++Files/perror/perror.vcproj b/VC++Files/perror/perror.vcproj index 2a7bb6407c0..2a7bb6407c0 100755..100644 --- a/VC++Files/perror/perror.vcproj +++ b/VC++Files/perror/perror.vcproj diff --git a/VC++Files/regex/regex.vcproj b/VC++Files/regex/regex.vcproj index 1b52017ca3b..1b52017ca3b 100755..100644 --- a/VC++Files/regex/regex.vcproj +++ b/VC++Files/regex/regex.vcproj diff --git a/VC++Files/replace/replace.vcproj b/VC++Files/replace/replace.vcproj index 270ff494539..270ff494539 100755..100644 --- a/VC++Files/replace/replace.vcproj +++ b/VC++Files/replace/replace.vcproj diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index 6db2aca8d1c..7a9ad3e1c76 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -1283,10 +1283,6 @@ SOURCE=.\protocol.cpp # End Source File # Begin Source File -SOURCE=.\protocol_cursor.cpp -# End Source File -# Begin Source File - SOURCE=.\records.cpp !IF "$(CFG)" == "mysqld - Win32 Release" @@ -1863,6 +1859,10 @@ SOURCE=.\sql_trigger.cpp # End Source File # Begin Source File +SOURCE=.\sql_cursor.cpp +# End Source File +# Begin Source File + SOURCE=.\sql_udf.cpp # End Source File # Begin Source File diff --git a/VC++Files/sql/mysqld.vcproj b/VC++Files/sql/mysqld.vcproj index db84f081ac8..49bf74ae5a2 100755..100644 --- a/VC++Files/sql/mysqld.vcproj +++ b/VC++Files/sql/mysqld.vcproj @@ -1252,7 +1252,7 @@ </FileConfiguration> </File> <File - RelativePath="examples\ha_archive.cpp"> + RelativePath="ha_archive.cpp"> <FileConfiguration Name="classic nt|Win32"> <Tool @@ -4578,7 +4578,7 @@ </FileConfiguration> </File> <File - RelativePath="protocol_cursor.cpp"> + RelativePath="sql_cursor.cpp"> <FileConfiguration Name="classic nt|Win32"> <Tool diff --git a/VC++Files/strings/strings.vcproj b/VC++Files/strings/strings.vcproj index 8e16a0c7221..8e16a0c7221 100755..100644 --- a/VC++Files/strings/strings.vcproj +++ b/VC++Files/strings/strings.vcproj diff --git a/VC++Files/test1/mysql_thr.c b/VC++Files/test1/mysql_thr.c index c2743cb8e4c..a1ac09f2784 100644 --- a/VC++Files/test1/mysql_thr.c +++ b/VC++Files/test1/mysql_thr.c @@ -33,7 +33,7 @@ typedef CRITICAL_SECTION pthread_mutex_t; #define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
#define pthread_mutex_unlock(A) LeaveCriticalSection(A)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
-#define pthread_handler_decl(A,B) unsigned __cdecl A(void *B)
+#define pthread_handler_t unsigned __cdecl typedef unsigned (__cdecl *pthread_handler)(void *);
#define pthread_self() GetCurrentThread()
@@ -155,7 +155,7 @@ int _my_errno(void) ** The test program
*****************************************************************************/
-pthread_handler_decl(test_thread,arg)
+pthread_handler_t test_thread(void *arg) {
MYSQL mysql;
MYSQL_RES *res;
diff --git a/VC++Files/test1/test1.vcproj b/VC++Files/test1/test1.vcproj index 6a850f7b2e3..6a850f7b2e3 100755..100644 --- a/VC++Files/test1/test1.vcproj +++ b/VC++Files/test1/test1.vcproj diff --git a/VC++Files/tests/mysql_client_test.vcproj b/VC++Files/tests/mysql_client_test.vcproj index adcc680b6e7..89a9b71e60a 100755..100644 --- a/VC++Files/tests/mysql_client_test.vcproj +++ b/VC++Files/tests/mysql_client_test.vcproj @@ -25,7 +25,7 @@ AdditionalIncludeDirectories="../include,../" PreprocessorDefinitions="DBUG_OFF;_WINDOWS;SAFE_MUTEX;USE_TLS;MYSQL_CLIENT;__WIN__;_WIN32" StringPooling="TRUE" - RuntimeLibrary="1" + RuntimeLibrary="0" EnableFunctionLevelLinking="TRUE" PrecompiledHeaderFile=".\Release/mysql_client_test.pch" AssemblerListingLocation=".\Release/" @@ -38,7 +38,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" - AdditionalDependencies="odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib Ws2_32.lib" OutputFile="..\client_release\mysql_client_test.exe" LinkIncremental="1" SuppressStartupBanner="TRUE" @@ -98,7 +98,7 @@ Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" - AdditionalDependencies="odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Debug\yassl.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib" OutputFile="..\client_debug\mysql_client_test.exe" LinkIncremental="1" SuppressStartupBanner="TRUE" diff --git a/VC++Files/thr_test/thr_test.c b/VC++Files/thr_test/thr_test.c index 3427eed8441..efb9ea27ba7 100644 --- a/VC++Files/thr_test/thr_test.c +++ b/VC++Files/thr_test/thr_test.c @@ -44,7 +44,7 @@ typedef CRITICAL_SECTION pthread_mutex_t; #define pthread_mutex_lock(A) (EnterCriticalSection(A),0) #define pthread_mutex_unlock(A) LeaveCriticalSection(A) #define pthread_mutex_destroy(A) DeleteCriticalSection(A) -#define pthread_handler_decl(A,B) unsigned __cdecl A(void *B) +#define pthread_handler_t unsigned __cdecl typedef unsigned (__cdecl *pthread_handler)(void *); #define pthread_self() GetCurrentThread() @@ -174,7 +174,7 @@ int _my_errno(void) ** The test program *****************************************************************************/ -pthread_handler_decl(test_thread,arg) +pthread_handler_t test_thread(void *arg) { pthread_mutex_lock(&LOCK_thread_count); thread_count--; diff --git a/VC++Files/thr_test/thr_test.vcproj b/VC++Files/thr_test/thr_test.vcproj index ede9bd04de8..ede9bd04de8 100755..100644 --- a/VC++Files/thr_test/thr_test.vcproj +++ b/VC++Files/thr_test/thr_test.vcproj diff --git a/VC++Files/vio/vio.vcproj b/VC++Files/vio/vio.vcproj index 3f50c1546fb..3f50c1546fb 100755..100644 --- a/VC++Files/vio/vio.vcproj +++ b/VC++Files/vio/vio.vcproj diff --git a/VC++Files/zlib/zlib.vcproj b/VC++Files/zlib/zlib.vcproj index ee17d915a1a..ee17d915a1a 100755..100644 --- a/VC++Files/zlib/zlib.vcproj +++ b/VC++Files/zlib/zlib.vcproj diff --git a/client/client_priv.h b/client/client_priv.h index 18102fa8b16..a9d5364df49 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -51,5 +51,5 @@ enum options_client #endif OPT_TRIGGERS, OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE, - OPT_AUTO_CLOSE + OPT_TZ_UTC, OPT_AUTO_CLOSE }; diff --git a/client/mysql.cc b/client/mysql.cc index f4361f77f4c..bf417e73e22 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -320,7 +320,7 @@ static void initialize_readline (char *name); static void fix_history(String *final_command); #endif -static COMMANDS *find_command (char *name,char cmd_name); +static COMMANDS *find_command(char *name,char cmd_name); static bool add_line(String &buffer,char *line,char *in_string, bool *ml_comment); static void remove_cntrl(String &buffer); @@ -959,10 +959,15 @@ static int get_options(int argc, char **argv) static int read_and_execute(bool interactive) { -#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) +#if defined(OS2) || defined(__NETWARE__) char linebuffer[254]; String buffer; #endif +#if defined(__WIN__) + String tmpbuf; + String buffer; +#endif + char *line; char in_string=0; ulong line_number=0; @@ -993,7 +998,7 @@ static int read_and_execute(bool interactive) #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) tee_fputs(prompt, stdout); -#ifdef __NETWARE__ +#if defined(__NETWARE__) line=fgets(linebuffer, sizeof(linebuffer)-1, stdin); /* Remove the '\n' */ if (line) @@ -1002,7 +1007,23 @@ static int read_and_execute(bool interactive) if (p != NULL) *p = '\0'; } -#else +#elif defined(__WIN__) + if (!tmpbuf.is_alloced()) + tmpbuf.alloc(65535); + tmpbuf.length(0); + buffer.length(0); + unsigned long clen; + do + { + line= my_cgets((char*)tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen); + buffer.append(line, clen); + /* + if we got buffer fully filled than there is a chance that + something else is still in console input buffer + */ + } while (tmpbuf.alloced_length() <= clen); + line= buffer.c_ptr(); +#else /* OS2 */ buffer.length(0); /* _cgets() expects the buffer size - 3 as the first byte */ linebuffer[0]= (char) sizeof(linebuffer) - 3; @@ -1078,17 +1099,24 @@ static int read_and_execute(bool interactive) status.exit_status=0; } } + #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) buffer.free(); #endif +#if defined( __WIN__) + tmpbuf.free(); +#endif + return status.exit_status; } -static COMMANDS *find_command (char *name,char cmd_char) +static COMMANDS *find_command(char *name,char cmd_char) { uint len; char *end; + DBUG_ENTER("find_command"); + DBUG_PRINT("enter",("name: '%s' char: %d", name ? name : "NULL", cmd_char)); if (!name) { @@ -1100,12 +1128,16 @@ static COMMANDS *find_command (char *name,char cmd_char) while (my_isspace(charset_info,*name)) name++; /* - As special case we allow row that starts with word delimiter - to be able to change delimiter if someone has delimiter 'delimiter'. + If there is an \\g in the row or if the row has a delimiter but + this is not a delimiter command, let add_line() take care of + parsing the row and calling find_command() */ if (strstr(name, "\\g") || (strstr(name, delimiter) && - strncmp(name, "delimiter", 9))) - return ((COMMANDS *) 0); + strlen(name) >= 9 && + my_strnncoll(charset_info,(uchar*) name, + 9, + (const uchar*) "delimiter", 9))) + DBUG_RETURN((COMMANDS *) 0); if ((end=strcont(name," \t"))) { len=(uint) (end - name); @@ -1121,15 +1153,18 @@ static COMMANDS *find_command (char *name,char cmd_char) for (uint i= 0; commands[i].name; i++) { if (commands[i].func && - ((name && + ((name && !my_strnncoll(charset_info,(uchar*)name,len, (uchar*)commands[i].name,len) && !commands[i].name[len] && (!end || (end && commands[i].takes_params))) || !name && commands[i].cmd_char == cmd_char)) - return (&commands[i]); + { + DBUG_PRINT("exit",("found command: %s", commands[i].name)); + DBUG_RETURN(&commands[i]); + } } - return ((COMMANDS *) 0); + DBUG_RETURN((COMMANDS *) 0); } @@ -1140,15 +1175,16 @@ static bool add_line(String &buffer,char *line,char *in_string, char buff[80], *pos, *out; COMMANDS *com; bool need_space= 0; + DBUG_ENTER("add_line"); if (!line[0] && buffer.is_empty()) - return 0; + DBUG_RETURN(0); #ifdef HAVE_READLINE if (status.add_to_history && line[0] && not_in_history(line)) add_history(line); #endif #ifdef USE_MB - char *strend=line+(uint) strlen(line); + char *end_of_line=line+(uint) strlen(line); #endif for (pos=out=line ; (inchar= (uchar) *pos) ; pos++) @@ -1157,13 +1193,19 @@ static bool add_line(String &buffer,char *line,char *in_string, buffer.is_empty()) continue; #ifdef USE_MB - int l; + int length; if (use_mb(charset_info) && - (l = my_ismbchar(charset_info, pos, strend))) { - while (l--) - *out++ = *pos++; - pos--; - continue; + (length= my_ismbchar(charset_info, pos, end_of_line))) + { + if (!*ml_comment) + { + while (length--) + *out++ = *pos++; + pos--; + } + else + pos+= length - 1; + continue; } #endif if (!*ml_comment && inchar == '\\') @@ -1183,7 +1225,7 @@ static bool add_line(String &buffer,char *line,char *in_string, const String tmp(line,(uint) (out-line), charset_info); buffer.append(tmp); if ((*com->func)(&buffer,pos-1) > 0) - return 1; // Quit + DBUG_RETURN(1); // Quit if (com->takes_params) { for (pos++ ; @@ -1201,29 +1243,40 @@ static bool add_line(String &buffer,char *line,char *in_string, { sprintf(buff,"Unknown command '\\%c'.",inchar); if (put_info(buff,INFO_ERROR) > 0) - return 1; + DBUG_RETURN(1); *out++='\\'; *out++=(char) inchar; continue; } } - - else if (!*ml_comment && (*pos == *delimiter && - is_prefix(pos + 1, delimiter + 1)) && - !*in_string) + else if (!*ml_comment && !*in_string && + (*pos == *delimiter && is_prefix(pos + 1, delimiter + 1) || + buffer.length() == 0 && (out - line) >= 9 && + !my_strcasecmp(charset_info, line, "delimiter"))) { uint old_delimiter_length= delimiter_length; if (out != line) buffer.append(line, (uint) (out - line)); // Add this line if ((com= find_command(buffer.c_ptr(), 0))) { + if (com->func == com_delimiter) + { + /* + Delimiter wants the get rest of the given line as argument to + allow one to change ';' to ';;' and back + */ + char *end= strend(pos); + buffer.append(pos, (uint) (end - pos)); + /* Ensure pos will point at \0 after the pos+= below */ + pos= end - old_delimiter_length + 1; + } if ((*com->func)(&buffer, buffer.c_ptr()) > 0) - return 1; // Quit + DBUG_RETURN(1); // Quit } else { if (com_go(&buffer, 0) > 0) // < 0 is not fatal - return 1; + DBUG_RETURN(1); } buffer.length(0); out= line; @@ -1275,9 +1328,9 @@ static bool add_line(String &buffer,char *line,char *in_string, if (buffer.length() + length >= buffer.alloced_length()) buffer.realloc(buffer.length()+length+IO_SIZE); if (!(*ml_comment) && buffer.append(line,length)) - return 1; + DBUG_RETURN(1); } - return 0; + DBUG_RETURN(0); } /***************************************************************** diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index fb9ed3af70c..ffb653eabdb 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1003,7 +1003,8 @@ static int dump_remote_log_entries(const char* logname) { char buf[128]; LAST_EVENT_INFO last_event_info; - uint len, logname_len; + ulong len; + uint logname_len; NET* net; int error= 0; my_off_t old_off= start_position_mot; @@ -1434,7 +1435,7 @@ int main(int argc, char** argv) of transaction. */ fprintf(result_file, - "ROLLBACK;\n" + "# End of log file\nROLLBACK /* added by mysqlbinlog */;\n" "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n"); if (disable_log_bin) fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n"); diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 35d57e0394e..2eb3e55c2e9 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -497,6 +497,9 @@ static int process_all_tables_in_db(char *database) static int use_db(char *database) { + if (mysql_get_server_version(sock) >= 50003 && + !my_strcasecmp(&my_charset_latin1, database, "information_schema")) + return 1; if (mysql_select_db(sock, database)) { DBerror(sock, "when selecting the database"); diff --git a/client/mysqldump.c b/client/mysqldump.c index 7c81f6909c1..0e7248697c2 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -30,7 +30,7 @@ ** master/autocommit code by Brian Aker <brian@tangent.org> ** SSL by ** Andrei Errapart <andreie@no.spam.ee> -** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> +** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> ** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up ** and adapted to mysqldump 05/11/01 by Jani Tolonen ** Added --single-transaction option 06/06/2002 by Peter Zaitsev @@ -70,6 +70,11 @@ /* Size of buffer for dump's select query */ #define QUERY_LENGTH 1536 +/* ignore table flags */ +#define IGNORE_NONE 0x00 /* no ignore */ +#define IGNORE_DATA 0x01 /* don't dump data for this table */ +#define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ + static char *add_load_option(char *ptr, const char *object, const char *statement); static ulong find_set(TYPELIB *lib, const char *x, uint length, @@ -87,7 +92,7 @@ static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1, opt_single_transaction=0, opt_comments= 0, opt_compact= 0, opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, opt_complete_insert= 0, opt_drop_database= 0, - opt_dump_triggers= 0; + opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*sock=0; static my_bool insert_pat_inited=0; @@ -209,9 +214,7 @@ static struct my_option my_long_options[] = {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", (gptr*) &default_charset, (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; " - "currently ignored because of http://bugs.mysql.com/bug.php?id=7815 " - "but will be re-enabled later", + {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; ", (gptr*) &opt_delayed, (gptr*) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"delete-master-logs", OPT_DELETE_MASTER_LOGS, @@ -339,6 +342,9 @@ static struct my_option my_long_options[] = {"result-file", 'r', "Direct output to a given file. This option should be used in MSDOS, because it prevents new line '\\n' from being converted to '\\r\\n' (carriage return + line feed).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"routines", 'R', "Dump routines FUNCTIONS and PROCEDURES.", + (gptr*) &opt_routines, (gptr*) &opt_routines, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, {"set-charset", OPT_SET_CHARSET, "Add 'SET NAMES default_character_set' to the output. Enabled by default; suppress with --skip-set-charset.", (gptr*) &opt_set_charset, (gptr*) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1, @@ -379,6 +385,9 @@ static struct my_option my_long_options[] = {"triggers", OPT_TRIGGERS, "Dump triggers for each dumped table", (gptr*) &opt_dump_triggers, (gptr*) &opt_dump_triggers, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"tz-utc", OPT_TZ_UTC, + "SET TIME_ZONE='+00:00' at top of dump to allow dumping of TIMESTAMP data between servers with different time zones.", + (gptr*) &opt_tz_utc, (gptr*) &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, #ifndef DONT_ALLOW_USER_CHANGE {"user", 'u', "User for login if not current user.", (gptr*) ¤t_user, (gptr*) ¤t_user, 0, GET_STR, REQUIRED_ARG, @@ -408,7 +417,7 @@ static int init_dumping(char *); static int dump_databases(char **); static int dump_all_databases(); static char *quote_name(const char *name, char *buff, my_bool force); -static const char *check_if_ignore_table(const char *table_name); +char check_if_ignore_table(const char *table_name, char *table_type); static char *primary_key_fields(const char *table_name); static my_bool get_view_structure(char *table, char* db); static my_bool dump_all_views_in_db(char *database); @@ -503,6 +512,13 @@ static void write_header(FILE *sql_file, char *db_name) "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;" "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;" "\n/*!40101 SET NAMES %s */;\n",default_charset); + + if (opt_tz_utc) + { + fprintf(sql_file, "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n"); + fprintf(sql_file, "/*!40103 SET TIME_ZONE='+00:00' */;\n"); + } + if (!path) { fprintf(md_result_file,"\ @@ -529,6 +545,9 @@ static void write_footer(FILE *sql_file) } else if (!opt_compact) { + if (opt_tz_utc) + fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n"); + fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n"); if (!path) { @@ -717,25 +736,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } break; } -#ifndef REMOVE_THIS_CODE_WHEN_FIX_BUG_7815 - case (int) OPT_DELAYED: - /* - Because of http://bugs.mysql.com/bug.php?id=7815, we disable - --delayed-insert; when the bug gets fixed by checking the storage engine - (using the table definition cache) before printing INSERT DELAYED, we - can correct the option's description and re-enable it again (scheduled - for later 5.0 or 5.1 versions). - It's ok to do the if() below as get_one_option is called after - opt_delayed is set. - */ - if (opt_delayed) - { - fprintf(stderr, "Warning: ignoring --delayed-insert (as explained " - "in the output of 'mysqldump --help').\n"); - opt_delayed= 0; - } - break; -#endif } return 0; } @@ -915,6 +915,20 @@ static int dbConnect(char *host, char *user,char *passwd) safe_exit(EX_MYSQLERR); return 1; } + /* + set time_zone to UTC to allow dumping date types between servers with + different time zone settings + */ + if (opt_tz_utc) + { + my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */"); + if (mysql_query_with_error_report(sock, 0, buff)) + { + mysql_close(sock); + safe_exit(EX_MYSQLERR); + return 1; + } + } return 0; } /* dbConnect */ @@ -961,6 +975,22 @@ static my_bool test_if_special_chars(const char *str) +/* + quote_name(name, buff, force) + + Quotes char string, taking into account compatible mode + + Args + + name Unquoted string containing that which will be quoted + buff The buffer that contains the quoted value, also returned + force Flag to make it ignore 'test_if_special_chars' + + Returns + + buff quoted string + +*/ static char *quote_name(const char *name, char *buff, my_bool force) { char *to= buff; @@ -1157,7 +1187,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name, uint i; MYSQL_FIELD *field; ulong *lengths= mysql_fetch_lengths(tableRes); - + fprintf(xml_file, "\t\t<%s", row_name); check_io(xml_file); mysql_field_seek(tableRes, 0); @@ -1177,21 +1207,131 @@ static void print_xml_row(FILE *xml_file, const char *row_name, check_io(xml_file); } +/* + dump_routines_for_db + -- retrievs list of routines for a given db, and prints out + the CREATE PROCEDURE definition into the output (the dump). + + This function has logic to print the appropriate syntax depending on whether + this is a procedure or functions + + RETURN + 0 Success + 1 Error +*/ + +static uint dump_routines_for_db(char *db) +{ + char query_buff[512]; + const char *routine_type[]= {"FUNCTION", "PROCEDURE"}; + char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; + char *routine_name; + int i; + FILE *sql_file= md_result_file; + MYSQL_RES *routine_res, *routine_list_res; + MYSQL_ROW row, routine_list_row; + DBUG_ENTER("dump_routines_for_db"); + DBUG_PRINT("enter", ("db: '%s'", db)); + + mysql_real_escape_string(sock, db_name_buff, db, strlen(db)); + + /* nice comments */ + if (opt_comments) + fprintf(sql_file, "\n--\n-- Dumping routines for database '%s'\n--\n", db); + + /* + not using "mysql_query_with_error_report" because we may have not + enough privileges to lock mysql.proc. + */ + if (lock_tables) + mysql_query(sock, "LOCK TABLES mysql.proc READ"); + + fprintf(sql_file, "DELIMITER ;;\n"); + + /* 0, retrieve and dump functions, 1, procedures */ + for (i= 0; i <= 1; i++) + { + my_snprintf(query_buff, sizeof(query_buff), + "SHOW %s STATUS WHERE Db = '%s'", + routine_type[i], db_name_buff); + + if (mysql_query_with_error_report(sock, &routine_list_res, query_buff)) + DBUG_RETURN(1); + + if (mysql_num_rows(routine_list_res)) + { + + while ((routine_list_row= mysql_fetch_row(routine_list_res))) + { + DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i], + name_buff)); + routine_name= quote_name(routine_list_row[1], name_buff, 0); + my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s", + routine_type[i], routine_name); + + if (mysql_query_with_error_report(sock, &routine_res, query_buff)) + DBUG_RETURN(1); + + while ((row= mysql_fetch_row(routine_res))) + { + /* + if the user has EXECUTE privilege he see routine names, but NOT the + routine body of other routines that are not the creator of! + */ + DBUG_PRINT("info",("length of body for %s row[2] '%s' is %d", + routine_name, row[2], strlen(row[2]))); + if (strlen(row[2])) + { + if (opt_drop) + fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;;\n", + routine_type[i], routine_name); + /* + we need to change sql_mode only for the CREATE + PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name + */; + fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/;;\n", + row[1] /* sql_mode */); + fprintf(sql_file, "/*!50003 %s */;;\n", row[2]); + fprintf(sql_file, + "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/" + ";;\n"); + } + } /* end of routine printing */ + } /* end of list of routines */ + mysql_free_result(routine_res); + } + mysql_free_result(routine_list_res); + } /* end of for i (0 .. 1) */ + /* set the delimiter back to ';' */ + fprintf(sql_file, "DELIMITER ;\n"); + + if (lock_tables) + mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); + DBUG_RETURN(0); +} /* - getTableStructure -- retrievs database structure, prints out corresponding - CREATE statement and fills out insert_pat. + get_table_structure -- retrievs database structure, prints out corresponding + CREATE statement and fills out insert_pat if the table is the type we will + be dumping. + + ARGS + table - table name + db - db name + table_type - table type ie "InnoDB" + ignore_flag - what we must particularly ignore - see IGNORE_ defines above RETURN number of fields in table, 0 if error */ -static uint get_table_structure(char *table, char *db) +static uint get_table_structure(char *table, char *db, char *table_type, + char *ignore_flag) { MYSQL_RES *tableRes; MYSQL_ROW row; - my_bool init=0; - uint numFields; + my_bool init=0, delayed, write_data, complete_insert; + uint num_fields; char *result_table, *opt_quoted_table; const char *insert_option; char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; @@ -1200,18 +1340,32 @@ static uint get_table_structure(char *table, char *db) FILE *sql_file = md_result_file; int len; DBUG_ENTER("get_table_structure"); - DBUG_PRINT("enter", ("db: %s, table: %s", db, table)); + DBUG_PRINT("enter", ("db: %s table: %s", db, table)); - if (!insert_pat_inited) + *ignore_flag= check_if_ignore_table(table, table_type); + + delayed= opt_delayed; + if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED)) { - insert_pat_inited= init_dynamic_string(&insert_pat, "", 1024, 1024); + delayed= 0; + if (verbose) + fprintf(stderr, + "-- Warning: Unable to use delayed inserts for table '%s' " + "because it's of type %s\n", table, table_type); } - else - dynstr_set(&insert_pat, ""); - insert_option= ((opt_delayed && opt_ignore) ? " DELAYED IGNORE " : - opt_delayed ? " DELAYED " : - opt_ignore ? " IGNORE " : ""); + complete_insert= 0; + if ((write_data= !(*ignore_flag & IGNORE_DATA))) + { + complete_insert= opt_complete_insert; + if (!insert_pat_inited) + insert_pat_inited= init_dynamic_string(&insert_pat, "", 1024, 1024); + else + dynstr_set(&insert_pat, ""); + } + + insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " : + delayed ? " DELAYED " : opt_ignore ? " IGNORE " : ""); if (verbose) fprintf(stderr, "-- Retrieving table structure for table %s...\n", table); @@ -1220,7 +1374,8 @@ static uint get_table_structure(char *table, char *db) "SET OPTION SQL_QUOTE_SHOW_CREATE=%d", (opt_quoted || opt_keywords)); if (!create_options) - strmov(query_buff+len, "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */"); + strmov(query_buff+len, + "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */"); result_table= quote_name(table, table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); @@ -1330,41 +1485,6 @@ static uint get_table_structure(char *table, char *db) fprintf(sql_file, "%s;\n", row[1]); check_io(sql_file); mysql_free_result(tableRes); - if (opt_dump_triggers && - mysql_get_server_version(sock) >= 50009) - { - my_snprintf(query_buff, sizeof(query_buff), - "SHOW TRIGGERS LIKE %s", - quote_for_like(table, name_buff)); - - - if (mysql_query_with_error_report(sock, &tableRes, query_buff)) - { - if (path) - my_fclose(sql_file, MYF(MY_WME)); - safe_exit(EX_MYSQLERR); - DBUG_RETURN(0); - } - if (mysql_num_rows(tableRes)) - fprintf(sql_file, "\n/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n\ -DELIMITER //;\n"); - while ((row=mysql_fetch_row(tableRes))) - { - fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/ //\n\ -/*!50003 CREATE TRIGGER %s %s %s ON %s FOR EACH ROW%s*/ //\n\n", - row[6], /* sql_mode */ - quote_name(row[0], name_buff, 0), /* Trigger */ - row[4], /* Timing */ - row[1], /* Event */ - result_table, - row[3] /* Statement */); - } - if (mysql_num_rows(tableRes)) - fprintf(sql_file, - "DELIMITER ;//\n\ -/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;"); - mysql_free_result(tableRes); - } } my_snprintf(query_buff, sizeof(query_buff), "show fields from %s", result_table); @@ -1376,34 +1496,44 @@ DELIMITER //;\n"); DBUG_RETURN(0); } - dynstr_append_mem(&insert_pat, "INSERT ", 7); - dynstr_append(&insert_pat, insert_option); - dynstr_append_mem(&insert_pat, "INTO ", 5); - dynstr_append(&insert_pat, opt_quoted_table); - if (opt_complete_insert) - { - dynstr_append_mem(&insert_pat, " (", 2); - } - else + /* + If write_data is true, then we build up insert statements for + the table's data. Note: in subsequent lines of code, this test + will have to be performed each time we are appending to + insert_pat. + */ + if (write_data) { - dynstr_append_mem(&insert_pat, " VALUES ", 8); - if (!extended_insert) - dynstr_append_mem(&insert_pat, "(", 1); + dynstr_append_mem(&insert_pat, "INSERT ", 7); + dynstr_append(&insert_pat, insert_option); + dynstr_append_mem(&insert_pat, "INTO ", 5); + dynstr_append(&insert_pat, opt_quoted_table); + if (complete_insert) + { + dynstr_append_mem(&insert_pat, " (", 2); + } + else + { + dynstr_append_mem(&insert_pat, " VALUES ", 8); + if (!extended_insert) + dynstr_append_mem(&insert_pat, "(", 1); + } } while ((row=mysql_fetch_row(tableRes))) { - if (init) + if (complete_insert) { - if (opt_complete_insert) + if (init) + { dynstr_append_mem(&insert_pat, ", ", 2); - } - init=1; - if (opt_complete_insert) + } + init=1; dynstr_append(&insert_pat, quote_name(row[SHOW_FIELDNAME], name_buff, 0)); + } } - numFields = (uint) mysql_num_rows(tableRes); + num_fields= (uint) mysql_num_rows(tableRes); mysql_free_result(tableRes); } else @@ -1449,19 +1579,20 @@ DELIMITER //;\n"); check_io(sql_file); } - dynstr_append_mem(&insert_pat, "INSERT ", 7); - dynstr_append(&insert_pat, insert_option); - dynstr_append_mem(&insert_pat, "INTO ", 5); - dynstr_append(&insert_pat, result_table); - if (opt_complete_insert) - { - dynstr_append_mem(&insert_pat, " (", 2); - } - else + if (write_data) { - dynstr_append_mem(&insert_pat, " VALUES ", 8); - if (!extended_insert) - dynstr_append_mem(&insert_pat, "(", 1); + dynstr_append_mem(&insert_pat, "INSERT ", 7); + dynstr_append(&insert_pat, insert_option); + dynstr_append_mem(&insert_pat, "INTO ", 5); + dynstr_append(&insert_pat, result_table); + if (opt_complete_insert) + dynstr_append_mem(&insert_pat, " (", 2); + else + { + dynstr_append_mem(&insert_pat, " VALUES ", 8); + if (!extended_insert) + dynstr_append_mem(&insert_pat, "(", 1); + } } while ((row=mysql_fetch_row(tableRes))) @@ -1474,7 +1605,7 @@ DELIMITER //;\n"); fputs(",\n",sql_file); check_io(sql_file); } - if (opt_complete_insert) + if (complete_insert) dynstr_append_mem(&insert_pat, ", ", 2); } init=1; @@ -1509,7 +1640,7 @@ DELIMITER //;\n"); check_io(sql_file); } } - numFields = (uint) mysql_num_rows(tableRes); + num_fields = (uint) mysql_num_rows(tableRes); mysql_free_result(tableRes); if (!tFlag) { @@ -1561,7 +1692,7 @@ DELIMITER //;\n"); print_xml_row(sql_file, "key", tableRes, &row); continue; } - + if (atoi(row[3]) == 1) { if (keynr++) @@ -1618,9 +1749,7 @@ DELIMITER //;\n"); else { if (opt_xml) - { print_xml_row(sql_file, "options", tableRes, &row); - } else { fputs("/*!",sql_file); @@ -1653,10 +1782,75 @@ continue_xml: write_footer(sql_file); my_fclose(sql_file, MYF(MY_WME)); } - DBUG_RETURN(numFields); + DBUG_RETURN(num_fields); } /* get_table_structure */ +/* + + dump_triggers_for_table + + Dumps the triggers given a table/db name. This should be called after + the tables have been dumped in case a trigger depends on the existence + of a table + +*/ + +static void dump_triggers_for_table (char *table, char *db) +{ + char *result_table; + char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; + char query_buff[512]; + uint old_opt_compatible_mode=opt_compatible_mode; + FILE *sql_file = md_result_file; + MYSQL_RES *result; + MYSQL_ROW row; + + DBUG_ENTER("dump_triggers_for_table"); + DBUG_PRINT("enter", ("db: %s, table: %s", db, table)); + + /* Do not use ANSI_QUOTES on triggers in dump */ + opt_compatible_mode&= ~MASK_ANSI_QUOTES; + result_table= quote_name(table, table_buff, 1); + + my_snprintf(query_buff, sizeof(query_buff), + "SHOW TRIGGERS LIKE %s", + quote_for_like(table, name_buff)); + + if (mysql_query_with_error_report(sock, &result, query_buff)) + { + if (path) + my_fclose(sql_file, MYF(MY_WME)); + safe_exit(EX_MYSQLERR); + DBUG_VOID_RETURN; + } + if (mysql_num_rows(result)) + fprintf(sql_file, "\n/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n\ +DELIMITER ;;\n"); + while ((row=mysql_fetch_row(result))) + { + fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n\ +/*!50003 CREATE TRIGGER %s %s %s ON %s FOR EACH ROW%s */;;\n\n", + row[6], /* sql_mode */ + quote_name(row[0], name_buff, 0), /* Trigger */ + row[4], /* Timing */ + row[1], /* Event */ + result_table, + row[3] /* Statement */); + } + if (mysql_num_rows(result)) + fprintf(sql_file, + "DELIMITER ;\n" + "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"); + mysql_free_result(result); + /* + make sure to set back opt_compatible mode to + original value + */ + opt_compatible_mode=old_opt_compatible_mode; + DBUG_VOID_RETURN; +} + static char *add_load_option(char *ptr,const char *object, const char *statement) { @@ -1678,10 +1872,10 @@ static char *add_load_option(char *ptr,const char *object, /* -** Allow the user to specify field terminator strings like: -** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline) -** This is done by doubleing ' and add a end -\ if needed to avoid -** syntax errors from the SQL parser. + Allow the user to specify field terminator strings like: + "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline) + This is done by doubling ' and add a end -\ if needed to avoid + syntax errors from the SQL parser. */ static char *field_escape(char *to,const char *from,uint length) @@ -1722,20 +1916,40 @@ static char *alloc_query_str(ulong size) /* -** dump_table saves database contents as a series of INSERT statements. + + SYNOPSIS + dump_table() + + dump_table saves database contents as a series of INSERT statements. + + ARGS + table - table name + db - db name + + RETURNS + void */ -static void dump_table(uint numFields, char *table) +static void dump_table(char *table, char *db) { + char ignore_flag; char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3]; + char table_type[NAME_LEN]; char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table; char *query= query_buf; + int error= 0; + ulong rownr, row_break, total_length, init_length; + uint num_fields; MYSQL_RES *res; MYSQL_FIELD *field; MYSQL_ROW row; - ulong rownr, row_break, total_length, init_length; - const char *table_type; - int error= 0; + DBUG_ENTER("dump_table"); + + /* + Make sure you get the create table info before the following check for + --no-data flag below. Otherwise, the create table info won't be printed. + */ + num_fields= get_table_structure(table, db, table_type, &ignore_flag); /* Check --no-data flag */ if (dFlag) @@ -1744,32 +1958,37 @@ static void dump_table(uint numFields, char *table) fprintf(stderr, "-- Skipping dump data for table '%s', --no-data was used\n", table); - return; + DBUG_VOID_RETURN; } + DBUG_PRINT("info", + ("ignore_flag: %x num_fields: %d", (int) ignore_flag, + num_fields)); + /* + If the table type is a merge table or any type that has to be + _completely_ ignored and no data dumped + */ + if (ignore_flag & IGNORE_DATA) + { + if (verbose) + fprintf(stderr, + "-- Warning: Skipping data for table '%s' because it's of type %s\n", + table, table_type); + DBUG_VOID_RETURN; + } /* Check that there are any fields in the table */ - if (numFields == 0) + if (num_fields == 0) { if (verbose) fprintf(stderr, "-- Skipping dump data for table '%s', it has no fields\n", table); - return; + DBUG_VOID_RETURN; } result_table= quote_name(table,table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); - /* Check table type */ - if ((table_type= check_if_ignore_table(table))) - { - if (verbose) - fprintf(stderr, - "-- Skipping data for table '%s' because it's of type %s\n", - table, table_type); - return; - } - if (verbose) fprintf(stderr, "-- Sending SELECT query...\n"); if (path) @@ -1812,7 +2031,7 @@ static void dump_table(uint numFields, char *table) if (mysql_real_query(sock, query, (uint) (end - query))) { DB_error(sock, "when executing 'SELECT INTO OUTFILE'"); - return; + DBUG_VOID_RETURN; } } else @@ -1867,7 +2086,7 @@ static void dump_table(uint numFields, char *table) DB_error(sock, "when retrieving data from server"); if (verbose) fprintf(stderr, "-- Retrieving rows...\n"); - if (mysql_num_fields(res) != numFields) + if (mysql_num_fields(res) != num_fields) { fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n", my_progname, result_table); @@ -1930,14 +2149,15 @@ static void dump_table(uint numFields, char *table) error= EX_CONSCHECK; goto err; } - + /* 63 is my_charset_bin. If charsetnr is not 63, we have not a BLOB but a TEXT column. we'll dump in hex only BLOB columns. */ is_blob= (opt_hex_blob && field->charsetnr == 63 && - (field->type == MYSQL_TYPE_STRING || + (field->type == MYSQL_TYPE_BIT || + field->type == MYSQL_TYPE_STRING || field->type == MYSQL_TYPE_VAR_STRING || field->type == MYSQL_TYPE_VARCHAR || field->type == MYSQL_TYPE_BLOB || @@ -2164,14 +2384,14 @@ static void dump_table(uint numFields, char *table) mysql_free_result(res); if (query != query_buf) my_free(query, MYF(MY_ALLOW_ZERO_PTR)); - } - return; + } + DBUG_VOID_RETURN; err: if (query != query_buf) my_free(query, MYF(MY_ALLOW_ZERO_PTR)); safe_exit(error); - return; + DBUG_VOID_RETURN; } /* dump_table */ @@ -2372,12 +2592,20 @@ static int dump_all_tables_in_db(char *database) char *end= strmov(afterdot, table); if (include_table(hash_key, end - hash_key)) { - numrows = get_table_structure(table, database); - dump_table(numrows,table); + dump_table(table,database); my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); order_by= 0; + if (opt_dump_triggers && ! opt_xml && + mysql_get_server_version(sock) >= 50009) + dump_triggers_for_table(table, database); } } + if (opt_routines && !opt_xml && + mysql_get_server_version(sock) >= 50009) + { + DBUG_PRINT("info", ("Dumping routines for database %s", database)); + dump_routines_for_db(database); + } if (opt_xml) { fputs("</database>\n", md_result_file); @@ -2498,7 +2726,7 @@ static int get_actual_table_name(const char *old_table_name, static int dump_selected_tables(char *db, char **table_names, int tables) { - uint numrows, i; + uint i; char table_buff[NAME_LEN*+3]; char new_table_name[NAME_LEN]; DYNAMIC_STRING lock_tables_query; @@ -2567,8 +2795,10 @@ static int dump_selected_tables(char *db, char **table_names, int tables) { table_name= hash_element(&dump_tables, i); DBUG_PRINT("info",("Dumping table %s", table_name)); - numrows= get_table_structure(table_name, db); - dump_table(numrows, table_name); + dump_table(table_name,db); + if (opt_dump_triggers && + mysql_get_server_version(sock) >= 50009) + dump_triggers_for_table(table_name, db); } /* Dump each selected view */ @@ -2580,6 +2810,13 @@ static int dump_selected_tables(char *db, char **table_names, int tables) get_view_structure(table_name, db); } } + /* obtain dump of routines (procs/functions) */ + if (opt_routines && !opt_xml && + mysql_get_server_version(sock) >= 50009) + { + DBUG_PRINT("info", ("Dumping routines for database %s", db)); + dump_routines_for_db(db); + } hash_free(&dump_tables); my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); order_by= 0; @@ -2757,28 +2994,37 @@ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, /* - Check if we the table is one of the table types that should be ignored: - MRG_ISAM, MRG_MYISAM SYNOPSIS + + Check if we the table is one of the table types that should be ignored: + MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts. + If the table should be altogether ignored, it returns a TRUE, FALSE if it + should not be ignored. If the user has selected to use INSERT DELAYED, it + sets the value of the bool pointer supports_delayed_inserts to 0 if not + supported, 1 if it is supported. + + ARGS + check_if_ignore_table() table_name Table name to check + table_type Type of table GLOBAL VARIABLES sock MySQL socket verbose Write warning messages RETURN - 0 Table should be backuped - # Type of table (that should be skipped) + char (bit value) See IGNORE_ values at top */ -static const char *check_if_ignore_table(const char *table_name) +char check_if_ignore_table(const char *table_name, char *table_type) { + char result= IGNORE_NONE; char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN]; MYSQL_RES *res; MYSQL_ROW row; - const char *result= 0; + DBUG_ENTER("check_if_ignore_table"); /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff)); @@ -2792,7 +3038,7 @@ static const char *check_if_ignore_table(const char *table_name) fprintf(stderr, "-- Warning: Couldn't get status information for table %s (%s)\n", table_name,mysql_error(sock)); - return 0; /* assume table is ok */ + DBUG_RETURN(result); /* assume table is ok */ } } if (!(row= mysql_fetch_row(res))) @@ -2801,18 +3047,38 @@ static const char *check_if_ignore_table(const char *table_name) "Error: Couldn't read status information for table %s (%s)\n", table_name, mysql_error(sock)); mysql_free_result(res); - return 0; /* assume table is ok */ + DBUG_RETURN(result); /* assume table is ok */ } if (!(row[1])) - result= "VIEW"; + strmake(table_type, "VIEW", NAME_LEN-1); else { - if (strcmp(row[1], (result= "MRG_MyISAM")) && - strcmp(row[1], (result= "MRG_ISAM"))) - result= 0; + /* + If the table type matches any of these, we do support delayed inserts. + Note: we do not want to skip dumping this table if if is not one of + these types, but we do want to use delayed inserts in the dump if + the table type is _NOT_ one of these types + */ + strmake(table_type, row[1], NAME_LEN-1); + if (opt_delayed) + { + if (strcmp(table_type,"MyISAM") && + strcmp(table_type,"ISAM") && + strcmp(table_type,"ARCHIVE") && + strcmp(table_type,"HEAP") && + strcmp(table_type,"MEMORY")) + result= IGNORE_INSERT_DELAYED; + } + + /* + If these two types, we do want to skip dumping the table + */ + if (!dFlag && + (!strcmp(table_type,"MRG_MyISAM") || !strcmp(table_type,"MRG_ISAM"))) + result= IGNORE_DATA; } mysql_free_result(res); - return result; + DBUG_RETURN(result); } /* diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 43b0672e03e..ca0a751e963 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -37,8 +37,9 @@ static char *add_load_option(char *ptr,const char *object, const char *statement); static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0, - replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0, + replace=0,silent=0,ignore=0,opt_compress=0, opt_low_priority= 0, tty_password= 0; +static uint opt_local_file=0; static MYSQL mysql_connection; static char *opt_password=0, *current_user=0, *current_host=0, *current_db=0, *fields_terminated=0, diff --git a/client/mysqltest.c b/client/mysqltest.c index 57b81e46b66..6653d24e575 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -59,12 +59,16 @@ #include <stdarg.h> #include <sys/stat.h> #include <violite.h> -#include <regex.h> /* Our own version of lib */ +#include "my_regex.h" /* Our own version of lib */ #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> #endif #ifndef WEXITSTATUS -# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +# ifdef __WIN__ +# define WEXITSTATUS(stat_val) (stat_val) +# else +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +# endif #endif /* MAX_QUERY is 256K -- there is a test in sp-big that is >128K */ #define MAX_QUERY (256*1024) @@ -98,6 +102,10 @@ #define DEFAULT_DELIMITER ";" #define MAX_DELIMITER 16 +#define RESULT_OK 0 +#define RESULT_CONTENT_MISMATCH 1 +#define RESULT_LENGTH_MISMATCH 2 + enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, @@ -105,12 +113,11 @@ enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, /* ************************************************************************ */ /* - A line that starts with !$ or $S, and the list of error codes to - --error are stored in an internal array of structs. This struct can - hold numeric SQL error codes or SQLSTATE codes as strings. The - element next to the last active element in the list is set to type - ERR_EMPTY. When an SQL statement return an error we use this list to - check if this is an expected error. + The list of error codes to --error are stored in an internal array of + structs. This struct can hold numeric SQL error codes or SQLSTATE codes + as strings. The element next to the last active element in the list is + set to type ERR_EMPTY. When an SQL statement return an error we use + this list to check if this is an expected error. */ enum match_err_type @@ -136,7 +143,8 @@ typedef struct long code; } st_error; -static st_error global_error[] = { +static st_error global_error[] = +{ #include <mysqld_ername.h> { 0, 0 } }; @@ -148,13 +156,13 @@ static uint global_expected_errors; static int record = 0, opt_sleep=0; static char *db = 0, *pass=0; -const char* user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; +const char *user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; static int port = 0; static my_bool opt_big_test= 0, opt_compress= 0, silent= 0, verbose = 0; static my_bool tty_password= 0, ps_protocol= 0, ps_protocol_enabled= 0; static int parsing_disabled= 0; static uint start_lineno, *lineno; -const char* manager_user="root",*manager_host=0; +const char *manager_user="root",*manager_host=0; char *manager_pass=0; int manager_port=MYSQL_MANAGER_PORT; int manager_wait_timeout=3; @@ -164,9 +172,16 @@ static char **default_argv; static const char *load_default_groups[]= { "mysqltest","client",0 }; static char line_buffer[MAX_DELIMITER], *line_buffer_pos= line_buffer; -static FILE* file_stack[MAX_INCLUDE_DEPTH]; -static FILE** cur_file; -static FILE** file_stack_end; +typedef struct +{ + FILE* file; + const char *file_name; +} test_file; + +static test_file file_stack[MAX_INCLUDE_DEPTH]; +static test_file* cur_file; +static test_file* file_stack_end; + static uint lineno_stack[MAX_INCLUDE_DEPTH]; static char TMPDIR[FN_REFLEN]; static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; @@ -198,13 +213,14 @@ static int got_end_timer= FALSE; static void timer_output(void); static ulonglong timer_now(void); -static regex_t ps_re; /* Holds precompiled re for valid PS statements */ +static my_regex_t ps_re; /* Holds precompiled re for valid PS statements */ static void ps_init_re(void); static int ps_match_re(char *); static char *ps_eprint(int); static void ps_free_reg(void); -static const char *embedded_server_groups[] = { +static const char *embedded_server_groups[]= +{ "server", "embedded", "mysqltest_SERVER", @@ -320,7 +336,7 @@ Q_COMMENT_WITH_COMMAND /* this should really be called command */ struct st_query { - char *query, *query_buf,*first_argument,*end; + char *query, *query_buf,*first_argument,*last_argument,*end; int first_word_len; my_bool abort_on_error, require_file; match_err expected_errno[MAX_EXPECTED_ERRORS]; @@ -336,7 +352,7 @@ const char *command_names[]= "connect", /* the difference between sleep and real_sleep is that sleep will use the delay from command line (--sleep) if there is one. - real_sleep always uses delay from it's argument. + real_sleep always uses delay from mysqltest's command line argument. the logic is that sometimes delays are cpu-dependent (and --sleep can be used to set this delay. real_sleep is used for cpu-independent delays @@ -423,7 +439,7 @@ static void var_free(void* v); int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname); void reject_dump(const char *record_file, char *buf, int size); -int close_connection(struct st_query* q); +int close_connection(struct st_query*); static void set_charset(struct st_query*); VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing); @@ -449,9 +465,9 @@ static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); void free_pointer_array(POINTER_ARRAY *pa); static int initialize_replace_buffer(void); static void free_replace_buffer(void); -static void do_eval(DYNAMIC_STRING* query_eval, const char *query); +static void do_eval(DYNAMIC_STRING *query_eval, const char *query); void str_to_file(const char *fname, char *str, int size); -int do_server_op(struct st_query* q,const char *op); +int do_server_op(struct st_query *q,const char *op); struct st_replace *glob_replace; static char *out_buff; @@ -475,13 +491,14 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); -static int normal_handle_error(const char *query, struct st_query *q, - MYSQL *mysql, DYNAMIC_STRING *ds); -static int normal_handle_no_error(struct st_query *q); +static int handle_error(const char *query, struct st_query *q, + unsigned int err_errno, const char *err_error, + const char *err_sqlstate, DYNAMIC_STRING *ds); +static int handle_no_error(struct st_query *q); -static void do_eval(DYNAMIC_STRING* query_eval, const char* query) +static void do_eval(DYNAMIC_STRING* query_eval, const char *query) { - const char* p; + const char *p; register char c; register int escaped = 0; VAR* v; @@ -538,10 +555,13 @@ static void close_cons() static void close_files() { DBUG_ENTER("close_files"); - for (; cur_file != file_stack ; cur_file--) + for (; cur_file >= file_stack; cur_file--) { - if (*cur_file != stdin && *cur_file) - my_fclose(*cur_file,MYF(0)); + DBUG_PRINT("info", ("file_name: %s", cur_file->file_name)); + if (cur_file->file && cur_file->file != stdin) + my_fclose(cur_file->file, MYF(0)); + my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + cur_file->file_name= 0; } DBUG_VOID_RETURN; } @@ -584,14 +604,19 @@ static void free_used_memory() DBUG_VOID_RETURN; } -static void die(const char* fmt, ...) +static void die(const char *fmt, ...) { va_list args; DBUG_ENTER("die"); va_start(args, fmt); if (fmt) { - fprintf(stderr, "%s: ", my_progname); + fprintf(stderr, "mysqltest: "); + if (cur_file && cur_file != file_stack) + fprintf(stderr, "In included file \"%s\": ", + cur_file->file_name); + if (start_lineno != 0) + fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); fflush(stderr); @@ -615,7 +640,7 @@ static void abort_not_supported_test() exit(62); } -static void verbose_msg(const char* fmt, ...) +static void verbose_msg(const char *fmt, ...) { va_list args; DBUG_ENTER("verbose_msg"); @@ -624,7 +649,9 @@ static void verbose_msg(const char* fmt, ...) va_start(args, fmt); - fprintf(stderr, "%s: At line %u: ", my_progname, start_lineno); + fprintf(stderr, "mysqltest: "); + if (start_lineno > 0) + fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); @@ -634,12 +661,12 @@ static void verbose_msg(const char* fmt, ...) void init_parser() { - parser.current_line = parser.read_lines = 0; - memset(&var_reg,0, sizeof(var_reg)); + parser.current_line= parser.read_lines= 0; + memset(&var_reg, 0, sizeof(var_reg)); } -int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname) +int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { MY_STAT stat_info; char *tmp, *res_ptr; @@ -665,7 +692,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname) DBUG_PRINT("info",("Size differs: result size: %u file size: %u", ds->length, stat_info.st_size)); DBUG_PRINT("info",("result: '%s'", ds->str)); - DBUG_RETURN(2); + DBUG_RETURN(RESULT_LENGTH_MISMATCH); } if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) die(NullS); @@ -682,7 +709,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname) res_ptr = res_ds.str; if ((res_len = res_ds.length) != ds->length) { - res = 2; + res= RESULT_LENGTH_MISMATCH; goto err; } } @@ -692,7 +719,8 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname) res_len = stat_info.st_size; } - res = (memcmp(res_ptr, ds->str, res_len)) ? 1 : 0; + res= (memcmp(res_ptr, ds->str, res_len)) ? + RESULT_CONTENT_MISMATCH : RESULT_OK; err: if (res && eval_result) @@ -706,36 +734,33 @@ err: DBUG_RETURN(res); } -static int check_result(DYNAMIC_STRING* ds, const char* fname, +static int check_result(DYNAMIC_STRING* ds, const char *fname, my_bool require_option) { - int error = 0; - int res=dyn_string_cmp(ds, fname); + int res= dyn_string_cmp(ds, fname); DBUG_ENTER("check_result"); if (res && require_option) abort_not_supported_test(); switch (res) { - case 0: + case RESULT_OK: break; /* ok */ - case 2: + case RESULT_LENGTH_MISMATCH: verbose_msg("Result length mismatch"); - error = 1; break; - case 1: + case RESULT_CONTENT_MISMATCH: verbose_msg("Result content mismatch"); - error = 1; break; default: /* impossible */ die("Unknown error code from dyn_string_cmp()"); } - if (error) + if (res != RESULT_OK) reject_dump(fname, ds->str, ds->length); - DBUG_RETURN(error); + DBUG_RETURN(res); } -VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw, +VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing) { int digit; @@ -748,7 +773,7 @@ VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw, digit = *++var_name - '0'; if (digit < 0 || digit >= 10) { - const char* save_var_name = var_name, *end; + const char *save_var_name = var_name, *end; uint length; end = (var_name_end) ? *var_name_end : 0; while (my_isvar(charset_info,*var_name) && var_name != end) @@ -790,7 +815,7 @@ err: DBUG_RETURN(0); } -static VAR *var_obtain(const char* name, int len) +static VAR *var_obtain(const char *name, int len) { VAR* v; if ((v = (VAR*)hash_search(&var_hash, name, len))) @@ -827,9 +852,11 @@ int var_set(const char *var_name, const char *var_name_end, } -int open_file(const char* name) +int open_file(const char *name) { char buff[FN_REFLEN]; + DBUG_ENTER("open_file"); + DBUG_PRINT("enter", ("name: %s", name)); if (!test_if_hard_path(name)) { strxmov(buff, opt_basedir, name, NullS); @@ -837,19 +864,51 @@ int open_file(const char* name) } fn_format(buff,name,"","",4); - if (*cur_file && cur_file == file_stack_end) + if (cur_file == file_stack_end) die("Source directives are nesting too deep"); - if (!(*(cur_file+1) = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) - die(NullS); cur_file++; + if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) + { + cur_file--; + die("Could not open file %s", buff); + } + cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); *++lineno=1; + DBUG_RETURN(0); +} - return 0; + +/* + Check for unexpected "junk" after the end of query + This is normally caused by missing delimiters +*/ + +int check_eol_junk(const char *eol) +{ + const char *p= eol; + DBUG_ENTER("check_eol_junk"); + DBUG_PRINT("enter", ("eol: %s", eol)); + /* Remove all spacing chars except new line */ + while (*p && my_isspace(charset_info, *p) && (*p != '\n')) + p++; + + /* Check for extra delimiter */ + if (*p && !strncmp(p, delimiter, delimiter_length)) + die("Extra delimiter \"%s\" found", delimiter); + + /* Allow trailing # comment */ + if (*p && *p != '#') + { + if (*p == '\n') + die("Missing delimiter"); + die("End of line junk detected: \"%s\"", p); + } + DBUG_RETURN(0); } /* ugly long name, but we are following the convention */ -int do_wait_for_slave_to_stop(struct st_query* q __attribute__((unused))) +int do_wait_for_slave_to_stop(struct st_query *q __attribute__((unused))) { MYSQL* mysql = &cur_con->mysql; for (;;) @@ -877,7 +936,7 @@ int do_wait_for_slave_to_stop(struct st_query* q __attribute__((unused))) return 0; } -int do_require_manager(struct st_query* a __attribute__((unused))) +int do_require_manager(struct st_query *query __attribute__((unused)) ) { if (!manager) abort_not_supported_test(); @@ -885,95 +944,121 @@ int do_require_manager(struct st_query* a __attribute__((unused))) } #ifndef EMBEDDED_LIBRARY -int do_server_start(struct st_query* q) +int do_server_start(struct st_query *q) { - return do_server_op(q,"start"); + return do_server_op(q, "start"); } -int do_server_stop(struct st_query* q) +int do_server_stop(struct st_query *q) { - return do_server_op(q,"stop"); + return do_server_op(q, "stop"); } -int do_server_op(struct st_query* q,const char* op) +int do_server_op(struct st_query *q, const char *op) { - char* p=q->first_argument; - char com_buf[256],*com_p; + char *p= q->first_argument; + char com_buf[256], *com_p; if (!manager) { die("Manager is not initialized, manager commands are not possible"); } - com_p=strmov(com_buf,op); - com_p=strmov(com_p,"_exec "); + com_p= strmov(com_buf,op); + com_p= strmov(com_p,"_exec "); if (!*p) - die("Missing server name in server_%s\n",op); - while (*p && !my_isspace(charset_info,*p)) + die("Missing server name in server_%s", op); + while (*p && !my_isspace(charset_info, *p)) *com_p++= *p++; - *com_p++=' '; - com_p=int10_to_str(manager_wait_timeout,com_p,10); - *com_p++ = '\n'; - *com_p=0; - if (mysql_manager_command(manager,com_buf,(int)(com_p-com_buf))) - die("Error in command: %s(%d)",manager->last_error,manager->last_errno); + *com_p++= ' '; + com_p= int10_to_str(manager_wait_timeout, com_p, 10); + *com_p++= '\n'; + *com_p= 0; + if (mysql_manager_command(manager, com_buf, (int)(com_p-com_buf))) + die("Error in command: %s(%d)", manager->last_error, manager->last_errno); while (!manager->eof) { - if (mysql_manager_fetch_line(manager,com_buf,sizeof(com_buf))) + if (mysql_manager_fetch_line(manager, com_buf, sizeof(com_buf))) die("Error fetching result line: %s(%d)", manager->last_error, manager->last_errno); } + q->last_argument= p; return 0; } #endif -int do_source(struct st_query* q) + +/* + Source and execute the given file + + SYNOPSIS + do_source() + query called command + + DESCRIPTION + source <file_name> + + Open the file <file_name> and execute it + +*/ + +int do_source(struct st_query *query) { - char* p=q->first_argument, *name; + char *p= query->first_argument, *name; if (!*p) - die("Missing file name in source\n"); - name = p; + die("Missing file name in source"); + name= p; while (*p && !my_isspace(charset_info,*p)) p++; - *p = 0; - + if (*p) + *p++= 0; + query->last_argument= p; + /* + If this file has already been sourced, dont source it again. + It's already available in the q_lines cache + */ + if (parser.current_line < (parser.read_lines - 1)) + return 0; return open_file(name); } + /* Execute given command. SYNOPSIS do_exec() - q called command + query called command DESCRIPTION - If one uses --exec command [args] command in .test file - we will execute the command and record its output. + exec <command> + + Execute the text between exec and end of line in a subprocess. + The error code returned from the subprocess is checked against the + expected error array, previously set with the --error command. + It can thus be used to execute a command that shall fail. - RETURN VALUES - 0 ok - 1 error */ -static void do_exec(struct st_query* q) +static void do_exec(struct st_query *query) { int error; - DYNAMIC_STRING *ds= NULL; /* Assign just to avoid warning */ + DYNAMIC_STRING *ds= NULL; DYNAMIC_STRING ds_tmp; char buf[1024]; FILE *res_file; - char *cmd= q->first_argument; + char *cmd= query->first_argument; DBUG_ENTER("do_exec"); while (*cmd && my_isspace(charset_info, *cmd)) cmd++; if (!*cmd) - die("Missing argument in exec\n"); + die("Missing argument in exec"); + query->last_argument= query->end; DBUG_PRINT("info", ("Executing '%s'", cmd)); - if (!(res_file= popen(cmd, "r")) && q->abort_on_error) - die("popen() failed\n"); + if (!(res_file= popen(cmd, "r")) && query->abort_on_error) + die("popen(\"%s\", \"r\") failed", cmd); if (disable_result_log) { @@ -985,7 +1070,7 @@ static void do_exec(struct st_query* q) } else { - if (q->record_file[0]) + if (query->record_file[0]) { init_dynamic_string(&ds_tmp, "", 16384, 65536); ds= &ds_tmp; @@ -1002,33 +1087,35 @@ static void do_exec(struct st_query* q) uint status= WEXITSTATUS(error), i; my_bool ok= 0; - if (q->abort_on_error) - die("At line %u: command \"%s\" failed", start_lineno, cmd); + if (query->abort_on_error) + die("command \"%s\" failed", cmd); DBUG_PRINT("info", ("error: %d, status: %d", error, status)); - for (i=0 ; (uint) i < q->expected_errors ; i++) + for (i= 0; i < query->expected_errors; i++) { DBUG_PRINT("info", ("error: %d, status: %d", error, status)); DBUG_PRINT("info", ("expected error: %d", - q->expected_errno[i].code.errnum)); - if ((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == status)) + query->expected_errno[i].code.errnum)); + if ((query->expected_errno[i].type == ERR_ERRNO) && + (query->expected_errno[i].code.errnum == status)) + { ok= 1; - verbose_msg("At line %u: command \"%s\" failed with expected error: %d", - start_lineno, cmd, status); + DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d", + cmd, status)); + } } if (!ok) - die("At line: %u: command \"%s\" failed with wrong error: %d", - start_lineno, cmd, status); + die("command \"%s\" failed with wrong error: %d", + cmd, status); } - else if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + else if (query->expected_errno[0].type == ERR_ERRNO && + query->expected_errno[0].code.errnum != 0) { /* Error code we wanted was != 0, i.e. not an expected success */ - die("At line: %u: command \"%s\" succeeded - should have failed with errno %d...", - start_lineno, cmd, q->expected_errno[0].code.errnum); + die("command \"%s\" succeeded - should have failed with errno %d...", + cmd, query->expected_errno[0].code.errnum); } if (!disable_result_log) @@ -1038,14 +1125,14 @@ static void do_exec(struct st_query* q) if (record) { - if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); + if (!query->record_file[0] && !result_file) + die("Missing result file"); if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); + str_to_file(query->record_file, ds->str, ds->length); } - else if (q->record_file[0]) + else if (query->record_file[0]) { - error= check_result(ds, q->record_file, q->require_file); + error= check_result(ds, query->record_file, query->require_file); } if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -1053,7 +1140,7 @@ static void do_exec(struct st_query* q) } -int var_query_set(VAR* v, const char* p, const char** p_end) +int var_query_set(VAR* v, const char *p, const char** p_end) { char* end = (char*)((p_end && *p_end) ? *p_end : p + strlen(p)); MYSQL_RES *res; @@ -1104,19 +1191,27 @@ int var_query_set(VAR* v, const char* p, const char** p_end) return 0; } -void var_copy(VAR* dest, VAR* src) +void var_copy(VAR *dest, VAR *src) { - dest->int_val=src->int_val; - dest->int_dirty=src->int_dirty; + dest->int_val= src->int_val; + dest->int_dirty= src->int_dirty; + + /* Alloc/realloc data for str_val in dest */ if (dest->alloced_len < src->alloced_len && - !(dest->str_val=my_realloc(dest->str_val,src->alloced_len+1, - MYF(MY_WME)))) + !(dest->str_val= dest->str_val + ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) + : my_malloc(src->alloced_len, MYF(MY_WME)))) die("Out of memory"); - dest->str_val_len=src->str_val_len; - memcpy(dest->str_val,src->str_val,src->str_val_len+1); + else + dest->alloced_len= src->alloced_len; + + /* Copy str_val data to dest */ + dest->str_val_len= src->str_val_len; + if (src->str_val_len) + memcpy(dest->str_val, src->str_val, src->str_val_len); } -int eval_expr(VAR* v, const char* p, const char** p_end) +int eval_expr(VAR* v, const char *p, const char** p_end) { VAR* vp; if (*p == '$') @@ -1157,29 +1252,58 @@ int eval_expr(VAR* v, const char* p, const char** p_end) return 1; } -int do_inc(struct st_query* q) + +enum enum_operator { - char* p=q->first_argument; - VAR* v; - v = var_get(p, 0, 1, 0); - v->int_val++; - v->int_dirty = 1; - return 0; -} + DO_DEC, + DO_INC +}; + +/* + Decrease or increase the value of a variable + + SYNOPSIS + do_modify_var() + query called command + name human readable name of operator + operator operation to perform on the var + + DESCRIPTION + dec $var_name + inc $var_name -int do_dec(struct st_query* q) +*/ + +int do_modify_var(struct st_query *query, const char *name, + enum enum_operator operator) { - char* p=q->first_argument; + const char *p= query->first_argument; VAR* v; - v = var_get(p, 0, 1, 0); - v->int_val--; - v->int_dirty = 1; + if (!*p) + die("Missing arguments to %s", name); + if (*p != '$') + die("First argument to %s must be a variable (start with $)", name); + v= var_get(p, &p, 1, 0); + switch (operator) { + case DO_DEC: + v->int_val--; + break; + case DO_INC: + v->int_val++; + break; + default: + die("Invalid operator to do_operator"); + break; + } + v->int_dirty= 1; + query->last_argument= (char*)++p; return 0; } -int do_system(struct st_query* q) + +int do_system(struct st_query *q) { - char* p=q->first_argument; + char *p=q->first_argument; VAR v; var_init(&v, 0, 0, 0, 0); eval_expr(&v, p, 0); /* NULL terminated */ @@ -1191,63 +1315,96 @@ int do_system(struct st_query* q) memcpy(expr_buf, v.str_val, v.str_val_len); expr_buf[v.str_val_len] = 0; DBUG_PRINT("info", ("running system command '%s'", expr_buf)); - if (system(expr_buf) && q->abort_on_error) - die("system command '%s' failed", expr_buf); + if (system(expr_buf)) + { + if (q->abort_on_error) + die("system command '%s' failed", expr_buf); + /* If ! abort_on_error, display message and continue */ + verbose_msg("system command '%s' failed", expr_buf); + } } + else + die("Missing arguments to system, nothing to do!"); var_free(&v); + q->last_argument= q->end; return 0; } -int do_echo(struct st_query* q) + +/* + Print the content between echo and <delimiter> to result file. + If content is a variable, the variable value will be retrieved + + SYNOPSIS + do_echo() + q called command + + DESCRIPTION + Usage 1: + echo text + Print the text after echo until end of command to result file + + Usage 2: + echo $<var_name> + Print the content of the variable <var_name> to result file + +*/ + +int do_echo(struct st_query *q) { - char* p=q->first_argument; + char *p= q->first_argument; + DYNAMIC_STRING *ds; + DYNAMIC_STRING ds_tmp; VAR v; var_init(&v,0,0,0,0); - eval_expr(&v, p, 0); /* NULL terminated */ - if (v.str_val_len) + + if (q->record_file[0]) { - fflush(stdout); - write(1, v.str_val, v.str_val_len); + init_dynamic_string(&ds_tmp, "", 256, 512); + ds= &ds_tmp; } - write(1, "\n", 1); + else + ds= &ds_res; + + eval_expr(&v, p, 0); /* NULL terminated */ + if (v.str_val_len) + dynstr_append_mem(ds, v.str_val, v.str_val_len); + dynstr_append_mem(ds, "\n", 1); var_free(&v); + if (ds == &ds_tmp) + dynstr_free(&ds_tmp); + q->last_argument= q->end; return 0; } -int do_sync_with_master2(const char* p) +int do_sync_with_master2(long offset) { MYSQL_RES* res; MYSQL_ROW row; - MYSQL* mysql = &cur_con->mysql; + MYSQL* mysql= &cur_con->mysql; char query_buf[FN_REFLEN+128]; - int offset= 0, tries= 0; + int tries= 0; int rpl_parse; if (!master_pos.file[0]) - { - die("Line %u: Calling 'sync_with_master' without calling 'save_master_pos'", start_lineno); - } - rpl_parse = mysql_rpl_parse_enabled(mysql); + die("Calling 'sync_with_master' without calling 'save_master_pos'"); + rpl_parse= mysql_rpl_parse_enabled(mysql); mysql_disable_rpl_parse(mysql); - if (*p) - offset = atoi(p); - sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file, master_pos.pos + offset); wait_for_position: if (mysql_query(mysql, query_buf)) - die("line %u: failed in %s: %d: %s", start_lineno, query_buf, - mysql_errno(mysql), mysql_error(mysql)); + die("failed in %s: %d: %s", query_buf, mysql_errno(mysql), + mysql_error(mysql)); - if (!(last_result = res = mysql_store_result(mysql))) - die("line %u: mysql_store_result() returned NULL for '%s'", start_lineno, - query_buf); - if (!(row = mysql_fetch_row(res))) - die("line %u: empty result in %s", start_lineno, query_buf); + if (!(last_result= res= mysql_store_result(mysql))) + die("mysql_store_result() returned NULL for '%s'", query_buf); + if (!(row= mysql_fetch_row(res))) + die("empty result in %s", query_buf); if (!row[0]) { /* @@ -1255,10 +1412,7 @@ wait_for_position: SLAVE has been issued ? */ if (tries++ == 3) - { - die("line %u: could not sync with master ('%s' returned NULL)", - start_lineno, query_buf); - } + die("could not sync with master ('%s' returned NULL)", query_buf); sleep(1); /* So at most we will wait 3 seconds and make 4 tries */ mysql_free_result(res); goto wait_for_position; @@ -1271,9 +1425,21 @@ wait_for_position: return 0; } -int do_sync_with_master(struct st_query* q) +int do_sync_with_master(struct st_query *query) { - return do_sync_with_master2(q->first_argument); + long offset= 0; + char *p= query->first_argument; + const char *offset_start= p; + if (*offset_start) + { + for (; my_isdigit(charset_info, *p); p++) + offset = offset * 10 + *p - '0'; + + if(*p && !my_isspace(charset_info, *p)) + die("Invalid integer argument \"%s\"", offset_start); + query->last_argument= p; + } + return do_sync_with_master2(offset); } int do_save_master_pos() @@ -1288,14 +1454,13 @@ int do_save_master_pos() mysql_disable_rpl_parse(mysql); if (mysql_query(mysql, query= "show master status")) - die("At line %u: failed in show master status: %d: %s", start_lineno, + die("failed in show master status: %d: %s", mysql_errno(mysql), mysql_error(mysql)); if (!(last_result =res = mysql_store_result(mysql))) - die("line %u: mysql_store_result() retuned NULL for '%s'", start_lineno, - query); + die("mysql_store_result() retuned NULL for '%s'", query); if (!(row = mysql_fetch_row(res))) - die("line %u: empty result in show master status", start_lineno); + die("empty result in show master status"); strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1); master_pos.pos = strtoul(row[1], (char**) 0, 10); mysql_free_result(res); last_result=0; @@ -1307,21 +1472,51 @@ int do_save_master_pos() } -int do_let(struct st_query* q) +/* + Assign the variable <var_name> with <var_val> + + SYNOPSIS + do_let() + query called command + + DESCRIPTION + let $<var_name>=<var_val><delimiter> + + <var_name> - is the string string found between the $ and = + <var_val> - is the content between the = and <delimiter>, it may span + multiple line and contain any characters except <delimiter> + <delimiter> - is a string containing of one or more chars, default is ; + + RETURN VALUES + Program will die if error detected +*/ + +int do_let(struct st_query *query) { - char* p=q->first_argument; + char *p= query->first_argument; char *var_name, *var_name_end, *var_val_start; + + /* Find <var_name> */ if (!*p) - die("Missing variable name in let\n"); - var_name = p; - while (*p && (*p != '=' || my_isspace(charset_info,*p))) + die("Missing arguments to let"); + var_name= p; + while (*p && (*p != '=') && !my_isspace(charset_info,*p)) + p++; + var_name_end= p; + if (var_name+1 == var_name_end) + die("Missing variable name in let"); + while (my_isspace(charset_info,*p)) p++; - var_name_end = p; - if (*p == '=') p++; + if (*p++ != '=') + die("Missing assignment operator in let"); + + /* Find start of <var_val> */ while (*p && my_isspace(charset_info,*p)) p++; - var_val_start = p; - return var_set(var_name, var_name_end, var_val_start, q->end); + var_val_start= p; + query->last_argument= query->end; + /* Assign var_val to var_name */ + return var_set(var_name, var_name_end, var_val_start, query->end); } @@ -1340,7 +1535,7 @@ int var_set_errno(int sql_errno) } -int do_rpl_probe(struct st_query* q __attribute__((unused))) +int do_rpl_probe(struct st_query *query __attribute__((unused))) { DBUG_ENTER("do_rpl_probe"); if (mysql_rpl_probe(&cur_con->mysql)) @@ -1349,71 +1544,104 @@ int do_rpl_probe(struct st_query* q __attribute__((unused))) } -int do_enable_rpl_parse(struct st_query* q __attribute__((unused))) +int do_enable_rpl_parse(struct st_query *query __attribute__((unused))) { mysql_enable_rpl_parse(&cur_con->mysql); return 0; } -int do_disable_rpl_parse(struct st_query* q __attribute__((unused))) +int do_disable_rpl_parse(struct st_query *query __attribute__((unused))) { mysql_disable_rpl_parse(&cur_con->mysql); return 0; } -int do_sleep(struct st_query* q, my_bool real_sleep) +/* + Sleep the number of specifed seconds + + SYNOPSIS + do_sleep() + q called command + real_sleep use the value from opt_sleep as number of seconds to sleep + + DESCRIPTION + sleep <seconds> + real_sleep + +*/ + +int do_sleep(struct st_query *query, my_bool real_sleep) { - char *p=q->first_argument; - while (*p && my_isspace(charset_info,*p)) + int error= 0; + char *p= query->first_argument; + char *sleep_start, *sleep_end= query->end; + double sleep_val; + + while (my_isspace(charset_info, *p)) p++; if (!*p) - die("Missing argument in sleep\n"); + die("Missing argument to sleep"); + sleep_start= p; + /* Check that arg starts with a digit, not handled by my_strtod */ + if (!my_isdigit(charset_info, *sleep_start)) + die("Invalid argument to sleep \"%s\"", query->first_argument); + sleep_val= my_strtod(sleep_start, &sleep_end, &error); + if (error) + die("Invalid argument to sleep \"%s\"", query->first_argument); + + /* Fixed sleep time selected by --sleep option */ if (opt_sleep && !real_sleep) - my_sleep(opt_sleep * 1000000L); - else - my_sleep((ulong) (atof(p) * 1000000L)); + sleep_val= opt_sleep; + + my_sleep((ulong) (sleep_val * 1000000L)); + query->last_argument= sleep_end; return 0; } -static void get_file_name(char *filename, struct st_query* q) +static void get_file_name(char *filename, struct st_query *q) { - char* p=q->first_argument; - strnmov(filename, p, FN_REFLEN); - /* Remove end space */ - while (p > filename && my_isspace(charset_info,p[-1])) - p--; - p[0]=0; + char *p= q->first_argument, *name; + if (!*p) + die("Missing file name argument"); + name= p; + while (*p && !my_isspace(charset_info,*p)) + p++; + if (*p) + *p++= 0; + q->last_argument= p; + strmake(filename, name, FN_REFLEN); } -static void set_charset(struct st_query* q) +static void set_charset(struct st_query *q) { - char* charset_name= q->first_argument; - char* tmp; + char *charset_name= q->first_argument; + char *p; if (!charset_name || !*charset_name) - die("Missing charset name in 'character_set'\n"); + die("Missing charset name in 'character_set'"); /* Remove end space */ - tmp= charset_name; - while (*tmp && !my_isspace(charset_info,*tmp)) - tmp++; - *tmp= 0; - + p= charset_name; + while (*p && !my_isspace(charset_info,*p)) + p++; + if(*p) + *p++= 0; + q->last_argument= p; charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME)); if (!charset_info) abort_not_supported_test(); } -static uint get_errcodes(match_err *to,struct st_query* q) +static uint get_errcodes(match_err *to,struct st_query *q) { - char* p= q->first_argument; + char *p= q->first_argument; uint count= 0; DBUG_ENTER("get_errcodes"); if (!*p) - die("Missing argument in %s\n", q->query); + die("Missing argument in %s", q->query); do { @@ -1447,20 +1675,20 @@ static uint get_errcodes(match_err *to,struct st_query* q) } } if (!e->name) - die("Unknown SQL error '%s'\n", start); + die("Unknown SQL error '%s'", start); } else { long val; if (!(p= str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val))) - die("Invalid argument in %s\n", q->query); + die("Invalid argument in %s", q->query); to[count].code.errnum= (uint) val; to[count].type= ERR_ERRNO; } count++; } while (*(p++) == ','); - + q->last_argument= (p - 1); to[count].type= ERR_EMPTY; /* End of data */ DBUG_RETURN(count); } @@ -1474,7 +1702,7 @@ static uint get_errcodes(match_err *to,struct st_query* q) static char *get_string(char **to_ptr, char **from_ptr, - struct st_query* q) + struct st_query *q) { reg1 char c,sep; char *to= *to_ptr, *from= *from_ptr, *start=to; @@ -1522,7 +1750,7 @@ static char *get_string(char **to_ptr, char **from_ptr, *to++=c; } if (*from != ' ' && *from) - die("Wrong string argument in %s\n", q->query); + die("Wrong string argument in %s", q->query); while (my_isspace(charset_info,*from)) /* Point to next string */ from++; @@ -1557,7 +1785,7 @@ static char *get_string(char **to_ptr, char **from_ptr, static void get_replace(struct st_query *q) { uint i; - char *from=q->first_argument; + char *from= q->first_argument; char *buff,*start; char word_end_chars[256],*pos; POINTER_ARRAY to_array,from_array; @@ -1568,14 +1796,14 @@ static void get_replace(struct st_query *q) bzero((char*) &to_array,sizeof(to_array)); bzero((char*) &from_array,sizeof(from_array)); if (!*from) - die("Missing argument in %s\n", q->query); + die("Missing argument in %s", q->query); start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); while (*from) { char *to=buff; to=get_string(&buff, &from, q); if (!*from) - die("Wrong number of arguments to replace in %s\n", q->query); + die("Wrong number of arguments to replace_result in '%s'", q->query); insert_pointer_name(&from_array,to); to=get_string(&buff, &from, q); insert_pointer_name(&to_array,to); @@ -1589,10 +1817,11 @@ static void get_replace(struct st_query *q) (uint) from_array.typelib.count, word_end_chars)) || initialize_replace_buffer()) - die("Can't initialize replace from %s\n", q->query); + die("Can't initialize replace from '%s'", q->query); free_pointer_array(&from_array); free_pointer_array(&to_array); my_free(start, MYF(0)); + q->last_argument= q->end; DBUG_VOID_RETURN; } @@ -1608,25 +1837,18 @@ void free_replace() DBUG_VOID_RETURN; } -int select_connection(char *p) + +int select_connection_name(const char *name) { - char* name; struct connection *con; - DBUG_ENTER("select_connection"); - DBUG_PRINT("enter",("name: '%s'",p)); + DBUG_ENTER("select_connection2"); + DBUG_PRINT("enter",("name: '%s'", name)); - if (!*p) - die("Missing connection name in connect\n"); - name = p; - while (*p && !my_isspace(charset_info,*p)) - p++; - *p = 0; - - for (con = cons; con < next_con; con++) + for (con= cons; con < next_con; con++) { if (!strcmp(con->name, name)) { - cur_con = con; + cur_con= con; DBUG_RETURN(0); } } @@ -1634,21 +1856,42 @@ int select_connection(char *p) DBUG_RETURN(1); /* Never reached */ } -int close_connection(struct st_query* q) + +int select_connection(struct st_query *query) +{ + char *name; + char *p= query->first_argument; + DBUG_ENTER("select_connection"); + + if (!*p) + die("Missing connection name in connect"); + name= p; + while (*p && !my_isspace(charset_info,*p)) + p++; + if (*p) + *p++= 0; + query->last_argument= p; + return select_connection_name(name); +} + + +int close_connection(struct st_query *q) { - char* p=q->first_argument, *name; + char *p= q->first_argument, *name; struct connection *con; DBUG_ENTER("close_connection"); DBUG_PRINT("enter",("name: '%s'",p)); if (!*p) - die("Missing connection name in connect\n"); - name = p; + die("Missing connection name in connect"); + name= p; while (*p && !my_isspace(charset_info,*p)) p++; - *p = 0; - for (con = cons; con < next_con; con++) + if (*p) + *p++= 0; + q->last_argument= p; + for (con= cons; con < next_con; con++) { if (!strcmp(con->name, name)) { @@ -1678,21 +1921,21 @@ int close_connection(struct st_query* q) ) are delimiters/terminators */ -char* safe_get_param(char* str, char** arg, const char* msg) +char* safe_get_param(char *str, char** arg, const char *msg) { DBUG_ENTER("safe_get_param"); while (*str && my_isspace(charset_info,*str)) str++; - *arg = str; + *arg= str; for (; *str && *str != ',' && *str != ')' ; str++) { if (my_isspace(charset_info,*str)) - *str = 0; + *str= 0; } if (!*str) die(msg); - *str++ = 0; + *str++= 0; DBUG_RETURN(str); } @@ -1732,18 +1975,19 @@ void init_manager() 0 - success, non-0 - failure */ -int safe_connect(MYSQL* con, const char* host, const char* user, - const char* pass, - const char* db, int port, const char* sock) +int safe_connect(MYSQL* con, const char *host, const char *user, + const char *pass, + const char *db, int port, const char *sock) { - int con_error = 1; + int con_error= 1; + my_bool reconnect= 1; int i; - for (i = 0; i < MAX_CON_TRIES; ++i) + for (i= 0; i < MAX_CON_TRIES; ++i) { if (mysql_real_connect(con, host,user, pass, db, port, sock, - CLIENT_MULTI_STATEMENTS)) + CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS)) { - con_error = 0; + con_error= 0; break; } sleep(CON_RETRY_SLEEP); @@ -1752,7 +1996,7 @@ int safe_connect(MYSQL* con, const char* host, const char* user, TODO: change this to 0 in future versions, but the 'kill' test relies on existing behavior */ - con->reconnect= 1; + mysql_options(con, MYSQL_OPT_RECONNECT, (char *)&reconnect); return con_error; } @@ -1786,6 +2030,7 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, int* create_conn) { DYNAMIC_STRING ds_tmp, *ds; + my_bool reconnect= 1; int error= 0; /* @@ -1831,11 +2076,12 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0, CLIENT_MULTI_STATEMENTS)) { - error= normal_handle_error("connect", q, con, ds); + error= handle_error("connect", q, mysql_errno(con), mysql_error(con), + mysql_sqlstate(con), ds); *create_conn= 0; goto err; } - else if (normal_handle_no_error(q)) + else if (handle_no_error(q)) { /* Fail if there was no error but we expected it. @@ -1851,12 +2097,12 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, TODO: change this to 0 in future versions, but the 'kill' test relies on existing behavior */ - con->reconnect= 1; + mysql_options(con, MYSQL_OPT_RECONNECT, (char *)&reconnect); if (record) { if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); + die("Missing result file"); if (!result_file) str_to_file(q->record_file, ds->str, ds->length); } @@ -1871,14 +2117,14 @@ err: } -int do_connect(struct st_query* q) +int do_connect(struct st_query *q) { - char* con_name, *con_user,*con_pass, *con_host, *con_port_str, + char *con_name, *con_user,*con_pass, *con_host, *con_port_str, *con_db, *con_sock; - char* p=q->first_argument; + char *p= q->first_argument; char buff[FN_REFLEN]; int con_port; - int free_con_sock = 0; + int free_con_sock= 0; int error= 0; int create_conn= 1; @@ -1888,40 +2134,41 @@ int do_connect(struct st_query* q) if (*p != '(') die("Syntax error in connect - expected '(' found '%c'", *p); p++; - p = safe_get_param(p, &con_name, "missing connection name"); - p = safe_get_param(p, &con_host, "missing connection host"); - p = safe_get_param(p, &con_user, "missing connection user"); - p = safe_get_param(p, &con_pass, "missing connection password"); - p = safe_get_param(p, &con_db, "missing connection db"); + p= safe_get_param(p, &con_name, "missing connection name"); + p= safe_get_param(p, &con_host, "missing connection host"); + p= safe_get_param(p, &con_user, "missing connection user"); + p= safe_get_param(p, &con_pass, "missing connection password"); + p= safe_get_param(p, &con_db, "missing connection db"); if (!*p || *p == ';') /* Default port and sock */ { - con_port=port; - con_sock=(char*) unix_sock; + con_port= port; + con_sock= (char*) unix_sock; } else { VAR* var_port, *var_sock; - p = safe_get_param(p, &con_port_str, "missing connection port"); + p= safe_get_param(p, &con_port_str, "missing connection port"); if (*con_port_str == '$') { - if (!(var_port = var_get(con_port_str, 0, 0, 0))) + if (!(var_port= var_get(con_port_str, 0, 0, 0))) die("Unknown variable '%s'", con_port_str+1); - con_port = var_port->int_val; + con_port= var_port->int_val; } else - con_port=atoi(con_port_str); - p = safe_get_param(p, &con_sock, "missing connection socket"); + con_port= atoi(con_port_str); + p= safe_get_param(p, &con_sock, "missing connection socket"); if (*con_sock == '$') { - if (!(var_sock = var_get(con_sock, 0, 0, 0))) + if (!(var_sock= var_get(con_sock, 0, 0, 0))) die("Unknown variable '%s'", con_sock+1); - if (!(con_sock = (char*)my_malloc(var_sock->str_val_len+1, MYF(0)))) + if (!(con_sock= (char*)my_malloc(var_sock->str_val_len+1, MYF(0)))) die("Out of memory"); - free_con_sock = 1; + free_con_sock= 1; memcpy(con_sock, var_sock->str_val, var_sock->str_val_len); - con_sock[var_sock->str_val_len] = 0; + con_sock[var_sock->str_val_len]= 0; } } + q->last_argument= p; if (next_con == cons_end) die("Connection limit exhausted - increase MAX_CONS in mysqltest.c"); @@ -1941,11 +2188,10 @@ int do_connect(struct st_query* q) if (con_sock && !free_con_sock && *con_sock && *con_sock != FN_LIBCHAR) con_sock=fn_format(buff, con_sock, TMPDIR, "",0); if (!con_db[0]) - con_db=db; + con_db= db; /* Special database to allow one to connect without a database name */ if (con_db && !strcmp(con_db,"*NO-ONE*")) - con_db=0; - + con_db= 0; if (q->abort_on_error) { if ((safe_connect(&next_con->mysql, con_host, con_user, con_pass, @@ -1970,14 +2216,15 @@ int do_connect(struct st_query* q) } -int do_done(struct st_query* q) +int do_done(struct st_query *q) { - /* Dummy statement to eliminate compiler warning */ - q->type = Q_END_BLOCK; - /* Check if empty block stack */ if (cur_block == block_stack) + { + if (*q->query != '}') + die("Stray 'end' command - end of block before beginning"); die("Stray '}' - end of block before beginning"); + } /* Test if inner block has been executed */ if (cur_block->ok && cur_block->cmd == cmd_while) @@ -1998,9 +2245,10 @@ int do_done(struct st_query* q) int do_block(enum block_cmd cmd, struct st_query* q) { - char* p=q->first_argument; - const char* expr_start, *expr_end; + char *p= q->first_argument; + const char *expr_start, *expr_end; VAR v; + const char *cmd_name= (cmd == cmd_while ? "while" : "if"); /* Check stack overflow */ if (cur_block == block_stack_end) @@ -2020,12 +2268,21 @@ int do_block(enum block_cmd cmd, struct st_query* q) } /* Parse and evaluate test expression */ - expr_start = strchr(p, '('); + expr_start= strchr(p, '('); if (!expr_start) - die("missing '(' in while"); - expr_end = strrchr(expr_start, ')'); + die("missing '(' in %s", cmd_name); + expr_end= strrchr(expr_start, ')'); if (!expr_end) - die("missing ')' in while"); + die("missing ')' in %s", cmd_name); + p= (char*)expr_end+1; + + while (*p && my_isspace(charset_info, *p)) + p++; + if (*p == '{') + die("Missing newline between %s and '{'", cmd_name); + if (*p) + die("Missing '{' after %s. Found \"%s\"", cmd_name, p); + var_init(&v,0,0,0,0); eval_expr(&v, ++expr_start, &expr_end); @@ -2071,7 +2328,7 @@ my_bool end_of_query(int c) return 0; for (i= 1; i < delimiter_length && - (c= my_getc(*cur_file)) == *(delimiter + i); + (c= my_getc(cur_file->file)) == *(delimiter + i); i++) tmp[i]= c; @@ -2086,33 +2343,72 @@ my_bool end_of_query(int c) } -int read_line(char* buf, int size) +/* + Read one "line" from the file + + SYNOPSIS + read_line + buf buffer for the read line + size size of the buffer i.e max size to read + + DESCRIPTION + This function actually reads several lines an adds them to the + buffer buf. It will continue to read until it finds what it believes + is a complete query. + + Normally that means it will read lines until it reaches the + "delimiter" that marks end of query. Default delimiter is ';' + The function should be smart enough not to detect delimiter's + found inside strings sorrounded with '"' and '\'' escaped strings. + + If the first line in a query starts with '#' or '-' this line is treated + as a comment. A comment is always terminated when end of line '\n' is + reached. + +*/ + +int read_line(char *buf, int size) { int c; char quote; - char* p= buf, *buf_end= buf + size - 1; + char *p= buf, *buf_end= buf + size - 1; int no_save= 0; enum {R_NORMAL, R_Q, R_Q_IN_Q, R_SLASH_IN_Q, R_COMMENT, R_LINE_START} state= R_LINE_START; DBUG_ENTER("read_line"); + LINT_INIT(quote); start_lineno= *lineno; for (; p < buf_end ;) { no_save= 0; - c= my_getc(*cur_file); - if (feof(*cur_file)) + c= my_getc(cur_file->file); + if (feof(cur_file->file)) { found_eof: - if ((*cur_file) != stdin) - my_fclose(*cur_file, MYF(0)); - cur_file--; + if (cur_file->file != stdin) + { + my_fclose(cur_file->file, MYF(0)); + cur_file->file= 0; + } + my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + cur_file->file_name= 0; lineno--; + start_lineno= *lineno; if (cur_file == file_stack) { + /* We're back at the first file, check if + all { have matching } + */ + if (cur_block != block_stack) + { + start_lineno= *(lineno+1); + die("Missing end of block"); + } DBUG_PRINT("info", ("end of file")); DBUG_RETURN(1); } + cur_file--; continue; } @@ -2146,7 +2442,8 @@ int read_line(char* buf, int size) } break; case R_LINE_START: - if (c == '#' || c == '-' || parsing_disabled) + /* Only accept start of comment if this is the first line in query */ + if ((*lineno == start_lineno) && (c == '#' || c == '-' || parsing_disabled)) { state = R_COMMENT; } @@ -2216,9 +2513,9 @@ int read_line(char* buf, int size) for (i= 1; i < charlen; i++) { - if (feof(*cur_file)) + if (feof(cur_file->file)) goto found_eof; /* FIXME: could we just break here?! */ - c= my_getc(*cur_file); + c= my_getc(cur_file->file); *p++ = c; } if (! my_ismbchar(charset_info, mb_start, p)) @@ -2235,15 +2532,34 @@ int read_line(char* buf, int size) } } *p= 0; /* Always end with \0 */ - DBUG_RETURN(feof(*cur_file)); + DBUG_RETURN(feof(cur_file->file)); } +/* + Create a query from a set of lines + + SYNOPSIS + read_query() + q_ptr pointer where to return the new query + + DESCRIPTION + Converts lines returned by read_line into a query, this involves + parsing the first word in the read line to find the query type. + + + A -- comment may contain a valid query as the first word after the + comment start. Thus it's always checked to see if that is the case. + The advantage with this approach is to be able to execute commands + terminated by new line '\n' regardless how many "delimiter" it contain. + + If query starts with @<file_name> this will specify a file to .... +*/ static char read_query_buf[MAX_QUERY]; int read_query(struct st_query** q_ptr) { - char *p = read_query_buf, * p1 ; + char *p= read_query_buf, *p1; struct st_query* q; DBUG_ENTER("read_query"); @@ -2260,16 +2576,16 @@ int read_query(struct st_query** q_ptr) q->require_file= 0; q->first_word_len= 0; - q->type = Q_UNKNOWN; + q->type= Q_UNKNOWN; q->query_buf= q->query= 0; if (read_line(read_query_buf, sizeof(read_query_buf))) { DBUG_RETURN(1); } - DBUG_PRINT("info", ("query: %s", read_query_buf)); + DBUG_PRINT("info", ("query: %s", read_query_buf)); if (*p == '#') { - q->type = Q_COMMENT; + q->type= Q_COMMENT; /* This goto is to avoid losing the "expected error" info. */ goto end; } @@ -2279,8 +2595,6 @@ int read_query(struct st_query** q_ptr) sizeof(global_expected_errno)); q->expected_errors= global_expected_errors; q->abort_on_error= (global_expected_errors == 0 && abort_on_error); - bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); - global_expected_errors=0; } if (p[0] == '-' && p[1] == '-') @@ -2290,34 +2604,6 @@ int read_query(struct st_query** q_ptr) } else if (!parsing_disabled) { - if (*p == '!') - { - q->abort_on_error= 0; - p++; - if (*p == '$') - { - int expected_errno= 0; - p++; - for (; my_isdigit(charset_info, *p); p++) - expected_errno = expected_errno * 10 + *p - '0'; - q->expected_errno[0].code.errnum = expected_errno; - q->expected_errno[0].type= ERR_ERRNO; - q->expected_errno[1].type= ERR_EMPTY; - q->expected_errors=1; - } - else if (*p == 'S') /* SQLSTATE */ - { - int i; - p++; - for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++) - q->expected_errno[0].code.sqlstate[i]= *p; - q->expected_errno[0].code.sqlstate[i]= '\0'; - q->expected_errno[0].type= ERR_SQLSTATE; - q->expected_errno[1].type= ERR_EMPTY; - q->expected_errors=1; - } - } - while (*p && my_isspace(charset_info, *p)) p++ ; if (*p == '@') @@ -2478,8 +2764,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), argument= buff; } fn_format(buff, argument, "", "", 4); - if (!(*++cur_file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) - die("Could not open %s: errno = %d", argument, errno); + DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); + if (!(cur_file->file= + my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) + die("Could not open %s: errno = %d", buff, errno); + cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); break; } case 'm': @@ -2564,7 +2853,7 @@ int parse_args(int argc, char **argv) return 0; } -char* safe_str_append(char* buf, const char* str, int size) +char* safe_str_append(char *buf, const char *str, int size) { int i,c ; for (i = 0; (c = *str++) && i < size - 1; i++) @@ -2573,7 +2862,7 @@ char* safe_str_append(char* buf, const char* str, int size) return buf; } -void str_to_file(const char* fname, char* str, int size) +void str_to_file(const char *fname, char *str, int size) { int fd; char buff[FN_REFLEN]; @@ -2583,7 +2872,7 @@ void str_to_file(const char* fname, char* str, int size) fname=buff; } fn_format(buff,fname,"","",4); - + if ((fd = my_open(buff, O_WRONLY | O_CREAT | O_TRUNC, MYF(MY_WME | MY_FFNF))) < 0) die("Could not open %s: errno = %d", buff, errno); @@ -2592,7 +2881,7 @@ void str_to_file(const char* fname, char* str, int size) my_close(fd, MYF(0)); } -void reject_dump(const char* record_file, char* buf, int size) +void reject_dump(const char *record_file, char *buf, int size) { char reject_file[FN_REFLEN]; str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size); @@ -2608,7 +2897,7 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, { len=(int) replace_strings(glob_replace, &out_buff, &out_length, val); if (len == -1) - die("Out of memory in replace\n"); + die("Out of memory in replace"); val=out_buff; } dynstr_append_mem(ds, val, len); @@ -2682,8 +2971,6 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags); static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags); static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds); -static int run_query_stmt_handle_error(char *query, struct st_query *q, - MYSQL_STMT *stmt, DYNAMIC_STRING *ds); static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, DYNAMIC_STRING *ds); @@ -2747,8 +3034,8 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) { got_error_on_send= mysql_send_query(mysql, query, query_len); if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY) - die("At line %u: unable to send query '%s' (mysql_errno=%d , errno=%d)", - start_lineno, query, mysql_errno(mysql), errno); + die("unable to send query '%s' (mysql_errno=%d , errno=%d)", + query, mysql_errno(mysql), errno); } do @@ -2767,17 +3054,12 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) (!(last_result= res= mysql_store_result(mysql)) && mysql_field_count(mysql))) { - if (normal_handle_error(query, q, mysql, ds)) + if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds)) error= 1; goto end; } - if (normal_handle_no_error(q)) - { - error= 1; - goto end; - } - if (!disable_result_log) { ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ @@ -2822,12 +3104,9 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) MYSQL_RES *warn_res=0; uint count= mysql_warning_count(mysql); if (!mysql_real_query(mysql, "SHOW WARNINGS", 13)) - { warn_res= mysql_store_result(mysql); - } if (!warn_res) - verbose_msg("Warning count is %u but didn't get any warnings\n", - count); + die("Warning count is %u but didn't get any warnings", count); else { dynstr_append_mem(ds, "Warnings:\n", 10); @@ -2852,21 +3131,34 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (record) { if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); + die("Missing result file"); if (!result_file) str_to_file(q->record_file, ds->str, ds->length); } else if (q->record_file[0]) { - error = check_result(ds, q->record_file, q->require_file); + error= check_result(ds, q->record_file, q->require_file); } if (res) mysql_free_result(res); last_result= 0; counter++; } while (!(err= mysql_next_result(mysql))); - if (err >= 1) - mysql_error(mysql); + if (err > 0) + { + /* We got an error from mysql_next_result, maybe expected */ + if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds)) + error= 1; + goto end; + } + + /* If we come here the query is both executed and read successfully */ + if (handle_no_error(q)) + { + error= 1; + goto end; + } end: free_replace(); @@ -2887,14 +3179,15 @@ end: /* - Handle errors which occurred after execution of conventional (non-prepared) - statement. + Handle errors which occurred after execution SYNOPSIS - normal_handle_error() + handle_error() query - query string q - query context - mysql - connection through which query was sent to server + err_errno - error number + err_error - error message + err_sqlstate - sql state ds - dynamic string which is used for output buffer NOTE @@ -2906,85 +3199,80 @@ end: 1 - Some other error was expected. */ -static int normal_handle_error(const char *query, struct st_query *q, - MYSQL *mysql, DYNAMIC_STRING *ds) +static int handle_error(const char *query, struct st_query *q, + unsigned int err_errno, const char *err_error, + const char* err_sqlstate, DYNAMIC_STRING *ds) { uint i; - - DBUG_ENTER("normal_handle_error"); + + DBUG_ENTER("handle_error"); if (q->require_file) abort_not_supported_test(); - + if (q->abort_on_error) - die("At line %u: query '%s' failed: %d: %s", start_lineno, query, - mysql_errno(mysql), mysql_error(mysql)); - else + die("query '%s' failed: %d: %s", query, err_errno, err_error); + + for (i= 0 ; (uint) i < q->expected_errors ; i++) { - for (i= 0 ; (uint) i < q->expected_errors ; i++) + if (((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == err_errno)) || + ((q->expected_errno[i].type == ERR_SQLSTATE) && + (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0))) { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == mysql_errno(mysql))) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate, mysql_sqlstate(mysql)) == 0))) + if (q->expected_errors == 1) { - if (q->expected_errors == 1) - { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds, "ERROR ", 6); - replace_dynstr_append(ds, mysql_sqlstate(mysql)); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, mysql_error(mysql)); - dynstr_append_mem(ds,"\n",1); - } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) - dynstr_append(ds,"Got one of the listed errors\n"); - /* OK */ - DBUG_RETURN(0); + /* Only log error if there is one possible error */ + dynstr_append_mem(ds, "ERROR ", 6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds,"\n",1); } + /* Don't log error if we may not get an error */ + else if (q->expected_errno[0].type == ERR_SQLSTATE || + (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0)) + dynstr_append(ds,"Got one of the listed errors\n"); + /* OK */ + DBUG_RETURN(0); } + } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); + DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append(ds, mysql_sqlstate(mysql)); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, mysql_error(mysql)); - dynstr_append_mem(ds, "\n", 1); + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds, "\n", 1); - if (i) - { - if (q->expected_errno[0].type == ERR_ERRNO) - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_errno(mysql), - q->expected_errno[0].code.errnum); - else - verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, mysql_sqlstate(mysql), - q->expected_errno[0].code.sqlstate); - DBUG_RETURN(1); - } - - /* - If we do not abort on error, failure to run the query does not fail the - whole test case. - */ - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql), - mysql_error(mysql)); - DBUG_RETURN(0); + if (i) + { + if (q->expected_errno[0].type == ERR_ERRNO) + die("query '%s' failed with wrong errno %d instead of %d...", + q->query, err_errno, q->expected_errno[0].code.errnum); + else + die("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, err_sqlstate, q->expected_errno[0].code.sqlstate); + DBUG_RETURN(1); } - return 0; /* Keep compiler happy */ + + /* + If we do not abort on error, failure to run the query does not fail the + whole test case. + */ + verbose_msg("query '%s' failed: %d: %s", q->query, err_errno, + err_error); + DBUG_RETURN(0); } /* - Handle absence of errors after execution of convetional statement. + Handle absence of errors after execution SYNOPSIS - normal_handle_error() + handle_no_error() q - context of query RETURN VALUE @@ -2992,24 +3280,24 @@ static int normal_handle_error(const char *query, struct st_query *q, 1 - Some error was expected from this query. */ -static int normal_handle_no_error(struct st_query *q) +static int handle_no_error(struct st_query *q) { - DBUG_ENTER("normal_handle_no_error"); + DBUG_ENTER("handle_no_error"); if (q->expected_errno[0].type == ERR_ERRNO && q->expected_errno[0].code.errnum != 0) { /* Error code we wanted was != 0, i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); + die("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0].code.errnum); DBUG_RETURN(1); } else if (q->expected_errno[0].type == ERR_SQLSTATE && strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) { /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", - q->query, q->expected_errno[0].code.sqlstate); + die("query '%s' succeeded - should have failed with sqlstate %s...", + q->query, q->expected_errno[0].code.sqlstate); DBUG_RETURN(1); } @@ -3029,7 +3317,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) { int error= 0; /* Function return code if "goto end;" */ int err; /* Temporary storage of return code from calls */ - int query_len, got_error_on_execute; + int query_len; ulonglong num_rows; char *query; MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ @@ -3044,8 +3332,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) may be a new connection. */ if (!(stmt= mysql_stmt_init(mysql))) - die("At line %u: unable init stmt structure"); - + die("unable init stmt structure"); + if (q->type != Q_EVAL) { query= q->query; @@ -3086,30 +3374,21 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) if (err != 0) { - if (q->abort_on_error) - { - die("At line %u: unable to prepare statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); - } - else - { - /* - Preparing is part of normal execution and some errors may be expected - */ - error= run_query_stmt_handle_error(query, q, stmt, ds); - goto end; - } + /* + Preparing is part of normal execution and some errors may be expected + */ + if (handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) + error= 1; + goto end; } /* We may have got warnings already, collect them if any */ - /* FIXME we only want this if the statement succeeds I think */ if (!disable_ps_warnings) run_query_stmt_handle_warnings(mysql, ds); /* - No need to call mysql_stmt_bind_param() because we have no + No need to call mysql_stmt_bind_param() because we have no parameter markers. To optimize performance we use a global 'stmt' that is initiated @@ -3118,22 +3397,13 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) prepared statement. */ - if ((got_error_on_execute= mysql_stmt_execute(stmt)) != 0) /* 0 == Success */ + if (mysql_stmt_execute(stmt) != 0) /* 0 == Success */ { - if (q->abort_on_error) - { - /* We got an error, unexpected */ - die("At line %u: unable to execute statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, mysql_stmt_error(stmt), - mysql_stmt_errno(stmt), got_error_on_execute); - } - else - { - /* We got an error, maybe expected */ - error= run_query_stmt_handle_error(query, q, stmt, ds); - goto end; - } + /* We got an error, maybe expected */ + if (handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) + error= 1; + goto end; } /* @@ -3143,11 +3413,10 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) */ { my_bool one= 1; - if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, - (void*) &one) != 0) - die("At line %u: unable to set stmt attribute " - "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)", - start_lineno, query, err); + if ((err= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, + (void*) &one)) != 0) + die("unable to set stmt attribute " + "'STMT_ATTR_UPDATE_MAX_LENGTH' err: %d", err); } /* @@ -3156,29 +3425,16 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) */ if ((err= mysql_stmt_store_result(stmt)) != 0) { - if (q->abort_on_error) - { - /* We got an error, unexpected */ - die("At line %u: unable to execute statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, mysql_stmt_error(stmt), - mysql_stmt_errno(stmt), got_error_on_execute); - } - else - { - /* We got an error, maybe expected */ - error= run_query_stmt_handle_error(query, q, stmt, ds); - goto end; - } + /* We got an error, maybe expected */ + if(handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) + error = 1; + goto end; } /* If we got here the statement was both executed and read succeesfully */ - - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + if (handle_no_error(q)) { - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); error= 1; goto end; } @@ -3197,8 +3453,6 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) MYSQL_FIELD *field= mysql_fetch_fields(res); uint num_fields= mysql_num_fields(res); - /* FIXME check error from the above? */ - if (display_metadata) run_query_display_metadata(field, num_fields, ds); @@ -3251,18 +3505,18 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) /* Fill in the data into the structures created above */ if ((err= mysql_stmt_bind_result(stmt, bind)) != 0) - die("At line %u: unable to bind result to statement '%s': " + die("unable to bind result to statement '%s': " "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); /* Read result from each row */ for (row_idx= 0; row_idx < num_rows; row_idx++) { if ((err= mysql_stmt_fetch(stmt)) != 0) - die("At line %u: unable to fetch all rows from statement '%s': " + die("unable to fetch all rows from statement '%s': " "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); /* Read result from each column */ @@ -3300,9 +3554,9 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) } if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA) - die("At line %u: fetch didn't end with MYSQL_NO_DATA from statement " + die("fetch didn't end with MYSQL_NO_DATA from statement " "'%s': %s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); free_replace_column(); @@ -3339,7 +3593,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) if (record) { if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); + die("Missing result file"); if (!result_file) str_to_file(q->record_file, ds->str, ds->length); } @@ -3351,9 +3605,6 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) mysql_free_result(res); /* Free normal result set with meta data */ last_result= 0; /* FIXME have no idea what this is about... */ - if (err >= 1) - mysql_error(mysql); /* FIXME strange, has no effect... */ - end: free_replace(); last_result=0; @@ -3444,8 +3695,8 @@ static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) { MYSQL_RES *warn_res= mysql_store_result(mysql); if (!warn_res) - verbose_msg("Warning count is %u but didn't get any warnings\n", - count); + die("Warning count is %u but didn't get any warnings", + count); else { dynstr_append_mem(ds, "Warnings:\n", 10); @@ -3458,71 +3709,6 @@ static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) } -static int run_query_stmt_handle_error(char *query, struct st_query *q, - MYSQL_STMT *stmt, DYNAMIC_STRING *ds) -{ - if (q->require_file) /* FIXME don't understand this one */ - { - abort_not_supported_test(); - } - - if (q->abort_on_error) - die("At line %u: query '%s' failed: %d: %s", start_lineno, query, - mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - else - { - int i; - - for (i=0 ; (uint) i < q->expected_errors ; i++) - { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == mysql_stmt_errno(stmt))) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate, - mysql_stmt_sqlstate(stmt)) == 0))) - { - if (i == 0 && q->expected_errors == 1) - { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds,"ERROR ",6); - replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt)); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds,mysql_stmt_error(stmt)); - dynstr_append_mem(ds,"\n",1); - } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) - dynstr_append(ds,"Got one of the listed errors\n"); - return 0; /* Ok */ - } - } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, - q->expected_errors)); - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt)); - dynstr_append_mem(ds,": ",2); - replace_dynstr_append(ds, mysql_stmt_error(stmt)); - dynstr_append_mem(ds,"\n",1); - if (i) - { - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_stmt_errno(stmt), q->expected_errno[0]); - return 1; /* Error */ - } - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - /* - if we do not abort on error, failure to run the query does - not fail the whole test case - */ - return 0; - } - - return 0; -} - /****************************************************************************\ * Functions to match SQL statements that can be prepared \****************************************************************************/ @@ -3543,12 +3729,13 @@ static void ps_init_re(void) "[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|" "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])"; - int err= regcomp(&ps_re, ps_re_str, (REG_EXTENDED | REG_ICASE | REG_NOSUB), - &my_charset_latin1); + int err= my_regcomp(&ps_re, ps_re_str, + (REG_EXTENDED | REG_ICASE | REG_NOSUB), + &my_charset_latin1); if (err) { char erbuf[100]; - int len= regerror(err, &ps_re, erbuf, sizeof(erbuf)); + int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf)); fprintf(stderr, "error %s, %d/%d `%s'\n", ps_eprint(err), len, (int)sizeof(erbuf), erbuf); exit(1); @@ -3558,7 +3745,7 @@ static void ps_init_re(void) static int ps_match_re(char *stmt_str) { - int err= regexec(&ps_re, stmt_str, (size_t)0, NULL, 0); + int err= my_regexec(&ps_re, stmt_str, (size_t)0, NULL, 0); if (err == 0) return 1; @@ -3567,7 +3754,7 @@ static int ps_match_re(char *stmt_str) else { char erbuf[100]; - int len= regerror(err, &ps_re, erbuf, sizeof(erbuf)); + int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf)); fprintf(stderr, "error %s, %d/%d `%s'\n", ps_eprint(err), len, (int)sizeof(erbuf), erbuf); exit(1); @@ -3577,7 +3764,7 @@ static int ps_match_re(char *stmt_str) static char *ps_eprint(int err) { static char epbuf[100]; - size_t len= regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf)); + size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf)); assert(len <= sizeof(epbuf)); return(epbuf); } @@ -3585,7 +3772,7 @@ static char *ps_eprint(int err) static void ps_free_reg(void) { - regfree(&ps_re); + my_regfree(&ps_re); } /****************************************************************************/ @@ -3619,6 +3806,22 @@ void get_query_type(struct st_query* q) q->type != Q_DISABLE_PARSING) q->type= Q_COMMENT; } + else if (q->type == Q_COMMENT_WITH_COMMAND && + q->query[q->first_word_len-1] == ';') + { + /* + Detect comment with command using extra delimiter + Ex --disable_query_log; + ^ Extra delimiter causing the command + to be skipped + */ + save= q->query[q->first_word_len-1]; + q->query[q->first_word_len-1]= 0; + type= find_type(q->query, &command_typelib, 1+2); + q->query[q->first_word_len-1]= save; + if (type > 0) + die("Extra delimiter \";\" found"); + } DBUG_VOID_RETURN; } @@ -3710,8 +3913,10 @@ int main(int argc, char **argv) { int error = 0; struct st_query *q; - my_bool require_file=0, q_send_flag=0, abort_flag= 0; + my_bool require_file=0, q_send_flag=0, abort_flag= 0, + query_executed= 0; char save_file[FN_REFLEN]; + MY_STAT res_info; MY_INIT(argv[0]); /* Use all time until exit if no explicit 'start_timer' */ @@ -3726,14 +3931,14 @@ int main(int argc, char **argv) memset(file_stack, 0, sizeof(file_stack)); memset(&master_pos, 0, sizeof(master_pos)); - file_stack_end = file_stack + MAX_INCLUDE_DEPTH; - cur_file = file_stack; + file_stack_end= file_stack + MAX_INCLUDE_DEPTH - 1; + cur_file= file_stack; lineno = lineno_stack; my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, INIT_Q_LINES); memset(block_stack, 0, sizeof(block_stack)); - block_stack_end= block_stack + BLOCK_STACK_DEPTH; + block_stack_end= block_stack + BLOCK_STACK_DEPTH - 1; cur_block= block_stack; cur_block->ok= TRUE; /* Outer block should always be executed */ cur_block->cmd= cmd_none; @@ -3746,8 +3951,11 @@ int main(int argc, char **argv) embedded_server_args, (char**) embedded_server_groups)) die("Can't initialize MySQL server"); - if (cur_file == file_stack) - *++cur_file = stdin; + if (cur_file == file_stack && cur_file->file == 0) + { + cur_file->file= stdin; + cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME)); + } *lineno=1; #ifndef EMBEDDED_LIBRARY if (manager_host) @@ -3793,19 +4001,20 @@ int main(int argc, char **argv) get_query_type(q); if (cur_block->ok) { + q->last_argument= q->first_argument; processed = 1; switch (q->type) { case Q_CONNECT: error|= do_connect(q); break; - case Q_CONNECTION: select_connection(q->first_argument); break; + case Q_CONNECTION: select_connection(q); break; case Q_DISCONNECT: case Q_DIRTY_CLOSE: close_connection(q); break; case Q_RPL_PROBE: do_rpl_probe(q); break; case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break; case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break; - case Q_ENABLE_QUERY_LOG: disable_query_log=0; break; + case Q_ENABLE_QUERY_LOG: disable_query_log=0; break; case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break; case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break; @@ -3828,19 +4037,24 @@ int main(int argc, char **argv) case Q_SERVER_START: do_server_start(q); break; case Q_SERVER_STOP: do_server_stop(q); break; #endif - case Q_INC: do_inc(q); break; - case Q_DEC: do_dec(q); break; + case Q_INC: do_modify_var(q, "inc", DO_INC); break; + case Q_DEC: do_modify_var(q, "dec", DO_DEC); break; case Q_ECHO: do_echo(q); break; case Q_SYSTEM: do_system(q); break; case Q_DELIMITER: strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); delimiter_length= strlen(delimiter); + q->last_argument= q->first_argument+delimiter_length; break; - case Q_DISPLAY_VERTICAL_RESULTS: display_result_vertically= TRUE; break; - case Q_DISPLAY_HORIZONTAL_RESULTS: - display_result_vertically= FALSE; break; + case Q_DISPLAY_VERTICAL_RESULTS: + display_result_vertically= TRUE; + break; + case Q_DISPLAY_HORIZONTAL_RESULTS: + display_result_vertically= FALSE; + break; case Q_LET: do_let(q); break; - case Q_EVAL_RESULT: eval_result = 1; break; + case Q_EVAL_RESULT: + eval_result = 1; break; case Q_EVAL: if (q->query == q->query_buf) { @@ -3873,6 +4087,8 @@ int main(int argc, char **argv) } error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); display_result_vertically= old_display_result_vertically; + q->last_argument= q->end; + query_executed= 1; break; } case Q_QUERY: @@ -3897,6 +4113,8 @@ int main(int argc, char **argv) save_file[0]=0; } error |= run_query(&cur_con->mysql, q, flags); + query_executed= 1; + q->last_argument= q->end; break; } case Q_SEND: @@ -3916,6 +4134,8 @@ int main(int argc, char **argv) is given on this connection. */ error |= run_query(&cur_con->mysql, q, QUERY_SEND); + query_executed= 1; + q->last_argument= q->end; break; case Q_RESULT: get_file_name(save_file,q); @@ -3940,23 +4160,22 @@ int main(int argc, char **argv) { do_save_master_pos(); if (*q->first_argument) - select_connection(q->first_argument); + select_connection(q); else - { - char buf[] = "slave"; - select_connection(buf); - } - do_sync_with_master2(""); + select_connection_name("slave"); + do_sync_with_master2(0); break; } case Q_COMMENT: /* Ignore row */ case Q_COMMENT_WITH_COMMAND: + q->last_argument= q->end; break; case Q_PING: (void) mysql_ping(&cur_con->mysql); break; - case Q_EXEC: + case Q_EXEC: do_exec(q); + query_executed= 1; break; case Q_START_TIMER: /* Overwrite possible earlier start of timer */ @@ -3967,7 +4186,7 @@ int main(int argc, char **argv) timer_output(); got_end_timer= TRUE; break; - case Q_CHARACTER_SET: + case Q_CHARACTER_SET: set_charset(q); break; case Q_DISABLE_PS_PROTOCOL: @@ -3977,11 +4196,17 @@ int main(int argc, char **argv) ps_protocol_enabled= ps_protocol; break; case Q_DISABLE_RECONNECT: - cur_con->mysql.reconnect= 0; + { + my_bool reconnect= 0; + mysql_options(&cur_con->mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); break; + } case Q_ENABLE_RECONNECT: - cur_con->mysql.reconnect= 1; + { + my_bool reconnect= 1; + mysql_options(&cur_con->mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); break; + } case Q_DISABLE_PARSING: parsing_disabled++; break; @@ -3997,13 +4222,16 @@ int main(int argc, char **argv) case Q_EXIT: abort_flag= 1; break; - default: processed = 0; break; + + default: + processed= 0; + break; } } if (!processed) { - current_line_inc = 0; + current_line_inc= 0; switch (q->type) { case Q_WHILE: do_block(cmd_while, q); break; case Q_IF: do_block(cmd_if, q); break; @@ -4011,16 +4239,48 @@ int main(int argc, char **argv) default: current_line_inc = 1; break; } } + else + check_eol_junk(q->last_argument); + + if (q->type != Q_ERROR) + { + /* + As soon as any non "error" command has been executed, + the array with expected errors should be cleared + */ + global_expected_errors= 0; + bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); + } parser.current_line += current_line_inc; } - if (result_file && ds_res.length) + if (!query_executed && result_file && my_stat(result_file, &res_info, 0)) + { + /* + my_stat() successful on result file. Check if we have not run a + single query, but we do have a result file that contains data. + Note that we don't care, if my_stat() fails. For example for + non-existing or non-readable file we assume it's fine to have + no query output from the test file, e.g. regarded as no error. + */ + if (res_info.st_size) + error|= (RESULT_CONTENT_MISMATCH | RESULT_LENGTH_MISMATCH); + } + if (ds_res.length && !error) { - if (!record) - error |= check_result(&ds_res, result_file, q->require_file); + if (result_file) + { + if (!record) + error |= check_result(&ds_res, result_file, q->require_file); + else + str_to_file(result_file, ds_res.str, ds_res.length); + } else - str_to_file(result_file, ds_res.str, ds_res.length); + { + /* Print the result to stdout */ + printf("%s", ds_res.str); + } } dynstr_free(&ds_res); @@ -4874,7 +5134,7 @@ static void get_replace_column(struct st_query *q) free_replace_column(); if (!*from) - die("Missing argument in %s\n", q->query); + die("Missing argument in %s", q->query); /* Allocate a buffer for results */ start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); @@ -4885,15 +5145,16 @@ static void get_replace_column(struct st_query *q) to= get_string(&buff, &from, q); if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) - die("Wrong column number to replace_columns in %s\n", q->query); + die("Wrong column number to replace_column in '%s'", q->query); if (!*from) - die("Wrong number of arguments to replace in %s\n", q->query); + die("Wrong number of arguments to replace_column in '%s'", q->query); to= get_string(&buff, &from, q); my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); set_if_bigger(max_replace_column, column_number); } my_free(start, MYF(0)); + q->last_argument= q->end; } #if defined(__NETWARE__) || defined(__WIN__) @@ -4944,7 +5205,7 @@ static char *subst_env_var(const char *str) if (!(subst= getenv(env_var))) { my_free(result, MYF(0)); - die("MYSQLTEST.NLM: Environment variable %s is not defined\n", + die("MYSQLTEST.NLM: Environment variable %s is not defined", env_var); } diff --git a/cmd-line-utils/readline/complete.c b/cmd-line-utils/readline/complete.c index 2196c66a54c..df0a698b81f 100644 --- a/cmd-line-utils/readline/complete.c +++ b/cmd-line-utils/readline/complete.c @@ -21,10 +21,18 @@ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #define READLINE_LIBRARY +#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) +#define _XOPEN_SOURCE 500 +#endif + #include "config_readline.h" #include <sys/types.h> + +/* To get SuSE 9.3 to define wcwidth() (in wchar.h) */ + #include <fcntl.h> + #if defined (HAVE_SYS_FILE_H) # include <sys/file.h> #endif @@ -1149,7 +1157,8 @@ compute_lcd_of_matches (match_list, matches, text) rl_completion_found_quote && rl_filename_quoting_desired) { - dtext = (*rl_filename_dequoting_function) (text, rl_completion_quote_character); + dtext = (*rl_filename_dequoting_function) + ((char*) text, rl_completion_quote_character); text = dtext; } diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c index cab76c0da81..06eaa5e4be2 100644 --- a/cmd-line-utils/readline/display.c +++ b/cmd-line-utils/readline/display.c @@ -21,10 +21,16 @@ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #define READLINE_LIBRARY +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif + #include "config_readline.h" #include <sys/types.h> +/* To get SuSE 9.3 to define wcwidth() (in wchar.h) */ + #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif /* HAVE_UNISTD_H */ diff --git a/cmd-line-utils/readline/mbutil.c b/cmd-line-utils/readline/mbutil.c index c88e9485f39..284ea63aae4 100644 --- a/cmd-line-utils/readline/mbutil.c +++ b/cmd-line-utils/readline/mbutil.c @@ -21,9 +21,16 @@ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #define READLINE_LIBRARY +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif + #include "config_readline.h" #include <sys/types.h> + +/* To get SuSE 9.3 to define wcwidth() (in wchar.h) */ + #include <fcntl.h> #include "posixjmp.h" diff --git a/config/ac-macros/character_sets.m4 b/config/ac-macros/character_sets.m4 index 3ecc4bb5a03..1ab6e7dd780 100644 --- a/config/ac-macros/character_sets.m4 +++ b/config/ac-macros/character_sets.m4 @@ -343,7 +343,7 @@ case $default_charset in default_charset_default_collation="ucs2_general_ci" define(UCSC1, ucs2_general_ci ucs2_bin) define(UCSC2, ucs2_czech_ci ucs2_danish_ci) - define(UCSC3, ucs2_estonian_ci ucs2_icelandic_ci) + define(UCSC3, ucs2_esperanto_ci ucs2_estonian_ci ucs2_icelandic_ci) define(UCSC4, ucs2_latvian_ci ucs2_lithuanian_ci) define(UCSC5, ucs2_persian_ci ucs2_polish_ci ucs2_romanian_ci) define(UCSC6, ucs2_slovak_ci ucs2_slovenian_ci) @@ -367,7 +367,7 @@ case $default_charset in else define(UTFC1, utf8_general_ci utf8_bin) define(UTFC2, utf8_czech_ci utf8_danish_ci) - define(UTFC3, utf8_estonian_ci utf8_icelandic_ci) + define(UTFC3, utf8_esperanto_ci utf8_estonian_ci utf8_icelandic_ci) define(UTFC4, utf8_latvian_ci utf8_lithuanian_ci) define(UTFC5, utf8_persian_ci utf8_polish_ci utf8_romanian_ci) define(UTFC6, utf8_slovak_ci utf8_slovenian_ci) diff --git a/config/ac-macros/ha_federated.m4 b/config/ac-macros/ha_federated.m4 index 4383a9d8d55..5c991f31666 100644 --- a/config/ac-macros/ha_federated.m4 +++ b/config/ac-macros/ha_federated.m4 @@ -6,7 +6,7 @@ AC_DEFUN([MYSQL_CHECK_FEDERATED], [ AC_ARG_WITH([federated-storage-engine], [ --with-federated-storage-engine - Enable the MySQL Storage Engine], + Enable the MySQL Federated Storage Engine], [federateddb="$withval"], [federateddb=no]) AC_MSG_CHECKING([for MySQL federated storage engine]) diff --git a/config/ac-macros/ha_ndbcluster.m4 b/config/ac-macros/ha_ndbcluster.m4 index 509cd868909..2ff598242e4 100644 --- a/config/ac-macros/ha_ndbcluster.m4 +++ b/config/ac-macros/ha_ndbcluster.m4 @@ -140,7 +140,7 @@ AC_DEFUN([MYSQL_CHECK_NDBCLUSTER], [ AC_MSG_RESULT([Using NDB Cluster]) AC_DEFINE([HAVE_NDBCLUSTER_DB], [1], [Using Ndb Cluster DB]) have_ndbcluster="yes" - ndbcluster_includes="-I../ndb/include -I../ndb/include/ndbapi" + ndbcluster_includes="-I../ndb/include -I../ndb/include/ndbapi -I../ndb/include/mgmapi" ndbcluster_libs="\$(top_builddir)/ndb/src/.libs/libndbclient.a" ndbcluster_system_libs="" ndb_mgmclient_libs="\$(top_builddir)/ndb/src/mgmclient/libndbmgmclient.la" diff --git a/config/ac-macros/readline.m4 b/config/ac-macros/readline.m4 index 79c6479d15d..e47d0a44483 100644 --- a/config/ac-macros/readline.m4 +++ b/config/ac-macros/readline.m4 @@ -59,3 +59,42 @@ AC_DEFUN([MYSQL_CHECK_NEW_RL_INTERFACE], [ ) ) ]) + +dnl +dnl check for availability of multibyte characters and functions +dnl (Based on BASH_CHECK_MULTIBYTE in aclocal.m4 of readline-5.0) +dnl +AC_DEFUN([MYSQL_CHECK_MULTIBYTE], +[ +AC_CHECK_HEADERS(wctype.h) +AC_CHECK_HEADERS(wchar.h) +AC_CHECK_HEADERS(langinfo.h) + +AC_CHECK_FUNC(mbsrtowcs, AC_DEFINE([HAVE_MBSRTOWCS],[],[Define if you have mbsrtowcs])) +AC_CHECK_FUNC(mbrtowc, AC_DEFINE([HAVE_MBRTOWC],[],[Define if you have mbrtowc])) +AC_CHECK_FUNC(mbrlen, AC_DEFINE([HAVE_MBRLEN],[],[Define if you have mbrlen])) +AC_CHECK_FUNC(wctomb, AC_DEFINE([HAVE_WCTOMB],[],[Define if you have wctomb])) +AC_CHECK_FUNC(wcwidth, AC_DEFINE([HAVE_WCWIDTH],[],[Define if you have wcwidth])) +AC_CHECK_FUNC(wcsdup, AC_DEFINE([HAVE_WCSDUP],[],[Define if you check wcsdup])) + +AC_CACHE_CHECK([for mbstate_t], mysql_cv_have_mbstate_t, +[AC_TRY_COMPILE([ +#include <wchar.h>], [ + mbstate_t ps; + mbstate_t *psp; + psp = (mbstate_t *)0; +], mysql_cv_have_mbstate_t=yes, mysql_cv_have_mbstate_t=no)]) +if test $mysql_cv_have_mbstate_t = yes; then + AC_DEFINE([HAVE_MBSTATE_T],[],[Define if mysql_cv_have_mbstate_t=yes]) +fi + +AC_CACHE_CHECK([for nl_langinfo and CODESET], mysql_cv_langinfo_codeset, +[AC_TRY_LINK( +[#include <langinfo.h>], +[char* cs = nl_langinfo(CODESET);], +mysql_cv_langinfo_codeset=yes, mysql_cv_langinfo_codeset=no)]) +if test $mysql_cv_langinfo_codeset = yes; then + AC_DEFINE([HAVE_LANGINFO_CODESET],[],[Define if mysql_cv_langinfo_codeset=yes]) +fi + +]) diff --git a/config/ac-macros/yassl.m4 b/config/ac-macros/yassl.m4 index 92133339343..dcd72cb14f1 100644 --- a/config/ac-macros/yassl.m4 +++ b/config/ac-macros/yassl.m4 @@ -20,6 +20,18 @@ AC_DEFUN([MYSQL_CHECK_YASSL], [ -L\$(top_builddir)/extra/yassl/taocrypt/src -ltaocrypt" openssl_includes="-I\$(top_srcdir)/extra/yassl/include" AC_DEFINE([HAVE_OPENSSL], [1], [Defined by configure. Using yaSSL for OpenSSL emulation.]) + AC_DEFINE([HAVE_YASSL], [1], [Defined by configure. Using yaSSL for OpenSSL emulation.]) + # System specific checks + yassl_integer_extra_cxxflags="" + case $host_cpu--$CXX_VERSION in + sparc*--*Sun*C++*5.6*) + # Disable inlining when compiling taocrypt/src/integer.cpp + yassl_integer_extra_cxxflags="+d" + AC_MSG_NOTICE([disabling inlining for yassl/taocrypt/src/integer.cpp]) + ;; + esac + AC_SUBST([yassl_integer_extra_cxxflags]) + else yassl_dir="" AC_MSG_RESULT(no) diff --git a/configure.in b/configure.in index 97e07baffd4..40ff480bb94 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.13-beta) +AM_INIT_AUTOMAKE(mysql, 5.0.16) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -18,8 +18,8 @@ SHARED_LIB_VERSION=15:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=13 -NDB_VERSION_STATUS="beta" +NDB_VERSION_BUILD=16 +NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? # Remember that regexps needs to quote [ and ] since this is run through m4 @@ -322,19 +322,19 @@ case "$target_os" in ;; esac ;; - sysv5UnixWare*) + sysv5UnixWare* | sysv5OpenUNIX8*) if test "$GCC" != "yes"; then - # We are using built-in inline function + # Use the built-in alloca() CFLAGS="$CFLAGS -Kalloca" fi CXXFLAGS="$CXXFLAGS -DNO_CPLUSPLUS_ALLOCA" ;; - sysv5OpenUNIX8*) + sysv5SCO_SV6.0.0*) if test "$GCC" != "yes"; then - # We are using built-in inline function + # Use the built-in alloca() CFLAGS="$CFLAGS -Kalloca" + CXXFLAGS="$CFLAGS -Kalloca" fi - CXXFLAGS="$CXXFLAGS -DNO_CPLUSPLUS_ALLOCA" ;; esac AC_SUBST(CC) @@ -1021,7 +1021,7 @@ case $SYSTEM_TYPE in *darwin5*) if test "$ac_cv_prog_gcc" = "yes" then - FLAGS="-traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH" + FLAGS="-traditional-cpp -DHAVE_DARWIN5_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH" CFLAGS="$CFLAGS $FLAGS" CXXFLAGS="$CXXFLAGS $FLAGS" MAX_C_OPTIMIZE="-O" @@ -1031,17 +1031,16 @@ case $SYSTEM_TYPE in *darwin6*) if test "$ac_cv_prog_gcc" = "yes" then - FLAGS="-DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH" + FLAGS="-D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH" CFLAGS="$CFLAGS $FLAGS" CXXFLAGS="$CXXFLAGS $FLAGS" MAX_C_OPTIMIZE="-O" fi ;; - *darwin[[7-8]]*) - # don't forget to escape [] like above + *darwin*) if test "$ac_cv_prog_gcc" = "yes" then - FLAGS="-DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT" + FLAGS="-D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT" CFLAGS="$CFLAGS $FLAGS" CXXFLAGS="$CXXFLAGS $FLAGS" MAX_C_OPTIMIZE="-O" @@ -1359,8 +1358,6 @@ then if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null then AC_DEFINE(HAVE_UNIXWARE7_THREADS, [1]) - else - AC_DEFINE(HAVE_UNIXWARE7_POSIX, [1]) fi AC_MSG_RESULT("yes") # We must have cc @@ -1386,87 +1383,40 @@ then AC_MSG_RESULT("no") fi fi -# Hack for SCO UnixWare7 -# -if test "$with_named_thread" = "no" -then - AC_MSG_CHECKING("SCO UnixWare7 native threads") - if expr "$SYSTEM_TYPE" : ".*UnixWare*" > /dev/null - then - if test -f /usr/lib/libthread.so -o -f /usr/lib/libthreadT.so - then - MYSQL_REMOVE_SOCKET_FROM_LIBS_HACK - if expr "$CC" : ".*gcc.*" - then - with_named_thread="-pthread -lsocket -lnsl" - else - with_named_thread="-Kthread -lsocket -lnsl" - fi - if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null - then - AC_DEFINE(HAVE_UNIXWARE7_THREADS, [1]) - else - AC_DEFINE(HAVE_UNIXWARE7_POSIX, [1]) - fi - # We must have cc - AC_MSG_CHECKING("for gcc") - if expr "$CC" : ".*gcc.*" - then - CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" - CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" - else - CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" - CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" - fi - AC_MSG_RESULT("yes") - else - AC_MSG_ERROR([configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual.]) - fi - else - AC_MSG_RESULT("no") - fi -fi -# Hack for Caldera OpenUNIX8 +# +# Check for SCO threading libraries # if test "$with_named_thread" = "no" then - AC_MSG_CHECKING("OpenUNIX8 native threads") - if expr "$SYSTEM_TYPE" : ".*OpenUNIX*" > /dev/null + AC_MSG_CHECKING([SCO OpenServer 6, UnixWare 7 or OpenUNIX 8 native threads]) + if expr "$SYSTEM_TYPE" : ".*UnixWare.*" > /dev/null || \ + expr "$SYSTEM_TYPE" : ".*SCO_SV6.*" > /dev/null || \ + expr "$SYSTEM_TYPE" : ".*OpenUNIX.*" > /dev/null then if test -f /usr/lib/libthread.so -o -f /usr/lib/libthreadT.so then MYSQL_REMOVE_SOCKET_FROM_LIBS_HACK - if expr "$CC" : ".*gcc.*" + if expr "$CC" : ".*gcc.*" > /dev/null then - with_named_thread="-pthread -lsocket -lnsl" + with_named_thread="-pthread -lsocket -lnsl" + CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; else with_named_thread="-Kthread -lsocket -lnsl" + CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; fi if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null then - AC_DEFINE([HAVE_UNIXWARE7_THREADS], [1], - [UNIXWARE7 threads are not posix]) - else - AC_DEFINE([HAVE_UNIXWARE7_POSIX], [1], - [new UNIXWARE7 threads that are not yet posix]) - fi - # We must have cc - AC_MSG_CHECKING("for gcc") - if expr "$CC" : ".*gcc.*" - then - CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" - CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" - else - CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" - CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" + AC_DEFINE(HAVE_UNIXWARE7_THREADS, [1], [Have UnixWare 7 (or similar) almost-POSIX threading library]) fi - AC_MSG_RESULT("yes") + AC_MSG_RESULT(yes) else - AC_MSG_ERROR([configure: error: Can't find thread libs on Caldera OpenUNIX 8. See the Installation chapter in the Reference Manual.]) + AC_MSG_ERROR([configure: error: Can't find thread library on SCO/Caldera system. See the Installation chapter in the Reference Manual.]) fi else - AC_MSG_RESULT("no") + AC_MSG_RESULT(no) fi fi @@ -1860,6 +1810,7 @@ MYSQL_HAVE_TIOCSTAT MYSQL_STRUCT_DIRENT_D_INO MYSQL_STRUCT_DIRENT_D_NAMLEN MYSQL_TYPE_SIGHANDLER +MYSQL_CHECK_MULTIBYTE if test "$with_named_curses" = "no" then MYSQL_CHECK_LIB_TERMCAP @@ -1911,7 +1862,7 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bzero chsize cuserid fchmod fcntl \ realpath rename rint rwlock_init setupterm \ shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \ sighold sigset sigthreadmask \ - snprintf socket stpcpy strcasecmp strerror strnlen strpbrk strstr strtol \ + snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr strtol \ strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr) # @@ -2508,7 +2459,7 @@ then AC_CONFIG_FILES(bdb/Makefile) echo "CONFIGURING FOR BERKELEY DB" - bdb_conf_flags="--disable-shared" + bdb_conf_flags="--disable-shared --build=$build_alias" if test $with_debug = "yes" then bdb_conf_flags="$bdb_conf_flags --enable-debug --enable-diagnostic" diff --git a/dbug/my_main.c b/dbug/my_main.c index ed1c9329235..31c15aa67aa 100644 --- a/dbug/my_main.c +++ b/dbug/my_main.c @@ -8,6 +8,7 @@ #endif #include <my_global.h> /* This includes dbug.h */ +#include <my_pthread.h> int main (argc, argv) int argc; diff --git a/extra/Makefile.am b/extra/Makefile.am index cb06e7495f9..457fddce673 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -38,7 +38,7 @@ $(top_builddir)/include/mysqld_ername.h: $(top_builddir)/include/mysqld_error.h $(top_builddir)/include/sql_state.h: $(top_builddir)/include/mysqld_error.h bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \ - resolve_stack_dump mysql_waitpid + resolve_stack_dump mysql_waitpid innochecksum noinst_PROGRAMS = charset2html # Don't update the files from bitkeeper diff --git a/extra/comp_err.c b/extra/comp_err.c index 85833999d5c..d0e387dcd35 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -51,7 +51,7 @@ uint file_pos[MAX_ROWS]; const char *empty_string= ""; /* For empty states */ /* - Default values for command line options. See getopt structure for defintions + Default values for command line options. See getopt structure for definitions for these. */ @@ -131,7 +131,8 @@ static struct languages *parse_charset_string(char *str); static struct errors *parse_error_string(char *ptr, int er_count); static struct message *parse_message_string(struct message *new_message, char *str); -static struct message *find_message(struct errors *err, const char *lang); +static struct message *find_message(struct errors *err, const char *lang, + my_bool no_default); static int parse_input_file(const char *file_name, struct errors **top_error, struct languages **top_language); static int get_options(int *argc, char ***argv); @@ -227,7 +228,7 @@ static int create_header_files(struct errors *error_head) { /* generating mysqld_error.h - fprintf() will automaticly add \r on windows + fprintf() will automatically add \r on windows */ fprintf(er_definef, "#define %s %d\n", tmp_error->er_name, tmp_error->d_code); @@ -305,7 +306,7 @@ static int create_sys_files(struct languages *lang_head, for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error) { /* dealing with messages */ - tmp= find_message(tmp_error, tmp_lang->lang_short_name); + tmp= find_message(tmp_error, tmp_lang->lang_short_name, FALSE); if (!tmp) { @@ -450,6 +451,13 @@ static int parse_input_file(const char *file_name, struct errors **top_error, current_error->er_name); DBUG_RETURN(0); } + if (find_message(current_error, current_message.lang_short_name, TRUE)) + { + fprintf(stderr, "Duplicate message string for error '%s'" + " in language '%s'\n", + current_error->er_name, current_message.lang_short_name); + DBUG_RETURN(0); + } if (insert_dynamic(¤t_error->msg, (byte *) & current_message)) DBUG_RETURN(0); continue; @@ -518,14 +526,14 @@ static uint parse_error_offset(char *str) } -/* Parsing of the default language line. e.g. "default-lanuage eng" */ +/* Parsing of the default language line. e.g. "default-language eng" */ static char *parse_default_language(char *str) { char *slang; DBUG_ENTER("parse_default_language"); - /* skipping the "default_language" keyword */ + /* skipping the "default-language" keyword */ str= find_end_of_word(str); /* skipping space(s) and/or tabs after the keyword */ str= skip_delimiters(str); @@ -556,11 +564,19 @@ static char *parse_default_language(char *str) /* - For given error finds message on given language, if does not exist, - returns english. -*/ + Find the message in a particular language + + SYNOPSIS + find_message() + err Error to find message for + lang Language of message to find + no_default Don't return default (English) if does not exit -static struct message *find_message(struct errors *err, const char *lang) + RETURN VALUE + Returns the message structure if one is found, or NULL if not. +*/ +static struct message *find_message(struct errors *err, const char *lang, + my_bool no_default) { struct message *tmp, *return_val= 0; uint i, count; @@ -579,7 +595,7 @@ static struct message *find_message(struct errors *err, const char *lang) return_val= tmp; } } - DBUG_RETURN(return_val); + DBUG_RETURN(no_default ? NULL : return_val); } @@ -697,7 +713,7 @@ static struct errors *parse_error_string(char *str, int er_count) DBUG_ENTER("parse_error_string"); DBUG_PRINT("enter", ("str: %s", str)); - /* create a new a element */ + /* create a new element */ new_error= (struct errors *) my_malloc(sizeof(*new_error), MYF(MY_WME)); if (my_init_dynamic_array(&new_error->msg, sizeof(struct message), 0, 0)) @@ -762,7 +778,7 @@ static struct errors *parse_error_string(char *str, int er_count) /* - Parsing the string with charset/full lang name/short lang name; + Parsing the string with full lang name/short lang name/charset; returns pointer to the language structure */ @@ -814,7 +830,7 @@ static struct languages *parse_charset_string(char *str) DBUG_RETURN(0); /* Fatal error */ DBUG_PRINT("info", ("charset: %s", new_lang->charset)); - /* skipping space, tub or "," */ + /* skipping space, tab or "," */ str= skip_delimiters(str); } while (*str != ';' && *str); diff --git a/extra/innochecksum.c b/extra/innochecksum.c new file mode 100644 index 00000000000..739953298af --- /dev/null +++ b/extra/innochecksum.c @@ -0,0 +1,328 @@ +/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + InnoDB offline file checksum utility. 85% of the code in this file + was taken wholesale fron the InnoDB codebase. + + The final 15% was originally written by Mark Smith of Danga + Interactive, Inc. <junior@danga.com> + + Published with a permission. +*/ + +/* needed to have access to 64 bit file functions */ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +/* all of these ripped from InnoDB code from MySQL 4.0.22 */ +#define UT_HASH_RANDOM_MASK 1463735687 +#define UT_HASH_RANDOM_MASK2 1653893711 +#define FIL_PAGE_LSN 16 +#define FIL_PAGE_FILE_FLUSH_LSN 26 +#define FIL_PAGE_OFFSET 4 +#define FIL_PAGE_DATA 38 +#define FIL_PAGE_END_LSN_OLD_CHKSUM 8 +#define FIL_PAGE_SPACE_OR_CHKSUM 0 +#define UNIV_PAGE_SIZE (2 * 8192) + +/* command line argument to do page checks (that's it) */ +/* another argument to specify page ranges... seek to right spot and go from there */ + +typedef unsigned long int ulint; +typedef unsigned char byte; + +/* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */ +ulint mach_read_from_4(byte *b) +{ + return( ((ulint)(b[0]) << 24) + + ((ulint)(b[1]) << 16) + + ((ulint)(b[2]) << 8) + + (ulint)(b[3]) + ); +} + +ulint +ut_fold_ulint_pair( +/*===============*/ + /* out: folded value */ + ulint n1, /* in: ulint */ + ulint n2) /* in: ulint */ +{ + return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1) + ^ UT_HASH_RANDOM_MASK) + n2); +} + +ulint +ut_fold_binary( +/*===========*/ + /* out: folded value */ + byte* str, /* in: string of bytes */ + ulint len) /* in: length */ +{ + ulint i; + ulint fold= 0; + + for (i= 0; i < len; i++) + { + fold= ut_fold_ulint_pair(fold, (ulint)(*str)); + + str++; + } + + return(fold); +} + +ulint +buf_calc_page_new_checksum( +/*=======================*/ + /* out: checksum */ + byte* page) /* in: buffer page */ +{ + ulint checksum; + + /* Since the fields FIL_PAGE_FILE_FLUSH_LSN and ..._ARCH_LOG_NO + are written outside the buffer pool to the first pages of data + files, we have to skip them in the page checksum calculation. + We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the + checksum is stored, and also the last 8 bytes of page because + there we store the old formula checksum. */ + + checksum= ut_fold_binary(page + FIL_PAGE_OFFSET, + FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET) + + ut_fold_binary(page + FIL_PAGE_DATA, + UNIV_PAGE_SIZE - FIL_PAGE_DATA + - FIL_PAGE_END_LSN_OLD_CHKSUM); + checksum= checksum & 0xFFFFFFFF; + + return(checksum); +} + +ulint +buf_calc_page_old_checksum( +/*=======================*/ + /* out: checksum */ + byte* page) /* in: buffer page */ +{ + ulint checksum; + + checksum= ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN); + + checksum= checksum & 0xFFFFFFFF; + + return(checksum); +} + + +int main(int argc, char **argv) +{ + FILE *f; /* our input file */ + byte *p; /* storage of pages read */ + int bytes; /* bytes read count */ + ulint ct; /* current page number (0 based) */ + int now; /* current time */ + int lastt; /* last time */ + ulint oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* ulints for checksum storage */ + struct stat st; /* for stat, if you couldn't guess */ + unsigned long long int size; /* size of file (has to be 64 bits) */ + ulint pages; /* number of pages in file */ + ulint start_page= 0, end_page= 0, use_end_page= 0; /* for starting and ending at certain pages */ + off_t offset= 0; + int just_count= 0; /* if true, just print page count */ + int verbose= 0; + int debug= 0; + int c; + int fd; + + /* remove arguments */ + while ((c= getopt(argc, argv, "cvds:e:p:")) != -1) + { + switch (c) + { + case 'v': + verbose= 1; + break; + case 'c': + just_count= 1; + break; + case 's': + start_page= atoi(optarg); + break; + case 'e': + end_page= atoi(optarg); + use_end_page= 1; + break; + case 'p': + start_page= atoi(optarg); + end_page= atoi(optarg); + use_end_page= 1; + break; + case 'd': + debug= 1; + break; + case ':': + fprintf(stderr, "option -%c requires an argument\n", optopt); + return 1; + break; + case '?': + fprintf(stderr, "unrecognized option: -%c\n", optopt); + return 1; + break; + } + } + + /* debug implies verbose... */ + if (debug) verbose= 1; + + /* make sure we have the right arguments */ + if (optind >= argc) + { + printf("InnoDB offline file checksum utility.\n"); + printf("usage: %s [-c] [-s <start page>] [-e <end page>] [-p <page>] [-v] [-d] <filename>\n", argv[0]); + printf("\t-c\tprint the count of pages in the file\n"); + printf("\t-s n\tstart on this page number (0 based)\n"); + printf("\t-e n\tend at this page number (0 based)\n"); + printf("\t-p n\tcheck only this page (0 based)\n"); + printf("\t-v\tverbose (prints progress every 5 seconds)\n"); + printf("\t-d\tdebug mode (prints checksums for each page)\n"); + return 1; + } + + /* stat the file to get size and page count */ + if (stat(argv[optind], &st)) + { + perror("error statting file"); + return 1; + } + size= st.st_size; + pages= size / UNIV_PAGE_SIZE; + if (just_count) + { + printf("%lu\n", pages); + return 0; + } + else if (verbose) + { + printf("file %s= %llu bytes (%lu pages)...\n", argv[1], size, pages); + printf("checking pages in range %lu to %lu\n", start_page, use_end_page ? end_page : (pages - 1)); + } + + /* open the file for reading */ + f= fopen(argv[optind], "r"); + if (!f) + { + perror("error opening file"); + return 1; + } + + /* seek to the necessary position */ + if (start_page) + { + fd= fileno(f); + if (!fd) + { + perror("unable to obtain file descriptor number"); + return 1; + } + + offset= (off_t)start_page * (off_t)UNIV_PAGE_SIZE; + + if (lseek(fd, offset, SEEK_SET) != offset) + { + perror("unable to seek to necessary offset"); + return 1; + } + } + + /* allocate buffer for reading (so we don't realloc every time) */ + p= (byte *)malloc(UNIV_PAGE_SIZE); + + /* main checksumming loop */ + ct= start_page; + lastt= 0; + while (!feof(f)) + { + bytes= fread(p, 1, UNIV_PAGE_SIZE, f); + if (!bytes && feof(f)) return 0; + if (bytes != UNIV_PAGE_SIZE) + { + fprintf(stderr, "bytes read (%d) doesn't match universal page size (%d)\n", bytes, UNIV_PAGE_SIZE); + return 1; + } + + /* check the "stored log sequence numbers" */ + logseq= mach_read_from_4(p + FIL_PAGE_LSN + 4); + logseqfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4); + if (debug) + printf("page %lu: log sequence number: first = %lu; second = %lu\n", ct, logseq, logseqfield); + if (logseq != logseqfield) + { + fprintf(stderr, "page %lu invalid (fails log sequence number check)\n", ct); + return 1; + } + + /* check old method of checksumming */ + oldcsum= buf_calc_page_old_checksum(p); + oldcsumfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM); + if (debug) + printf("page %lu: old style: calculated = %lu; recorded = %lu\n", ct, oldcsum, oldcsumfield); + if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum) + { + fprintf(stderr, "page %lu invalid (fails old style checksum)\n", ct); + return 1; + } + + /* now check the new method */ + csum= buf_calc_page_new_checksum(p); + csumfield= mach_read_from_4(p + FIL_PAGE_SPACE_OR_CHKSUM); + if (debug) + printf("page %lu: new style: calculated = %lu; recorded = %lu\n", ct, csum, csumfield); + if (csumfield != 0 && csum != csumfield) + { + fprintf(stderr, "page %lu invalid (fails new style checksum)\n", ct); + return 1; + } + + /* end if this was the last page we were supposed to check */ + if (use_end_page && (ct >= end_page)) + return 0; + + /* do counter increase and progress printing */ + ct++; + if (verbose) + { + if (ct % 64 == 0) + { + now= time(0); + if (!lastt) lastt= now; + if (now - lastt >= 1) + { + printf("page %lu okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100); + lastt= now; + } + } + } + } + return 0; +} + diff --git a/extra/perror.c b/extra/perror.c index dedd558e4cf..919088ba42e 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -25,6 +25,7 @@ #include <my_getopt.h> #ifdef HAVE_NDBCLUSTER_DB #include "../ndb/src/ndbapi/ndberror.c" +#include "../ndb/src/kernel/error/ndbd_exit_codes.c" #endif static my_bool verbose, print_all_codes; @@ -235,8 +236,11 @@ int main(int argc,char *argv[]) #ifdef HAVE_NDBCLUSTER_DB if (ndb_code) { - if (ndb_error_string(code, ndb_string, sizeof(ndb_string)) < 0) - msg= 0; + if ((ndb_error_string(code, ndb_string, sizeof(ndb_string)) < 0) && + (ndbd_exit_string(code, ndb_string, sizeof(ndb_string)) < 0)) + { + msg= 0; + } else msg= ndb_string; } diff --git a/extra/yassl/mySTL/helpers.hpp b/extra/yassl/mySTL/helpers.hpp index 8d2061fc4f1..de825c23fec 100644 --- a/extra/yassl/mySTL/helpers.hpp +++ b/extra/yassl/mySTL/helpers.hpp @@ -28,14 +28,11 @@ #define mySTL_HELPERS_HPP #include <stdlib.h> -#include <new> // placement new - - -#ifdef __IBMCPP__ /* Workaround for the lack of operator new(size_t, void*) in IBM VA C++ 6.0 + Also used as a workaround to avoid including <new> */ struct Dummy {}; @@ -45,9 +42,6 @@ } typedef Dummy* yassl_pointer; -#else - typedef void* yassl_pointer; -#endif namespace mySTL { diff --git a/extra/yassl/mySTL/list.hpp b/extra/yassl/mySTL/list.hpp index 8aaeefaafe8..dd8485f48a7 100644 --- a/extra/yassl/mySTL/list.hpp +++ b/extra/yassl/mySTL/list.hpp @@ -164,7 +164,7 @@ void list<T>::push_front(T t) { void* mem = malloc(sizeof(node)); if (!mem) abort(); - node* add = new (mem) node(t); + node* add = new (reinterpret_cast<yassl_pointer>(mem)) node(t); if (head_) { add->next_ = head_; @@ -210,7 +210,7 @@ void list<T>::push_back(T t) { void* mem = malloc(sizeof(node)); if (!mem) abort(); - node* add = new (mem) node(t); + node* add = new (reinterpret_cast<yassl_pointer>(mem)) node(t); if (tail_) { tail_->next_ = add; diff --git a/extra/yassl/mySTL/vector.hpp b/extra/yassl/mySTL/vector.hpp index e7f63c37c7c..9eab91cfda8 100644 --- a/extra/yassl/mySTL/vector.hpp +++ b/extra/yassl/mySTL/vector.hpp @@ -45,7 +45,8 @@ struct vector_base { vector_base() : start_(0), finish_(0), end_of_storage_(0) {} vector_base(size_t n) { - start_ = static_cast<T*>(malloc(n * sizeof(T))); + // Don't allow malloc(0), if n is 0 use 1 + start_ = static_cast<T*>(malloc((n ? n : 1) * sizeof(T))); if (!start_) abort(); finish_ = start_; end_of_storage_ = start_ + n; diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp index 2252dfafdc5..91cea1f9753 100644 --- a/extra/yassl/src/socket_wrapper.cpp +++ b/extra/yassl/src/socket_wrapper.cpp @@ -93,11 +93,15 @@ void Socket::closeSocket() uint Socket::get_ready() const { - unsigned long ready = 0; - #ifdef _WIN32 + unsigned long ready = 0; ioctlsocket(socket_, FIONREAD, &ready); #else + /* + 64-bit Solaris requires the variable passed to + FIONREAD be a 32-bit value. + */ + int ready = 0; ioctl(socket_, FIONREAD, &ready); #endif diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp index d37c44049b2..8cea205377e 100644 --- a/extra/yassl/src/ssl.cpp +++ b/extra/yassl/src/ssl.cpp @@ -171,13 +171,25 @@ int SSL_accept(SSL* ssl) sendServerHelloDone(*ssl); ssl->flushBuffer(); - processReply(*ssl); + // Java Client sends fragmented response + while (ssl->getStates().getServer() < + clientFinishedComplete) { + if (ssl->GetError()) break; + processReply(*ssl); + } } sendChangeCipher(*ssl); sendFinished(*ssl, server_end); ssl->flushBuffer(); - if (ssl->getSecurity().get_resuming()) - processReply(*ssl); + if (ssl->getSecurity().get_resuming()) { + + // Java Client sends fragmented response + while (ssl->getStates().getServer() < + clientFinishedComplete) { + if (ssl->GetError()) break; + processReply(*ssl); + } + } ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); diff --git a/extra/yassl/taocrypt/include/hmac.hpp b/extra/yassl/taocrypt/include/hmac.hpp index 543366afc3a..cf029812ce2 100644 --- a/extra/yassl/taocrypt/include/hmac.hpp +++ b/extra/yassl/taocrypt/include/hmac.hpp @@ -56,12 +56,12 @@ private: T mac_; // MSVC 6 HACK, gives compiler error if calculated in array - enum { BSIZE = T::BLOCK_SIZE / sizeof(word32), - DSIZE = T::DIGEST_SIZE / sizeof(word32) }; + enum { HMAC_BSIZE = T::BLOCK_SIZE / sizeof(word32), + HMAC_DSIZE = T::DIGEST_SIZE / sizeof(word32) }; - word32 ip_[BSIZE]; // align ipad_ on word32 - word32 op_[BSIZE]; // align opad_ on word32 - word32 innerH_[DSIZE]; // align innerHash_ on word32 + word32 ip_[HMAC_BSIZE]; // align ipad_ on word32 + word32 op_[HMAC_BSIZE]; // align opad_ on word32 + word32 innerH_[HMAC_DSIZE]; // align innerHash_ on word32 void KeyInnerHash(); diff --git a/extra/yassl/taocrypt/include/misc.hpp b/extra/yassl/taocrypt/include/misc.hpp index 187d5cc6769..f705cc99970 100644 --- a/extra/yassl/taocrypt/include/misc.hpp +++ b/extra/yassl/taocrypt/include/misc.hpp @@ -91,7 +91,14 @@ public: // no gas on these systems ?, disable for now -#if defined(__sun__) || defined (__QNX__) +#if defined(__sun__) || defined (__QNX__) || defined (__APPLE__) + #define TAOCRYPT_DISABLE_X86ASM +#endif + + +// Disable assmebler when compiling with icc +// Temporary workaround for bug12717 +#if defined(__INTEL_COMPILER) #define TAOCRYPT_DISABLE_X86ASM #endif diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp index f506040f0d8..254e67a7f64 100644 --- a/extra/yassl/taocrypt/include/runtime.hpp +++ b/extra/yassl/taocrypt/include/runtime.hpp @@ -25,7 +25,8 @@ -#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) && !defined(__ICC) +#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) +#if !(defined(__ICC) || defined(__INTEL_COMPILER)) #define yaSSL_NEW_HPP @@ -46,5 +47,6 @@ static int __cxa_pure_virtual() } // extern "C" #endif // __GNUC__ > 2 +#endif // ! _ICC #endif // yaSSL_NEW_HPP && __GNUC__ diff --git a/extra/yassl/taocrypt/include/types.hpp b/extra/yassl/taocrypt/include/types.hpp index 92164eaaab4..db9c3792bbd 100644 --- a/extra/yassl/taocrypt/include/types.hpp +++ b/extra/yassl/taocrypt/include/types.hpp @@ -61,9 +61,10 @@ typedef unsigned int word32; // compilers we've found 64-bit multiply insructions for #if defined(__GNUC__) || defined(_MSC_VER) || defined(__DECCXX) +#if !(defined(__ICC) || defined(__INTEL_COMPILER)) #define HAVE_64_MULTIPLY #endif - +#endif #if defined(HAVE_64_MULTIPLY) && (defined(__alpha__) || defined(__ia64__) \ || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__)) diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am index 4549c218d87..c4fc4607622 100644 --- a/extra/yassl/taocrypt/src/Makefile.am +++ b/extra/yassl/taocrypt/src/Makefile.am @@ -1,9 +1,12 @@ INCLUDES = -I../include -I../../mySTL -noinst_LTLIBRARIES = libtaocrypt.la +noinst_LTLIBRARIES = libtaocrypt.la libtaoint.la libtaocrypt_la_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ - coding.cpp dh.cpp des.cpp dsa.cpp file.cpp hash.cpp integer.cpp \ + coding.cpp dh.cpp des.cpp dsa.cpp file.cpp hash.cpp \ md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \ template_instnt.cpp +libtaocrypt_la_LIBADD = libtaoint.la +libtaoint_la_SOURCES = integer.cpp +libtaoint_la_CXXFLAGS = @yassl_integer_extra_cxxflags@ EXTRA_DIST = ../include/*.hpp AM_CXXFLAGS = -DYASSL_PURE_C diff --git a/extra/yassl/taocrypt/src/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp index ef051332098..0b33bb38aea 100644 --- a/extra/yassl/taocrypt/src/misc.cpp +++ b/extra/yassl/taocrypt/src/misc.cpp @@ -24,7 +24,6 @@ #include "runtime.hpp" #include "misc.hpp" -#include <new> // for NewHandler void* operator new(size_t sz, TaoCrypt::new_t) diff --git a/extra/yassl/taocrypt/src/random.cpp b/extra/yassl/taocrypt/src/random.cpp index e1e6416eb00..cf0720b11d8 100644 --- a/extra/yassl/taocrypt/src/random.cpp +++ b/extra/yassl/taocrypt/src/random.cpp @@ -95,7 +95,11 @@ OS_Seed::OS_Seed() { fd_ = open("/dev/urandom",O_RDONLY); if (fd_ == -1) + { + fd_ = open("/dev/random",O_RDONLY); + if (fd_ == -1) error_.SetError(OPEN_RAN_E); + } } diff --git a/heap/hp_hash.c b/heap/hp_hash.c index d643f776731..77f3cf6d80b 100644 --- a/heap/hp_hash.c +++ b/heap/hp_hash.c @@ -551,11 +551,13 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2, } if (cs->mbmaxlen > 1) { + uint safe_length1= char_length1; + uint safe_length2= char_length2; uint char_length= seg->length / cs->mbmaxlen; - char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length1); - set_if_smaller(char_length1, seg->length); - char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length2); - set_if_smaller(char_length2, seg->length); + char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length); + set_if_smaller(char_length1, safe_length1); + char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length); + set_if_smaller(char_length2, safe_length2); } if (cs->coll->strnncollsp(seg->charset, diff --git a/include/config-win.h b/include/config-win.h index 4eaf97cd4f5..fe099c11a2f 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -193,7 +193,7 @@ typedef uint rf_SetTimer; /* Convert some simple functions to Posix */ -#define sigset(A,B) signal((A),(B)) +#define my_sigset(A,B) signal((A),(B)) #define finite(A) _finite(A) #define sleep(A) Sleep((A)*1000) #define popen(A) popen(A,B) _popen((A),(B)) diff --git a/include/keycache.h b/include/keycache.h index a292a69b0a3..9fe1cce5da5 100644 --- a/include/keycache.h +++ b/include/keycache.h @@ -90,10 +90,10 @@ typedef struct st_key_cache /* Statistics variables. These are reset in reset_key_cache_counters(). */ ulong global_blocks_changed; /* number of currently dirty blocks */ - ulong global_cache_w_requests;/* number of write requests (write hits) */ - ulong global_cache_write; /* number of writes from the cache to files */ - ulong global_cache_r_requests;/* number of read requests (read hits) */ - ulong global_cache_read; /* number of reads from files to the cache */ + ulonglong global_cache_w_requests;/* number of write requests (write hits) */ + ulonglong global_cache_write; /* number of writes from cache to files */ + ulonglong global_cache_r_requests;/* number of read requests (read hits) */ + ulonglong global_cache_read; /* number of reads from files to cache */ int blocks; /* max number of blocks in the cache */ my_bool in_init; /* Set to 1 in MySQL during init/resize */ diff --git a/include/m_ctype.h b/include/m_ctype.h index e0a26c4ce56..b7361cb7d7b 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -231,6 +231,7 @@ typedef struct charset_info_st uint mbmaxlen; uint16 min_sort_char; uint16 max_sort_char; /* For LIKE optimization */ + uchar pad_char; my_bool escape_with_backslash_is_dangerous; MY_CHARSET_HANDLER *cset; diff --git a/include/m_string.h b/include/m_string.h index 33ba9c155c2..c02ce92cd88 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -129,15 +129,6 @@ extern void bmove_align(gptr dst,const gptr src,uint len); #define bmove512(A,B,C) memcpy(A,B,C) #endif -#ifdef HAVE_purify -#define memcpy_overlap(A,B,C) \ -DBUG_ASSERT((A) <= (B) || ((B)+(C)) <= (A)); \ -bmove((byte*) (A),(byte*) (B),(size_t) (C)); -#else -#define memcpy_overlap(A,B,C) memcpy((A), (B), (C)) -#endif /* HAVE_purify */ - - /* Prototypes for string functions */ #if !defined(bfill) && !defined(HAVE_BFILL) diff --git a/include/my_global.h b/include/my_global.h index a4177f8ea7c..b32a8fe6baa 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -107,6 +107,14 @@ #define _GNU_SOURCE 1 #endif +/* + Temporary solution to solve bug#7156. Include "sys/types.h" before + the thread headers, else the function madvise() will not be defined +*/ +#if defined(HAVE_SYS_TYPES_H) && ( defined(sun) || defined(__sun) ) +#include <sys/types.h> +#endif + /* The client defines this to avoid all thread code */ #if defined(UNDEF_THREADS_HACK) #undef THREAD @@ -230,7 +238,7 @@ C_MODE_END /* Fix a bug in gcc 2.8.0 on IRIX 6.2 */ -#if SIZEOF_LONG == 4 && defined(__LONG_MAX__) +#if SIZEOF_LONG == 4 && defined(__LONG_MAX__) && (__GNUC__ == 2 && __GNUC_MINOR__ == 8) #undef __LONG_MAX__ /* Is a longlong value in gcc 2.8.0 ??? */ #define __LONG_MAX__ 2147483647 #endif @@ -344,7 +352,9 @@ extern "C" int madvise(void *addr, size_t len, int behav); #undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */ #undef LONGLONG_MAX /* standard system library 'limits.h' */ #ifdef __cplusplus -#define HAVE_RINT /* rint() and isnan() functions are not */ +#ifndef HAVE_RINT +#define HAVE_RINT +#endif /* rint() and isnan() functions are not */ #define rint(a) std::rint(a) /* visible in C++ scope due to an error */ #define isnan(a) std::isnan(a) /* in the usr/include/math.h on QNX */ #endif @@ -834,6 +844,7 @@ typedef off_t os_off_t; #define socket_errno WSAGetLastError() #define SOCKET_EINTR WSAEINTR #define SOCKET_EAGAIN WSAEINPROGRESS +#define SOCKET_ETIMEDOUT WSAETIMEDOUT #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE @@ -841,6 +852,7 @@ typedef off_t os_off_t; #define socket_errno sock_errno() #define SOCKET_EINTR SOCEINTR #define SOCKET_EAGAIN SOCEINPROGRESS +#define SOCKET_ETIMEDOUT SOCKET_EINTR #define SOCKET_EWOULDBLOCK SOCEWOULDBLOCK #define SOCKET_ENFILE SOCENFILE #define SOCKET_EMFILE SOCEMFILE @@ -850,6 +862,7 @@ typedef off_t os_off_t; #define closesocket(A) close(A) #define SOCKET_EINTR EINTR #define SOCKET_EAGAIN EAGAIN +#define SOCKET_ETIMEDOUT SOCKET_EINTR #define SOCKET_EWOULDBLOCK EWOULDBLOCK #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE diff --git a/include/my_pthread.h b/include/my_pthread.h index 47a38d1a642..3d9056541d7 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -25,7 +25,10 @@ #endif #ifdef __cplusplus +#define EXTERN_C extern "C" extern "C" { +#else +#define EXTERN_C #endif /* __cplusplus */ #if defined(__WIN__) || defined(OS2) @@ -77,10 +80,10 @@ struct timespec { /* For pthread_cond_timedwait() */ typedef int pthread_mutexattr_t; #define win_pthread_self my_thread_var->pthread_self #ifdef OS2 -#define pthread_handler_decl(A,B) void * _Optlink A(void *B) +#define pthread_handler_t EXTERN_C void * _Optlink typedef void * (_Optlink *pthread_handler)(void *); #else -#define pthread_handler_decl(A,B) void * __cdecl A(void *B) +#define pthread_handler_t EXTERN_C void * __cdecl typedef void * (__cdecl *pthread_handler)(void *); #endif @@ -144,7 +147,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *); #define pthread_kill(A,B) raise(B) #define pthread_exit(A) pthread_dummy() #else -#define pthread_mutex_init(A,B) InitializeCriticalSection(A) +#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) #define pthread_mutex_lock(A) (EnterCriticalSection(A),0) #define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT) #define pthread_mutex_unlock(A) LeaveCriticalSection(A) @@ -184,7 +187,7 @@ typedef int pthread_attr_t; /* Needed by Unixware 7.0.0 */ #define pthread_key_create(A,B) thr_keycreate((A),(B)) #define pthread_key_delete(A) thr_keydelete(A) -#define pthread_handler_decl(A,B) void *A(void *B) +#define pthread_handler_t EXTERN_C void * #define pthread_key(T,V) pthread_key_t V void * my_pthread_getspecific_imp(pthread_key_t key); @@ -262,7 +265,7 @@ extern int my_pthread_getprio(pthread_t thread_id); #define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V)) #define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V)) #define pthread_detach_this_thread() -#define pthread_handler_decl(A,B) void *A(void *B) +#define pthread_handler_t EXTERN_C void * typedef void *(* pthread_handler)(void *); /* Test first for RTS or FSU threads */ @@ -289,8 +292,6 @@ extern int my_pthread_create_detached; #undef HAVE_PTHREAD_RWLOCK_RDLOCK #undef HAVE_SNPRINTF -#define sigset(A,B) pthread_signal((A),(void (*)(int)) (B)) -#define signal(A,B) pthread_signal((A),(void (*)(int)) (B)) #define my_pthread_attr_setprio(A,B) #endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */ @@ -298,11 +299,6 @@ extern int my_pthread_create_detached; int sigwait(sigset_t *set, int *sig); #endif -#if defined(HAVE_UNIXWARE7_POSIX) -#undef HAVE_NONPOSIX_SIGWAIT -#define HAVE_NONPOSIX_SIGWAIT /* sigwait takes only 1 argument */ -#endif - #ifndef HAVE_NONPOSIX_SIGWAIT #define my_sigwait(A,B) sigwait((A),(B)) #else @@ -327,14 +323,26 @@ extern int my_pthread_cond_init(pthread_cond_t *mp, #if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(_AIX) int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */ #endif -#if !defined(HAVE_SIGSET) && !defined(HAVE_mit_thread) && !defined(sigset) -#define sigset(A,B) do { struct sigaction s; sigset_t set; \ - sigemptyset(&set); \ - s.sa_handler = (B); \ - s.sa_mask = set; \ - s.sa_flags = 0; \ - sigaction((A), &s, (struct sigaction *) NULL); \ - } while (0) + + +/* + We define my_sigset() and use that instead of the system sigset() so that + we can favor an implementation based on sigaction(). On some systems, such + as Mac OS X, sigset() results in flags such as SA_RESTART being set, and + we want to make sure that no such flags are set. +*/ +#if defined(HAVE_SIGACTION) && !defined(my_sigset) +#define my_sigset(A,B) do { struct sigaction s; sigset_t set; \ + sigemptyset(&set); \ + s.sa_handler = (B); \ + s.sa_mask = set; \ + s.sa_flags = 0; \ + sigaction((A), &s, (struct sigaction *) NULL); \ + } while (0) +#elif defined(HAVE_SIGSET) && !defined(my_sigset) +#define my_sigset(A,B) sigset((A),(B)) +#elif !defined(my_sigset) +#define my_sigset(A,B) signal((A),(B)) #endif #ifndef my_pthread_setprio @@ -414,16 +422,13 @@ struct tm *gmtime_r(const time_t *clock, struct tm *res); #define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } #endif -#ifdef HAVE_DARWIN_THREADS +#ifdef HAVE_DARWIN5_THREADS #define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) #define pthread_kill(A,B) pthread_dummy(0) #define pthread_condattr_init(A) pthread_dummy(0) #define pthread_condattr_destroy(A) pthread_dummy(0) -#define pthread_signal(A,B) pthread_dummy(0) #undef pthread_detach_this_thread #define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(tmp); } -#undef sigset -#define sigset(A,B) pthread_signal((A),(void (*)(int)) (B)) #endif #if ((defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT)) || defined(HAVE_DEC_3_2_THREADS)) && !defined(HAVE_CTHREADS_WRAPPER) diff --git a/include/my_sys.h b/include/my_sys.h index c46da655fa4..76031806b82 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -98,7 +98,6 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MY_RETURN_REAL_PATH 32 /* return full path for file */ #define MY_SAFE_PATH 64 /* Return NULL if too long path */ #define MY_RELATIVE_PATH 128 /* name is relative to 'dir' */ -#define MY_UNIX_PATH 256 /* convert path to UNIX format */ /* My seek flags */ #define MY_SEEK_SET 0 @@ -159,7 +158,8 @@ extern gptr my_memdup(const byte *from,uint length,myf MyFlags); extern char *my_strdup(const char *from,myf MyFlags); extern char *my_strdup_with_length(const byte *from, uint length, myf MyFlags); -#define my_free(PTR,FG) my_no_flags_free(PTR) +/* we do use FG (as a no-op) in below so that a typo on FG is caught */ +#define my_free(PTR,FG) ((void)FG,my_no_flags_free(PTR)) #define CALLER_INFO_PROTO /* nothing */ #define CALLER_INFO /* nothing */ #define ORIG_CALLER_INFO /* nothing */ @@ -237,9 +237,6 @@ extern CHARSET_INFO *all_charsets[256]; extern CHARSET_INFO compiled_charsets[]; /* statistics */ -extern ulong my_cache_w_requests, my_cache_write, my_cache_r_requests, - my_cache_read; -extern ulong my_blocks_used, my_blocks_changed; extern ulong my_file_opened,my_stream_opened, my_tmp_file_created; extern uint mysys_usage_id; extern my_bool my_init_done; @@ -265,6 +262,7 @@ extern char wild_many,wild_one,wild_prefix; extern const char *charsets_dir; extern char *defaults_extra_file; extern const char *defaults_group_suffix; +extern const char *defaults_file; extern my_bool timed_mutexes; @@ -283,7 +281,7 @@ enum loglevel { enum cache_type { - READ_CACHE,WRITE_CACHE, + TYPE_NOT_SET= 0, READ_CACHE, WRITE_CACHE, SEQ_READ_APPEND /* sequential read or append */, READ_FIFO, READ_NET,WRITE_NET}; @@ -778,6 +776,7 @@ extern void my_free_lock(byte *ptr,myf flags); extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size); extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size); +extern gptr multi_alloc_root(MEM_ROOT *mem_root, ...); extern void free_root(MEM_ROOT *root, myf MyFLAGS); extern void set_prealloc_root(MEM_ROOT *root, char *ptr); extern void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, @@ -890,6 +889,9 @@ int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror, void my_security_attr_free(SECURITY_ATTRIBUTES *sa); +/* implemented in my_conio.c */ +char* my_cgets(char *string, unsigned long clen, unsigned long* plen); + #endif #ifdef __NETWARE__ void netware_reg_user(const char *ip, const char *user, diff --git a/include/myisam.h b/include/myisam.h index 03194fe42ae..39cc61ad204 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -381,6 +381,20 @@ typedef struct st_sort_key_blocks /* Used when sorting */ } SORT_KEY_BLOCKS; +/* + MyISAM supports several statistics collection methods. Currently statistics + collection method is not stored in MyISAM file and has to be specified for + each table analyze/repair operation in MI_CHECK::stats_method. +*/ + +typedef enum +{ + /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */ + MI_STATS_METHOD_NULLS_NOT_EQUAL, + /* Treat NULLs as equal when collecting statistics (like 4.0 did) */ + MI_STATS_METHOD_NULLS_EQUAL +} enum_mi_stats_method; + typedef struct st_mi_check_param { ulonglong auto_increment_value; @@ -411,6 +425,7 @@ typedef struct st_mi_check_param void *thd; const char *db_name, *table_name; const char *op_name; + enum_mi_stats_method stats_method; } MI_CHECK; typedef struct st_sort_ft_buf diff --git a/include/mysql.h b/include/mysql.h index 2ba41e6d367..c4b4e026e5b 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -146,7 +146,7 @@ enum mysql_option MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, - MYSQL_REPORT_DATA_TRUNCATION + MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT }; struct st_mysql_options { diff --git a/include/mysql_com.h b/include/mysql_com.h index 969fba4a433..1e595cdbba3 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -409,6 +409,7 @@ my_bool check_scramble(const char *reply, const char *message, const unsigned char *hash_stage2); void get_salt_from_password(unsigned char *res, const char *password); void make_password_from_salt(char *to, const unsigned char *hash_stage2); +char *octet2hex(char *to, const char *str, unsigned int len); /* end of password.c */ diff --git a/include/violite.h b/include/violite.h index 48046346f8c..b48f3724f5b 100644 --- a/include/violite.h +++ b/include/violite.h @@ -74,6 +74,8 @@ int vio_fastsend(Vio *vio); int vio_keepalive(Vio *vio, my_bool onoff); /* Whenever we should retry the last read/write operation. */ my_bool vio_should_retry(Vio *vio); +/* Check that operation was timed out */ +my_bool vio_was_interrupted(Vio *vio); /* Short text description of the socket for those, who are curious.. */ const char* vio_description(Vio *vio); /* Return the type of the connection */ @@ -153,6 +155,7 @@ int vio_close_shared_memory(Vio * vio); #define vio_fastsend(vio) (vio)->fastsend(vio) #define vio_keepalive(vio, set_keep_alive) (vio)->viokeepalive(vio, set_keep_alive) #define vio_should_retry(vio) (vio)->should_retry(vio) +#define vio_was_interrupted(vio) (vio)->was_interrupted(vio) #define vio_close(vio) ((vio)->vioclose)(vio) #define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt) #define vio_in_addr(vio, in) (vio)->in_addr(vio, in) @@ -198,6 +201,7 @@ struct st_vio my_bool (*peer_addr)(Vio*, char *, uint16*); void (*in_addr)(Vio*, struct in_addr*); my_bool (*should_retry)(Vio*); + my_bool (*was_interrupted)(Vio*); int (*vioclose)(Vio*); void (*timeout)(Vio*, unsigned int which, unsigned int timeout); void *ssl_arg; diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index aa3aef7f97c..3a3b64dd51b 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -321,7 +321,9 @@ buf_page_is_corrupted( fprintf(stderr, " InnoDB: Error: page %lu log sequence number %lu %lu\n" "InnoDB: is in the future! Current system log sequence number %lu %lu.\n" -"InnoDB: Your database may be corrupt.\n", +"InnoDB: Your database may be corrupt or you may have copied the InnoDB\n" +"InnoDB: tablespace but not the InnoDB log files. See\n" +"http://dev.mysql.com/doc/mysql/en/backing-up.html for more information.\n", (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET), (ulong) ut_dulint_get_high( mach_read_from_8(read_buf + FIL_PAGE_LSN)), diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index ffb16790b2d..e39d1ae0a71 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -230,7 +230,7 @@ buf_flush_buffered_writes(void) ulint len2; ulint i; - if (trx_doublewrite == NULL) { + if (!srv_use_doublewrite_buf || trx_doublewrite == NULL) { os_aio_simulated_wake_handler_threads(); return; @@ -503,7 +503,7 @@ buf_flush_write_block_low( #endif buf_flush_init_for_writing(block->frame, block->newest_modification, block->space, block->offset); - if (!trx_doublewrite) { + if (!srv_use_doublewrite_buf || !trx_doublewrite) { fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER, FALSE, block->space, block->offset, 0, UNIV_PAGE_SIZE, (void*)block->frame, (void*)block); diff --git a/innobase/data/data0data.c b/innobase/data/data0data.c index 194213a04e1..19304a7a8e1 100644 --- a/innobase/data/data0data.c +++ b/innobase/data/data0data.c @@ -561,12 +561,12 @@ dtuple_convert_big_rec( } /* We do not store externally fields which are smaller than - DICT_MAX_COL_PREFIX_LEN */ + DICT_MAX_INDEX_COL_LEN */ - ut_a(DICT_MAX_COL_PREFIX_LEN > REC_1BYTE_OFFS_LIMIT); + ut_a(DICT_MAX_INDEX_COL_LEN > REC_1BYTE_OFFS_LIMIT); if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10 - + DICT_MAX_COL_PREFIX_LEN) { + + DICT_MAX_INDEX_COL_LEN) { /* Cannot shorten more */ mem_heap_free(heap); @@ -588,10 +588,10 @@ dtuple_convert_big_rec( dfield = dtuple_get_nth_field(entry, longest_i); vector->fields[n_fields].field_no = longest_i; - ut_a(dfield->len > DICT_MAX_COL_PREFIX_LEN); + ut_a(dfield->len > DICT_MAX_INDEX_COL_LEN); vector->fields[n_fields].len = dfield->len - - DICT_MAX_COL_PREFIX_LEN; + - DICT_MAX_INDEX_COL_LEN; vector->fields[n_fields].data = mem_heap_alloc(heap, vector->fields[n_fields].len); diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 9580a80e7e7..fb95ffbd80c 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -1625,7 +1625,7 @@ dict_index_add_col( variable-length fields, so that the extern flag can be embedded in the length word. */ - if (field->fixed_len > DICT_MAX_COL_PREFIX_LEN) { + if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) { field->fixed_len = 0; } @@ -2189,7 +2189,7 @@ dict_foreign_error_report( dict_foreign_error_report_low(file, fk->foreign_table_name); fputs(msg, file); fputs(" Constraint:\n", file); - dict_print_info_on_foreign_key_in_create_format(file, NULL, fk); + dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE); if (fk->foreign_index) { fputs("\nThe index in the foreign key in table is ", file); ut_print_name(file, NULL, fk->foreign_index->name); @@ -2871,8 +2871,12 @@ dict_create_foreign_constraints_low( table2 can be written also with the database name before it: test.table2; the default database is the database of parameter name */ - const char* name) /* in: table full name in the normalized form + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) + /* in: if TRUE, fail with error code + DB_CANNOT_ADD_CONSTRAINT if any foreign + keys are found. */ { dict_table_t* table; dict_table_t* referenced_table; @@ -2994,6 +2998,18 @@ loop: } if (*ptr == '\0') { + /* The proper way to reject foreign keys for temporary + tables would be to split the lexing and syntactical + analysis of foreign key clauses from the actual adding + of them, so that ha_innodb.cc could first parse the SQL + command, determine if there are any foreign keys, and + if so, immediately reject the command if the table is a + temporary one. For now, this kludge will work. */ + if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) + { + return DB_CANNOT_ADD_CONSTRAINT; + } + /**********************************************************/ /* The following call adds the foreign key constraints to the data dictionary system tables on disk */ @@ -3417,9 +3433,12 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ - const char* name) /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ { char* str; ulint err; @@ -3428,7 +3447,8 @@ dict_create_foreign_constraints( str = dict_strip_comments(sql_string); heap = mem_heap_create(10000); - err = dict_create_foreign_constraints_low(trx, heap, str, name); + err = dict_create_foreign_constraints_low(trx, heap, str, name, + reject_fks); mem_heap_free(heap); mem_free(str); @@ -4310,9 +4330,10 @@ CREATE TABLE. */ void dict_print_info_on_foreign_key_in_create_format( /*============================================*/ - FILE* file, /* in: file where to print */ - trx_t* trx, /* in: transaction */ - dict_foreign_t* foreign)/* in: foreign key constraint */ + FILE* file, /* in: file where to print */ + trx_t* trx, /* in: transaction */ + dict_foreign_t* foreign, /* in: foreign key constraint */ + ibool add_newline) /* in: whether to add a newline */ { const char* stripped_id; ulint i; @@ -4325,7 +4346,16 @@ dict_print_info_on_foreign_key_in_create_format( stripped_id = foreign->id; } - fputs(",\n CONSTRAINT ", file); + putc(',', file); + + if (add_newline) { + /* SHOW CREATE TABLE wants constraints each printed nicely + on its own line, while error messages want no newlines + inserted. */ + fputs("\n ", file); + } + + fputs(" CONSTRAINT ", file); ut_print_name(file, trx, stripped_id); fputs(" FOREIGN KEY (", file); @@ -4427,7 +4457,7 @@ dict_print_info_on_foreign_keys( while (foreign != NULL) { if (create_table_format) { dict_print_info_on_foreign_key_in_create_format( - file, trx, foreign); + file, trx, foreign, TRUE); } else { ulint i; fputs("; (", file); diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h index 1f3a32fa70c..d28b0b129a1 100644 --- a/innobase/include/btr0btr.h +++ b/innobase/include/btr0btr.h @@ -23,16 +23,6 @@ special big record storage structure */ #define BTR_PAGE_MAX_REC_SIZE (UNIV_PAGE_SIZE / 2 - 200) -/* Maximum key size in a B-tree: the records on non-leaf levels must be -shorter than this */ - -#define BTR_PAGE_MAX_KEY_SIZE 1024 - -/* If data in page drops below this limit, we try to compress it. -NOTE! The value has to be > 2 * BTR_MAX_KEY_SIZE */ - -#define BTR_COMPRESS_LIMIT (UNIV_PAGE_SIZE / 4 + 1); - /* Latching modes for the search function (in btr0cur.*) */ #define BTR_SEARCH_LEAF RW_S_LATCH #define BTR_MODIFY_LEAF RW_X_LATCH diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic index 06d45dd5501..d4a7b3c64b8 100644 --- a/innobase/include/data0type.ic +++ b/innobase/include/data0type.ic @@ -420,7 +420,7 @@ dtype_get_fixed_size( } /*************************************************************************** -Returns the size of a fixed size data type, 0 if not a fixed size type. */ +Returns the minimum size of a data type. */ UNIV_INLINE ulint dtype_get_min_size( diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index d9cda402bac..5215d51cabe 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -228,9 +228,12 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ - const char* name); /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks); /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ /************************************************************************** Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */ @@ -372,9 +375,10 @@ CREATE TABLE. */ void dict_print_info_on_foreign_key_in_create_format( /*============================================*/ - FILE* file, /* in: file where to print */ - trx_t* trx, /* in: transaction */ - dict_foreign_t* foreign);/* in: foreign key constraint */ + FILE* file, /* in: file where to print */ + trx_t* trx, /* in: transaction */ + dict_foreign_t* foreign, /* in: foreign key constraint */ + ibool add_newline); /* in: whether to add a newline */ /************************************************************************ Displays the names of the index and the table. */ void diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index ff6c4ec9b28..7eec86d0bcb 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -152,12 +152,12 @@ struct dict_col_struct{ in some of the functions below */ }; -/* DICT_MAX_COL_PREFIX_LEN is measured in bytes. Starting from 4.1.6, we -set max col prefix len to < 3 * 256, so that one can create a column prefix -index on 255 characters of a TEXT field also in the UTF-8 charset. In that -charset, a character may take at most 3 bytes. */ +/* DICT_MAX_INDEX_COL_LEN is measured in bytes and is the max index column +length + 1. Starting from 4.1.6, we set it to < 3 * 256, so that one can +create a column prefix index on 255 characters of a TEXT field also in the +UTF-8 charset. In that charset, a character may take at most 3 bytes. */ -#define DICT_MAX_COL_PREFIX_LEN 768 +#define DICT_MAX_INDEX_COL_LEN 768 /* Data structure for a field in an index */ struct dict_field_struct{ @@ -169,12 +169,12 @@ struct dict_field_struct{ prefix in bytes in a MySQL index of type, e.g., INDEX (textcol(25)); must be smaller than - DICT_MAX_COL_PREFIX_LEN; NOTE that + DICT_MAX_INDEX_COL_LEN; NOTE that in the UTF-8 charset, MySQL sets this to 3 * the prefix len in UTF-8 chars */ ulint fixed_len; /* 0 or the fixed length of the column if smaller than - DICT_MAX_COL_PREFIX_LEN */ + DICT_MAX_INDEX_COL_LEN */ ulint fixed_offs; /* offset to the field, or ULINT_UNDEFINED if it is not fixed within the record (due to preceding diff --git a/innobase/include/mem0mem.h b/innobase/include/mem0mem.h index 87afdb8f91c..3768e93c03e 100644 --- a/innobase/include/mem0mem.h +++ b/innobase/include/mem0mem.h @@ -99,8 +99,7 @@ heap freeing. */ /********************************************************************* NOTE: Use the corresponding macros instead of this function. Creates a memory heap which allocates memory from dynamic space. For debugging -purposes, takes also the file name and line as argument in the debug -version. */ +purposes, takes also the file name and line as argument. */ UNIV_INLINE mem_heap_t* mem_heap_create_func( diff --git a/innobase/include/mem0mem.ic b/innobase/include/mem0mem.ic index 8c87c884d78..28562f7c9f8 100644 --- a/innobase/include/mem0mem.ic +++ b/innobase/include/mem0mem.ic @@ -371,8 +371,7 @@ mem_heap_free_top( /********************************************************************* NOTE: Use the corresponding macros instead of this function. Creates a memory heap which allocates memory from dynamic space. For debugging -purposes, takes also the file name and line as argument in the debug -version. */ +purposes, takes also the file name and line as argument. */ UNIV_INLINE mem_heap_t* mem_heap_create_func( diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index adbc4afafd2..224fd59a76b 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -432,6 +432,17 @@ os_file_read( offset */ ulint n); /* in: number of bytes to read */ /*********************************************************************** +Rewind file to its start, read at most size - 1 bytes from it to str, and +NUL-terminate str. All errors are silently ignored. This function is +mostly meant to be used with temporary files. */ + +void +os_file_read_string( +/*================*/ + FILE* file, /* in: file to read from */ + char* str, /* in: buffer where to read */ + ulint size); /* in: size of buffer */ +/*********************************************************************** Requests a synchronous positioned read operation. This function does not do any error handling. In case of error it returns FALSE. */ diff --git a/innobase/include/page0page.ic b/innobase/include/page0page.ic index fd5281fdbec..655ff245aa8 100644 --- a/innobase/include/page0page.ic +++ b/innobase/include/page0page.ic @@ -175,6 +175,19 @@ page_rec_is_comp( /* out: nonzero if in compact format */ const rec_t* rec) /* in: record */ { +#ifdef UNIV_RELEASE_NOT_YET_STABLE + if (UNIV_UNLIKELY((ulint)rec < (ulint)(buf_pool->frame_zero)) + || UNIV_UNLIKELY((ulint)rec >= (ulint)(buf_pool->high_end))) { + + ut_print_timestamp(stderr); + fprintf(stderr, +"InnoDB: Error: trying to read a stray page rec %p\n" +"InnoDB: buf pool start is at %p, end at %p\n", + rec, buf_pool->frame_zero, + buf_pool->high_end); + ut_error; + } +#endif return(page_is_comp(ut_align_down((rec_t*) rec, UNIV_PAGE_SIZE))); } diff --git a/innobase/include/rem0rec.h b/innobase/include/rem0rec.h index 1d15b8d1c77..69b397c9682 100644 --- a/innobase/include/rem0rec.h +++ b/innobase/include/rem0rec.h @@ -312,6 +312,15 @@ rec_offs_nth_extern( const ulint* offsets,/* in: array returned by rec_get_offsets() */ ulint n); /* in: nth field */ /********************************************************** +Returns nonzero if the SQL NULL bit is set in nth field of rec. */ +UNIV_INLINE +ulint +rec_offs_nth_sql_null( +/*==================*/ + /* out: nonzero if SQL NULL */ + const ulint* offsets,/* in: array returned by rec_get_offsets() */ + ulint n); /* in: nth field */ +/********************************************************** Gets the physical size of a field. */ UNIV_INLINE ulint diff --git a/innobase/include/rem0rec.ic b/innobase/include/rem0rec.ic index e2dceb6bae5..9c24f385f4f 100644 --- a/innobase/include/rem0rec.ic +++ b/innobase/include/rem0rec.ic @@ -955,6 +955,22 @@ rec_offs_nth_extern( } /********************************************************** +Returns nonzero if the SQL NULL bit is set in nth field of rec. */ +UNIV_INLINE +ulint +rec_offs_nth_sql_null( +/*==================*/ + /* out: nonzero if SQL NULL */ + const ulint* offsets,/* in: array returned by rec_get_offsets() */ + ulint n) /* in: nth field */ +{ + ut_ad(rec_offs_validate(NULL, NULL, offsets)); + ut_ad(n < rec_offs_n_fields(offsets)); + return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n] + & REC_OFFS_SQL_NULL)); +} + +/********************************************************** Gets the physical size of a field. */ UNIV_INLINE ulint diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 4e6ff73b0f8..b5da4634d98 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -335,8 +335,14 @@ int row_create_index_for_mysql( /*=======================*/ /* out: error number or DB_SUCCESS */ - dict_index_t* index, /* in: index defintion */ - trx_t* trx); /* in: transaction handle */ + dict_index_t* index, /* in: index definition */ + trx_t* trx, /* in: transaction handle */ + const ulint* field_lengths); /* in: if not NULL, must contain + dict_index_get_n_fields(index) + actual field lengths for the + index columns, which are + then checked for not being too + large. */ /************************************************************************* Scans a table create SQL string and adds to the data dictionary the foreign key constraints declared in the string. This function @@ -355,9 +361,13 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ - const char* name); /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks); /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ + /************************************************************************* The master thread in srv0srv.c calls this regularly to drop tables which we must drop in background after queries to them have ended. Such lazy diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 5dbf003594f..0dc82893ad1 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -56,6 +56,22 @@ void trx_search_latch_release_if_reserved( /*=================================*/ trx_t* trx); /* in: transaction */ +/********************************************************************** +Set detailed error message for the transaction. */ +void +trx_set_detailed_error( +/*===================*/ + trx_t* trx, /* in: transaction struct */ + const char* msg); /* in: detailed error message */ +/***************************************************************** +Set detailed error message for the transaction from a file. Note that the +file is rewinded before reading from it. */ + +void +trx_set_detailed_error_from_file( +/*=============================*/ + trx_t* trx, /* in: transaction struct */ + FILE* file); /* in: file to read message from */ /******************************************************************** Retrieves the error_info field from a trx. */ @@ -205,7 +221,7 @@ trx_recover_for_mysql( XID* xid_list, /* in/out: prepared transactions */ ulint len); /* in: number of slots in xid_list */ /*********************************************************************** -This function is used to commit one X/Open XA distributed transaction +This function is used to find one X/Open XA distributed transaction which is in the prepared state */ trx_t * trx_get_trx_by_xid( @@ -649,6 +665,9 @@ struct trx_struct{ trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log records which are currently processed by a rollback operation */ + /*------------------------------*/ + char detailed_error[256]; /* detailed error message for last + error, or empty. */ }; #define TRX_MAX_N_THREADS 32 /* maximum number of concurrent diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 6849dcd9c51..15650f22ed8 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -80,6 +80,10 @@ memory is read outside the allocated blocks. */ /* Make a non-inline debug version */ +/* You can remove this define when the release is stable. This define adds +some consistency checks to code. They use a little CPU time. */ +#define UNIV_RELEASE_NOT_YET_STABLE + /* #define UNIV_DEBUG #define UNIV_MEM_DEBUG diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h index 74357f6bf13..b9bbe0b5c92 100644 --- a/innobase/include/ut0mem.h +++ b/innobase/include/ut0mem.h @@ -119,6 +119,31 @@ int ut_strcmp(const void* str1, const void* str2); /************************************************************************** +Copies up to size - 1 characters from the NUL-terminated string src to +dst, NUL-terminating the result. Returns strlen(src), so truncation +occurred if the return value >= size. */ + +ulint +ut_strlcpy( +/*=======*/ + /* out: strlen(src) */ + char* dst, /* in: destination buffer */ + const char* src, /* in: source buffer */ + ulint size); /* in: size of destination buffer */ + +/************************************************************************** +Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last +(size - 1) bytes of src, not the first. */ + +ulint +ut_strlcpy_rev( +/*===========*/ + /* out: strlen(src) */ + char* dst, /* in: destination buffer */ + const char* src, /* in: source buffer */ + ulint size); /* in: size of destination buffer */ + +/************************************************************************** Compute strlen(ut_strcpyq(str, q)). */ UNIV_INLINE ulint diff --git a/innobase/mem/mem0mem.c b/innobase/mem/mem0mem.c index 85f0119d02a..daf78008d45 100644 --- a/innobase/mem/mem0mem.c +++ b/innobase/mem/mem0mem.c @@ -187,9 +187,7 @@ mem_heap_create_block( } block->magic_n = MEM_BLOCK_MAGIC_N; - ut_memcpy(&(block->file_name), file_name + ut_strlen(file_name) - 7, - 7); - block->file_name[7]='\0'; + ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name)); block->line = line; #ifdef MEM_PERIODIC_CHECK diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 9c87b59f018..20a3303d12d 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -2249,6 +2249,29 @@ error_handling: } /*********************************************************************** +Rewind file to its start, read at most size - 1 bytes from it to str, and +NUL-terminate str. All errors are silently ignored. This function is +mostly meant to be used with temporary files. */ + +void +os_file_read_string( +/*================*/ + FILE* file, /* in: file to read from */ + char* str, /* in: buffer where to read */ + ulint size) /* in: size of buffer */ +{ + size_t flen; + + if (size == 0) { + return; + } + + rewind(file); + flen = fread(str, 1, size - 1, file); + str[flen] = '\0'; +} + +/*********************************************************************** Requests a synchronous write operation. */ ibool diff --git a/innobase/os/os0proc.c b/innobase/os/os0proc.c index 167aed93de7..24bb007e504 100644 --- a/innobase/os/os0proc.c +++ b/innobase/os/os0proc.c @@ -292,6 +292,9 @@ os_awe_allocate_physical_mem( return(TRUE); #else + UT_NOT_USED(n_megabytes); + UT_NOT_USED(page_info); + return(FALSE); #endif } @@ -349,6 +352,8 @@ os_awe_allocate_virtual_mem_window( return(ptr); #else + UT_NOT_USED(size); + return(NULL); #endif } @@ -476,6 +481,10 @@ os_awe_map_physical_mem_to_window( return(TRUE); #else + UT_NOT_USED(ptr); + UT_NOT_USED(n_mem_pages); + UT_NOT_USED(page_info); + return(FALSE); #endif } diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 356d7c8c163..487e8f40a39 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -631,7 +631,21 @@ os_fast_mutex_free( DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); #else - ut_a(0 == pthread_mutex_destroy(fast_mutex)); + int ret; + + ret = pthread_mutex_destroy(fast_mutex); + + if (ret != 0) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: error: return value %lu when calling\n" +"InnoDB: pthread_mutex_destroy().\n", (ulint)ret); + fprintf(stderr, +"InnoDB: Byte contents of the pthread mutex at %p:\n", fast_mutex); + ut_print_buf(stderr, (const byte*)fast_mutex, + sizeof(os_fast_mutex_t)); + fprintf(stderr, "\n"); + } #endif if (os_sync_mutex_inited) { /* When freeing the last mutexes, we have diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c index fbc33aea669..9480c978755 100644 --- a/innobase/rem/rem0rec.c +++ b/innobase/rem/rem0rec.c @@ -621,7 +621,7 @@ rec_set_nth_field_extern_bit_new( if (field->fixed_len) { /* fixed-length fields cannot be external (Fixed-length fields longer than - DICT_MAX_COL_PREFIX_LEN will be treated as + DICT_MAX_INDEX_COL_LEN will be treated as variable-length ones in dict_index_add_col().) */ ut_ad(i != ith); continue; diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 75d8117a73e..5e833372299 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -579,6 +579,32 @@ row_ins_cascade_calc_update_vec( } /************************************************************************* +Set detailed error message associated with foreign key errors for +the given transaction. */ +static +void +row_ins_set_detailed( +/*=================*/ + trx_t* trx, /* in: transaction */ + dict_foreign_t* foreign) /* in: foreign key constraint */ +{ + + FILE* tf = os_file_create_tmpfile(); + + if (tf) { + ut_print_name(tf, trx, foreign->foreign_table_name); + dict_print_info_on_foreign_key_in_create_format(tf, trx, + foreign, FALSE); + + trx_set_detailed_error_from_file(trx, tf); + + fclose(tf); + } else { + trx_set_detailed_error(trx, "temp file creation failed"); + } +} + +/************************************************************************* Reports a foreign key error associated with an update or a delete of a parent table index entry. */ static @@ -598,6 +624,8 @@ row_ins_foreign_report_err( FILE* ef = dict_foreign_err_file; trx_t* trx = thr_get_trx(thr); + row_ins_set_detailed(trx, foreign); + mutex_enter(&dict_foreign_err_mutex); rewind(ef); ut_print_timestamp(ef); @@ -607,7 +635,8 @@ row_ins_foreign_report_err( fputs("Foreign key constraint fails for table ", ef); ut_print_name(ef, trx, foreign->foreign_table_name); fputs(":\n", ef); - dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign); + dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign, + TRUE); putc('\n', ef); fputs(errstr, ef); fputs(" in parent table, in index ", ef); @@ -648,7 +677,9 @@ row_ins_foreign_report_add_err( child table */ { FILE* ef = dict_foreign_err_file; - + + row_ins_set_detailed(trx, foreign); + mutex_enter(&dict_foreign_err_mutex); rewind(ef); ut_print_timestamp(ef); @@ -657,7 +688,8 @@ row_ins_foreign_report_add_err( fputs("Foreign key constraint fails for table ", ef); ut_print_name(ef, trx, foreign->foreign_table_name); fputs(":\n", ef); - dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign); + dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign, + TRUE); fputs("\nTrying to add in child table, in index ", ef); ut_print_name(ef, trx, foreign->foreign_index->name); if (entry) { @@ -1224,6 +1256,9 @@ run_again: if (check_table == NULL || check_table->ibd_file_missing) { if (check_ref) { FILE* ef = dict_foreign_err_file; + + row_ins_set_detailed(trx, foreign); + mutex_enter(&dict_foreign_err_mutex); rewind(ef); ut_print_timestamp(ef); @@ -1233,7 +1268,7 @@ run_again: ut_print_name(ef, trx, foreign->foreign_table_name); fputs(":\n", ef); dict_print_info_on_foreign_key_in_create_format(ef, - trx, foreign); + trx, foreign, TRUE); fputs("\nTrying to add to index ", ef); ut_print_name(ef, trx, foreign->foreign_index->name); fputs(" tuple:\n", ef); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 2ac0824b331..82f7daf2ed8 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -513,14 +513,15 @@ handle_new_error: return(TRUE); - } else if (err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT + } else if (err == DB_DEADLOCK || err == DB_LOCK_TABLE_FULL) { /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ trx_general_rollback_for_mysql(trx, FALSE, NULL); - } else if (err == DB_OUT_OF_FILE_SPACE) { + } else if (err == DB_OUT_OF_FILE_SPACE + || err == DB_LOCK_WAIT_TIMEOUT) { if (savept) { /* Roll back the latest, possibly incomplete insertion or update */ @@ -1972,13 +1973,20 @@ row_create_index_for_mysql( /*=======================*/ /* out: error number or DB_SUCCESS */ dict_index_t* index, /* in: index definition */ - trx_t* trx) /* in: transaction handle */ + trx_t* trx, /* in: transaction handle */ + const ulint* field_lengths) /* in: if not NULL, must contain + dict_index_get_n_fields(index) + actual field lengths for the + index columns, which are + then checked for not being too + large. */ { ind_node_t* node; mem_heap_t* heap; que_thr_t* thr; ulint err; ulint i, j; + ulint len; #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); @@ -2017,10 +2025,16 @@ row_create_index_for_mysql( } } - /* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */ + /* Check also that prefix_len and actual length + < DICT_MAX_INDEX_COL_LEN */ + + len = dict_index_get_nth_field(index, i)->prefix_len; - if (dict_index_get_nth_field(index, i)->prefix_len - >= DICT_MAX_COL_PREFIX_LEN) { + if (field_lengths) { + len = ut_max(len, field_lengths[i]); + } + + if (len >= DICT_MAX_INDEX_COL_LEN) { err = DB_TOO_BIG_RECORD; goto error_handling; @@ -2087,9 +2101,12 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ - const char* name) /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ { ulint err; @@ -2110,7 +2127,8 @@ row_table_add_foreign_constraints( trx->dict_operation = TRUE; - err = dict_create_foreign_constraints(trx, sql_string, name); + err = dict_create_foreign_constraints(trx, sql_string, name, + reject_fks); if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index a77010d939b..1b66f14f5d7 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2724,7 +2724,9 @@ row_sel_get_clust_rec_for_mysql( if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED && !lock_clust_rec_cons_read_sees(clust_rec, clust_index, *offsets, trx->read_view)) { - + + /* The following call returns 'offsets' associated with + 'old_vers' */ err = row_sel_build_prev_vers_for_mysql( trx->read_view, clust_index, prebuilt, clust_rec, @@ -3055,13 +3057,14 @@ row_search_for_mysql( cursor 'direction' should be 0. */ { dict_index_t* index = prebuilt->index; + ibool comp = index->table->comp; dtuple_t* search_tuple = prebuilt->search_tuple; btr_pcur_t* pcur = prebuilt->pcur; trx_t* trx = prebuilt->trx; dict_index_t* clust_index; que_thr_t* thr; rec_t* rec; - rec_t* index_rec; + rec_t* result_rec; rec_t* clust_rec; rec_t* old_vers; ulint err = DB_SUCCESS; @@ -3491,7 +3494,7 @@ rec_loop: /* PHASE 4: Look for matching records in a loop */ rec = btr_pcur_get_rec(pcur); - ut_ad(!!page_rec_is_comp(rec) == index->table->comp); + ut_ad(!!page_rec_is_comp(rec) == comp); #ifdef UNIV_SEARCH_DEBUG /* fputs("Using ", stderr); @@ -3544,19 +3547,23 @@ rec_loop: /* Do sanity checks in case our cursor has bumped into page corruption */ - if (page_rec_is_comp(rec)) { + if (comp) { next_offs = rec_get_next_offs(rec, TRUE); if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) { + goto wrong_offs; } } else { next_offs = rec_get_next_offs(rec, FALSE); if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) { + goto wrong_offs; } } + if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) { - wrong_offs: + +wrong_offs: if (srv_force_recovery == 0 || moves_up == FALSE) { ut_print_timestamp(stderr); buf_page_print(buf_frame_align(rec)); @@ -3599,6 +3606,9 @@ rec_loop: goto next_rec; } } + /*-------------------------------------------------------------*/ + + /* Calculate the 'offsets' associated with 'rec' */ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); @@ -3619,8 +3629,6 @@ rec_loop: } } - /*-------------------------------------------------------------*/ - /* Note that we cannot trust the up_match value in the cursor at this place because we can arrive here after moving the cursor! Thus we have to recompare rec and search_tuple to determine if they @@ -3711,7 +3719,7 @@ rec_loop: if (!set_also_gap_locks || srv_locks_unsafe_for_binlog || (unique_search && !UNIV_UNLIKELY(rec_get_deleted_flag( - rec, page_rec_is_comp(rec))))) { + rec, comp)))) { goto no_gap_lock; } else { @@ -3767,6 +3775,8 @@ no_gap_lock: && !lock_clust_rec_cons_read_sees(rec, index, offsets, trx->read_view)) { + /* The following call returns 'offsets' + associated with 'old_vers' */ err = row_sel_build_prev_vers_for_mysql( trx->read_view, clust_index, prebuilt, rec, @@ -3795,19 +3805,20 @@ no_gap_lock: is necessary, because we can only get the undo information via the clustered index record. */ - /* Get the clustered index record if needed */ - index_rec = rec; ut_ad(index != clust_index); goto requires_clust_rec; } } - if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, page_rec_is_comp(rec)))) { + /* NOTE that at this point rec can be an old version of a clustered + index record built for a consistent read. We cannot assume after this + point that rec is on a buffer pool page. Functions like + page_rec_is_comp() cannot be used! */ - /* The record is delete-marked: we can skip it if this is - not a consistent read which might see an earlier version - of a non-clustered index record */ + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp))) { + + /* The record is delete-marked: we can skip it */ if (srv_locks_unsafe_for_binlog && prebuilt->select_lock_type != LOCK_NONE) { @@ -3823,25 +3834,26 @@ no_gap_lock: goto next_rec; } - /* Get the clustered index record if needed and if we did - not do the search using the clustered index */ - - index_rec = rec; + /* Get the clustered index record if needed, if we did not do the + search using the clustered index. */ if (index != clust_index && prebuilt->need_to_access_clustered) { requires_clust_rec: - /* Before and after this "if" block, "offsets" will be - related to "rec", which may be in a secondary index "index" or - the clustered index ("clust_index"). However, after this - "if" block, "rec" may be pointing to - "clust_rec" of "clust_index". */ + /* We use a 'goto' to the preceding label if a consistent + read of a secondary index record requires us to look up old + versions of the associated clustered index record. */ + ut_ad(rec_offs_validate(rec, index, offsets)); /* It was a non-clustered index and we must fetch also the clustered index record */ mtr_has_extra_clust_latch = TRUE; + + /* The following call returns 'offsets' associated with + 'clust_rec'. Note that 'clust_rec' can be an old version + built for a consistent read. */ err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec, thr, &clust_rec, @@ -3858,8 +3870,7 @@ requires_clust_rec: goto next_rec; } - if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, - page_rec_is_comp(clust_rec)))) { + if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) { /* The record is delete marked: we can skip it */ @@ -3879,17 +3890,27 @@ requires_clust_rec: } if (prebuilt->need_to_access_clustered) { - rec = clust_rec; - ut_ad(rec_offs_validate(rec, clust_index, offsets)); + + result_rec = clust_rec; + + ut_ad(rec_offs_validate(result_rec, clust_index, + offsets)); } else { + /* We used 'offsets' for the clust rec, recalculate + them for 'rec' */ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); + result_rec = rec; } + } else { + result_rec = rec; } - /* We found a qualifying row */ - ut_ad(rec_offs_validate(rec, - rec == clust_rec ? clust_index : index, + /* We found a qualifying record 'result_rec'. At this point, + 'offsets' are associated with 'result_rec'. */ + + ut_ad(rec_offs_validate(result_rec, + result_rec != rec ? clust_index : index, offsets)); if ((match_mode == ROW_SEL_EXACT @@ -3910,8 +3931,8 @@ requires_clust_rec: not cache rows because there the cursor is a scrollable cursor. */ - row_sel_push_cache_row_for_mysql(prebuilt, rec, offsets); - + row_sel_push_cache_row_for_mysql(prebuilt, result_rec, + offsets); if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) { goto got_row; @@ -3920,13 +3941,14 @@ requires_clust_rec: goto next_rec; } else { if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) { - memcpy(buf + 4, rec - rec_offs_extra_size(offsets), + memcpy(buf + 4, result_rec + - rec_offs_extra_size(offsets), rec_offs_size(offsets)); mach_write_to_4(buf, rec_offs_extra_size(offsets) + 4); } else { if (!row_sel_store_mysql_rec(buf, prebuilt, - rec, offsets)) { + result_rec, offsets)) { err = DB_TOO_BIG_RECORD; goto lock_wait_or_error; @@ -3934,15 +3956,18 @@ requires_clust_rec: } if (prebuilt->clust_index_was_generated) { - if (rec != index_rec) { + if (result_rec != rec) { offsets = rec_get_offsets( - index_rec, index, offsets, + rec, index, offsets, ULINT_UNDEFINED, &heap); } - row_sel_store_row_id_to_prebuilt(prebuilt, index_rec, + row_sel_store_row_id_to_prebuilt(prebuilt, rec, index, offsets); } } + + /* From this point on, 'offsets' are invalid. */ + got_row: /* We have an optimization to save CPU time: if this is a consistent read on a unique condition on the clustered index, then we do not @@ -3993,7 +4018,7 @@ next_rec: if (moves_up) { if (UNIV_UNLIKELY(!btr_pcur_move_to_next(pcur, &mtr))) { - not_moved: +not_moved: btr_pcur_store_position(pcur, &mtr); if (match_mode != 0) { diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 4f44dbeae67..ff1ad1dfd05 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -395,6 +395,18 @@ row_upd_changes_field_size_or_external( old_len = rec_offs_nth_size(offsets, upd_field->field_no); + if (rec_offs_comp(offsets) + && rec_offs_nth_sql_null(offsets, upd_field->field_no)) { + /* Note that in the compact table format, for a + variable length field, an SQL NULL will use zero + bytes in the offset array at the start of the physical + record, but a zero-length value (empty string) will + use one byte! Thus, we cannot use update-in-place + if we update an SQL NULL varchar to an empty string! */ + + old_len = UNIV_SQL_NULL; + } + if (old_len != new_len) { return(TRUE); diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 325b0a109cf..e5151ebf631 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1540,7 +1540,7 @@ NetWare. */ #endif sync_order_checks_on = TRUE; - if (srv_use_doublewrite_buf && trx_doublewrite == NULL) { + if (trx_doublewrite == NULL) { /* Create the doublewrite buffer to a new tablespace */ trx_sys_create_doublewrite_buf(); diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index bf48c30e942..23f1dc40d00 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -126,22 +126,6 @@ trx_doublewrite_init( } /******************************************************************** -Frees the doublewrite buffer. */ -static -void -trx_doublewrite_free(void) -/*======================*/ -{ - mutex_free(&(trx_doublewrite->mutex)); - - mem_free(trx_doublewrite->buf_block_arr); - ut_free(trx_doublewrite->write_buf_unaligned); - - mem_free(trx_doublewrite); - trx_doublewrite = NULL; -} - -/******************************************************************** Marks the trx sys header when we have successfully upgraded to the >= 4.1.x multiple tablespace format. */ @@ -529,9 +513,6 @@ trx_sys_doublewrite_init_or_restore_pages( fil_flush_file_spaces(FIL_TABLESPACE); - if (!srv_use_doublewrite_buf) - trx_doublewrite_free(); - leave_func: ut_free(unaligned_read_buf); } diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 078befb81d2..090057f5d46 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -52,6 +52,32 @@ trx_start_if_not_started_noninline( trx_start_if_not_started(trx); } +/***************************************************************** +Set detailed error message for the transaction. */ + +void +trx_set_detailed_error( +/*===================*/ + trx_t* trx, /* in: transaction struct */ + const char* msg) /* in: detailed error message */ +{ + ut_strlcpy(trx->detailed_error, msg, sizeof(trx->detailed_error)); +} + +/***************************************************************** +Set detailed error message for the transaction from a file. Note that the +file is rewinded before reading from it. */ + +void +trx_set_detailed_error_from_file( +/*=============================*/ + trx_t* trx, /* in: transaction struct */ + FILE* file) /* in: file to read message from */ +{ + os_file_read_string(file, trx->detailed_error, + sizeof(trx->detailed_error)); +} + /******************************************************************** Retrieves the error_info field from a trx. */ @@ -130,6 +156,7 @@ trx_create( trx->undo_no_arr = NULL; trx->error_state = DB_SUCCESS; + trx->detailed_error[0] = '\0'; trx->sess = sess; trx->que_state = TRX_QUE_RUNNING; diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index 3e8fd79a739..47b1e24e5e1 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -343,6 +343,54 @@ ut_free_all_mem(void) } /************************************************************************** +Copies up to size - 1 characters from the NUL-terminated string src to +dst, NUL-terminating the result. Returns strlen(src), so truncation +occurred if the return value >= size. */ + +ulint +ut_strlcpy( +/*=======*/ + /* out: strlen(src) */ + char* dst, /* in: destination buffer */ + const char* src, /* in: source buffer */ + ulint size) /* in: size of destination buffer */ +{ + ulint src_size = strlen(src); + + if (size != 0) { + ulint n = ut_min(src_size, size - 1); + + memcpy(dst, src, n); + dst[n] = '\0'; + } + + return(src_size); +} + +/************************************************************************** +Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last +(size - 1) bytes of src, not the first. */ + +ulint +ut_strlcpy_rev( +/*===========*/ + /* out: strlen(src) */ + char* dst, /* in: destination buffer */ + const char* src, /* in: source buffer */ + ulint size) /* in: size of destination buffer */ +{ + ulint src_size = strlen(src); + + if (size != 0) { + ulint n = ut_min(src_size, size - 1); + + memcpy(dst, src + src_size - n, n + 1); + } + + return(src_size); +} + +/************************************************************************** Make a quoted copy of a NUL-terminated string. Leading and trailing quotes will not be included; only embedded quotes will be escaped. See also ut_strlenq() and ut_memcpyq(). */ diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 9aef03f20d2..943b75f9973 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -37,7 +37,7 @@ SUBDIRS = . examples libmysqld_sources= libmysqld.c lib_sql.cc emb_qcache.cc libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c \ my_time.c -sqlexamplessources = ha_example.cc ha_archive.cc ha_tina.cc +sqlexamplessources = ha_example.cc ha_tina.cc noinst_HEADERS = embedded_priv.h emb_qcache.h @@ -60,10 +60,10 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \ sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \ unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \ - spatial.cc gstream.cc sql_help.cc tztime.cc protocol_cursor.cc \ + spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \ - ha_blackhole.cc + ha_blackhole.cc ha_archive.cc libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources) libmysqld_a_SOURCES= diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index a86d467299c..8552b1c2b8a 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -423,9 +423,9 @@ int init_embedded_server(int argc, char **argv, char **groups) acl_error= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!(acl_error= acl_init((THD *)0, opt_noacl)) && + if (!(acl_error= acl_init(opt_noacl)) && !opt_noacl) - (void) grant_init((THD *)0); + (void) grant_init(); #endif if (acl_error || my_tz_init((THD *)0, default_tz_name, opt_bootstrap)) { @@ -514,8 +514,8 @@ void *create_embedded_thd(int client_flag, char *db) thd->db= db; thd->db_length= db ? strip_sp(db) : 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS - thd->db_access= DB_ACLS; - thd->master_access= ~NO_ACCESS; + thd->security_ctx->db_access= DB_ACLS; + thd->security_ctx->master_access= ~NO_ACCESS; #endif thd->net.query_cache_query= 0; @@ -532,10 +532,9 @@ err: int check_embedded_connection(MYSQL *mysql) { THD *thd= (THD*)mysql->thd; - thd->host= (char*)my_localhost; - thd->host_or_ip= thd->host; - thd->user= my_strdup(mysql->user, MYF(0)); - thd->priv_user= thd->user; + Security_context *sctx= thd->security_ctx; + sctx->host_or_ip= sctx->host= (char*)my_localhost; + sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0)); return check_user(thd, COM_CONNECT, NULL, 0, thd->db, true); } @@ -543,26 +542,27 @@ int check_embedded_connection(MYSQL *mysql) int check_embedded_connection(MYSQL *mysql) { THD *thd= (THD*)mysql->thd; + Security_context *sctx= thd->security_ctx; int result; char scramble_buff[SCRAMBLE_LENGTH]; int passwd_len; if (mysql->options.client_ip) { - thd->host= my_strdup(mysql->options.client_ip, MYF(0)); - thd->ip= my_strdup(thd->host, MYF(0)); + sctx->host= my_strdup(mysql->options.client_ip, MYF(0)); + sctx->ip= my_strdup(sctx->host, MYF(0)); } else - thd->host= (char*)my_localhost; - thd->host_or_ip= thd->host; + sctx->host= (char*)my_localhost; + sctx->host_or_ip= sctx->host; - if (acl_check_host(thd->host,thd->ip)) + if (acl_check_host(sctx->host, sctx->ip)) { result= ER_HOST_NOT_PRIVILEGED; goto err; } - thd->user= my_strdup(mysql->user, MYF(0)); + sctx->user= my_strdup(mysql->user, MYF(0)); if (mysql->passwd && mysql->passwd[0]) { memset(thd->scramble, 55, SCRAMBLE_LENGTH); // dummy scramble diff --git a/man/which.2 b/man/which.2 deleted file mode 100644 index 30d5557ed01..00000000000 --- a/man/which.2 +++ /dev/null @@ -1,54 +0,0 @@ -.TH WHICH 1 "20 December 2000" -.SH NAME -which - Jani please supply one. -.SH USAGE -which [options] [--] programname [...] -.SH SYNOPSIS -.B which -.RB [ \-\-version | \-[vV] ] -.RB [ \-\-skip\-dot ] -.RB [ \-\-skip\-tilde ] -.RB [ \-\-show\-dot ] -.RB [ \-\-show\-tilde ] -.RB [ \-\-tty\-only ] -.RB [ \-\-all | \-a ] -.RB [ \-\-read\-alias | \-i ] -.RB [ \-\-skip\-alias ] -.SH DESCRIPTION -.TP -.BR which -supports by executing -.TP -.BR \-\-version | \-[vV] -Print version and exit successfully. -.TP -.BR \-\-skip\-dot -Skip directories in PATH that start with a dot. -.TP -.BR \-\-skip\-tilde -Skip directories in PATH that start with a tilde. -.TP -.BR \-\-show\-dot -Don\'t expand a dot to current directory in output. -.TP -.BR \-\-show\-tilde -Output a tilde for HOME directory for non-root. -.TP -.BR \-\-tty\-only -Stop processing options on the right if not on tty. -.TP -.BR \-\-all | \-a -Print all matches in PATH, not just the first -.TP -.BR \-\-read\-alias | \-i -Read list of aliases from stdin. -.TP -.BR \-\-skip\-alias -Ignore option -.BR --read-alias; -don\'t read stdin. -.SH "SEE ALSO" -isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), mysqld_safe (1), which1 (1), zap (1), -.SH AUTHOR -Ver 1.0, distribution 3.23.29a Michael (Monty) Widenius (monty@tcx.se), TCX Datakonsult AB (http://www.tcx.se). This software comes with no warranty. Manual page by L. (Kill-9) Pedersen (kill-9@kill-9.dk), Mercurmedia Data Model Architect / system developer (http://www.mercurmedia.com) -.\" end of man page
\ No newline at end of file diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index c18984c7584..19f0ef77136 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -473,7 +473,8 @@ static int _ftb_check_phrase(const byte *s0, const byte *e0, for (;;) { n_word= (FT_WORD *)phrase_element->data; - if (my_strnncoll(cs, h_word.pos, h_word.len, n_word->pos, n_word->len)) + if (my_strnncoll(cs, (const uchar *) h_word.pos, h_word.len, + (const uchar *) n_word->pos, n_word->len)) break; if (! (phrase_element= phrase_element->next)) DBUG_RETURN(1); diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 7a506fd11c6..8460db61a36 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -266,7 +266,8 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, so if ndocs == 0, FT_INFO.doc[] must not be accessed. */ dlist=(FT_INFO *)my_malloc(sizeof(FT_INFO)+ - sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1), + sizeof(FT_DOC)* + (int)(aio.dtree.elements_in_tree-1), MYF(0)); if (!dlist) goto err; diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ffb7cdd503f..f5d46210944 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -80,6 +80,7 @@ void myisamchk_init(MI_CHECK *param) param->start_check_pos=0; param->max_record_length= LONGLONG_MAX; param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE; + param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; } /* Check the status flags for the table */ @@ -559,10 +560,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, ha_checksum *key_checksum, uint level) { int flag; - uint used_length,comp_flag,nod_flag,key_length=0,not_used; + uint used_length,comp_flag,nod_flag,key_length=0; uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos; my_off_t next_page,record; char llbuff[22]; + uint diff_pos; DBUG_ENTER("chk_index"); DBUG_DUMP("buff",(byte*) buff,mi_getint(buff)); @@ -620,7 +622,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, } if ((*keys)++ && (flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length, - comp_flag, ¬_used)) >=0) + comp_flag, &diff_pos)) >=0) { DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length); DBUG_DUMP("new",(byte*) key, key_length); @@ -636,11 +638,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, { if (*keys != 1L) /* not first_key */ { - uint diff; - ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, - SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, - &diff); - param->unique_count[diff-1]++; + if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) + ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, + SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, + &diff_pos); + param->unique_count[diff_pos-1]++; } } (*key_checksum)+= mi_byte_checksum((byte*) key, @@ -1045,9 +1047,12 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) /* We don't need to lock the key tree here as we don't allow concurrent threads when running myisamchk */ - int search_result= (keyinfo->flag & HA_SPATIAL) ? + int search_result= +#ifdef HAVE_RTREE_KEYS + (keyinfo->flag & HA_SPATIAL) ? rtree_find_first(info, key, info->lastkey, key_length, SEARCH_SAME) : +#endif _mi_search(info,keyinfo,info->lastkey,key_length, SEARCH_SAME, info->s->state.key_root[key]); if (search_result) @@ -1090,7 +1095,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) "Keypointers and record positions doesn't match"); error=1; } - else if (param->glob_crc != info->s->state.checksum && + else if (param->glob_crc != info->state->checksum && (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))) { @@ -1386,7 +1391,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, info->state->data_file_length=sort_param.max_pos; } if (param->testflag & T_CALC_CHECKSUM) - share->state.checksum=param->glob_crc; + info->state->checksum=param->glob_crc; if (!(param->testflag & T_SILENT)) { @@ -2014,7 +2019,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, sort_param.sort_info=&sort_info; sort_param.fix_datafile= (my_bool) (! rep_quick); sort_param.master =1; - + del=info->state->del; param->glob_crc=0; if (param->testflag & T_CALC_CHECKSUM) @@ -2154,7 +2159,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, my_errno); } if (param->testflag & T_CALC_CHECKSUM) - share->state.checksum=param->glob_crc; + info->state->checksum=param->glob_crc; if (my_chsize(share->kfile,info->state->key_file_length,0,MYF(0))) mi_check_print_warning(param, @@ -2575,7 +2580,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, my_errno); } if (param->testflag & T_CALC_CHECKSUM) - share->state.checksum=param->glob_crc; + info->state->checksum=param->glob_crc; if (my_chsize(share->kfile,info->state->key_file_length,0,MYF(0))) mi_check_print_warning(param, @@ -3194,9 +3199,11 @@ int sort_write_record(MI_SORT_PARAM *sort_param) break; case COMPRESSED_RECORD: reclength=info->packed_length; - length=save_pack_length(block_buff,reclength); + length= save_pack_length((uint) share->pack.version, block_buff, + reclength); if (info->s->base.blobs) - length+=save_pack_length(block_buff+length,info->blob_length); + length+= save_pack_length((uint) share->pack.version, + block_buff + length, info->blob_length); if (my_b_write(&info->rec_cache,block_buff,length) || my_b_write(&info->rec_cache,(byte*) sort_param->rec_buff,reclength)) { @@ -3248,9 +3255,10 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE, &diff_pos); - ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, - (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, - &diff_pos); + if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) + ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, + (uchar*) a, USE_WHOLE_KEY, + SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos); sort_param->unique[diff_pos-1]++; } else @@ -3803,7 +3811,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) (*org_info)->s->state.create_time=share.state.create_time; (*org_info)->s->state.unique=(*org_info)->this_unique= share.state.unique; - (*org_info)->s->state.checksum=share.state.checksum; + (*org_info)->state->checksum=info.state->checksum; (*org_info)->state->del=info.state->del; (*org_info)->s->state.dellink=share.state.dellink; (*org_info)->state->empty=info.state->empty; @@ -3987,9 +3995,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, unique[0]= (#different values of {keypart1}) - 1 unique[1]= (#different values of {keypart2,keypart1} tuple) - unique[0] - 1 ... - Here we assume that NULL != NULL (see SEARCH_NULL_ARE_NOT_EQUAL). The - 'unique' array is collected in one sequential scan through the entire + The 'unique' array is collected in one sequential scan through the entire index. This is done in two places: in chk_index() and in sort_key_write(). + Statistics collection may consider NULLs as either equal or unequal (see + SEARCH_NULL_ARE_NOT_EQUAL, MI_STATS_METHOD_*). Output is an array: rec_per_key_part[k] = diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index e782d21afe7..ddc8a403a33 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -40,12 +40,12 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg, end= key+ keyseg->length; if (keyseg->flag & HA_NULL_PART) { - if (!*key) + /* A NULL value is encoded by a 1-byte flag. Zero means NULL. */ + if (! *(key++)) { fprintf(stream,"NULL"); continue; } - key++; } switch (keyseg->type) { diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index 60a07254e82..62ca7f8ff61 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -93,7 +93,7 @@ int mi_delete(MI_INFO *info,const byte *record) if ((*share->delete_record)(info)) goto err; /* Remove record from database */ - info->s->state.checksum-=info->checksum; + info->state->checksum-=info->checksum; info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED; info->state->records--; diff --git a/myisam/mi_delete_all.c b/myisam/mi_delete_all.c index 3033249886f..a30abb95070 100644 --- a/myisam/mi_delete_all.c +++ b/myisam/mi_delete_all.c @@ -41,7 +41,7 @@ int mi_delete_all_rows(MI_INFO *info) info->state->key_file_length=share->base.keystart; info->state->data_file_length=0; info->state->empty=info->state->key_empty=0; - state->checksum=0; + info->state->checksum=0; for (i=share->base.max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; ) state->key_del[i]= HA_OFFSET_ERROR; diff --git a/myisam/mi_key.c b/myisam/mi_key.c index ae50900a190..4cabfc91197 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -358,7 +358,7 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, byte *blob_ptr; DBUG_ENTER("_mi_put_key_in_record"); - blob_ptr= info->lastkey2; /* Place to put blob parts */ + blob_ptr= (byte*) info->lastkey2; /* Place to put blob parts */ key=(byte*) info->lastkey; /* KEy that was read */ key_end=key+info->lastkey_length; for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++) diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 82663e0c318..955d55cf765 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -199,7 +199,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d", len,MI_BASE_INFO_SIZE)) } - disk_pos=my_n_base_info_read((uchar*) disk_cache + base_pos, &share->base); + disk_pos= (char*) + my_n_base_info_read((uchar*) disk_cache + base_pos, &share->base); share->state.state_length=base_pos; if (!(open_flags & HA_OPEN_FOR_REPAIR) && @@ -822,7 +823,7 @@ uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite) mi_sizestore(ptr,state->state.empty); ptr +=8; mi_sizestore(ptr,state->state.key_empty); ptr +=8; mi_int8store(ptr,state->auto_increment); ptr +=8; - mi_int8store(ptr,(ulonglong) state->checksum);ptr +=8; + mi_int8store(ptr,(ulonglong) state->state.checksum);ptr +=8; mi_int4store(ptr,state->process); ptr +=4; mi_int4store(ptr,state->unique); ptr +=4; mi_int4store(ptr,state->status); ptr +=4; @@ -863,7 +864,7 @@ uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite) } -char *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state) +uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state) { uint i,keys,key_parts,key_blocks; memcpy_fixed(&state->header,ptr, sizeof(state->header)); @@ -884,7 +885,7 @@ char *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state) state->state.empty = mi_sizekorr(ptr); ptr +=8; state->state.key_empty= mi_sizekorr(ptr); ptr +=8; state->auto_increment=mi_uint8korr(ptr); ptr +=8; - state->checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8; + state->state.checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8; state->process= mi_uint4korr(ptr); ptr +=4; state->unique = mi_uint4korr(ptr); ptr +=4; state->status = mi_uint4korr(ptr); ptr +=4; @@ -974,7 +975,7 @@ uint mi_base_info_write(File file, MI_BASE_INFO *base) } -char *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base) +uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base) { base->keystart = mi_sizekorr(ptr); ptr +=8; base->max_data_file_length = mi_sizekorr(ptr); ptr +=8; diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index c251e4dda4a..e242e9d506d 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -151,11 +151,12 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) my_errno=HA_ERR_END_OF_FILE; goto err0; } - if (memcmp((byte*) header,(byte*) myisam_pack_file_magic,4)) + if (memcmp((byte*) header, (byte*) myisam_pack_file_magic, 3)) { my_errno=HA_ERR_WRONG_IN_RECORD; goto err0; } + share->pack.version= header[3]; share->pack.header_length= uint4korr(header+4); share->min_pack_length=(uint) uint4korr(header+8); share->max_pack_length=(uint) uint4korr(header+12); @@ -1070,38 +1071,12 @@ uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file, return BLOCK_FATAL_ERROR; DBUG_DUMP("header",(byte*) header,ref_length); } - if (header[0] < 254) - { - info->rec_len=header[0]; - head_length=1; - } - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - head_length=3; - } - else - { - info->rec_len=uint3korr(header+1); - head_length=4; - } + head_length= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[head_length] < 254) - { - info->blob_len=header[head_length]; - head_length++; - } - else if (header[head_length] == 254) - { - info->blob_len=uint2korr(header+head_length+1); - head_length+=3; - } - else - { - info->blob_len=uint3korr(header+head_length+1); - head_length+=4; - } + head_length+= read_pack_length((uint) myisam->s->pack.version, + header + head_length, &info->blob_len); if (!(mi_alloc_rec_buff(myisam,info->rec_len + info->blob_len, &myisam->rec_buff))) return BLOCK_FATAL_ERROR; /* not enough memory */ @@ -1251,34 +1226,12 @@ void _mi_unmap_file(MI_INFO *info) static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info, uchar *header) { - if (header[0] < 254) - info->rec_len= *header++; - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - header+=3; - } - else - { - info->rec_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[0] < 254) - { - info->blob_len= *header++; - } - else if (header[0] == 254) - { - info->blob_len=uint2korr(header+1); - header+=3; - } - else - { - info->blob_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->blob_len); /* mi_alloc_rec_buff sets my_errno on error */ if (!(mi_alloc_rec_buff(myisam, info->blob_len, &myisam->rec_buff))) @@ -1350,7 +1303,7 @@ static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf, /* Save length of row */ -uint save_pack_length(byte *block_buff,ulong length) +uint save_pack_length(uint version, byte *block_buff, ulong length) { if (length < 254) { @@ -1364,6 +1317,46 @@ uint save_pack_length(byte *block_buff,ulong length) return 3; } *(uchar*) block_buff=255; - int3store(block_buff+1,(ulong) length); - return 4; + if (version == 1) /* old format */ + { + DBUG_ASSERT(length <= 0xFFFFFF); + int3store(block_buff + 1, (ulong) length); + return 4; + } + else + { + int4store(block_buff + 1, (ulong) length); + return 5; + } +} + + +uint read_pack_length(uint version, const uchar *buf, ulong *length) +{ + if (buf[0] < 254) + { + *length= buf[0]; + return 1; + } + else if (buf[0] == 254) + { + *length= uint2korr(buf + 1); + return 3; + } + if (version == 1) /* old format */ + { + *length= uint3korr(buf + 1); + return 4; + } + else + { + *length= uint4korr(buf + 1); + return 5; + } +} + + +uint calc_pack_length(uint version, ulong length) +{ + return (length < 254) ? 1 : (length < 65536) ? 3 : (version == 1) ? 4 : 5; } diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c index 635a7eb2c48..e6f4d39ab49 100644 --- a/myisam/mi_rkey.c +++ b/myisam/mi_rkey.c @@ -31,8 +31,8 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, HA_KEYSEG *last_used_keyseg; uint pack_key_length, use_key_length, nextflag; DBUG_ENTER("mi_rkey"); - DBUG_PRINT("enter",("base: %lx inx: %d search_flag: %d", - info,inx,search_flag)); + DBUG_PRINT("enter", ("base: %lx buf: %lx inx: %d search_flag: %d", + (long) info, (long) buf, inx, search_flag)); if ((inx = _mi_check_index(info,inx)) < 0) DBUG_RETURN(my_errno); @@ -56,9 +56,12 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, { if (key_len == 0) key_len=USE_WHOLE_KEY; + /* Save the packed key for later use in the second buffer of lastkey. */ key_buff=info->lastkey+info->s->base.max_key_length; pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (uchar*) key, key_len, &last_used_keyseg); + /* Save packed_key_length for use by the MERGE engine. */ + info->pack_key_length= pack_key_length; DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE, keyinfo->seg, key_buff, pack_key_length);); } diff --git a/myisam/mi_search.c b/myisam/mi_search.c index b7360dba7f3..92efdfee457 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -259,15 +259,16 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, { mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; - DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p", - length, page, end)); + DBUG_PRINT("error",("Found wrong key: length: %u page: %lx end: %lx", + length, (long) page, (long) end)); DBUG_RETURN(MI_FOUND_WRONG_KEY); } if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag, ¬_used)) >= 0) break; #ifdef EXTRA_DEBUG - DBUG_PRINT("loop",("page: %p key: '%s' flag: %d", page, t_buff, flag)); + DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d", (long) page, t_buff, + flag)); #endif memcpy(buff,t_buff,length); *ret_pos=page; @@ -275,7 +276,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, if (flag == 0) memcpy(buff,t_buff,length); /* Result is first key */ *last_key= page == end; - DBUG_PRINT("exit",("flag: %d ret_pos: %p", flag, *ret_pos)); + DBUG_PRINT("exit",("flag: %d ret_pos: %lx", flag, (long) *ret_pos)); DBUG_RETURN(flag); } /* _mi_seq_search */ @@ -415,8 +416,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, { mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; - DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p", - length, page, end)); + DBUG_PRINT("error",("Found wrong key: length: %u page: %lx end: %lx", + length, (long) page, (long) end)); DBUG_RETURN(MI_FOUND_WRONG_KEY); } @@ -550,7 +551,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, *last_key= page == end; - DBUG_PRINT("exit",("flag: %d ret_pos: %p", flag, *ret_pos)); + DBUG_PRINT("exit",("flag: %d ret_pos: %lx", flag, (long) *ret_pos)); DBUG_RETURN(flag); } /* _mi_prefix_search */ @@ -812,8 +813,8 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if (length > keyseg->length) { DBUG_PRINT("error", - ("Found too long null packed key: %u of %u at %p", - length, keyseg->length, *page_pos)); + ("Found too long null packed key: %u of %u at %lx", + length, keyseg->length, (long) *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; @@ -869,8 +870,8 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, } if (length > (uint) keyseg->length) { - DBUG_PRINT("error",("Found too long packed key: %u of %u at %p", - length, keyseg->length, *page_pos)); + DBUG_PRINT("error",("Found too long packed key: %u of %u at %lx", + length, keyseg->length, (long) *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; @@ -915,22 +916,32 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, reg1 HA_KEYSEG *keyseg; uchar *start_key,*page,*page_end,*from,*from_end; uint length,tmp; + DBUG_ENTER("_mi_get_binary_pack_key"); page= *page_pos; page_end=page+MI_MAX_KEY_BUFF+1; start_key=key; + /* + Keys are compressed the following way: + + prefix length Packed length of prefix for the prev key. (1 or 3 bytes) + for each key segment: + [is null] Null indicator if can be null (1 byte, zero means null) + [length] Packed length if varlength (1 or 3 bytes) + pointer Reference to the data file (last_keyseg->length). + */ get_key_length(length,page); if (length) { if (length > keyinfo->maxlength) { - DBUG_PRINT("error",("Found too long binary packed key: %u of %u at %p", - length, keyinfo->maxlength, *page_pos)); + DBUG_PRINT("error",("Found too long binary packed key: %u of %u at %lx", + length, keyinfo->maxlength, (long) *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; - return 0; /* Wrong key */ + DBUG_RETURN(0); /* Wrong key */ } from=key; from_end=key+length; } @@ -973,9 +984,9 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, length-=tmp; from=page; from_end=page_end; } - DBUG_PRINT("info",("key: %p from: %p length: %u", - key, from, length)); - memcpy_overlap((byte*) key, (byte*) from, (size_t) length); + DBUG_PRINT("info",("key: %lx from: %lx length: %u", + (long) key, (long) from, length)); + memmove((byte*) key, (byte*) from, (size_t) length); key+=length; from+=length; } @@ -992,12 +1003,12 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, DBUG_PRINT("error",("Error when unpacking key")); mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; - return 0; /* Error */ + DBUG_RETURN(0); /* Error */ } memcpy((byte*) key,(byte*) from,(size_t) length); *page_pos= from+length; } - return((uint) (key-start_key)+keyseg->length); + DBUG_RETURN((uint) (key-start_key)+keyseg->length); } @@ -1031,7 +1042,8 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, } } } - DBUG_PRINT("exit",("page: %p length: %u", page, *return_key_length)); + DBUG_PRINT("exit",("page: %lx length: %u", (long) page, + *return_key_length)); DBUG_RETURN(page); } /* _mi_get_key */ @@ -1083,7 +1095,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uint nod_flag; uchar *lastpos; DBUG_ENTER("_mi_get_last_key"); - DBUG_PRINT("enter",("page: %p endpos: %p", page, endpos)); + DBUG_PRINT("enter",("page: %lx endpos: %lx", (long) page, (long) endpos)); nod_flag=mi_test_if_nod(page); if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY))) @@ -1103,14 +1115,16 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey); if (*return_key_length == 0) { - DBUG_PRINT("error",("Couldn't find last key: page: %p", page)); + DBUG_PRINT("error",("Couldn't find last key: page: %lx", + (long) page)); mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } } } - DBUG_PRINT("exit",("lastpos: %p length: %u", lastpos, *return_key_length)); + DBUG_PRINT("exit",("lastpos: %lx length: %u", (long) lastpos, + *return_key_length)); DBUG_RETURN(lastpos); } /* _mi_get_last_key */ @@ -1649,7 +1663,8 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, ref_length=0; next_length_pack=0; } - DBUG_PRINT("test",("length: %d next_key: %p", length, next_key)); + DBUG_PRINT("test",("length: %d next_key: %lx", length, + (long) next_key)); { uint tmp_length; diff --git a/myisam/mi_static.c b/myisam/mi_static.c index 4c9d814f7d6..fc585eb5543 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -27,7 +27,7 @@ LIST *myisam_open_list=0; uchar NEAR myisam_file_magic[]= { (uchar) 254, (uchar) 254,'\007', '\001', }; uchar NEAR myisam_pack_file_magic[]= -{ (uchar) 254, (uchar) 254,'\010', '\001', }; +{ (uchar) 254, (uchar) 254,'\010', '\002', }; my_string myisam_log_filename=(char*) "myisam.log"; File myisam_log_file= -1; uint myisam_quick_table_bits=9; diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c index 5727c699469..60225ccc7f3 100644 --- a/myisam/mi_test1.c +++ b/myisam/mi_test1.c @@ -237,7 +237,7 @@ static int run_test(const char *filename) pos=HA_OFFSET_ERROR; } if (found != row_count) - printf("Found %ld of %ld rows\n", found,row_count); + printf("Found %ld of %ld rows\n", (ulong) found, (ulong) row_count); } if (!silent) @@ -303,7 +303,8 @@ static int run_test(const char *filename) if ((error=mi_rrnd(file,read_record,i == 1 ? 0L : HA_OFFSET_ERROR)) == -1) { if (found != row_count-deleted) - printf("Found only %ld of %ld rows\n",found,row_count-deleted); + printf("Found only %ld of %ld rows\n", (ulong) found, + (ulong) (row_count - deleted)); break; } if (!error) diff --git a/myisam/mi_test2.c b/myisam/mi_test2.c index 95c8ce56a13..6a6dcb971a2 100644 --- a/myisam/mi_test2.c +++ b/myisam/mi_test2.c @@ -831,17 +831,19 @@ end: puts("Locking used"); if (use_blob) puts("blobs used"); -#if 0 printf("key cache status: \n\ blocks used:%10lu\n\ +not flushed:%10lu\n\ w_requests: %10lu\n\ writes: %10lu\n\ r_requests: %10lu\n\ reads: %10lu\n", - my_blocks_used, - my_cache_w_requests, my_cache_write, - my_cache_r_requests, my_cache_read); -#endif + dflt_key_cache->blocks_used, + dflt_key_cache->global_blocks_changed, + (ulong) dflt_key_cache->global_cache_w_requests, + (ulong) dflt_key_cache->global_cache_write, + (ulong) dflt_key_cache->global_cache_r_requests, + (ulong) dflt_key_cache->global_cache_read); } end_key_cache(dflt_key_cache,1); if (blob_buffer) diff --git a/myisam/mi_update.c b/myisam/mi_update.c index ab23f2e6da9..86652996afe 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -162,7 +162,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) if (auto_key_changed) update_auto_increment(info,newrec); if (share->calc_checksum) - share->state.checksum+=(info->checksum - old_checksum); + info->state->checksum+=(info->checksum - old_checksum); info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV | key_changed); diff --git a/myisam/mi_write.c b/myisam/mi_write.c index c8f9aa84a41..8785adae9a2 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -142,7 +142,7 @@ int mi_write(MI_INFO *info, byte *record) { if ((*share->write_record)(info,record)) goto err; - share->state.checksum+=info->checksum; + info->state->checksum+=info->checksum; } if (share->base.auto_key) update_auto_increment(info,record); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 78ae756bf7c..a90495e5fcb 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -67,6 +67,7 @@ static const char *field_pack[]= "no zeros", "blob", "constant", "table-lockup", "always zero","varchar","unique-hash","?","?"}; +static const char *myisam_stats_method_str="nulls_unequal"; static void get_options(int *argc,char * * *argv); static void print_version(void); @@ -155,7 +156,7 @@ enum options_mc { OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE, OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN, OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE, - OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE + OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD }; static struct my_option my_long_options[] = @@ -336,6 +337,11 @@ static struct my_option my_long_options[] = "Use stopwords from this file instead of built-in list.", (gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"stats_method", OPT_STATS_METHOD, + "Specifies how index statistics collection code should threat NULLs. " + "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).", + (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -465,6 +471,12 @@ static void usage(void) #include <help_end.h> +const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal", + NullS}; +TYPELIB myisam_stats_method_typelib= { + array_elements(myisam_stats_method_names) - 1, "", + myisam_stats_method_names, NULL}; + /* Read options */ static my_bool @@ -684,6 +696,18 @@ get_one_option(int optid, else check_param.testflag|= T_CALC_CHECKSUM; break; + case OPT_STATS_METHOD: + { + int method; + myisam_stats_method_str= argument; + if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0) + { + fprintf(stderr, "Invalid value of stats_method: %s.\n", argument); + exit(1); + } + check_param.stats_method= (enum_mi_stats_method) (method-1); + break; + } #ifdef DEBUG /* Only useful if debugging */ case OPT_START_CHECK_POS: check_param.start_check_pos= strtoull(argument, NULL, 0); @@ -1237,7 +1261,7 @@ static void descript(MI_CHECK *param, register MI_INFO *info, my_string name) share->base.raid_chunksize); } if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) - printf("Checksum: %23s\n",llstr(info->s->state.checksum,llbuff)); + printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff)); ; if (share->options & HA_OPTION_DELAY_KEY_WRITE) printf("Keys are only flushed at close\n"); @@ -1552,7 +1576,7 @@ static int mi_sort_records(MI_CHECK *param, old_record_count=info->state->records; info->state->records=0; if (sort_info.new_data_file_type != COMPRESSED_RECORD) - share->state.checksum=0; + info->state->checksum=0; if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key], temp_buff, sort_key,new_file,update_index) || diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 74463ec065a..36328c9d9f1 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -38,6 +38,7 @@ typedef struct st_mi_status_info my_off_t key_empty; /* lost space in indexfile */ my_off_t key_file_length; my_off_t data_file_length; + ha_checksum checksum; } MI_STATUS_INFO; typedef struct st_mi_state_info @@ -75,7 +76,6 @@ typedef struct st_mi_state_info ulong sec_index_changed; /* Updated when new sec_index */ ulong sec_index_used; /* which extra index are in use */ ulonglong key_map; /* Which keys are in use */ - ha_checksum checksum; ulong version; /* timestamp of create */ time_t create_time; /* Time when created database */ time_t recover_time; /* Time for last recover */ @@ -149,6 +149,7 @@ typedef struct st_mi_blob /* Info of record */ typedef struct st_mi_isam_pack { ulong header_length; uint ref_length; + uchar version; } MI_PACK; @@ -260,6 +261,7 @@ struct st_myisam_info { uint last_rkey_length; /* Last length in mi_rkey() */ enum ha_rkey_function last_key_func; /* CONTAIN, OVERLAP, etc */ uint save_lastkey_length; + uint pack_key_length; /* For MYISAMMRG */ int errkey; /* Got last error on this key */ int lock_type; /* How database was locked */ int tmp_lock_type; /* When locked by readinfo */ @@ -673,13 +675,15 @@ extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info, extern void mi_report_error(int errcode, const char *file_name); extern my_bool _mi_memmap_file(MI_INFO *info); extern void _mi_unmap_file(MI_INFO *info); -extern uint save_pack_length(byte *block_buff,ulong length); +extern uint save_pack_length(uint version, byte *block_buff, ulong length); +extern uint read_pack_length(uint version, const uchar *buf, ulong *length); +extern uint calc_pack_length(uint version, ulong length); uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite); -char *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state); +uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state); uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead); uint mi_base_info_write(File file, MI_BASE_INFO *base); -char *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base); +uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base); int mi_keyseg_write(File file, const HA_KEYSEG *keyseg); char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg); uint mi_keydef_write(File file, MI_KEYDEF *keydef); @@ -724,7 +728,7 @@ int flush_pending_blocks(MI_SORT_PARAM *param); int sort_ft_buf_flush(MI_SORT_PARAM *sort_param); int thr_write_keys(MI_SORT_PARAM *sort_param); #ifdef THREAD -pthread_handler_decl(thr_find_all_keys,arg); +pthread_handler_t thr_find_all_keys(void *arg); #endif int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index b8f21392f8a..114e80d8f1a 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -2008,7 +2008,7 @@ static char *hexdigits(ulonglong value) static int write_header(PACK_MRG_INFO *mrg,uint head_length,uint trees, my_off_t tot_elements,my_off_t filelength) { - byte *buff=file_buffer.pos; + byte *buff= (byte*) file_buffer.pos; bzero(buff,HEAD_LENGTH); memcpy_fixed(buff,myisam_pack_file_magic,4); @@ -2024,7 +2024,7 @@ static int write_header(PACK_MRG_INFO *mrg,uint head_length,uint trees, if (test_only) return 0; VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0))); - return my_write(file_buffer.file,file_buffer.pos,HEAD_LENGTH, + return my_write(file_buffer.file,(const byte *) file_buffer.pos,HEAD_LENGTH, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0; } @@ -2417,6 +2417,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) HUFF_COUNTS *count,*end_count; HUFF_TREE *tree; MI_INFO *isam_file=mrg->file[0]; + uint pack_version= (uint) isam_file->s->pack.version; DBUG_ENTER("compress_isam_file"); /* Allocate a buffer for the records (excluding blobs). */ @@ -2455,25 +2456,11 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) huff_counts[i].tree->height+huff_counts[i].length_bits; } max_calc_length= (max_calc_length + 7) / 8; - if (max_calc_length < 254) - pack_ref_length=1; - else if (max_calc_length <= 65535) - pack_ref_length=3; - else - pack_ref_length=4; - + pack_ref_length= calc_pack_length(pack_version, max_calc_length); record_count=0; /* 'max_blob_length' is the max length of all blobs of a record. */ - pack_blob_length=0; - if (isam_file->s->base.blobs) - { - if (mrg->max_blob_length < 254) - pack_blob_length=1; - else if (mrg->max_blob_length <= 65535) - pack_blob_length=3; - else - pack_blob_length=4; - } + pack_blob_length= isam_file->s->base.blobs ? + calc_pack_length(pack_version, mrg->max_blob_length) : 0; max_pack_length=pack_ref_length+pack_blob_length; DBUG_PRINT("fields", ("===")); @@ -2485,7 +2472,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) { if (flush_buffer((ulong) max_calc_length + (ulong) max_pack_length)) break; - record_pos=file_buffer.pos; + record_pos= (byte*) file_buffer.pos; file_buffer.pos+=max_pack_length; for (start_pos=record, count= huff_counts; count < end_count ; count++) { @@ -2746,9 +2733,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) } flush_bits(); length=(ulong) ((byte*) file_buffer.pos - record_pos) - max_pack_length; - pack_length=save_pack_length(record_pos,length); + pack_length= save_pack_length(pack_version, record_pos, length); if (pack_blob_length) - pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length); + pack_length+= save_pack_length(pack_version, record_pos + pack_length, + tot_blob_length); DBUG_PRINT("fields", ("record: %lu length: %lu blob-length: %lu " "length-bytes: %lu", (ulong) record_count, length, tot_blob_length, pack_length)); @@ -2807,7 +2795,8 @@ static char *make_old_name(char *new_name, char *old_name) static void init_file_buffer(File file, pbool read_buffer) { file_buffer.file=file; - file_buffer.buffer=my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),MYF(MY_WME)); + file_buffer.buffer= (uchar*) my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE), + MYF(MY_WME)); file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-8; file_buffer.pos_in_file=0; error_on_write=0; @@ -2849,7 +2838,8 @@ static int flush_buffer(ulong neaded_length) file_buffer.pos_in_file+=length; if (test_only) return 0; - if (error_on_write|| my_write(file_buffer.file,file_buffer.buffer, + if (error_on_write|| my_write(file_buffer.file, + (const byte*) file_buffer.buffer, length, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL))) { @@ -2862,13 +2852,13 @@ static int flush_buffer(ulong neaded_length) { char *tmp; neaded_length+=256; /* some margin */ - tmp=my_realloc(file_buffer.buffer, neaded_length,MYF(MY_WME)); + tmp= my_realloc((char*) file_buffer.buffer, neaded_length,MYF(MY_WME)); if (!tmp) return 1; file_buffer.pos= ((uchar*) tmp + (ulong) (file_buffer.pos - file_buffer.buffer)); - file_buffer.buffer=tmp; - file_buffer.end=tmp+neaded_length-8; + file_buffer.buffer= (uchar*) tmp; + file_buffer.end= (uchar*) (tmp+neaded_length-8); } return 0; } @@ -2977,7 +2967,7 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->state.key_root[key]= HA_OFFSET_ERROR; for (key=0 ; key < share->state.header.max_block_size ; key++) share->state.key_del[key]= HA_OFFSET_ERROR; - share->state.checksum=crc; /* Save crc here */ + isam_file->state->checksum=crc; /* Save crc here */ share->changed=1; /* Force write of header */ share->state.open_count=0; share->global_changed=0; @@ -3013,7 +3003,7 @@ static int save_state_mrg(File file,PACK_MRG_INFO *mrg,my_off_t new_length, state.dellink= HA_OFFSET_ERROR; state.version=(ulong) time((time_t*) 0); mi_clear_all_keys_active(state.key_map); - state.checksum=crc; + state.state.checksum=crc; if (isam_file->s->base.keys) isamchk_neaded=1; state.changed=STATE_CHANGED | STATE_NOT_ANALYZED; /* Force check of table */ diff --git a/myisam/sort.c b/myisam/sort.c index fabd713ef45..6c718a0d453 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -307,7 +307,7 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys, #ifdef THREAD /* Search after all keys and place them in a temp. file */ -pthread_handler_decl(thr_find_all_keys,arg) +pthread_handler_t thr_find_all_keys(void *arg) { MI_SORT_PARAM *info= (MI_SORT_PARAM*) arg; int error; diff --git a/myisam/sp_key.c b/myisam/sp_key.c index 1d43f89cba9..77cecdc0931 100644 --- a/myisam/sp_key.c +++ b/myisam/sp_key.c @@ -142,7 +142,7 @@ static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims, { if ((*wkb) > end - 8) return -1; - get_double(&ord, *wkb); + get_double(&ord, (const byte*) *wkb); (*wkb)+= 8; if (ord < *mbr) float8store((char*) mbr, ord); diff --git a/myisammrg/myrg_rkey.c b/myisammrg/myrg_rkey.c index a85ef6a3b5e..f87b264081e 100644 --- a/myisammrg/myrg_rkey.c +++ b/myisammrg/myrg_rkey.c @@ -44,11 +44,12 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, MYRG_TABLE *table; MI_INFO *mi; int err; + DBUG_ENTER("myrg_rkey"); LINT_INIT(key_buff); LINT_INIT(pack_key_length); if (_myrg_init_queue(info,inx,search_flag)) - return my_errno; + DBUG_RETURN(my_errno); for (table=info->open_tables ; table != info->end_table ; table++) { @@ -57,8 +58,9 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, if (table == info->open_tables) { err=mi_rkey(mi,0,inx,key,key_len,search_flag); + /* Get the saved packed key and packed key length. */ key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length; - pack_key_length=mi->last_rkey_length; + pack_key_length=mi->pack_key_length; } else { @@ -71,17 +73,22 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, { if (err == HA_ERR_KEY_NOT_FOUND) continue; - return err; + DBUG_PRINT("exit", ("err: %d", err)); + DBUG_RETURN(err); } /* adding to queue */ queue_insert(&(info->by_key),(byte *)table); } + DBUG_PRINT("info", ("tables with matches: %u", info->by_key.elements)); if (!info->by_key.elements) - return HA_ERR_KEY_NOT_FOUND; + DBUG_RETURN(HA_ERR_KEY_NOT_FOUND); mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table; mi->once_flags|= RRND_PRESERVE_LASTINX; - return _myrg_mi_read_record(mi,buf); + DBUG_PRINT("info", ("using table no: %d", + info->current_table - info->open_tables + 1)); + DBUG_DUMP("result key", (byte*) mi->lastkey, mi->lastkey_length); + DBUG_RETURN(_myrg_mi_read_record(mi,buf)); } diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 9b0db5774f5..f1194d7fc2f 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -53,7 +53,8 @@ dist-hook: -$(INSTALL_DATA) $(srcdir)/t/*.imtest $(distdir)/t $(INSTALL_DATA) $(srcdir)/t/*.sql $(distdir)/t -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t - $(INSTALL_DATA) $(srcdir)/t/*.opt $(srcdir)/t/*.sh $(srcdir)/t/*.slave-mi $(distdir)/t + $(INSTALL_DATA) $(srcdir)/t/*.opt $(srcdir)/t/*.slave-mi $(distdir)/t + $(INSTALL_SCRIPT) $(srcdir)/t/*.sh $(distdir)/t $(INSTALL_DATA) $(srcdir)/include/*.inc $(distdir)/include $(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data @@ -61,6 +62,7 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(distdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(distdir)/lib @@ -78,7 +80,7 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/t/*.sql $(DESTDIR)$(testdir)/t -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t $(INSTALL_DATA) $(srcdir)/t/*.opt $(DESTDIR)$(testdir)/t - $(INSTALL_DATA) $(srcdir)/t/*.sh $(DESTDIR)$(testdir)/t + $(INSTALL_SCRIPT) $(srcdir)/t/*.sh $(DESTDIR)$(testdir)/t $(INSTALL_DATA) $(srcdir)/t/*.slave-mi $(DESTDIR)$(testdir)/t $(INSTALL_DATA) $(srcdir)/r/*.result $(DESTDIR)$(testdir)/r $(INSTALL_DATA) $(srcdir)/r/*.require $(DESTDIR)$(testdir)/r @@ -89,6 +91,7 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib diff --git a/mysql-test/README.stress b/mysql-test/README.stress new file mode 100644 index 00000000000..001ecceef1b --- /dev/null +++ b/mysql-test/README.stress @@ -0,0 +1,116 @@ + +Overview +-------- + +Stress script is designed to perform testsing of mysql server in +multi-thread environment. + +Stress script allows: + + - to use for stress testing mysqltest binary as test engine + - to use for stress testing both regular test suite and any + additional test suites (e.g. mysql-test-extra-5.0) + - to specify files with lists of tests both for initialization of + stress db and for further testing itself + - to define number of threads that will be concurrently used in testing + - to define limitations for test run. e.g. number of tests or loops + for execution or duration of testing, delay between test executions, etc. + - to get readable log file which can be used for identification of + errors arose during testing + +All functionality regarding stress testing was implemeted in +mysql-stress-test.pl script and there are two ways to run stress test: + + - for most cases it is enough to use options below for starting of + stress test from mysql-test-run wrapper. In this case server will + be run automatically, all preparation steps will be performed + and after that stress test will be started. + + - in advanced case one can run mysql-stress-test.pl script directly. + But it requires to perform some preparation steps and to specify a + bunch of options as well so this way may look a bit complicate. + +Usage +----- + +Below is list of stress test specific options for mysql-test-run: + +--stress + Enable stress mode + +--stress-suite=<suite name> + Test suite name that will be used in stress testing. + We assume that all suites are located in mysql-test/suite directory + There is one special suite name - <main|default> that corresponds + to regular test suite located in mysql-test directory. + +--stress-threads=<number of threads> + Number of threads that will be used in stress testing + +--stress-tests-file=<filename with list of tests> + Filename with list of tests(without .test suffix) that will be used in + stress testing. Default filename is stress_tests.txt and default + location of this file is suite/<suite name>/stress_tests.txt + +--stress-init-file=<filename with list of tests> + Filename with list of tests(without .test suffix) that will be used in + stress testing for initialization of stress db. These tests will be + executed only once before starting of test itself. Default filename + is stress_init.txt and default location of this file is + suite/<suite name>/stress_init.txt + +--stress-mode=<method which will be used for choosing tests from the list> + Possible values are: random(default), seq + + There are two possible modes which affect order of selecting of tests + from the list: + - in random mode tests will be selected in random order + - in seq mode each thread will execute tests in the loop one by one as + they specified in the list file. + +--stress-test-count= <number> + Total number of tests that will be executed concurrently by all threads + +--stress-loop-count= <number> + Total number of loops in seq mode that will be executed concurrently + by all threads + +--stress-test-duration= <number> + Duration of stress testing in seconds + +Examples +-------- + +1. Example of simple command line to start stress test: + + mysql-test-run --stress alias + +Runs stress test with default values for number of threads and number of tests, +with test 'alias' from suite 'main'. + +2. Using in stress testing tests from other suites: + + - mysql-test-run --stress --stress-threads=10 --stress-test-count=1000 \ + --stress-suite=example --stress-tests-file=testslist.txt + + Will run stress test with 10 threads, will execute 1000 tests by all + threads, test will be used from suite 'example', list of test will be + taken from file 'testslist.txt' + + - mysql-test-run --stress --stress-threads=10 --stress-test-count=1000 \ + --stress-suite=example sum_distinct + + Will run stress test with 10 threads, will execute 1000 tests by all + threads, test will be used from suite 'example', list of test contains + only one test 'sum_distinct' + +3. Debugging of issues found with stress test + + Right now stress test is not fully integrated in mysql-test-run + and does not support --gdb option so to debug issue found with stress + test you have to start separately mysql server under debuger and then + run stress test as: + + - mysql-test-run --extern --stress --stress-threads=10 \ + --stress-test-count=1000 --stress-suite=example \ + sum_distinct diff --git a/mysql-test/include/ctype_like_escape.inc b/mysql-test/include/ctype_like_escape.inc new file mode 100644 index 00000000000..ac97fbaa1a0 --- /dev/null +++ b/mysql-test/include/ctype_like_escape.inc @@ -0,0 +1,18 @@ +# +# Bugs: #13046: +# LIKE pattern matching using prefix index doesn't return correct result +# +select @@collation_connection; +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +-- should return ab_def +select c1 as c1u from t1 where c1 like 'ab\_def'; +-- should return ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +drop table t1; diff --git a/mysql-test/include/have_lowercase0.inc b/mysql-test/include/have_lowercase0.inc index f967c18928b..8d3ae02f61e 100644 --- a/mysql-test/include/have_lowercase0.inc +++ b/mysql-test/include/have_lowercase0.inc @@ -1,4 +1,4 @@ --require r/lowercase0.require ---disable_query_log; +--disable_query_log show variables like "lower_case_%"; ---enable_query_log; +--enable_query_log diff --git a/mysql-test/include/im_check_os.inc b/mysql-test/include/im_check_os.inc new file mode 100644 index 00000000000..9465115feb5 --- /dev/null +++ b/mysql-test/include/im_check_os.inc @@ -0,0 +1,7 @@ +--connect (dflt_server_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK) +--connection dflt_server_con + +--source include/not_windows.inc + +--connection default +--disconnect dflt_server_con diff --git a/mysql-test/include/mysqltest-x.inc b/mysql-test/include/mysqltest-x.inc new file mode 100644 index 00000000000..dd1468aed07 --- /dev/null +++ b/mysql-test/include/mysqltest-x.inc @@ -0,0 +1,2 @@ +echo Output from mysqltest-x.inc; + diff --git a/mysql-test/include/mysqltest_while.inc b/mysql-test/include/mysqltest_while.inc new file mode 100644 index 00000000000..90b05ee2695 --- /dev/null +++ b/mysql-test/include/mysqltest_while.inc @@ -0,0 +1,137 @@ +let $1 = 10; +while ($1) +{ +while ($1) +{ +while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + echo $1; + dec $1; +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index 37353e5974f..fd7b035e038 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -62,7 +62,7 @@ comment='Host privileges; Merged with database privileges'; CREATE TABLE user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, - Password char(41) binary DEFAULT '' NOT NULL, + Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 250c3562227..fb622f2bbb3 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -61,22 +61,6 @@ sub collect_test_cases ($) { $elem= $tname; $tname =~ s/\.imtest$//; $component_id= 'im'; - - if ( $::glob_use_embedded_server ) - { - mtr_report( - "Instance Manager's tests are not available in embedded mode." . - "Test case '$tname' is skipped."); - next; - } - - unless ( $::exe_im ) - { - mtr_report( - "Instance Manager executable is unavailable. " . - "Test case '$tname' is skipped."); - next; - } } # If target component is known, check that the specified test case @@ -84,7 +68,7 @@ sub collect_test_cases ($) { # # Otherwise, try to guess the target component. - if ( defined $component_id ) + if ( $component_id ) { if ( ! -f "$testdir/$elem") { @@ -96,11 +80,11 @@ sub collect_test_cases ($) { my $mysqld_test_exists = -f "$testdir/$tname.test"; my $im_test_exists = -f "$testdir/$tname.imtest"; - if ( $mysqld_test_exists && $im_test_exists ) + if ( $mysqld_test_exists and $im_test_exists ) { mtr_error("Ambiguos test case name ($tname)"); } - elsif ( ! $mysqld_test_exists && !$im_test_exists ) + elsif ( ! $mysqld_test_exists and ! $im_test_exists ) { mtr_error("Test case $tname is not found"); } @@ -115,7 +99,7 @@ sub collect_test_cases ($) { $component_id= 'im'; } } - + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,{}, $component_id); } @@ -403,6 +387,34 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'comment'}= mtr_fromfile($disabled_file); } + if ( $component_id eq 'im' ) + { + if ( $::glob_use_embedded_server ) + { + $tinfo->{'skip'}= 1; + + mtr_report( + "Instance Manager tests are not available in embedded mode. " . + "Test case '$tname' is skipped."); + } + elsif ( $::opt_ps_protocol ) + { + $tinfo->{'skip'}= 1; + + mtr_report( + "Instance Manager tests are not run with --ps-protocol. " . + "Test case '$tname' is skipped."); + } + elsif ( $::opt_skip_im ) + { + $tinfo->{'skip'}= 1; + + mtr_report( + "Instance Manager executable is unavailable." . + "Test case '$tname' is skipped."); + } + } + # We can't restart a running server that may be in use if ( $::glob_use_running_server and diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 1b6dcf0e7fc..b3a243444c1 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -166,7 +166,7 @@ sub spawn_impl ($$$$$$$$) { { if ( ! open(STDOUT,$log_file_open_mode,$output) ) { - mtr_error("can't redirect STDOUT to \"$output\": $!"); + mtr_child_error("can't redirect STDOUT to \"$output\": $!"); } } @@ -176,14 +176,14 @@ sub spawn_impl ($$$$$$$$) { { if ( ! open(STDERR,">&STDOUT") ) { - mtr_error("can't dup STDOUT: $!"); + mtr_child_error("can't dup STDOUT: $!"); } } else { if ( ! open(STDERR,$log_file_open_mode,$error) ) { - mtr_error("can't redirect STDERR to \"$output\": $!"); + mtr_child_error("can't redirect STDERR to \"$error\": $!"); } } } @@ -192,13 +192,13 @@ sub spawn_impl ($$$$$$$$) { { if ( ! open(STDIN,"<",$input) ) { - mtr_error("can't redirect STDIN to \"$input\": $!"); + mtr_child_error("can't redirect STDIN to \"$input\": $!"); } } if ( ! exec($path,@$arg_list_t) ) { - mtr_error("failed to execute \"$path\": $!"); + mtr_child_error("failed to execute \"$path\": $!"); } } } @@ -360,6 +360,7 @@ sub mtr_kill_leftovers () { # First, kill all masters and slaves that would conflict with # this run. Make sure to remove the PID file, if any. + # FIXME kill IM manager first, else it will restart the servers, how?! my @args; @@ -367,6 +368,16 @@ sub mtr_kill_leftovers () { { push(@args,{ pid => 0, # We don't know the PID + pidfile => $::instance_manager->{'instances'}->[$idx]->{'path_pid'}, + sockfile => $::instance_manager->{'instances'}->[$idx]->{'path_sock'}, + port => $::instance_manager->{'instances'}->[$idx]->{'port'}, + }); + } + + for ( my $idx; $idx < 2; $idx++ ) + { + push(@args,{ + pid => 0, # We don't know the PID pidfile => $::master->[$idx]->{'path_mypid'}, sockfile => $::master->[$idx]->{'path_mysock'}, port => $::master->[$idx]->{'path_myport'}, @@ -560,8 +571,8 @@ sub mtr_stop_mysqld_servers ($) { start_reap_all(); # Avoid zombies - SIGNAL: - mtr_kill_processes(\keys (%mysqld_pids)); + my @mysqld_pids= keys %mysqld_pids; + mtr_kill_processes(\@mysqld_pids); stop_reap_all(); # Get into control again @@ -680,7 +691,8 @@ sub mtr_mysqladmin_shutdown { mtr_add_arg($args, "shutdown"); # We don't wait for termination of mysqladmin my $pid= mtr_spawn($::exe_mysqladmin, $args, - "", $::path_manager_log, $::path_manager_log, ""); + "", $::path_manager_log, $::path_manager_log, "", + { append_log_file => 1 }); $mysql_admin_pids{$pid}= 1; } @@ -847,14 +859,16 @@ sub sleep_until_file_created ($$$) { sub mtr_kill_processes ($) { my $pids = shift; - foreach my $sig (15,9) + foreach my $sig (15, 9) { - my $retries= 20; # FIXME 20 seconds, this is silly! - kill($sig, @{$pids}); - while ( $retries-- and kill(0, @{$pids}) ) + my $retries= 10; + while (1) { - mtr_debug("Sleep 1 second waiting for processes to die"); - sleep(1) # Wait one second + kill($sig, @{$pids}); + last unless kill (0, @{$pids}) and $retries--; + + mtr_debug("Sleep 2 second waiting for processes to die"); + sleep(2); } } } diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 868653afaa4..515988ee5c7 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -19,6 +19,7 @@ sub mtr_print_header (); sub mtr_report (@); sub mtr_warning (@); sub mtr_error (@); +sub mtr_child_error (@); sub mtr_debug (@); @@ -74,7 +75,7 @@ sub mtr_show_failed_diff ($) { sub mtr_report_test_name ($) { my $tinfo= shift; - printf "%-31s ", $tinfo->{'name'}; + printf "%-30s ", $tinfo->{'name'}; } sub mtr_report_test_skipped ($) { @@ -122,13 +123,13 @@ sub mtr_report_test_failed ($) { # we should write out into $::path_timefile when the error occurs. if ( -f $::path_timefile ) { - print "Errors are (from $::path_timefile) :\n"; + print "\nErrors are (from $::path_timefile) :\n"; print mtr_fromfile($::path_timefile); # FIXME print_file() instead print "\n(the last lines may be the most important ones)\n"; } else { - print "Unexpected termination, probably when starting mysqld\n"; + print "\nUnexpected termination, probably when starting mysqld\n"; } } @@ -256,11 +257,11 @@ sub mtr_print_header () { print "\n"; if ( $::opt_timer ) { - print "TEST RESULT TIME (ms)\n"; + print "TEST RESULT TIME (ms)\n"; } else { - print "TEST RESULT\n"; + print "TEST RESULT\n"; } mtr_print_line(); print "\n"; @@ -286,6 +287,11 @@ sub mtr_error (@) { mtr_exit(1); } +sub mtr_child_error (@) { + print STDERR "mysql-test-run: *** ERROR(child): ",join(" ", @_),"\n"; + exit(1); +} + sub mtr_debug (@) { if ( $::opt_script_debug ) { diff --git a/mysql-test/my_manage.c b/mysql-test/my_manage.c index 88e68dfc27e..919d3bd0529 100644 --- a/mysql-test/my_manage.c +++ b/mysql-test/my_manage.c @@ -230,7 +230,10 @@ int wait_for_server_start(char *bin_dir __attribute__((unused)), char *user, char *password, int port,char *tmp_dir) { arg_list_t al; - int err= 0, i; + int err= 0; +#ifndef __WIN__ + int i; +#endif char trash[FN_REFLEN]; /* mysqladmin file */ diff --git a/mysql-test/mysql-stress-test.pl b/mysql-test/mysql-stress-test.pl new file mode 100755 index 00000000000..899dd06a746 --- /dev/null +++ b/mysql-test/mysql-stress-test.pl @@ -0,0 +1,1148 @@ +#!/usr/bin/perl +# ====================================================================== +# MySQL server stress test system +# ====================================================================== +# +########################################################################## +# +# SCENARIOS AND REQUIREMENTS +# +# The system should perform stress testing of MySQL server with +# following requirements and basic scenarios: +# +# Basic requirements: +# +# Design of stress script should allow one: +# +# - to use for stress testing mysqltest binary as test engine +# - to use for stress testing both regular test suite and any +# additional test suites (e.g. mysql-test-extra-5.0) +# - to specify files with lists of tests both for initialization of +# stress db and for further testing itself +# - to define number of threads that will be concurrently used in testing +# - to define limitations for test run. e.g. number of tests or loops +# for execution or duration of testing, delay between test executions, etc. +# - to get readable log file which can be used for identification of +# errors arose during testing +# +# Basic scenarios: +# +# * It should be possible to run stress script in standalone mode +# which will allow to create various scenarios of stress workloads: +# +# simple ones: +# +# box #1: +# - one instance of script with list of tests #1 +# +# and more advanced ones: +# +# box #1: +# - one instance of script with list of tests #1 +# - another instance of script with list of tests #2 +# box #2: +# - one instance of script with list of tests #3 +# - another instance of script with list of tests #4 +# that will recreate whole database to back it to clean +# state +# +# One kind of such complex scenarios maybe continued testing +# when we want to run stress tests from many boxes with various +# lists of tests that will last very long time. And in such case +# we need some wrapper for MySQL server that will restart it in +# case of crashes. +# +# * It should be possible to run stress script in ad-hoc mode from +# shell or perl versions of mysql-test-run. This allows developers +# to reproduce and debug errors that was found in continued stress +# testing +# +######################################################################## + +use Config; + +if (!defined($Config{useithreads})) +{ + die <<EOF; +It is unable to run threaded version of stress test on this system +due to disabled ithreads. Please check that installed perl binary +was built with support of ithreads. +EOF +} + +use threads; +use threads::shared; + +use IO::Socket; +use Sys::Hostname; +use File::Copy; +use File::Spec; +use File::Find; +use File::Basename; +use File::Path; +use Cwd; + +use Data::Dumper; +use Getopt::Long; + +my $stress_suite_version="1.0"; + +$|=1; + +$opt_server_host=""; +$opt_server_logs_dir=""; +$opt_help=""; +$opt_server_port=""; +$opt_server_socket=""; +$opt_server_user=""; +$opt_server_password=""; +$opt_server_database=""; +$opt_cleanup=""; +$opt_verbose=""; +$opt_log_error_details=""; + + +$opt_suite="main"; +$opt_stress_suite_basedir=""; +$opt_stress_basedir=""; +$opt_stress_datadir=""; +$opt_test_suffix=""; + +$opt_stress_mode="random"; + +$opt_loop_count=0; +$opt_test_count=0; +$opt_test_duration=0; +$opt_abort_on_error=0; +$opt_sleep_time = 0; +$opt_threads=1; +$pid_file="mysql_stress_test.pid"; +$opt_mysqltest= ($^O =~ /mswin32/i) ? "mysqltest.exe" : "mysqltest"; +$opt_check_tests_file=""; +@mysqltest_args=("--silent", "-v", "--skip-safemalloc"); + +# Client ip address +$client_ip=inet_ntoa((gethostbyname(hostname()))[4]); +$client_ip=~ s/\.//g; + +%tests_files=(client => {mtime => 0, data => []}, + initdb => {mtime => 0, data => []}); + +# Error codes and sub-strings with corresponding severity +# +# S1 - Critical errors - cause immediately abort of testing. These errors +# could be caused by server crash or impossibility +# of test execution +# +# S2 - Serious errors - these errors are bugs for sure as it knowns that +# they shouldn't appear during stress testing +# +# S3 - Non-seriuos errros - these errors could be caused by fact that +# we execute simultaneously statements that +# affect tests executed by other threads + +%error_strings = ( 'Failed in mysql_real_connect()' => S1, + 'not found (Errcode: 2)' => S1 ); + +%error_codes = ( 1012 => S2, 1015 => S2, 1021 => S2, + 1027 => S2, 1037 => S2, 1038 => S2, + 1039 => S2, 1040 => S2, 1046 => S2, + 1180 => S2, 1181 => S2, 1203 => S2, + 1205 => S2, 1206 => S2, 1207 => S2, + 1223 => S2, 2013 => S1); + +share(%test_counters); +%test_counters=( loop_count => 0, test_count=>0); + +share($exiting); +$exiting=0; + +share($test_counters_lock); +$test_counters_lock=0; +share($log_file_lock); +$log_file_lock=0; + +$SIG{INT}= \&sig_INT_handler; +$SIG{TERM}= \&sig_TERM_handler; + + +GetOptions("server-host=s", "server-logs-dir=s", "server-port=s", + "server-socket=s", "server-user=s", "server-password=s", + "server-database=s", + "stress-suite-basedir=s", "suite=s", "stress-init-file:s", + "stress-tests-file:s", "stress-basedir=s", "stress-mode=s", + "stress-datadir=s", + "threads=s", "sleep-time=s", "loop-count=i", "test-count=i", + "test-duration=i", "test-suffix=s", "check-tests-file", + "verbose", "log-error-details", "cleanup", "mysqltest=s", + "abort-on-error", "help") || usage(); + +usage() if ($opt_help); + +#$opt_abort_on_error=1; + +$test_dirname=get_timestamp(); +$test_dirname.="-$opt_test_suffix" if ($opt_test_suffix ne ''); + +print <<EOF; +############################################################# + CONFIGURATION STAGE +############################################################# +EOF + +if ($opt_stress_basedir eq '' || $opt_stress_suite_basedir eq '' || + $opt_server_logs_dir eq '') +{ + die <<EOF; + +Options --stress-basedir, --stress-suite-basedir and --server-logs-dir are +required. Please use these options to specify proper basedir for +client, test suite and location of server logs. + +stress-basedir: '$opt_stress_basedir' +stress-suite-basedir: '$opt_stress_suite_basedir' +server-logs-dir: '$opt_server_logs_dir' + +EOF +} + +#Workaround for case when we got relative but not absolute path +$opt_stress_basedir=File::Spec->rel2abs($opt_stress_basedir); +$opt_stress_suite_basedir=File::Spec->rel2abs($opt_stress_suite_basedir); +$opt_server_logs_dir=File::Spec->rel2abs($opt_server_logs_dir); + +if ($opt_stress_datadir ne '') +{ + $opt_stress_datadir=File::Spec->rel2abs($opt_stress_datadir); +} + +if (! -d "$opt_stress_basedir") +{ + die <<EOF; + +Directory '$opt_stress_basedir' does not exist. +Use --stress-basedir option to specify proper basedir for client + +EOF +} + +if (!-d $opt_stress_suite_basedir) +{ + die <<EOF; + +Directory '$opt_stress_suite_basedir' does not exist. +Use --stress-suite-basedir option to specify proper basedir for test suite + +EOF +} + +$test_dataset_dir=$opt_stress_suite_basedir; +if ($opt_stress_datadir ne '') +{ + if (-d $opt_stress_datadir) + { + $test_dataset_dir=$opt_stress_datadir; + + } + else + { + die <<EOF; +Directory '$opt_stress_datadir' not exists. Please specify proper one +with --stress-datadir option. +EOF + } +} + +if ($^O =~ /mswin32/i) +{ + $test_dataset_dir=~ s/\\/\\\\/g; +} +else +{ + $test_dataset_dir.="/"; +} + + + +if (!-d $opt_server_logs_dir) +{ + die <<EOF; + +Directory server-logs-dir '$opt_server_logs_dir' does not exist. +Use --server-logs-dir option to specify proper directory for storing +logs + +EOF +} +else +{ + #Create sub-directory for test session logs + mkpath(File::Spec->catdir($opt_server_logs_dir, $test_dirname), 0, 0755); + #Define filename of global session log file + $stress_log_file=File::Spec->catfile($opt_server_logs_dir, $test_dirname, + "mysql-stress-test.log"); +} + +if ($opt_suite ne '' && $opt_suite ne 'main' && $opt_suite ne 'default') +{ + $test_suite_dir=File::Spec->catdir($opt_stress_suite_basedir, "suite", $opt_suite); +} +else +{ + $test_suite_dir= $opt_stress_suite_basedir; +} + +if (!-d $test_suite_dir) +{ + die <<EOF + +Directory '$test_suite_dir' does not exist. +Use --suite options to specify proper dir for test suite + +EOF +} + +$test_suite_t_path=File::Spec->catdir($test_suite_dir,'t'); +$test_suite_r_path=File::Spec->catdir($test_suite_dir,'r'); + +foreach my $suite_dir ($test_suite_t_path, $test_suite_r_path) +{ + if (!-d $suite_dir) + { + die <<EOF; + +Directory '$suite_dir' does not exist. +Please ensure that you specified proper source location for +test/result files with --stress-suite-basedir option and name +of test suite with --suite option + +EOF + } +} + +$test_t_path=File::Spec->catdir($opt_stress_basedir,'t'); +$test_r_path=File::Spec->catdir($opt_stress_basedir,'r'); + +foreach $test_dir ($test_t_path, $test_r_path) +{ + if (-d $test_dir) + { + if ($opt_cleanup) + { + #Delete existing 't', 'r', 'r/*' subfolders in $stress_basedir + rmtree("$test_dir", 0, 0); + print "Cleanup $test_dir\n"; + } + else + { + die <<EOF; +Directory '$test_dir' already exist. +Please ensure that you specified proper location of working dir +for current test run with --stress-basedir option or in case of staled +directories use --cleanup option to remove ones +EOF + } + } + #Create empty 't', 'r' subfolders that will be filled later + mkpath("$test_dir", 0, 0777); +} + +if (!defined($opt_stress_tests_file) && !defined($opt_stress_init_file)) +{ + die <<EOF; +You should run stress script either with --stress-tests-file or with +--stress-init-file otions. See help for details. +EOF +} + +if (defined($opt_stress_tests_file)) +{ + if ($opt_stress_tests_file eq '') + { + #Default location of file with set of tests for current test run + $tests_files{client}->{filename}= File::Spec->catfile($opt_stress_suite_basedir, + "testslist_client.txt"); + } + else + { + $tests_files{client}->{filename}= $opt_stress_tests_file; + } + + if (!-f $tests_files{client}->{filename}) + { + die <<EOF; + +File '$tests_files{client}->{filename}' with list of tests not exists. +Please ensure that this file exists, readable or specify another one with +--stress-tests-file option. + +EOF + } +} + +if (defined($opt_stress_init_file)) +{ + if ($opt_stress_init_file eq '') + { + #Default location of file with set of tests for current test run + $tests_files{initdb}->{filename}= File::Spec->catfile($opt_stress_suite_basedir, + "testslist_initdb.txt"); + } + else + { + $tests_files{initdb}->{filename}= $opt_stress_init_file; + } + + if (!-f $tests_files{initdb}->{filename}) + { + die <<EOF; + +File '$tests_files{initdb}->{filename}' with list of tests for initialization of database +for stress test not exists. +Please ensure that this file exists, readable or specify another one with +--stress-init-file option. + +EOF + } +} + +if ($opt_stress_mode !~ /^(random|seq)$/) +{ + die <<EOF +Was specified wrong --stress-mode. Correct values 'random' and 'seq'. +EOF +} + +if (open(TEST, "$opt_mysqltest -V |")) +{ + $mysqltest_version=join("",<TEST>); + close(TEST); + print "FOUND MYSQLTEST BINARY: ", $mysqltest_version,"\n"; +} +else +{ + die <<EOF; +ERROR: mysqltest binary $opt_mysqltest not found $!. +You must either specify file location explicitly using --mysqltest +option, or make sure path to mysqltest binary is listed +in your PATH environment variable. +EOF +} + +# +#Adding mysql server specific command line options for mysqltest binary +# +$opt_server_host= $opt_server_host ? $opt_server_host : "localhost"; +$opt_server_port= $opt_server_port ? $opt_server_port : "3306"; +$opt_server_user= $opt_server_user ? $opt_server_user : "root"; +$opt_server_socket= $opt_server_socket ? $opt_server_socket : "/tmp/mysql.sock"; +$opt_server_database= $opt_server_database ? $opt_server_database : "test"; + +unshift @mysqltest_args, "--host=$opt_server_host"; +unshift @mysqltest_args, "--port=$opt_server_port"; +unshift @mysqltest_args, "--user=$opt_server_user"; +unshift @mysqltest_args, "--password=$opt_server_password"; +unshift @mysqltest_args, "--socket=$opt_server_socket"; +unshift @mysqltest_args, "--database=$opt_server_database"; + +#Export variables that could be used in tests +$ENV{MYSQL_TEST_DIR}=$test_dataset_dir; +$ENV{MASTER_MYPORT}=$opt_server_port; +$ENV{MASTER_MYSOCK}=$opt_server_socket; + +print <<EOF; +TEST-SUITE-BASEDIR: $opt_stress_suite_basedir +SUITE: $opt_suite +TEST-BASE-DIR: $opt_stress_basedir +TEST-DATADIR: $test_dataset_dir +SERVER-LOGS-DIR: $opt_server_logs_dir + +THREADS: $opt_threads +TEST-MODE: $opt_stress_mode + +EOF + +#------------------------------------------------------------------------------- +#At this stage we've already checked all needed pathes/files +#and ready to start the test +#------------------------------------------------------------------------------- + +if (defined($opt_stress_tests_file) || defined($opt_stress_init_file)) +{ + print <<EOF; +############################################################# + PREPARATION STAGE +############################################################# +EOF + + #Copy Test files from network share to 't' folder + print "\nCopying Test files from $test_suite_t_path to $test_t_path folder..."; + find({wanted=>\©_test_files, bydepth=>1}, "$test_suite_t_path"); + print "Done\n"; + + #$test_r_path/r0 dir reserved for initdb + $count_start= defined($opt_stress_init_file) ? 0 : 1; + + our $r_folder=''; + print "\nCreating 'r' folder and copying Protocol files to each 'r#' sub-folder..."; + for($count=$count_start; $count <= $opt_threads; $count++) + { + $r_folder = File::Spec->catdir($test_r_path, "r".$count); + mkpath("$r_folder", 0, 0777); + + find(\©_result_files,"$test_suite_r_path"); + } + print "Done\n\n"; +} + +if (defined($opt_stress_init_file)) +{ + print <<EOF; +############################################################# + INITIALIZATION STAGE +############################################################# +EOF + + #Set limits for stress db initialization + %limits=(loop_count => 1, test_count => undef); + + #Read list of tests from $opt_stress_init_file + read_tests_names($tests_files{initdb}); + test_loop($client_ip, 0, 'seq', $tests_files{initdb}); + #print Dumper($tests_files{initdb}),"\n"; + print <<EOF; + +Done initialization of stress database by tests from +$tests_files{initdb}->{filename} file. + +EOF +} + +if (defined($opt_stress_tests_file)) +{ + print <<EOF; +############################################################# + STRESS TEST RUNNING STAGE +############################################################# +EOF + + $exiting=0; + #Read list of tests from $opt_stress_tests_file + read_tests_names($tests_files{client}); + + #Reset current counter and set limits + %test_counters=( loop_count => 0, test_count=>0); + %limits=(loop_count => $opt_loop_count, test_count => $opt_test_count); + + if (($opt_loop_count && $opt_threads > $opt_loop_count) || + ($opt_test_count && $opt_threads > $opt_test_count)) + { + warn <<EOF; + +WARNING: Possible inaccuracies in number of executed loops or + tests because number of threads bigger than number of + loops or tests: + + Threads will be started: $opt_threads + Loops will be executed: $opt_loop_count + Tests will be executed: $opt_test_count + +EOF + } + + #Create threads (number depending on the variable ) + for ($id=1; $id<=$opt_threads && !$exiting; $id++) + { + $thrd[$id] = threads->create("test_loop", $client_ip, $id, + $opt_stress_mode, $tests_files{client}); + + print "main: Thread ID $id TID ",$thrd[$id]->tid," started\n"; + select(undef, undef, undef, 0.5); + } + + if ($opt_test_duration) + { + sleep($opt_test_duration); + kill INT, $$; #Interrupt child threads + } + + #Let other threads to process INT signal + sleep(1); + + for ($id=1; $id<=$opt_threads;$id++) + { + if (defined($thrd[$id])) + { + $thrd[$id]->join(); + } + } + print "EXIT\n"; +} + +sub test_init +{ + my ($env)=@_; + + $env->{session_id}=$env->{ip}."_".$env->{thread_id}; + $env->{r_folder}='r'.$env->{thread_id}; + $env->{screen_logs}=File::Spec->catdir($opt_server_logs_dir, $test_dirname, + "screen_logs", $env->{session_id}); + $env->{reject_logs}=File::Spec->catdir($opt_server_logs_dir, $test_dirname, + "reject_logs", $env->{session_id}); + + mkpath($env->{screen_logs}, 0, 0755) unless (-d $env->{screen_logs}); + mkpath($env->{reject_logs}, 0, 0755) unless (-d $env->{reject_logs}); + + $env->{session_log}= File::Spec->catfile($env->{screen_logs}, $env->{session_id}.".log"); +} + +sub test_execute +{ + my $env= shift; + my $test_name= shift; + + my $g_start= ""; + my $g_end= ""; + my $mysqltest_cmd= ""; + my @mysqltest_test_args=(); + my @stderr=(); + + #Get time stamp + $g_start = get_timestamp(); + $env->{errors}={}; + @{$env->{test_status}}=(); + + my $test_file= $test_name.".test"; + my $result_file= $test_name.".result"; + my $reject_file = $test_name.'.reject'; + my $output_file = $env->{session_id}.'_'.$test_name.'_'.$g_start."_".$env->{test_count}.'.txt'; + + my $test_filename = File::Spec->catfile($test_t_path, $test_file); + my $result_filename = File::Spec->catdir($test_r_path, $env->{r_folder}, $result_file); + my $reject_filename = File::Spec->catdir($test_r_path, $env->{r_folder}, $reject_file); + my $output_filename = File::Spec->catfile($env->{screen_logs}, $output_file); + + + push @mysqltest_test_args, "--basedir=$opt_stress_suite_basedir/", + "--tmpdir=$opt_stress_basedir", + "-x $test_filename", + "-R $result_filename", + "2>$output_filename"; + + $cmd= "$opt_mysqltest --no-defaults ".join(" ", @mysqltest_args)." ". + join(" ", @mysqltest_test_args); + + system($cmd); + + $exit_value = $? >> 8; + $signal_num = $? & 127; + $dumped_core = $? & 128; + + my $tid= threads->self->tid; + + if (-s $output_filename > 0) + { + #Read stderr for further analysis + open (STDERR_LOG, $output_filename) or + warn "Can't open file $output_filename"; + @stderr=<STDERR_LOG>; + close(STDERR_LOG); + + if ($opt_verbose) + { + $session_debug_file="$opt_stress_basedir/error$tid.txt"; + + stress_log($session_debug_file, + "Something wrong happened during execution of this command line:"); + stress_log($session_debug_file, "MYSQLTEST CMD - $cmd"); + stress_log($session_debug_file, "STDERR:".join("",@stderr)); + + stress_log($session_debug_file, "EXIT STATUS:\n1. EXIT: $exit_value \n". + "2. SIGNAL: $signal_num\n". + "3. CORE: $dumped_core\n"); + } + } + + #If something wrong trying to analyse stderr + if ($exit_value || $signal_num) + { + if (@stderr) + { + foreach my $line (@stderr) + { + #FIXME: we should handle case when for one sub-string/code + # we have several different error messages + # Now for both codes/substrings we assume that + # first found message will represent error + + #Check line for error codes + if (($err_msg, $err_code)= $line=~/failed: ((\d+):.+?$)/) + { + if (!exists($error_codes{$err_code})) + { + $severity="S3"; + $err_code=0; + } + else + { + $severity=$error_codes{$err_code}; + } + + if (!exists($env->{errors}->{$severity}->{$err_code})) + { + $env->{errors}->{$severity}->{$err_code}=[0, $err_msg]; + } + $env->{errors}->{$severity}->{$err_code}->[0]++; + $env->{errors}->{$severity}->{total}++; + } + + #Check line for error patterns + foreach $err_string (keys %error_strings) + { + $pattern= quotemeta $err_string; + if ($line =~ /$pattern/i) + { + my $severity= $error_strings{$err_string}; + if (!exists($env->{errors}->{$severity}->{$err_string})) + { + $env->{errors}->{$severity}->{$err_string}=[0, $line]; + } + $env->{errors}->{$severity}->{$err_string}->[0]++; + $env->{errors}->{$severity}->{total}++; + } + } + } + } + else + { + $env->{errors}->{S3}->{'Unknown error'}= + [1,"Unknown error. Nothing was output to STDERR"]; + $env->{errors}->{S3}->{total}=1; + } + } + + # + #FIXME: Here we can perform further analysis of recognized + # error codes + # + + foreach my $severity (sort {$a cmp $b} keys %{$env->{errors}}) + { + my $total=$env->{errors}->{$severity}->{total}; + if ($total) + { + push @{$env->{test_status}}, "Severity $severity: $total"; + $env->{errors}->{total}=+$total; + } + } + + #FIXME: Should we take into account $exit_value here? + # Now we assume that all stringified errors(i.e. errors without + # error codes) which are not exist in %error_string structure + # are OK + if (!$env->{errors}->{total}) + { + push @{$env->{test_status}},"No Errors. Test Passed OK"; + } + + log_session_errors($env, $test_file); + + if (!$exiting && ($signal_num == 2 || $signal_num == 15 || + ($opt_abort_on_error && $env->{errors}->{S1} > 0))) + { + #mysqltest was interrupted with INT or TERM signals or test was + #ran with --abort-on-error option and we got errors with severity S1 + #so we assume that we should cancel testing and exit + $exiting=1; + print STDERR<<EOF; +WARNING: + mysqltest was interrupted with INT or TERM signals or test was + ran with --abort-on-error option and we got errors with severity S1 + (test cann't connect to the server or server crashed) so we assume that + we should cancel testing and exit. Please check log file for this thread + in $stress_log_file or + inspect below output of the last test case executed with mysqltest to + find out cause of error. + + Output of mysqltest: + @stderr + +EOF + } + + if (-e $reject_filename) + { + move_to_logs($env->{reject_logs}, $reject_filename, $reject_file); + } + + if (-e $output_filename) + { + move_to_logs($env->{screen_logs}, $output_filename, $output_file); + } + +} + +sub test_loop +{ + my %client_env=(); + my $test_name=""; + + # KEY for session identification: IP-THREAD_ID + $client_env{ip} = shift; + $client_env{thread_id} = shift; + + $client_env{mode} = shift; + $client_env{tests_file}=shift; + + $client_env{test_seq_idx}=0; + + #Initialize session variables + test_init(\%client_env); + +LOOP: + + while(!$exiting) + { + if ($opt_check_tests_file) + { + #Check if tests_file was modified and reread it in this case + read_tests_names($client_env{tests_file}, 0); + } + + { + lock($test_counters_lock); + + if (($limits{loop_count} && $limits{loop_count} <= $test_counters{loop_count}*1) || + ($limits{test_count} && $limits{test_count} <= $test_counters{test_count}*1) ) + { + $exiting=1; + next LOOP; + } + } + + #Get random file name + if (($test_name = get_test(\%client_env)) ne '') + { + { + lock($test_counters_lock); + + #Save current counters values + $client_env{loop_count}=$test_counters{loop_count}; + $client_env{test_count}=$test_counters{test_count}; + } + #Run test and analyze results + test_execute(\%client_env, $test_name); + + print "test_loop[".$limits{loop_count}.":". + $limits{test_count}." ". + $client_env{loop_count}.":". + $client_env{test_count}."]:". + " TID ".$client_env{thread_id}. + " test: '$test_name' ". + " Errors: ".join(" ",@{$client_env{test_status}}),"\n"; + print "\n"; + } + + sleep($opt_sleep_time) if($opt_sleep_time); + + } +} + +sub move_to_logs ($$$) +{ + my $path_to_logs = shift; + my $src_file = shift; + my $random_filename = shift; + + my $dst_file = File::Spec->catfile($path_to_logs, $random_filename); + + move ($src_file, $dst_file) or warn<<EOF; +ERROR: move_to_logs: File $src_file cannot be moved to $dst_file: $! +EOF +} + +sub copy_test_files () +{ + if (/\.test$/) + { + $src_file = $File::Find::name; + #print "## $File::Find::topdir - $File::Find::dir - $src_file\n"; + + if ($File::Find::topdir eq $File::Find::dir && $src_file !~ /SCCS/) + { + $test_filename = basename($src_file); + $dst_file = File::Spec->catfile($test_t_path, $test_filename); + + copy($src_file, $dst_file) or die "ERROR: copy_test_files: File cannot be copied. $!"; + } + } +} + +sub copy_result_files () +{ + if (/\.result$/) + { + $src_file = $File::Find::name; + + if ($File::Find::topdir eq $File::Find::dir && $src_file !~ /SCCS/) + { + $result_filename = basename($src_file) ; + $dst_file = File::Spec->catfile($r_folder, $result_filename); + + copy($src_file, $dst_file) or die "ERROR: copy_result_files: File cannot be copied. $!"; + } + } +} + +sub get_timestamp +{ + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$ydat,$isdst) = localtime(); + + return sprintf("%04d%02d%02d%02d%02d%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec); +} + +sub read_tests_names +{ + my $tests_file = shift; + my $force_load = shift; + + if ($force_load || ( (stat($tests_file->{filename}))[9] != $tests_file->{mtime}) ) + { + open (TEST, $tests_file->{filename}) || die ("Could not open file <". + $tests_file->{filename}."> $!"); + @{$tests_file->{data}}= grep {!/^[#\r\n]|^$/} map { s/[\r\n]//g; $_ } <TEST>; + + close (TEST); + $tests_file->{mtime}=(stat(_))[9]; + } +} + +sub get_random_test +{ + my $envt=shift; + my $tests= $envt->{tests_file}->{data}; + + my $random = int(rand(@{$tests})); + my $test = $tests->[$random]; + + return $test; +} + +sub get_next_test +{ + my $envt=shift; + my $test; + + if (@{$envt->{tests_file}->{data}}) + { + $test=${$envt->{tests_file}->{data}}[$envt->{test_seq_idx}]; + $envt->{test_seq_idx}++; + } + + #If we reach bound of array, reset seq index and increment loop counter + if ($envt->{test_seq_idx} == scalar(@{$envt->{tests_file}->{data}})) + { + $envt->{test_seq_idx}=0; + { + lock($test_counters_lock); + $test_counters{loop_count}++; + } + } + + return $test; +} + +sub get_test +{ + my $envt=shift; + + { + lock($test_counters_lock); + $test_counters{test_count}++; + } + + if ($envt->{mode} eq 'seq') + { + return get_next_test($envt); + } + elsif ($envt->{mode} eq 'random') + { + return get_random_test($envt); + } +} + +sub stress_log +{ + my ($log_file, $line)=@_; + + { + open(SLOG,">>$log_file") or warn "Error during opening log file $log_file"; + print SLOG $line,"\n"; + close(SLOG); + } +} + +sub log_session_errors +{ + my ($env, $test_name) = @_; + my $line=''; + + { + lock ($log_file_lock); + + #header in the begining of log file + if (!-e $stress_log_file) + { + stress_log($stress_log_file, + "TestID TID Suite TestFileName Found Errors"); + stress_log($stress_log_file, + "======================================================="); + } + + $line=sprintf('%6d %3d %10s %20s %s', $env->{test_count}, threads->self->tid, + $opt_suite, $test_name, + join(",", @{$env->{test_status}})); + + stress_log($stress_log_file, $line); + #stress_log_with_lock($stress_log_file, "\n"); + + if ($opt_log_error_details) + { + foreach $severity (sort {$a cmp $b} keys %{$env->{errors}}) + { + stress_log($stress_log_file, ""); + foreach $error (keys %{$env->{errors}->{$severity}}) + { + if ($error ne 'total') + { + stress_log($stress_log_file, "$severity: Count:". + $env->{errors}->{$severity}->{$error}->[0]. + " Error:". $env->{errors}->{$severity}->{$error}->[1]); + } + } + } + } + } +} + +sub sig_INT_handler +{ + $SIG{INT}= \&sig_INT_handler; + $exiting=1; + print STDERR "$$: Got INT signal-------------------------------------------\n"; + +} + +sub sig_TERM_handler +{ + $SIG{TERM}= \&sig_TERM_handler; + $exiting=1; + print STDERR "$$: Got TERM signal\n"; +} + +sub usage +{ + print <<EOF; + +The MySQL Stress suite Ver $stress_suite_version + +mysql-stress-test.pl --stress-basedir=<dir> --stress-suite-basedir=<dir> --server-logs-dir=<dir> + +--server-host +--server-port +--server-socket +--server-user +--server-password +--server-logs-dir + Directory where all clients session logs will be stored. Usually + this is shared directory associated with server that used + in testing + + Required option. + +--stress-suite-basedir=<dir> + Directory that has r/ t/ subfolders with test/result files + which will be used for testing. Also by default we are looking + in this directory for 'stress-tests.txt' file which contains + list of tests. It is possible to specify other location of this + file with --stress-tests-file option. + + Required option. + +--stress-basedir=<dir> + Working directory for this test run. This directory will be used + as temporary location for results tracking during testing + + Required option. + +--stress-datadir=<dir> + Location of data files used which will be used in testing. + By default we search for these files in <dir>/data where dir + is value of --stress-suite-basedir option. + +--stress-init-file[=/path/to/file with tests for initialization of stress db] + Using of this option allows to perform initialization of database + by execution of test files. List of tests will be taken either from + specified file or if it omited from default file 'stress-init.txt' + located in <--stress-suite-basedir/--suite> dir + +--stress-tests-file[=/path/to/file with tests] + Using of this option allows to run stress test itself. Tests for testing + will be taken either from specified file or if it omited from default + file 'stress-tests.txt' located in <--stress-suite-basedir/--suite> dir + +--stress-mode= [random|seq] + There are two possible modes which affect order of selecting tests + from the list: + - in random mode tests will be selected in random order + - in seq mode each thread will execute tests in the loop one by one as + they specified in the list file. + +--sleep-time=<time in seconds> + Delay between test execution. Could be usefull in continued testsing + when one of instance of stress script perform periodical cleanup or + recreating of some database objects + +--threads=#number of threads + Define number of threads + +--check-tests-file + Check file with list of tests. If file was modified it will force to + reread list of tests. Could be usefull in continued testing for + adding/removing tests without script interruption + +--mysqltest=/path/to/mysqltest binary + +--verbose + +--cleanup + Force to clean up working directory (specified with --stress-basedir) + +--log-error-details + Enable errors details in the global error log file. (Default: off) + +--test-count=<number of executed tests before we have to exit> +--loop-count=<number of executed loops in sequential mode before we have to exit> +--test-duration=<number of seconds that stress test should run> + +Example of tool usage: + +perl mysql-stress-test.pl \ +--stress-suite-basedir=/opt/qa/mysql-test-extra-5.0/mysql-test \ +--stress-basedir=/opt/qa/test \ +--server-logs-dir=/opt/qa/logs \ +--test-count=20 \ +--stress-tests-file=innodb-tests.txt \ +--stress-init-file=innodb-init.txt \ +--threads=5 \ +--suite=funcs_1 \ +--mysqltest=/opt/mysql/mysql-5.0/client/mysqltest \ +--server-user=root \ +--server-database=test \ +--cleanup \ + +EOF +exit(0); +} + + diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d84a7dc1f87..6ed068c02d3 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2,37 +2,35 @@ # -*- cperl -*- # This is a transformation of the "mysql-test-run" Bourne shell script -# to Perl. This is just an intermediate step, the goal is to rewrite -# the Perl script to C. The complexity of the mysql-test-run script -# makes it a bit hard to write and debug it as a C program directly, -# so this is considered a prototype. +# to Perl. There are reasons this rewrite is not the prettiest Perl +# you have seen # -# Because of this the Perl coding style may in some cases look a bit -# funny. The rules used are +# - The original script is huge and for most part uncommented, +# not even a usage description of the flags. # -# - The coding style is as close as possible to the C/C++ MySQL -# coding standard. +# - There has been an attempt to write a replacement in C for the +# original Bourne shell script. It was kind of working but lacked +# lot of functionality to really be a replacement. Not to redo +# that mistake and catch all the obscure features of the original +# script, the rewrite in Perl is more close to the original script +# meaning it also share some of the ugly parts as well. # -# - Where NULL is to be returned, the undefined value is used. +# - The original intention was that this script was to be a prototype +# to be the base for a new C version with full functionality. Since +# then it was decided that the Perl version should replace the +# Bourne shell version, but the Perl style still reflects the wish +# to make the Perl to C step easy. # -# - Regexp comparisons are simple and can be translated to strcmp -# and other string functions. To ease this transformation matching -# is done in the lib "lib/mtr_match.pl", i.e. regular expressions -# should be avoided in the main program. +# Some coding style from the original intent has been kept # -# - The "unless" construct is not to be used. It is the same as "if !". -# -# - opendir/readdir/closedir is used instead of glob()/<*>. +# - To make this Perl script easy to alter even for those that not +# code Perl that often, the coding style is as close as possible to +# the C/C++ MySQL coding standard. # # - All lists of arguments to send to commands are Perl lists/arrays, # not strings we append args to. Within reason, most string # concatenation for arguments should be avoided. # -# - sprintf() is to be used, within reason, for all string creation. -# This mtr_add_arg() function is also based on sprintf(), i.e. you -# use a format string and put the variable argument in the argument -# list. -# # - Functions defined in the main program are not to be prefixed, # functions in "library files" are to be prefixed with "mtr_" (for # Mysql-Test-Run). There are some exceptions, code that fits best in @@ -173,12 +171,14 @@ our $exe_mysqladmin; our $exe_mysqlbinlog; our $exe_mysql_client_test; our $exe_mysqld; +our $exe_mysqlcheck; # Called from test case our $exe_mysqldump; # Called from test case our $exe_mysqlshow; # Called from test case our $exe_mysql_fix_system_tables; our $exe_mysqltest; our $exe_slave_mysqld; our $exe_im; +our $exe_my_print_defaults; our $opt_bench= 0; our $opt_small_bench= 0; @@ -234,14 +234,17 @@ our $opt_result_ext; our $opt_skip; our $opt_skip_rpl; our $opt_skip_test; +our $opt_skip_im; our $opt_sleep; our $opt_ps_protocol; our $opt_sleep_time_after_restart= 1; our $opt_sleep_time_for_delete= 10; -our $opt_testcase_timeout= 5; # 5 min max -our $opt_suite_timeout= 120; # 2 hours max +our $opt_testcase_timeout; +our $opt_suite_timeout; +my $default_testcase_timeout= 15; # 15 min max +my $default_suite_timeout= 120; # 2 hours max our $opt_socket; @@ -259,6 +262,7 @@ our $opt_user; our $opt_user_test; our $opt_valgrind; +our $opt_valgrind_mysqltest; our $opt_valgrind_all; our $opt_valgrind_options; @@ -472,6 +476,7 @@ sub command_line_setup () { # Read the command line # Note: Keep list, and the order, in sync with usage at end of this file + Getopt::Long::Configure("pass_through"); GetOptions( # Control what engine/variation to run 'embedded-server' => \$opt_embedded_server, @@ -487,6 +492,7 @@ sub command_line_setup () { 'do-test=s' => \$opt_do_test, 'suite=s' => \$opt_suite, 'skip-rpl' => \$opt_skip_rpl, + 'skip-im' => \$opt_skip_im, 'skip-test=s' => \$opt_skip_test, # Specify ports @@ -520,8 +526,9 @@ sub command_line_setup () { # Coverage, profiling etc 'gcov' => \$opt_gcov, 'gprof' => \$opt_gprof, - 'valgrind' => \$opt_valgrind, - 'valgrind-all' => \$opt_valgrind_all, + 'valgrind:s' => \$opt_valgrind, + 'valgrind-mysqltest:s' => \$opt_valgrind_mysqltest, + 'valgrind-all:s' => \$opt_valgrind_all, 'valgrind-options=s' => \$opt_valgrind_options, # Misc @@ -561,7 +568,21 @@ sub command_line_setup () { usage(""); } - @opt_cases= @ARGV; + foreach my $arg ( @ARGV ) + { + if ( $arg =~ /^--skip-/ ) + { + push(@opt_extra_mysqld_opt, $arg); + } + elsif ( $arg =~ /^-/ ) + { + usage("Invalid option \"$arg\""); + } + else + { + push(@opt_cases, $arg); + } + } # -------------------------------------------------------------------------- # Set the "var/" directory, as it is the base for everything else @@ -653,11 +674,6 @@ sub command_line_setup () { mtr_error("Coverage test needs the source - please use source dist"); } - if ( $glob_use_embedded_server and ! $opt_source_dist ) - { - mtr_error("Embedded server needs source tree - please use source dist"); - } - if ( $opt_gdb ) { $opt_wait_timeout= 300; @@ -699,29 +715,42 @@ sub command_line_setup () { $opt_with_ndbcluster= 0; } - # FIXME + # The ":s" in the argument spec, means we have three different cases + # + # undefined option not set + # "" option set with no argument + # "somestring" option is name/path of valgrind executable + + # Take executable path from any of them, if any + $opt_valgrind= $opt_valgrind_mysqltest if $opt_valgrind_mysqltest; + $opt_valgrind= $opt_valgrind_all if $opt_valgrind_all; + + # If valgrind flag not defined, define if other valgrind flags are + unless ( defined $opt_valgrind ) + { + $opt_valgrind= "" + if defined $opt_valgrind_mysqltest or defined $opt_valgrind_all; + } + + if ( ! $opt_testcase_timeout ) + { + $opt_testcase_timeout= $default_testcase_timeout; + $opt_testcase_timeout*= 10 if defined $opt_valgrind; + } + + if ( ! $opt_suite_timeout ) + { + $opt_suite_timeout= $default_suite_timeout; + $opt_suite_timeout*= 4 if defined $opt_valgrind; + } - #if ( $opt_valgrind or $opt_valgrind_all ) - #{ - # VALGRIND=`which valgrind` # this will print an error if not found FIXME - # Give good warning to the user and stop - # if ( ! $VALGRIND ) - # { - # print "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://valgrind.kde.org.\n" - # exit 1 - # } + if ( defined $opt_valgrind ) + { + $opt_sleep_time_after_restart= 10; + $opt_sleep_time_for_delete= 60; # >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr - # valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck" - # VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16" - # $opt_extra_mysqld_opt.= " --skip-safemalloc --skip-bdb"; - # SLEEP_TIME_AFTER_RESTART=10 - # $opt_sleep_time_for_delete= 60 - # $glob_use_running_server= "" - # if ( "$1"= "--valgrind-all" ) - # { - # VALGRIND="$VALGRIND -v --show-reachable=yes" - # } - #} + # valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck" + } if ( ! $opt_user ) { @@ -737,78 +766,96 @@ sub command_line_setup () { # Put this into a hash, will be a C struct - $master->[0]->{'path_myddir'}= "$opt_vardir/master-data"; - $master->[0]->{'path_myerr'}= "$opt_vardir/log/master.err"; - $master->[0]->{'path_mylog'}= "$opt_vardir/log/master.log"; - $master->[0]->{'path_mypid'}= "$opt_vardir/run/master.pid"; - $master->[0]->{'path_mysock'}= "$opt_tmpdir/master.sock"; - $master->[0]->{'path_myport'}= $opt_master_myport; - $master->[0]->{'start_timeout'}= 400; # enough time create innodb tables - - $master->[0]->{'ndbcluster'}= 1; # ndbcluster not started - - $master->[1]->{'path_myddir'}= "$opt_vardir/master1-data"; - $master->[1]->{'path_myerr'}= "$opt_vardir/log/master1.err"; - $master->[1]->{'path_mylog'}= "$opt_vardir/log/master1.log"; - $master->[1]->{'path_mypid'}= "$opt_vardir/run/master1.pid"; - $master->[1]->{'path_mysock'}= "$opt_tmpdir/master1.sock"; - $master->[1]->{'path_myport'}= $opt_master_myport + 1; - $master->[1]->{'start_timeout'}= 400; # enough time create innodb tables - - $slave->[0]->{'path_myddir'}= "$opt_vardir/slave-data"; - $slave->[0]->{'path_myerr'}= "$opt_vardir/log/slave.err"; - $slave->[0]->{'path_mylog'}= "$opt_vardir/log/slave.log"; - $slave->[0]->{'path_mypid'}= "$opt_vardir/run/slave.pid"; - $slave->[0]->{'path_mysock'}= "$opt_tmpdir/slave.sock"; - $slave->[0]->{'path_myport'}= $opt_slave_myport; - $slave->[0]->{'start_timeout'}= 400; - - $slave->[1]->{'path_myddir'}= "$opt_vardir/slave1-data"; - $slave->[1]->{'path_myerr'}= "$opt_vardir/log/slave1.err"; - $slave->[1]->{'path_mylog'}= "$opt_vardir/log/slave1.log"; - $slave->[1]->{'path_mypid'}= "$opt_vardir/run/slave1.pid"; - $slave->[1]->{'path_mysock'}= "$opt_tmpdir/slave1.sock"; - $slave->[1]->{'path_myport'}= $opt_slave_myport + 1; - $slave->[1]->{'start_timeout'}= 300; - - $slave->[2]->{'path_myddir'}= "$opt_vardir/slave2-data"; - $slave->[2]->{'path_myerr'}= "$opt_vardir/log/slave2.err"; - $slave->[2]->{'path_mylog'}= "$opt_vardir/log/slave2.log"; - $slave->[2]->{'path_mypid'}= "$opt_vardir/run/slave2.pid"; - $slave->[2]->{'path_mysock'}= "$opt_tmpdir/slave2.sock"; - $slave->[2]->{'path_myport'}= $opt_slave_myport + 2; - $slave->[2]->{'start_timeout'}= 300; - - $instance_manager->{'path_err'}= "$opt_vardir/log/im.err"; - $instance_manager->{'path_log'}= "$opt_vardir/log/im.log"; - $instance_manager->{'path_pid'}= "$opt_vardir/run/im.pid"; - $instance_manager->{'path_sock'}= "$opt_tmpdir/im.sock"; - $instance_manager->{'port'}= $im_port; - $instance_manager->{'start_timeout'}= $master->[0]->{'start_timeout'}; - $instance_manager->{'admin_login'}= 'im_admin'; - $instance_manager->{'admin_password'}= 'im_admin_secret'; - $instance_manager->{'admin_sha1'}= '*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295'; - $instance_manager->{'password_file'}= "$opt_vardir/im.passwd"; - $instance_manager->{'defaults_file'}= "$opt_vardir/im.cnf"; - - $instance_manager->{'instances'}->[0]->{'server_id'}= 1; - $instance_manager->{'instances'}->[0]->{'port'}= $im_mysqld1_port; - $instance_manager->{'instances'}->[0]->{'path_datadir'}= - "$opt_vardir/im_mysqld_1.data"; - $instance_manager->{'instances'}->[0]->{'path_sock'}= - "$opt_vardir/mysqld_1.sock"; - $instance_manager->{'instances'}->[0]->{'path_pid'}= - "$opt_vardir/mysqld_1.pid"; - - $instance_manager->{'instances'}->[1]->{'server_id'}= 2; - $instance_manager->{'instances'}->[1]->{'port'}= $im_mysqld2_port; - $instance_manager->{'instances'}->[1]->{'path_datadir'}= - "$opt_vardir/im_mysqld_2.data"; - $instance_manager->{'instances'}->[1]->{'path_sock'}= - "$opt_vardir/mysqld_2.sock"; - $instance_manager->{'instances'}->[1]->{'path_pid'}= - "$opt_vardir/mysqld_2.pid"; - $instance_manager->{'instances'}->[1]->{'nonguarded'}= 1; + $master->[0]= + { + path_myddir => "$opt_vardir/master-data", + path_myerr => "$opt_vardir/log/master.err", + path_mylog => "$opt_vardir/log/master.log", + path_mypid => "$opt_vardir/run/master.pid", + path_mysock => "$opt_tmpdir/master.sock", + path_myport => $opt_master_myport, + start_timeout => 400, # enough time create innodb tables + + ndbcluster => 1, # ndbcluster not started + }; + + $master->[1]= + { + path_myddir => "$opt_vardir/master1-data", + path_myerr => "$opt_vardir/log/master1.err", + path_mylog => "$opt_vardir/log/master1.log", + path_mypid => "$opt_vardir/run/master1.pid", + path_mysock => "$opt_tmpdir/master1.sock", + path_myport => $opt_master_myport + 1, + start_timeout => 400, # enough time create innodb tables + }; + + $slave->[0]= + { + path_myddir => "$opt_vardir/slave-data", + path_myerr => "$opt_vardir/log/slave.err", + path_mylog => "$opt_vardir/log/slave.log", + path_mypid => "$opt_vardir/run/slave.pid", + path_mysock => "$opt_tmpdir/slave.sock", + path_myport => $opt_slave_myport, + start_timeout => 400, + }; + + $slave->[1]= + { + path_myddir => "$opt_vardir/slave1-data", + path_myerr => "$opt_vardir/log/slave1.err", + path_mylog => "$opt_vardir/log/slave1.log", + path_mypid => "$opt_vardir/run/slave1.pid", + path_mysock => "$opt_tmpdir/slave1.sock", + path_myport => $opt_slave_myport + 1, + start_timeout => 300, + }; + + $slave->[2]= + { + path_myddir => "$opt_vardir/slave2-data", + path_myerr => "$opt_vardir/log/slave2.err", + path_mylog => "$opt_vardir/log/slave2.log", + path_mypid => "$opt_vardir/run/slave2.pid", + path_mysock => "$opt_tmpdir/slave2.sock", + path_myport => $opt_slave_myport + 2, + start_timeout => 300, + }; + + $instance_manager= + { + path_err => "$opt_vardir/log/im.err", + path_log => "$opt_vardir/log/im.log", + path_pid => "$opt_vardir/run/im.pid", + path_sock => "$opt_tmpdir/im.sock", + port => $im_port, + start_timeout => $master->[0]->{'start_timeout'}, + admin_login => 'im_admin', + admin_password => 'im_admin_secret', + admin_sha1 => '*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295', + password_file => "$opt_vardir/im.passwd", + defaults_file => "$opt_vardir/im.cnf", + }; + + $instance_manager->{'instances'}->[0]= + { + server_id => 1, + port => $im_mysqld1_port, + path_datadir => "$opt_vardir/im_mysqld_1.data", + path_sock => "$opt_tmpdir/mysqld_1.sock", + path_pid => "$opt_vardir/run/mysqld_1.pid", + }; + + $instance_manager->{'instances'}->[1]= + { + server_id => 2, + port => $im_mysqld2_port, + path_datadir => "$opt_vardir/im_mysqld_2.data", + path_sock => "$opt_tmpdir/mysqld_2.sock", + path_pid => "$opt_vardir/run/mysqld_2.pid", + nonguarded => 1, + }; if ( $opt_extern ) { @@ -853,7 +900,7 @@ sub executable_setup () { if ( $glob_use_embedded_server ) { my $path_examples= "$glob_basedir/libmysqld/examples"; - $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest"); + $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest_embedded"); $exe_mysql_client_test= mtr_exe_exists("$path_examples/mysql_client_test_embedded", "/usr/bin/false"); @@ -865,6 +912,7 @@ sub executable_setup () { mtr_exe_exists("$glob_basedir/tests/mysql_client_test", "/usr/bin/false"); } + $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); @@ -872,13 +920,15 @@ sub executable_setup () { $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); $exe_mysql_fix_system_tables= mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables"); + $exe_my_print_defaults= + mtr_script_exists("$glob_basedir/extra/my_print_defaults"); $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools"); $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm"; } else { $path_client_bindir= mtr_path_exists("$glob_basedir/bin"); - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); + $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); @@ -887,6 +937,8 @@ sub executable_setup () { $exe_mysql_fix_system_tables= mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables", "$glob_basedir/scripts/mysql_fix_privilege_tables"); + $exe_my_print_defaults= + mtr_script_exists("$path_client_bindir/my_print_defaults"); $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/", "$glob_basedir/share/english/"); @@ -970,10 +1022,14 @@ sub environment_setup () { # $ENV{'MYSQL_TCP_PORT'}= '@MYSQL_TCP_PORT@'; # FIXME $ENV{'MYSQL_TCP_PORT'}= 3306; + $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; + $ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock}; $ENV{'IM_MYSQLD1_PORT'}= $instance_manager->{instances}->[0]->{port}; + $ENV{'IM_MYSQLD1_PATH_PID'}=$instance_manager->{instances}->[0]->{path_pid}; $ENV{'IM_MYSQLD2_SOCK'}= $instance_manager->{instances}->[1]->{path_sock}; $ENV{'IM_MYSQLD2_PORT'}= $instance_manager->{instances}->[1]->{port}; + $ENV{'IM_MYSQLD2_PATH_PID'}=$instance_manager->{instances}->[1]->{path_pid}; if ( $glob_cygwin_perl ) { @@ -1067,7 +1123,7 @@ sub kill_and_cleanup () { foreach my $instance (@{$instance_manager->{'instances'}}) { - push (@data_dir_lst, $instance->{'path_datadir'}); + push(@data_dir_lst, $instance->{'path_datadir'}); } foreach my $data_dir (@data_dir_lst) @@ -1313,7 +1369,7 @@ sub mysql_install_db () { install_db('slave', $slave->[1]->{'path_myddir'}); install_db('slave', $slave->[2]->{'path_myddir'}); - if ( defined $exe_im) + if ( ! $opt_skip_im ) { im_prepare_env($instance_manager); } @@ -1462,12 +1518,7 @@ skip-ndbcluster EOF ; - if ( exists $instance->{nonguarded} and - defined $instance->{nonguarded} ) - { - print OUT "nonguarded\n"; - } - + print OUT "nonguarded\n" if $instance->{'nonguarded'}; print OUT "\n"; } @@ -1627,7 +1678,7 @@ sub run_testcase ($) { $master->[0]->{'running_master_is_special'}= 1; } } - elsif ( $tinfo->{'component_id'} eq 'im') + elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' ) { # We have to create defaults file every time, in order to ensure that it # will be the same for each test. The problem is that test can change the @@ -1725,7 +1776,8 @@ sub run_testcase ($) { # Stop Instance Manager if we are processing an IM-test case. # ---------------------------------------------------------------------- - if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' ) + if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' and + $instance_manager->{'pid'} ) { im_stop($instance_manager); } @@ -1878,7 +1930,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); - if ( $opt_valgrind ) + if ( defined $opt_valgrind ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); mtr_add_arg($args, "%s--skip-bdb", $prefix); @@ -2104,29 +2156,9 @@ sub mysqld_start ($$$$) { mtr_init_args(\$args); - if ( $opt_valgrind ) + if ( defined $opt_valgrind ) { - - mtr_add_arg($args, "--tool=memcheck"); - mtr_add_arg($args, "--alignment=8"); - mtr_add_arg($args, "--leak-check=yes"); - mtr_add_arg($args, "--num-callers=16"); - - if ( $opt_valgrind_all ) - { - mtr_add_arg($args, "-v"); - mtr_add_arg($args, "--show-reachable=yes"); - } - - if ( $opt_valgrind_options ) - { - # FIXME split earlier and put into @glob_valgrind_* - mtr_add_arg($args, split(' ', $opt_valgrind_options)); - } - - mtr_add_arg($args, $exe); - - $exe= $opt_valgrind; + valgrind_arguments($args, \$exe); } mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info); @@ -2135,7 +2167,9 @@ sub mysqld_start ($$$$) { { if ( $pid= mtr_spawn($exe, $args, "", $master->[$idx]->{'path_myerr'}, - $master->[$idx]->{'path_myerr'}, "") ) + $master->[$idx]->{'path_myerr'}, + "", + { append_log_file => 1 }) ) { return sleep_until_file_created($master->[$idx]->{'path_mypid'}, $master->[$idx]->{'start_timeout'}, $pid); @@ -2146,7 +2180,9 @@ sub mysqld_start ($$$$) { { if ( $pid= mtr_spawn($exe, $args, "", $slave->[$idx]->{'path_myerr'}, - $slave->[$idx]->{'path_myerr'}, "") ) + $slave->[$idx]->{'path_myerr'}, + "", + { append_log_file => 1 }) ) { return sleep_until_file_created($slave->[$idx]->{'path_mypid'}, $master->[$idx]->{'start_timeout'}, $pid); @@ -2160,7 +2196,7 @@ sub stop_masters_slaves () { print "Ending Tests\n"; - if (defined $instance_manager->{'pid'}) + if ( $instance_manager->{'pid'} ) { print "Shutting-down Instance Manager\n"; im_stop($instance_manager); @@ -2234,14 +2270,10 @@ sub im_start($$) { my $instance_manager = shift; my $opts = shift; - if ( ! defined $exe_im) - { - return; - } - my $args; mtr_init_args(\$args); - mtr_add_arg($args, "--defaults-file=" . $instance_manager->{'defaults_file'}); + mtr_add_arg($args, "--defaults-file=%s", + $instance_manager->{'defaults_file'}); foreach my $opt (@{$opts}) { @@ -2259,7 +2291,7 @@ sub im_start($$) { { append_log_file => 1 } # append log files ); - if ( ! defined $instance_manager->{'pid'} ) + if ( ! $instance_manager->{'pid'} ) { mtr_report('Could not start Instance Manager'); return; @@ -2269,10 +2301,14 @@ sub im_start($$) { # several processes and the parent process, created by mtr_spawn(), exits just # after start. So, we have to obtain Instance Manager PID from the PID file. - sleep_until_file_created( - $instance_manager->{'path_pid'}, - $instance_manager->{'start_timeout'}, - -1); # real PID is still unknown + if ( ! sleep_until_file_created( + $instance_manager->{'path_pid'}, + $instance_manager->{'start_timeout'}, + -1)) # real PID is still unknown + { + mtr_report("Instance Manager PID file is missing"); + return; + } $instance_manager->{'pid'} = mtr_get_pid_from_file($instance_manager->{'path_pid'}); @@ -2281,10 +2317,12 @@ sub im_start($$) { sub im_stop($) { my $instance_manager = shift; - if (! defined $instance_manager->{'pid'}) - { - return; - } + # Re-read pid from the file, since during tests Instance Manager could have + # been restarted, so its pid could have been changed. + + $instance_manager->{'pid'} = + mtr_get_pid_from_file($instance_manager->{'path_pid'}) + if -f $instance_manager->{'path_pid'}; # Inspired from mtr_stop_mysqld_servers(). @@ -2299,12 +2337,12 @@ sub im_stop($) { if ( -r $instances->[0]->{'path_pid'} ) { - push @pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'}); + push(@pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'})); } if ( -r $instances->[1]->{'path_pid'} ) { - push @pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'}); + push(@pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'})); } # Kill processes. @@ -2319,6 +2357,15 @@ sub im_stop($) { sub run_mysqltest ($) { my $tinfo= shift; + my $cmdline_mysqlcheck= "$exe_mysqlcheck --no-defaults -uroot " . + "--port=$master->[0]->{'path_myport'} " . + "--socket=$master->[0]->{'path_mysock'} --password="; + if ( $opt_debug ) + { + $cmdline_mysqlcheck .= + " --debug=d:t:A,$opt_vardir/log/mysqldump.trace"; + } + my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " . "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'} --password="; @@ -2378,12 +2425,14 @@ sub run_mysqltest ($) { # $ENV{'PATH'}= "/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11:$ENV{'PATH'}"; $ENV{'MYSQL'}= $cmdline_mysql; + $ENV{'MYSQL_CHECK'}= $cmdline_mysqlcheck; $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; $ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test; $ENV{'CHARSETSDIR'}= $path_charsetsdir; + $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= $exe_my_print_defaults; $ENV{'NDB_STATUS_OK'}= $flag_ndb_status_ok; $ENV{'NDB_MGM'}= $exe_ndb_mgm; @@ -2397,6 +2446,11 @@ sub run_mysqltest ($) { mtr_init_args(\$args); + if ( defined $opt_valgrind_mysqltest ) + { + valgrind_arguments($args, \$exe); + } + mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--silent"); mtr_add_arg($args, "-v"); @@ -2442,11 +2496,6 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--big-test"); } - if ( $opt_record ) - { - mtr_add_arg($args, "--record"); - } - if ( $opt_compress ) { mtr_add_arg($args, "--compress"); @@ -2472,9 +2521,6 @@ sub run_mysqltest ($) { $glob_mysql_test_dir); } - mtr_add_arg($args, "-R"); - mtr_add_arg($args, $tinfo->{'result_file'}); - # ---------------------------------------------------------------------- # If embedded server, we create server args to give mysqltest to pass on # ---------------------------------------------------------------------- @@ -2484,9 +2530,56 @@ sub run_mysqltest ($) { mysqld_arguments($args,'master',0,$tinfo->{'master_opt'},[]); } + # ---------------------------------------------------------------------- + # export MYSQL_TEST variable containing <path>/mysqltest <args> + # ---------------------------------------------------------------------- + $ENV{'MYSQL_TEST'}= "$exe_mysqltest " . join(" ", @$args); + + # ---------------------------------------------------------------------- + # Add arguments that should not go into the MYSQL_TEST env var + # ---------------------------------------------------------------------- + + mtr_add_arg($args, "-R"); + mtr_add_arg($args, $tinfo->{'result_file'}); + + if ( $opt_record ) + { + mtr_add_arg($args, "--record"); + } + return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,""); } + +sub valgrind_arguments { + my $args= shift; + my $exe= shift; + + mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option + mtr_add_arg($args, "--alignment=8"); + mtr_add_arg($args, "--leak-check=yes"); + mtr_add_arg($args, "--num-callers=16"); + mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) + if -f "$glob_mysql_test_dir/valgrind.supp"; + + if ( defined $opt_valgrind_all ) + { + mtr_add_arg($args, "-v"); + mtr_add_arg($args, "--show-reachable=yes"); + } + + if ( $opt_valgrind_options ) + { + # FIXME split earlier and put into @glob_valgrind_* + mtr_add_arg($args, split(' ', $opt_valgrind_options)); + } + + mtr_add_arg($args, $$exe); + + $$exe= $opt_valgrind || "valgrind"; +} + + ############################################################################## # # Usage @@ -2515,6 +2608,7 @@ Options to control what test suites or cases to run start-from=PREFIX Run test cases starting from test prefixed with PREFIX suite=NAME Run the test suite named NAME. The default is "main" skip-rpl Skip the replication test cases. + skip-im Don't start IM, and skip the IM test cases skip-test=PREFIX Skip test cases which name are prefixed with PREFIX Options that specify ports @@ -2551,8 +2645,11 @@ Options for coverage, profiling etc gcov FIXME gprof FIXME - valgrind FIXME - valgrind-all FIXME + valgrind[=EXE] Run the "mysqltest" executable as well as the "mysqld" + server using valgrind, optionally specifying the + executable path/name + valgrind-mysqltest[=EXE] In addition, run the "mysqltest" executable with valgrind + valgrind-all[=EXE] Adds verbose flag, and --show-reachable to valgrind valgrind-options=ARGS Extra options to give valgrind Misc options diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 22331387097..a4f8f2ac1f9 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -222,6 +222,7 @@ FAILED_CASES= EXTRA_MASTER_OPT="" EXTRA_MYSQL_TEST_OPT="" +EXTRA_MYSQLCHECK_OPT="" EXTRA_MYSQLDUMP_OPT="" EXTRA_MYSQLSHOW_OPT="" EXTRA_MYSQLBINLOG_OPT="" @@ -235,6 +236,7 @@ DO_GDB="" MANUAL_GDB="" DO_DDD="" DO_CLIENT_GDB="" +DO_VALGRIND_MYSQL_TEST="" SLEEP_TIME_AFTER_RESTART=1 SLEEP_TIME_FOR_DELETE=10 SLEEP_TIME_FOR_FIRST_MASTER=400 # Enough time to create innodb tables @@ -254,6 +256,17 @@ NDB_MGM_EXTRA_OPTS= NDB_MGMD_EXTRA_OPTS= NDBD_EXTRA_OPTS= +DO_STRESS="" +STRESS_SUITE="main" +STRESS_MODE="random" +STRESS_THREADS=5 +STRESS_TEST_COUNT=20 +STRESS_LOOP_COUNT="" +STRESS_TEST_DURATION="" +STRESS_INIT_FILE="" +STRESS_TEST_FILE="" +STRESS_TEST="" + while test $# -gt 0; do case "$1" in --embedded-server) @@ -342,6 +355,35 @@ while test $# -gt 0; do DO_BENCH=1 NO_SLAVE=1 ;; + --stress) + DO_STRESS=1 + NO_SLAVE=1 + SKIP_SLAVE=1 + ;; + --stress-suite=*) + STRESS_SUITE=`$ECHO "$1" | $SED -e "s;--stress-suite=;;"` + ;; + --stress-threads=*) + STRESS_THREADS=`$ECHO "$1" | $SED -e "s;--stress-threads=;;"` + ;; + --stress-test-file=*) + STRESS_TEST_FILE=`$ECHO "$1" | $SED -e "s;--stress-test-file=;;"` + ;; + --stress-init-file=*) + STRESS_INIT_FILE=`$ECHO "$1" | $SED -e "s;--stress-init-file=;;"` + ;; + --stress-mode=*) + STRESS_MODE=`$ECHO "$1" | $SED -e "s;--stress-mode=;;"` + ;; + --stress-loop-count=*) + STRESS_LOOP_COUNT=`$ECHO "$1" | $SED -e "s;--stress-loop-count=;;"` + ;; + --stress-test-count=*) + STRESS_TEST_COUNT=`$ECHO "$1" | $SED -e "s;--stress-test-count=;;"` + ;; + --stress-test-duration=*) + STRESS_TEST_DURATION=`$ECHO "$1" | $SED -e "s;--stress-test-duration=;;"` + ;; --big*) # Actually --big-test EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; --compress) @@ -432,6 +474,9 @@ while test $# -gt 0; do TMP=`$ECHO "$1" | $SED -e "s;--valgrind-options=;;"` VALGRIND="$VALGRIND $TMP" ;; + --valgrind-mysqltest) + DO_VALGRIND_MYSQL_TEST=1 + ;; --skip-ndbcluster | --skip-ndb) USE_NDBCLUSTER="" EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-ndbcluster" @@ -451,6 +496,8 @@ while test $# -gt 0; do --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/slave.trace" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT \ --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqltest.trace" + EXTRA_MYSQLCHECK_OPT="$EXTRA_MYSQLCHECK_OPT \ + --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqlcheck.trace" EXTRA_MYSQLDUMP_OPT="$EXTRA_MYSQLDUMP_OPT \ --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqldump.trace" EXTRA_MYSQLSHOW_OPT="$EXTRA_MYSQLSHOW_OPT \ @@ -553,6 +600,11 @@ if [ x$SOURCE_DIST = x1 ] ; then fi MYSQL_CLIENT_TEST="$BASEDIR/tests/mysql_client_test" fi + if [ -f "$BASEDIR/client/.libs/mysqlcheck" ] ; then + MYSQL_CHECK="$BASEDIR/client/.libs/mysqlcheck" + else + MYSQL_CHECK="$BASEDIR/client/mysqlcheck" + fi if [ -f "$BASEDIR/client/.libs/mysqldump" ] ; then MYSQL_DUMP="$BASEDIR/client/.libs/mysqldump" else @@ -575,6 +627,7 @@ if [ x$SOURCE_DIST = x1 ] ; then CLIENT_BINDIR="$BASEDIR/client" MYSQLADMIN="$CLIENT_BINDIR/mysqladmin" WAIT_PID="$BASEDIR/extra/mysql_waitpid" + MYSQL_MY_PRINT_DEFAULTS="$BASEDIR/extra/my_print_defaults" MYSQL_MANAGER_CLIENT="$CLIENT_BINDIR/mysqltestmanagerc" MYSQL_MANAGER="$BASEDIR/tools/mysqltestmanager" MYSQL_MANAGER_PWGEN="$CLIENT_BINDIR/mysqltestmanager-pwgen" @@ -630,11 +683,13 @@ else TESTS_BINDIR="$BASEDIR/bin" fi MYSQL_TEST="$CLIENT_BINDIR/mysqltest" + MYSQL_CHECK="$CLIENT_BINDIR/mysqlcheck" MYSQL_DUMP="$CLIENT_BINDIR/mysqldump" MYSQL_SHOW="$CLIENT_BINDIR/mysqlshow" MYSQL_BINLOG="$CLIENT_BINDIR/mysqlbinlog" MYSQLADMIN="$CLIENT_BINDIR/mysqladmin" WAIT_PID="$CLIENT_BINDIR/mysql_waitpid" + MYSQL_MY_PRINT_DEFAULTS="$CLIENT_BINDIR/my_print_defaults" MYSQL_MANAGER="$CLIENT_BINDIR/mysqltestmanager" MYSQL_MANAGER_CLIENT="$CLIENT_BINDIR/mysqltestmanagerc" MYSQL_MANAGER_PWGEN="$CLIENT_BINDIR/mysqltestmanager-pwgen" @@ -664,7 +719,7 @@ else MYSQL_CLIENT_TEST="$CLIENT_BINDIR/mysql_client_test_embedded" fi else - MYSQL_TEST="$CLIENT_BINDIR/mysqltest" + MYSQL_TEST="$VALGRIND_MYSQLTEST $CLIENT_BINDIR/mysqltest" MYSQL_CLIENT_TEST="$CLIENT_BINDIR/mysql_client_test" fi fi @@ -679,9 +734,13 @@ then SLAVE_MYSQLD=$MYSQLD fi +if [ x$DO_VALGRIND_MYSQL_TEST = x1 ] ; then + MYSQL_TEST="$VALGRIND $MYSQL_TEST" +fi + # If we should run all tests cases, we will use a local server for that -if [ -z "$1" ] +if [ -z "$1" -a -z "$DO_STRESS" ] then USE_RUNNING_SERVER=0 fi @@ -710,13 +769,14 @@ fi # Save path and name of mysqldump MYSQL_DUMP_DIR="$MYSQL_DUMP" export MYSQL_DUMP_DIR +MYSQL_CHECK="$MYSQL_CHECK --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLCHECK_OPT" MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT" MYSQL_SHOW="$MYSQL_SHOW -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLSHOW_OPT" MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR --character-sets-dir=$CHARSETSDIR $EXTRA_MYSQLBINLOG_OPT" MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD --basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose" MYSQL="$MYSQL --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD" -export MYSQL MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES -export CLIENT_BINDIR MYSQL_CLIENT_TEST CHARSETSDIR +export MYSQL MYSQL_CHECK MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES +export CLIENT_BINDIR MYSQL_CLIENT_TEST CHARSETSDIR MYSQL_MY_PRINT_DEFAULTS export NDB_TOOLS_DIR export NDB_MGM export NDB_BACKUP_DIR @@ -733,6 +793,7 @@ if [ x$USE_TIMER = x1 ] ; then fi MYSQL_TEST_BIN=$MYSQL_TEST MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS" +export MYSQL_TEST GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client GDB_MASTER_INIT=$MYSQL_TMP_DIR/gdbinit.master GDB_SLAVE_INIT=$MYSQL_TMP_DIR/gdbinit.slave @@ -746,7 +807,7 @@ if [ -n "$DO_CLIENT_GDB" -o -n "$DO_GDB" ] ; then XTERM=`which xterm` fi -export MYSQL MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES CLIENT_BINDIR MASTER_MYSOCK +export MYSQL MYSQL_CHECK MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES CLIENT_BINDIR MASTER_MYSOCK #++ # Function Definitions @@ -1168,7 +1229,7 @@ start_master() then CURR_MASTER_MYSQLD_TRACE="$EXTRA_MASTER_MYSQLD_TRACE$1" fi - if [ -z "$DO_BENCH" ] + if [ -z "$DO_BENCH" -a -z "$DO_STRESS" ] then master_args="--no-defaults --log-bin=$MYSQL_TEST_DIR/var/log/master-bin$1 \ --server-id=$id \ @@ -1605,7 +1666,7 @@ run_testcase () stop_master 1 report_current_test $tname start_master - if [ -n "$USE_NDBCLUSTER" -a -z "$DO_BENCH" ] ; then + if [ -n "$USE_NDBCLUSTER" -a -z "$DO_BENCH" -a -z "$DO_STRESS" ] ; then start_master 1 fi TZ=$MY_TZ; export TZ @@ -1621,7 +1682,7 @@ run_testcase () stop_master 1 report_current_test $tname start_master - if [ -n "$USE_NDBCLUSTER" -a -z "$DO_BENCH" ] ; then + if [ -n "$USE_NDBCLUSTER" -a -z "$DO_BENCH" -a -z "$DO_STRESS" ] ; then start_master 1 fi else @@ -1742,6 +1803,125 @@ run_testcase () fi } +run_stress_test() +{ + + STRESS_BASEDIR="$MYSQL_TEST_DIR/var/stress" + + #Clean-up old stress test basedir + if [ -d $STRESS_BASEDIR ] ; then + $RM -rf $STRESS_BASEDIR + fi + #Create stress test basedir + mkdir $STRESS_BASEDIR + + if [ "$STRESS_SUITE" != "main" -a "$STRESS_SUITE" != "default" ] ; then + STRESS_SUITE_DIR="$MYSQL_TEST_DIR/suite/$STRESS_SUITE" + else + STRESS_SUITE_DIR="$MYSQL_TEST_DIR" + fi + + if [ -d "$STRESS_SUITE_DIR" ] ; then + STRESS_SUITE_T_DIR="$STRESS_SUITE_DIR/t" + STRESS_SUITE_R_DIR="$STRESS_SUITE_DIR/r" + #FIXME: check that dirs above are exist + else + echo "Directory $STRESS_SUITE_DIR with test suite doesn't exists. Abort stress testing" + exit 1 + fi + + if [ -n "$STRESS_TEST" ] ; then + STRESS_TEST_FILE="$STRESS_BASEDIR/stress_tests.txt" + echo $STRESS_TEST > $STRESS_TEST_FILE + elif [ -n "$STRESS_TEST_FILE" ] ; then + STRESS_TEST_FILE="$STRESS_SUITE_DIR/$STRESS_TEST_FILE" + if [ ! -f "$STRESS_TEST_FILE" ] ; then + echo "Specified file $STRESS_TEST_FILE with list of tests does not exist" + echo "Please ensure that file exists and has proper permissions" + exit 1 + fi + else + STRESS_TEST_FILE="$STRESS_SUITE_DIR/stress_tests.txt" + if [ ! -f "$STRESS_TEST_FILE" ] ; then + echo "Default file $STRESS_TEST_FILE with list of tests does not exist." + echo "Please use --stress-test-file option to specify custom one or you can" + echo "just specify name of test for testing as last argument in command line" + exit 1 + fi + fi + + if [ -n "$STRESS_INIT_FILE" ] ; then + STRESS_INIT_FILE="$STRESS_SUITE_DIR/$STRESS_INIT_FILE" + if [ ! -f "$STRESS_INIT_FILE" ] ; then + echo "Specified file $STRESS_INIT_FILE with list of tests doesn't exist." + echo "Please ensure that file exists and has proper permissions" + exit 1 + fi + else + STRESS_INIT_FILE="$STRESS_SUITE_DIR/stress_init.txt" + #Check for default init file + if [ ! -f "$STRESS_INIT_FILE" ] ; then + STRESS_INIT_FILE="" + fi + fi + + if [ "$STRESS_MODE" != "random" -a "$STRESS_MODE" != "seq" ] ; then + echo "You specified wrong mode '$STRESS_MODE' for stress test." + echo "Correct values are 'random' or 'seq'" + exit 1 + fi + + STRESS_TEST_ARGS="--server-socket=$MASTER_MYSOCK \ + --server-user=$DBUSER \ + --server-database=$DB \ + --stress-suite-basedir=$MYSQL_TEST_DIR \ + --suite=$STRESS_SUITE \ + --stress-tests-file=$STRESS_TEST_FILE \ + --stress-basedir=$STRESS_BASEDIR \ + --server-logs-dir=$STRESS_BASEDIR \ + --stress-mode=$STRESS_MODE \ + --mysqltest=$BASEDIR/client/mysqltest \ + --threads=$STRESS_THREADS \ + --verbose \ + --cleanup \ + --log-error-details \ + --abort-on-error" + + if [ -n "$STRESS_INIT_FILE" ] ; then + STRESS_TEST_ARGS="$STRESS_TEST_ARGS --stress-init-file=$STRESS_INIT_FILE" + fi + + if [ -n "$STRESS_LOOP_COUNT" ] ; then + STRESS_TEST_ARGS="$STRESS_TEST_ARGS --loop-count=$STRESS_LOOP_COUNT" + fi + + if [ -n "$STRESS_TEST_COUNT" ] ; then + STRESS_TEST_ARGS="$STRESS_TEST_ARGS --test-count=$STRESS_TEST_COUNT" + fi + + if [ -n "$STRESS_TEST_DURATION" ] ; then + STRESS_TEST_ARGS="$STRESS_TEST_ARGS --test-duration=$STRESS_TEST_DURATION" + fi + + echo "Stress test related variables:" + echo "TESTS - $1" + echo "STRESS - $DO_STRESS" + echo "STRESS_SUITE - $STRESS_SUITE" + echo "STRESS_TEST_FILE - $STRESS_TEST_FILE" + echo "STRESS_INIT_FILE - $STRESS_INIT_FILE" + echo "STRESS_THREADS - $STRESS_THREADS" + echo "STRESS_MODE - $STRESS_MODE" + echo "STRESS_TEST_COUNT - $STRESS_TEST_COUNT" + echo "STRESS_LOOP_COUNT - $STRESS_LOOP_COUNT" + echo "STRESS_TEST_DURATION - $STRESS_TEST_DURATION" + + #echo "$STRESS_TEST_ARGS"; + #Run stress test + $MYSQL_TEST_DIR/mysql-stress-test.pl $STRESS_TEST_ARGS + + +} + ###################################################################### # Main script starts here ###################################################################### @@ -1856,6 +2036,32 @@ then exit fi +# +# Stress testing +# +if [ "$DO_STRESS" = 1 ] +then + + if [ -n "$1" ] ; then + STRESS_TEST="$1"; + fi + + if [ $USE_RUNNING_SERVER -eq 0 ] ; then + start_master + fi + + run_stress_test + + if [ $USE_RUNNING_SERVER -eq 0 ] ; then + mysql_stop + stop_manager + fi + + exit + +fi + + $ECHO if [ x$USE_TIMER = x1 ] ; then $ECHO "TEST RESULT TIME (ms)" diff --git a/mysql-test/mysql_test_run_new.c b/mysql-test/mysql_test_run_new.c index b23b7ceb6a1..33a69eba872 100644 --- a/mysql-test/mysql_test_run_new.c +++ b/mysql-test/mysql_test_run_new.c @@ -1741,7 +1741,6 @@ int main(int argc, char **argv) int* handle; char test[FN_LEN]; char mask[FN_REFLEN]; - char *p; int position; /* single test */ diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 6a710a8de10..9b60a187d0b 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -436,7 +436,7 @@ alter table t1 change a a char(10) character set cp1251; select a,hex(a) from t1; a hex(a) ÔÅÓÔ F2E5F1F2 -alter table t1 change a a binary(10); +alter table t1 change a a binary(4); select a,hex(a) from t1; a hex(a) òåñò F2E5F1F2 @@ -541,16 +541,16 @@ create table t1 ( a timestamp ); alter table t1 add unique ( a(1) ); ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys drop table t1; -create database mysqltest1; +create database mysqltest; create table t1 (c1 int); -alter table t1 rename mysqltest1.t1; +alter table t1 rename mysqltest.t1; drop table t1; ERROR 42S02: Unknown table 't1' -alter table mysqltest1.t1 rename t1; +alter table mysqltest.t1 rename t1; drop table t1; create table t1 (c1 int); -use mysqltest1; -drop database mysqltest1; +use mysqltest; +drop database mysqltest; alter table test.t1 rename t1; ERROR 3D000: No database selected alter table test.t1 rename test.t1; diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index a56902e8ae7..df524b491f1 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -109,3 +109,9 @@ select * from t1 procedure analyse(); Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype test.t1.df 1.1 2.2 8 8 0 0 1.650000000 0.302500000 ENUM('1.1','2.2') NOT NULL drop table t1; +create table t1 (d double); +insert into t1 values (100000); +select * from t1 procedure analyse (1,1); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.d 100000 100000 6 6 0 0 100000 0 MEDIUMINT(6) UNSIGNED NOT NULL +drop table t1; diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 075f0f716d2..788e1444db4 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -9902,5 +9902,1223 @@ auto fld1 companynr fld3 fld4 fld5 fld6 2 011401 37 breaking dreaded Steinberg W 3 011402 37 Romans scholastics jarring 4 011403 37 intercepted audiology tinily +CHECK TABLE t2; +Table Op Msg_type Msg_text +test.t2 check status OK +SELECT * FROM t2; +auto fld1 companynr fld3 fld4 fld5 fld6 +1 000001 00 Omaha teethe neat +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily +5 011501 37 bewilderingly wallet balled +6 011701 37 astound parters persist W +7 011702 37 admonishing eschew attainments +8 011703 37 sumac quitter fanatic +9 012001 37 flanking neat measures FAS +10 012003 37 combed Steinberg rightfulness +11 012004 37 subjective jarring capably +12 012005 37 scatterbrain tinily impulsive +13 012301 37 Eulerian balled starlet +14 012302 36 dubbed persist terminators +15 012303 37 Kane attainments untying +16 012304 37 overlay fanatic announces FAS +17 012305 37 perturb measures featherweight FAS +18 012306 37 goblins rightfulness pessimist FAS +19 012501 37 annihilates capably daughter +20 012602 37 Wotan impulsive decliner FAS +21 012603 37 snatching starlet lawgiver +22 012604 37 concludes terminators stated +23 012605 37 laterally untying readable +24 012606 37 yelped announces attrition +25 012701 37 grazing featherweight cascade FAS +26 012702 37 Baird pessimist motors FAS +27 012703 37 celery daughter interrogate +28 012704 37 misunderstander decliner pests W +29 013601 37 handgun lawgiver stairway +30 013602 37 foldout stated dopers FAS +31 013603 37 mystic readable testicle W +32 013604 37 succumbed attrition Parsifal W +33 013605 37 Nabisco cascade leavings +34 013606 37 fingerings motors postulation W +35 013607 37 aging interrogate squeaking +36 013608 37 afield pests contrasted +37 013609 37 ammonium stairway leftover +38 013610 37 boat dopers whiteners +39 013801 37 intelligibility testicle erases W +40 013802 37 Augustine Parsifal Punjab W +41 013803 37 teethe leavings Merritt +42 013804 37 dreaded postulation Quixotism +43 013901 37 scholastics squeaking sweetish FAS +44 016001 37 audiology contrasted dogging FAS +45 016201 37 wallet leftover scornfully FAS +46 016202 37 parters whiteners bellow +47 016301 37 eschew erases bills +48 016302 37 quitter Punjab cupboard FAS +49 016303 37 neat Merritt sureties FAS +50 016304 37 Steinberg Quixotism puddings +51 018001 37 jarring sweetish tapestry +52 018002 37 tinily dogging fetters +53 018003 37 balled scornfully bivalves +54 018004 37 persist bellow incurring +55 018005 37 attainments bills Adolph +56 018007 37 fanatic cupboard pithed +57 018008 37 measures sureties emergency +58 018009 37 rightfulness puddings Miles +59 018010 37 capably tapestry trimmings +60 018012 37 impulsive fetters tragedies W +61 018013 37 starlet bivalves skulking W +62 018014 37 terminators incurring flint +63 018015 37 untying Adolph flopping W +64 018016 37 announces pithed relaxing FAS +65 018017 37 featherweight emergency offload FAS +66 018018 37 pessimist Miles suites W +67 018019 37 daughter trimmings lists FAS +68 018020 37 decliner tragedies animized FAS +69 018021 37 lawgiver skulking multilayer W +70 018022 37 stated flint standardizes FAS +71 018023 37 readable flopping Judas +72 018024 37 attrition relaxing vacuuming W +73 018025 37 cascade offload dentally W +74 018026 37 motors suites humanness W +75 018027 37 interrogate lists inch W +76 018028 37 pests animized Weissmuller W +77 018029 37 stairway multilayer irresponsibly W +78 018030 37 dopers standardizes luckily FAS +79 018032 37 testicle Judas culled W +80 018033 37 Parsifal vacuuming medical FAS +81 018034 37 leavings dentally bloodbath FAS +82 018035 37 postulation humanness subschema W +83 018036 37 squeaking inch animals W +84 018037 37 contrasted Weissmuller Micronesia +85 018038 37 leftover irresponsibly repetitions +86 018039 37 whiteners luckily Antares +87 018040 37 erases culled ventilate W +88 018041 37 Punjab medical pityingly +89 018042 37 Merritt bloodbath interdependent +90 018043 37 Quixotism subschema Graves FAS +91 018044 37 sweetish animals neonatal +92 018045 37 dogging Micronesia scribbled FAS +93 018046 37 scornfully repetitions chafe W +94 018048 37 bellow Antares honoring +95 018049 37 bills ventilate realtor +96 018050 37 cupboard pityingly elite +97 018051 37 sureties interdependent funereal +98 018052 37 puddings Graves abrogating +99 018053 50 tapestry neonatal sorters +100 018054 37 fetters scribbled Conley +101 018055 37 bivalves chafe lectured +102 018056 37 incurring honoring Abraham +103 018057 37 Adolph realtor Hawaii W +104 018058 37 pithed elite cage +105 018059 36 emergency funereal hushes +106 018060 37 Miles abrogating Simla +107 018061 37 trimmings sorters reporters +108 018101 37 tragedies Conley Dutchman FAS +109 018102 37 skulking lectured descendants FAS +110 018103 37 flint Abraham groupings FAS +111 018104 37 flopping Hawaii dissociate +112 018201 37 relaxing cage coexist W +113 018202 37 offload hushes Beebe +114 018402 37 suites Simla Taoism +115 018403 37 lists reporters Connally +116 018404 37 animized Dutchman fetched FAS +117 018405 37 multilayer descendants checkpoints FAS +118 018406 37 standardizes groupings rusting +119 018409 37 Judas dissociate galling +120 018601 37 vacuuming coexist obliterates +121 018602 37 dentally Beebe traitor +122 018603 37 humanness Taoism resumes FAS +123 018801 37 inch Connally analyzable FAS +124 018802 37 Weissmuller fetched terminator FAS +125 018803 37 irresponsibly checkpoints gritty FAS +126 018804 37 luckily rusting firearm W +127 018805 37 culled galling minima +128 018806 37 medical obliterates Selfridge +129 018807 37 bloodbath traitor disable +130 018808 37 subschema resumes witchcraft W +131 018809 37 animals analyzable betroth W +132 018810 37 Micronesia terminator Manhattanize +133 018811 37 repetitions gritty imprint +134 018812 37 Antares firearm peeked +135 019101 37 ventilate minima swelling +136 019102 37 pityingly Selfridge interrelationships W +137 019103 37 interdependent disable riser +138 019201 37 Graves witchcraft Gandhian W +139 030501 37 neonatal betroth peacock A +140 030502 50 scribbled Manhattanize bee A +141 030503 37 chafe imprint kanji +142 030504 37 honoring peeked dental +143 031901 37 realtor swelling scarf FAS +144 036001 37 elite interrelationships chasm A +145 036002 37 funereal riser insolence A +146 036004 37 abrogating Gandhian syndicate +147 036005 37 sorters peacock alike +148 038001 37 Conley bee imperial A +149 038002 37 lectured kanji convulsion A +150 038003 37 Abraham dental railway A +151 038004 37 Hawaii scarf validate A +152 038005 37 cage chasm normalizes A +153 038006 37 hushes insolence comprehensive +154 038007 37 Simla syndicate chewing +155 038008 37 reporters alike denizen +156 038009 37 Dutchman imperial schemer +157 038010 37 descendants convulsion chronicle +158 038011 37 groupings railway Kline +159 038012 37 dissociate validate Anatole +160 038013 37 coexist normalizes partridges +161 038014 37 Beebe comprehensive brunch +162 038015 37 Taoism chewing recruited +163 038016 37 Connally denizen dimensions W +164 038017 37 fetched schemer Chicana W +165 038018 37 checkpoints chronicle announced +166 038101 37 rusting Kline praised FAS +167 038102 37 galling Anatole employing +168 038103 37 obliterates partridges linear +169 038104 37 traitor brunch quagmire +170 038201 37 resumes recruited western A +171 038202 37 analyzable dimensions relishing +172 038203 37 terminator Chicana serving A +173 038204 37 gritty announced scheduling +174 038205 37 firearm praised lore +175 038206 37 minima employing eventful +176 038208 37 Selfridge linear arteriole A +177 042801 37 disable quagmire disentangle +178 042802 37 witchcraft western cured A +179 046101 37 betroth relishing Fenton W +180 048001 37 Manhattanize serving avoidable A +181 048002 37 imprint scheduling drains A +182 048003 37 peeked lore detectably FAS +183 048004 37 swelling eventful husky +184 048005 37 interrelationships arteriole impelling +185 048006 37 riser disentangle undoes +186 048007 37 Gandhian cured evened +187 048008 37 peacock Fenton squeezes +188 048101 37 bee avoidable destroyer FAS +189 048102 37 kanji drains rudeness +190 048201 37 dental detectably beaner FAS +191 048202 37 scarf husky boorish +192 048203 37 chasm impelling Everhart +193 048204 37 insolence undoes encompass A +194 048205 37 syndicate evened mushrooms +195 048301 37 alike squeezes Alison A +196 048302 37 imperial destroyer externally FAS +197 048303 37 convulsion rudeness pellagra +198 048304 37 railway beaner cult +199 048305 37 validate boorish creek A +200 048401 37 normalizes Everhart Huffman +201 048402 37 comprehensive encompass Majorca FAS +202 048403 37 chewing mushrooms governing A +203 048404 37 denizen Alison gadfly FAS +204 048405 37 schemer externally reassigned FAS +205 048406 37 chronicle pellagra intentness W +206 048407 37 Kline cult craziness +207 048408 37 Anatole creek psychic +208 048409 37 partridges Huffman squabbled +209 048410 37 brunch Majorca burlesque +210 048411 37 recruited governing capped +211 048412 37 dimensions gadfly extracted A +212 048413 37 Chicana reassigned DiMaggio +213 048601 37 announced intentness exclamation FAS +214 048602 37 praised craziness subdirectory +215 048603 37 employing psychic fangs +216 048604 37 linear squabbled buyer A +217 048801 37 quagmire burlesque pithing A +218 050901 37 western capped transistorizing A +219 051201 37 relishing extracted nonbiodegradable +220 056002 37 serving DiMaggio dislocate +221 056003 37 scheduling exclamation monochromatic FAS +222 056004 37 lore subdirectory batting +223 056102 37 eventful fangs postcondition A +224 056203 37 arteriole buyer catalog FAS +225 056204 37 disentangle pithing Remus +226 058003 37 cured transistorizing devices A +227 058004 37 Fenton nonbiodegradable bike A +228 058005 37 avoidable dislocate qualify +229 058006 37 drains monochromatic detained +230 058007 37 detectably batting commended +231 058101 37 husky postcondition civilize +232 058102 37 impelling catalog Elmhurst +233 058103 37 undoes Remus anesthetizing +234 058105 37 evened devices deaf +235 058111 37 squeezes bike Brigham +236 058112 37 destroyer qualify title +237 058113 37 rudeness detained coarse +238 058114 37 beaner commended combinations +239 058115 37 boorish civilize grayness +240 058116 37 Everhart Elmhurst innumerable FAS +241 058117 37 encompass anesthetizing Caroline A +242 058118 37 mushrooms deaf fatty FAS +243 058119 37 Alison Brigham eastbound +244 058120 37 externally title inexperienced +245 058121 37 pellagra coarse hoarder A +246 058122 37 cult combinations scotch W +247 058123 37 creek grayness passport A +248 058124 37 Huffman innumerable strategic FAS +249 058125 37 Majorca Caroline gated +250 058126 37 governing fatty flog +251 058127 37 gadfly eastbound Pipestone +252 058128 37 reassigned inexperienced Dar +253 058201 37 intentness hoarder Corcoran +254 058202 37 craziness scotch flyers A +255 058303 37 psychic passport competitions W +256 058304 37 squabbled strategic suppliers FAS +257 058602 37 burlesque gated skips +258 058603 37 capped flog institutes +259 058604 37 extracted Pipestone troop A +260 058605 37 DiMaggio Dar connective W +261 058606 37 exclamation Corcoran denies +262 058607 37 subdirectory flyers polka +263 060401 36 fangs competitions observations FAS +264 061701 36 buyer suppliers askers +265 066201 36 pithing skips homeless FAS +266 066501 36 transistorizing institutes Anna +267 068001 36 nonbiodegradable troop subdirectories W +268 068002 36 dislocate connective decaying FAS +269 068005 36 monochromatic denies outwitting W +270 068006 36 batting polka Harpy W +271 068007 36 postcondition observations crazed +272 068008 36 catalog askers suffocate +273 068009 36 Remus homeless provers FAS +274 068010 36 devices Anna technically +275 068011 36 bike subdirectories Franklinizations +276 068202 36 qualify decaying considered +277 068302 36 detained outwitting tinnily +278 068303 36 commended Harpy uninterruptedly +279 068401 36 civilize crazed whistled A +280 068501 36 Elmhurst suffocate automate +281 068502 36 anesthetizing provers gutting W +282 068503 36 deaf technically surreptitious +283 068602 36 Brigham Franklinizations Choctaw +284 068603 36 title considered cooks +285 068701 36 coarse tinnily millivolt FAS +286 068702 36 combinations uninterruptedly counterpoise +287 068703 36 grayness whistled Gothicism +288 076001 36 innumerable automate feminine +289 076002 36 Caroline gutting metaphysically W +290 076101 36 fatty surreptitious sanding A +291 076102 36 eastbound Choctaw contributorily +292 076103 36 inexperienced cooks receivers FAS +293 076302 36 hoarder millivolt adjourn +294 076303 36 scotch counterpoise straggled A +295 076304 36 passport Gothicism druggists +296 076305 36 strategic feminine thanking FAS +297 076306 36 gated metaphysically ostrich +298 076307 36 flog sanding hopelessness FAS +299 076402 36 Pipestone contributorily Eurydice +300 076501 36 Dar receivers excitation W +301 076502 36 Corcoran adjourn presumes FAS +302 076701 36 flyers straggled imaginable FAS +303 078001 36 competitions druggists concoct W +304 078002 36 suppliers thanking peering W +305 078003 36 skips ostrich Phelps FAS +306 078004 36 institutes hopelessness ferociousness FAS +307 078005 36 troop Eurydice sentences +308 078006 36 connective excitation unlocks +309 078007 36 denies presumes engrossing W +310 078008 36 polka imaginable Ruth +311 078101 36 observations concoct tying +312 078103 36 askers peering exclaimers +313 078104 36 homeless Phelps synergy +314 078105 36 Anna ferociousness Huey W +315 082101 36 subdirectories sentences merging +316 083401 36 decaying unlocks judges A +317 084001 36 outwitting engrossing Shylock W +318 084002 36 Harpy Ruth Miltonism +319 086001 36 crazed tying hen W +320 086102 36 suffocate exclaimers honeybee FAS +321 086201 36 provers synergy towers +322 088001 36 technically Huey dilutes W +323 088002 36 Franklinizations merging numerals FAS +324 088003 36 considered judges democracy FAS +325 088004 36 tinnily Shylock Ibero- +326 088101 36 uninterruptedly Miltonism invalids +327 088102 36 whistled hen behavior +328 088103 36 automate honeybee accruing +329 088104 36 gutting towers relics A +330 088105 36 surreptitious dilutes rackets +331 088106 36 Choctaw numerals Fischbein W +332 088201 36 cooks democracy phony W +333 088203 36 millivolt Ibero- cross FAS +334 088204 36 counterpoise invalids cleanup +335 088302 37 Gothicism behavior conspirator +336 088303 37 feminine accruing label FAS +337 088305 37 metaphysically relics university +338 088402 37 sanding rackets cleansed FAS +339 088501 36 contributorily Fischbein ballgown +340 088502 36 receivers phony starlet +341 088503 36 adjourn cross aqueous +342 098001 58 straggled cleanup portrayal A +343 098002 58 druggists conspirator despising W +344 098003 58 thanking label distort W +345 098004 58 ostrich university palmed +346 098005 58 hopelessness cleansed faced +347 098006 58 Eurydice ballgown silverware +348 141903 29 excitation starlet assessor +349 098008 58 presumes aqueous spiders +350 098009 58 imaginable portrayal artificially +351 098010 58 concoct despising reminiscence +352 098011 58 peering distort Mexican +353 098012 58 Phelps palmed obnoxious +354 098013 58 ferociousness faced fragile +355 098014 58 sentences silverware apprehensible +356 098015 58 unlocks assessor births +357 098016 58 engrossing spiders garages +358 098017 58 Ruth artificially panty +359 098018 58 tying reminiscence anteater +360 098019 58 exclaimers Mexican displacement A +361 098020 58 synergy obnoxious drovers A +362 098021 58 Huey fragile patenting A +363 098022 58 merging apprehensible far A +364 098023 58 judges births shrieks +365 098024 58 Shylock garages aligning W +366 098025 37 Miltonism panty pragmatism +367 106001 36 hen anteater fevers W +368 108001 36 honeybee displacement reexamines A +369 108002 36 towers drovers occupancies +370 108003 36 dilutes patenting sweats FAS +371 108004 36 numerals far modulators +372 108005 36 democracy shrieks demand W +373 108007 36 Ibero- aligning Madeira +374 108008 36 invalids pragmatism Viennese W +375 108009 36 behavior fevers chillier W +376 108010 36 accruing reexamines wildcats FAS +377 108011 36 relics occupancies gentle +378 108012 36 rackets sweats Angles W +379 108101 36 Fischbein modulators accuracies +380 108102 36 phony demand toggle +381 108103 36 cross Madeira Mendelssohn W +382 108111 50 cleanup Viennese behaviorally +383 108105 36 conspirator chillier Rochford +384 108106 36 label wildcats mirror W +385 108107 36 university gentle Modula +386 108108 50 cleansed Angles clobbering +387 108109 36 ballgown accuracies chronography +388 108110 36 starlet toggle Eskimoizeds +389 108201 36 aqueous Mendelssohn British W +390 108202 36 portrayal behaviorally pitfalls +391 108203 36 despising Rochford verify W +392 108204 36 distort mirror scatter FAS +393 108205 36 palmed Modula Aztecan +394 108301 36 faced clobbering acuity W +395 108302 36 silverware chronography sinking W +396 112101 36 assessor Eskimoizeds beasts FAS +397 112102 36 spiders British Witt W +398 113701 36 artificially pitfalls physicists FAS +399 116001 36 reminiscence verify folksong A +400 116201 36 Mexican scatter strokes FAS +401 116301 36 obnoxious Aztecan crowder +402 116302 36 fragile acuity merry +403 116601 36 apprehensible sinking cadenced +404 116602 36 births beasts alimony A +405 116603 36 garages Witt principled A +406 116701 36 panty physicists golfing +407 116702 36 anteater folksong undiscovered +408 118001 36 displacement strokes irritates +409 118002 36 drovers crowder patriots A +410 118003 36 patenting merry rooms FAS +411 118004 36 far cadenced towering W +412 118005 36 shrieks alimony displease +413 118006 36 aligning principled photosensitive +414 118007 36 pragmatism golfing inking +415 118008 36 fevers undiscovered gainers +416 118101 36 reexamines irritates leaning A +417 118102 36 occupancies patriots hydrant A +418 118103 36 sweats rooms preserve +419 118202 36 modulators towering blinded A +420 118203 36 demand displease interactions A +421 118204 36 Madeira photosensitive Barry +422 118302 36 Viennese inking whiteness A +423 118304 36 chillier gainers pastimes W +424 118305 36 wildcats leaning Edenization +425 118306 36 gentle hydrant Muscat +426 118307 36 Angles preserve assassinated +427 123101 36 accuracies blinded labeled +428 123102 36 toggle interactions glacial A +429 123301 36 Mendelssohn Barry implied W +430 126001 36 behaviorally whiteness bibliographies W +431 126002 36 Rochford pastimes Buchanan +432 126003 36 mirror Edenization forgivably FAS +433 126101 36 Modula Muscat innuendo A +434 126301 36 clobbering assassinated den FAS +435 126302 36 chronography labeled submarines W +436 126402 36 Eskimoizeds glacial mouthful A +437 126601 36 British implied expiring +438 126602 36 pitfalls bibliographies unfulfilled FAS +439 126702 36 verify Buchanan precession +440 128001 36 scatter forgivably nullified +441 128002 36 Aztecan innuendo affects +442 128003 36 acuity den Cynthia +443 128004 36 sinking submarines Chablis A +444 128005 36 beasts mouthful betterments FAS +445 128007 36 Witt expiring advertising +446 128008 36 physicists unfulfilled rubies A +447 128009 36 folksong precession southwest FAS +448 128010 36 strokes nullified superstitious A +449 128011 36 crowder affects tabernacle W +450 128012 36 merry Cynthia silk A +451 128013 36 cadenced Chablis handsomest A +452 128014 36 alimony betterments Persian A +453 128015 36 principled advertising analog W +454 128016 36 golfing rubies complex W +455 128017 36 undiscovered southwest Taoist +456 128018 36 irritates superstitious suspend +457 128019 36 patriots tabernacle relegated +458 128020 36 rooms silk awesome W +459 128021 36 towering handsomest Bruxelles +460 128022 36 displease Persian imprecisely A +461 128023 36 photosensitive analog televise +462 128101 36 inking complex braking +463 128102 36 gainers Taoist true FAS +464 128103 36 leaning suspend disappointing FAS +465 128104 36 hydrant relegated navally W +466 128106 36 preserve awesome circus +467 128107 36 blinded Bruxelles beetles +468 128108 36 interactions imprecisely trumps +469 128202 36 Barry televise fourscore W +470 128203 36 whiteness braking Blackfoots +471 128301 36 pastimes true Grady +472 128302 36 Edenization disappointing quiets FAS +473 128303 36 Muscat navally floundered FAS +474 128304 36 assassinated circus profundity W +475 128305 36 labeled beetles Garrisonian W +476 128307 36 glacial trumps Strauss +477 128401 36 implied fourscore cemented FAS +478 128502 36 bibliographies Blackfoots contrition A +479 128503 36 Buchanan Grady mutations +480 128504 36 forgivably quiets exhibits W +481 128505 36 innuendo floundered tits +482 128601 36 den profundity mate A +483 128603 36 submarines Garrisonian arches +484 128604 36 mouthful Strauss Moll +485 128702 36 expiring cemented ropers +486 128703 36 unfulfilled contrition bombast +487 128704 36 precession mutations difficultly A +488 138001 36 nullified exhibits adsorption +489 138002 36 affects tits definiteness FAS +490 138003 36 Cynthia mate cultivation A +491 138004 36 Chablis arches heals A +492 138005 36 betterments Moll Heusen W +493 138006 36 advertising ropers target FAS +494 138007 36 rubies bombast cited A +495 138008 36 southwest difficultly congresswoman W +496 138009 36 superstitious adsorption Katherine +497 138102 36 tabernacle definiteness titter A +498 138103 36 silk cultivation aspire A +499 138104 36 handsomest heals Mardis +500 138105 36 Persian Heusen Nadia W +501 138201 36 analog target estimating FAS +502 138302 36 complex cited stuck A +503 138303 36 Taoist congresswoman fifteenth A +504 138304 36 suspend Katherine Colombo +505 138401 29 relegated titter survey A +506 140102 29 awesome aspire staffing +507 140103 29 Bruxelles Mardis obtain +508 140104 29 imprecisely Nadia loaded +509 140105 29 televise estimating slaughtered +510 140201 29 braking stuck lights A +511 140701 29 true fifteenth circumference +512 141501 29 disappointing Colombo dull A +513 141502 29 navally survey weekly A +514 141901 29 circus staffing wetness +515 141902 29 beetles obtain visualized +516 142101 29 trumps loaded Tannenbaum +517 142102 29 fourscore slaughtered moribund +518 142103 29 Blackfoots lights demultiplex +519 142701 29 Grady circumference lockings +520 143001 29 quiets dull thugs FAS +521 143501 29 floundered weekly unnerves +522 143502 29 profundity wetness abut +523 148001 29 Garrisonian visualized Chippewa A +524 148002 29 Strauss Tannenbaum stratifications A +525 148003 29 cemented moribund signaled +526 148004 29 contrition demultiplex Italianizes A +527 148005 29 mutations lockings algorithmic A +528 148006 29 exhibits thugs paranoid FAS +529 148007 29 tits unnerves camping A +530 148009 29 mate abut signifying A +531 148010 29 arches Chippewa Patrice W +532 148011 29 Moll stratifications search A +533 148012 29 ropers signaled Angeles A +534 148013 29 bombast Italianizes semblance +535 148023 36 difficultly algorithmic taxed +536 148015 29 adsorption paranoid Beatrice +537 148016 29 definiteness camping retrace +538 148017 29 cultivation signifying lockout +539 148018 29 heals Patrice grammatic +540 148019 29 Heusen search helmsman +541 148020 29 target Angeles uniform W +542 148021 29 cited semblance hamming +543 148022 29 congresswoman taxed disobedience +544 148101 29 Katherine Beatrice captivated A +545 148102 29 titter retrace transferals A +546 148201 29 aspire lockout cartographer A +547 148401 29 Mardis grammatic aims FAS +548 148402 29 Nadia helmsman Pakistani +549 148501 29 estimating uniform burglarized FAS +550 148502 29 stuck hamming saucepans A +551 148503 29 fifteenth disobedience lacerating A +552 148504 29 Colombo captivated corny +553 148601 29 survey transferals megabytes FAS +554 148602 29 staffing cartographer chancellor +555 150701 29 obtain aims bulk A +556 152101 29 loaded Pakistani commits A +557 152102 29 slaughtered burglarized meson W +558 155202 36 lights saucepans deputies +559 155203 29 circumference lacerating northeaster A +560 155204 29 dull corny dipole +561 155205 29 weekly megabytes machining 0 +562 156001 29 wetness chancellor therefore +563 156002 29 visualized bulk Telefunken +564 156102 29 Tannenbaum commits salvaging +565 156301 29 moribund meson Corinthianizes A +566 156302 29 demultiplex deputies restlessly A +567 156303 29 lockings northeaster bromides +568 156304 29 thugs dipole generalized A +569 156305 29 unnerves machining mishaps +570 156306 29 abut therefore quelling +571 156501 29 Chippewa Telefunken spiritual A +572 158001 29 stratifications salvaging beguiles FAS +573 158002 29 signaled Corinthianizes Trobriand FAS +574 158101 29 Italianizes restlessly fleeing A +575 158102 29 algorithmic bromides Armour A +576 158103 29 paranoid generalized chin A +577 158201 29 camping mishaps provers A +578 158202 29 signifying quelling aeronautic A +579 158203 29 Patrice spiritual voltage W +580 158204 29 search beguiles sash +581 158301 29 Angeles Trobriand anaerobic A +582 158302 29 semblance fleeing simultaneous A +583 158303 29 taxed Armour accumulating A +584 158304 29 Beatrice chin Medusan A +585 158305 29 retrace provers shouted A +586 158306 29 lockout aeronautic freakish +587 158501 29 grammatic voltage index FAS +588 160301 29 helmsman sash commercially +589 166101 50 uniform anaerobic mistiness A +590 166102 50 hamming simultaneous endpoint +591 168001 29 disobedience accumulating straight A +592 168002 29 captivated Medusan flurried +593 168003 29 transferals shouted denotative A +594 168101 29 cartographer freakish coming FAS +595 168102 29 aims index commencements FAS +596 168103 29 Pakistani commercially gentleman +597 168104 29 burglarized mistiness gifted +598 168202 29 saucepans endpoint Shanghais +599 168301 29 lacerating straight sportswriting A +600 168502 29 corny flurried sloping A +601 168503 29 megabytes denotative navies +602 168601 29 chancellor coming leaflet A +603 173001 40 bulk commencements shooter +604 173701 40 commits gentleman Joplin FAS +605 173702 40 meson gifted babies +606 176001 40 deputies Shanghais subdivision FAS +607 176101 40 northeaster sportswriting burstiness W +608 176201 40 dipole sloping belted FAS +609 176401 40 machining navies assails FAS +610 176501 40 therefore leaflet admiring W +611 176601 40 Telefunken shooter swaying 0 +612 176602 40 salvaging Joplin Goldstine FAS +613 176603 40 Corinthianizes babies fitting +614 178001 40 restlessly subdivision Norwalk W +615 178002 40 bromides burstiness weakening W +616 178003 40 generalized belted analogy FAS +617 178004 40 mishaps assails deludes +618 178005 40 quelling admiring cokes +619 178006 40 spiritual swaying Clayton +620 178007 40 beguiles Goldstine exhausts +621 178008 40 Trobriand fitting causality +622 178101 40 fleeing Norwalk sating FAS +623 178102 40 Armour weakening icon +624 178103 40 chin analogy throttles +625 178201 40 provers deludes communicants FAS +626 178202 40 aeronautic cokes dehydrate FAS +627 178301 40 voltage Clayton priceless FAS +628 178302 40 sash exhausts publicly +629 178401 40 anaerobic causality incidentals FAS +630 178402 40 simultaneous sating commonplace +631 178403 40 accumulating icon mumbles +632 178404 40 Medusan throttles furthermore W +633 178501 40 shouted communicants cautioned W +634 186002 37 freakish dehydrate parametrized A +635 186102 37 index priceless registration A +636 186201 40 commercially publicly sadly FAS +637 186202 40 mistiness incidentals positioning +638 186203 40 endpoint commonplace babysitting +639 186302 37 straight mumbles eternal A +640 188007 37 flurried furthermore hoarder +641 188008 37 denotative cautioned congregates +642 188009 37 coming parametrized rains +643 188010 37 commencements registration workers W +644 188011 37 gentleman sadly sags A +645 188012 37 gifted positioning unplug W +646 188013 37 Shanghais babysitting garage A +647 188014 37 sportswriting eternal boulder A +648 188015 37 sloping hoarder hollowly A +649 188016 37 navies congregates specifics +650 188017 37 leaflet rains Teresa +651 188102 37 shooter workers Winsett +652 188103 37 Joplin sags convenient A +653 188202 37 babies unplug buckboards FAS +654 188301 40 subdivision garage amenities +655 188302 40 burstiness boulder resplendent FAS +656 188303 40 belted hollowly priding FAS +657 188401 37 assails specifics configurations +658 188402 37 admiring Teresa untidiness A +659 188503 37 swaying Winsett Brice W +660 188504 37 Goldstine convenient sews FAS +661 188505 37 fitting buckboards participated +662 190701 37 Norwalk amenities Simon FAS +663 190703 50 weakening resplendent certificates +664 191701 37 analogy priding Fitzpatrick +665 191702 37 deludes configurations Evanston A +666 191703 37 cokes untidiness misted +667 196001 37 Clayton Brice textures A +668 196002 37 exhausts sews save +669 196003 37 causality participated count +670 196101 37 sating Simon rightful A +671 196103 37 icon certificates chaperone +672 196104 37 throttles Fitzpatrick Lizzy A +673 196201 37 communicants Evanston clenched A +674 196202 37 dehydrate misted effortlessly +675 196203 37 priceless textures accessed +676 198001 37 publicly save beaters A +677 198003 37 incidentals count Hornblower FAS +678 198004 37 commonplace rightful vests A +679 198005 37 mumbles chaperone indulgences FAS +680 198006 37 furthermore Lizzy infallibly A +681 198007 37 cautioned clenched unwilling FAS +682 198008 37 parametrized effortlessly excrete FAS +683 198009 37 registration accessed spools A +684 198010 37 sadly beaters crunches FAS +685 198011 37 positioning Hornblower overestimating FAS +686 198012 37 babysitting vests ineffective +687 198013 37 eternal indulgences humiliation A +688 198014 37 hoarder infallibly sophomore +689 198015 37 congregates unwilling star +690 198017 37 rains excrete rifles +691 198018 37 workers spools dialysis +692 198019 37 sags crunches arriving +693 198020 37 unplug overestimating indulge +694 198021 37 garage ineffective clockers +695 198022 37 boulder humiliation languages +696 198023 50 hollowly sophomore Antarctica A +697 198024 37 specifics star percentage +698 198101 37 Teresa rifles ceiling A +699 198103 37 Winsett dialysis specification +700 198105 37 convenient arriving regimented A +701 198106 37 buckboards indulge ciphers +702 198201 37 amenities clockers pictures A +703 198204 37 resplendent languages serpents A +704 198301 53 priding Antarctica allot A +705 198302 53 configurations percentage realized A +706 198303 53 untidiness ceiling mayoral A +707 198304 53 Brice specification opaquely A +708 198401 37 sews regimented hostess FAS +709 198402 37 participated ciphers fiftieth +710 198403 37 Simon pictures incorrectly +711 202101 37 certificates serpents decomposition FAS +712 202301 37 Fitzpatrick allot stranglings +713 202302 37 Evanston realized mixture FAS +714 202303 37 misted mayoral electroencephalography FAS +715 202304 37 textures opaquely similarities FAS +716 202305 37 save hostess charges W +717 202601 37 count fiftieth freest FAS +718 202602 37 rightful incorrectly Greenberg FAS +719 202605 37 chaperone decomposition tinting +720 202606 37 Lizzy stranglings expelled W +721 202607 37 clenched mixture warm +722 202901 37 effortlessly electroencephalography smoothed +723 202902 37 accessed similarities deductions FAS +724 202903 37 beaters charges Romano W +725 202904 37 Hornblower freest bitterroot +726 202907 37 vests Greenberg corset +727 202908 37 indulgences tinting securing +728 203101 37 infallibly expelled environing FAS +729 203103 37 unwilling warm cute +730 203104 37 excrete smoothed Crays +731 203105 37 spools deductions heiress FAS +732 203401 37 crunches Romano inform FAS +733 203402 37 overestimating bitterroot avenge +734 203404 37 ineffective corset universals +735 203901 37 humiliation securing Kinsey W +736 203902 37 sophomore environing ravines FAS +737 203903 37 star cute bestseller +738 203906 37 rifles Crays equilibrium +739 203907 37 dialysis heiress extents 0 +740 203908 37 arriving inform relatively +741 203909 37 indulge avenge pressure FAS +742 206101 37 clockers universals critiques FAS +743 206201 37 languages Kinsey befouled +744 206202 37 Antarctica ravines rightfully FAS +745 206203 37 percentage bestseller mechanizing FAS +746 206206 37 ceiling equilibrium Latinizes +747 206207 37 specification extents timesharing +748 206208 37 regimented relatively Aden +749 208001 37 ciphers pressure embassies +750 208002 37 pictures critiques males FAS +751 208003 37 serpents befouled shapelessly FAS +752 208004 37 allot rightfully genres FAS +753 208008 37 realized mechanizing mastering +754 208009 37 mayoral Latinizes Newtonian +755 208010 37 opaquely timesharing finishers FAS +756 208011 37 hostess Aden abates +757 208101 37 fiftieth embassies teem +758 208102 37 incorrectly males kiting FAS +759 208103 37 decomposition shapelessly stodgy FAS +760 208104 37 stranglings genres scalps FAS +761 208105 37 mixture mastering feed FAS +762 208110 37 electroencephalography Newtonian guitars +763 208111 37 similarities finishers airships +764 208112 37 charges abates store +765 208113 37 freest teem denounces +766 208201 37 Greenberg kiting Pyle FAS +767 208203 37 tinting stodgy Saxony +768 208301 37 expelled scalps serializations FAS +769 208302 37 warm feed Peruvian FAS +770 208305 37 smoothed guitars taxonomically FAS +771 208401 37 deductions airships kingdom A +772 208402 37 Romano store stint A +773 208403 37 bitterroot denounces Sault A +774 208404 37 corset Pyle faithful +775 208501 37 securing Saxony Ganymede FAS +776 208502 37 environing serializations tidiness FAS +777 208503 37 cute Peruvian gainful FAS +778 208504 37 Crays taxonomically contrary FAS +779 208505 37 heiress kingdom Tipperary FAS +780 210101 37 inform stint tropics W +781 210102 37 avenge Sault theorizers +782 210103 37 universals faithful renew 0 +783 210104 37 Kinsey Ganymede already +784 210105 37 ravines tidiness terminal +785 210106 37 bestseller gainful Hegelian +786 210107 37 equilibrium contrary hypothesizer +787 210401 37 extents Tipperary warningly FAS +788 213201 37 relatively tropics journalizing FAS +789 213203 37 pressure theorizers nested +790 213204 37 critiques renew Lars +791 213205 37 befouled already saplings +792 213206 37 rightfully terminal foothill +793 213207 37 mechanizing Hegelian labeled +794 216101 37 Latinizes hypothesizer imperiously FAS +795 216103 37 timesharing warningly reporters FAS +796 218001 37 Aden journalizing furnishings FAS +797 218002 37 embassies nested precipitable FAS +798 218003 37 males Lars discounts FAS +799 218004 37 shapelessly saplings excises FAS +800 143503 50 genres foothill Stalin +801 218006 37 mastering labeled despot FAS +802 218007 37 Newtonian imperiously ripeness FAS +803 218008 37 finishers reporters Arabia +804 218009 37 abates furnishings unruly +805 218010 37 teem precipitable mournfulness +806 218011 37 kiting discounts boom FAS +807 218020 37 stodgy excises slaughter A +808 218021 50 scalps Stalin Sabine +809 218022 37 feed despot handy FAS +810 218023 37 guitars ripeness rural +811 218024 37 airships Arabia organizer +812 218101 37 store unruly shipyard FAS +813 218102 37 denounces mournfulness civics FAS +814 218103 37 Pyle boom inaccuracy FAS +815 218201 37 Saxony slaughter rules FAS +816 218202 37 serializations Sabine juveniles FAS +817 218203 37 Peruvian handy comprised W +818 218204 37 taxonomically rural investigations +819 218205 37 kingdom organizer stabilizes A +820 218301 37 stint shipyard seminaries FAS +821 218302 37 Sault civics Hunter A +822 218401 37 faithful inaccuracy sporty FAS +823 218402 37 Ganymede rules test FAS +824 218403 37 tidiness juveniles weasels +825 218404 37 gainful comprised CERN +826 218407 37 contrary investigations tempering +827 218408 37 Tipperary stabilizes afore FAS +828 218409 37 tropics seminaries Galatean +829 218410 37 theorizers Hunter techniques W +830 226001 37 renew sporty error +831 226002 37 already test veranda +832 226003 37 terminal weasels severely +833 226004 37 Hegelian CERN Cassites FAS +834 226005 37 hypothesizer tempering forthcoming +835 226006 37 warningly afore guides +836 226007 37 journalizing Galatean vanish FAS +837 226008 37 nested techniques lied A +838 226203 37 Lars error sawtooth FAS +839 226204 37 saplings veranda fated FAS +840 226205 37 foothill severely gradually +841 226206 37 labeled Cassites widens +842 226207 37 imperiously forthcoming preclude +843 226208 37 reporters guides Jobrel +844 226209 37 furnishings vanish hooker +845 226210 37 precipitable lied rainstorm +846 226211 37 discounts sawtooth disconnects +847 228001 37 excises fated cruelty +848 228004 37 Stalin gradually exponentials A +849 228005 37 despot widens affective A +850 228006 37 ripeness preclude arteries +851 228007 37 Arabia Jobrel Crosby FAS +852 228008 37 unruly hooker acquaint +853 228009 37 mournfulness rainstorm evenhandedly +854 228101 37 boom disconnects percentage +855 228108 37 slaughter cruelty disobedience +856 228109 37 Sabine exponentials humility +857 228110 37 handy affective gleaning A +858 228111 37 rural arteries petted A +859 228112 37 organizer Crosby bloater A +860 228113 37 shipyard acquaint minion A +861 228114 37 civics evenhandedly marginal A +862 228115 37 inaccuracy percentage apiary A +863 228116 37 rules disobedience measures +864 228117 37 juveniles humility precaution +865 228118 37 comprised gleaning repelled +866 228119 37 investigations petted primary FAS +867 228120 37 stabilizes bloater coverings +868 228121 37 seminaries minion Artemia A +869 228122 37 Hunter marginal navigate +870 228201 37 sporty apiary spatial +871 228206 37 test measures Gurkha +872 228207 37 weasels precaution meanwhile A +873 228208 37 CERN repelled Melinda A +874 228209 37 tempering primary Butterfield +875 228210 37 afore coverings Aldrich A +876 228211 37 Galatean Artemia previewing A +877 228212 37 techniques navigate glut A +878 228213 37 error spatial unaffected +879 228214 37 veranda Gurkha inmate +880 228301 37 severely meanwhile mineral +881 228305 37 Cassites Melinda impending A +882 228306 37 forthcoming Butterfield meditation A +883 228307 37 guides Aldrich ideas +884 228308 37 vanish previewing miniaturizes W +885 228309 37 lied glut lewdly +886 228310 37 sawtooth unaffected title +887 228311 37 fated inmate youthfulness +888 228312 37 gradually mineral creak FAS +889 228313 37 widens impending Chippewa +890 228314 37 preclude meditation clamored +891 228401 65 Jobrel ideas freezes +892 228402 65 hooker miniaturizes forgivably FAS +893 228403 65 rainstorm lewdly reduce FAS +894 228404 65 disconnects title McGovern W +895 228405 65 cruelty youthfulness Nazis W +896 228406 65 exponentials creak epistle W +897 228407 65 affective Chippewa socializes W +898 228408 65 arteries clamored conceptions +899 228409 65 Crosby freezes Kevin +900 228410 65 acquaint forgivably uncovering +901 230301 37 evenhandedly reduce chews FAS +902 230302 37 percentage McGovern appendixes FAS +903 230303 37 disobedience Nazis raining +904 018062 37 humility epistle infest +905 230501 37 gleaning socializes compartment +906 230502 37 petted conceptions minting +907 230503 37 bloater Kevin ducks +908 230504 37 minion uncovering roped A +909 230505 37 marginal chews waltz +910 230506 37 apiary appendixes Lillian +911 230507 37 measures raining repressions A +912 230508 37 precaution infest chillingly +913 230509 37 repelled compartment noncritical +914 230901 37 primary minting lithograph +915 230902 37 coverings ducks spongers +916 230903 37 Artemia roped parenthood +917 230904 37 navigate waltz posed +918 230905 37 spatial Lillian instruments +919 230906 37 Gurkha repressions filial +920 230907 37 meanwhile chillingly fixedly +921 230908 37 Melinda noncritical relives +922 230909 37 Butterfield lithograph Pandora +923 230910 37 Aldrich spongers watering A +924 230911 37 previewing parenthood ungrateful +925 230912 37 glut posed secures +926 230913 37 unaffected instruments chastisers +927 230914 37 inmate filial icon +928 231304 37 mineral fixedly reuniting A +929 231305 37 impending relives imagining A +930 231306 37 meditation Pandora abiding A +931 231307 37 ideas watering omnisciently +932 231308 37 miniaturizes ungrateful Britannic +933 231309 37 lewdly secures scholastics A +934 231310 37 title chastisers mechanics A +935 231311 37 youthfulness icon humidly A +936 231312 37 creak reuniting masterpiece +937 231313 37 Chippewa imagining however +938 231314 37 clamored abiding Mendelian +939 231315 37 freezes omnisciently jarred +940 232102 37 forgivably Britannic scolds +941 232103 37 reduce scholastics infatuate +942 232104 37 McGovern mechanics willed A +943 232105 37 Nazis humidly joyfully +944 232106 37 epistle masterpiece Microsoft +945 232107 37 socializes however fibrosities +946 232108 37 conceptions Mendelian Baltimorean +947 232601 37 Kevin jarred equestrian +948 232602 37 uncovering scolds Goodrich +949 232603 37 chews infatuate apish A +950 232605 37 appendixes willed Adlerian +5950 1232605 37 appendixes willed Adlerian +5951 1232606 37 appendixes willed Adlerian +5952 1232607 37 appendixes willed Adlerian +5953 1232608 37 appendixes willed Adlerian +5954 1232609 37 appendixes willed Adlerian +951 232606 37 raining joyfully Tropez +952 232607 37 infest Microsoft nouns +953 232608 37 compartment fibrosities distracting +954 232609 37 minting Baltimorean mutton +955 236104 37 ducks equestrian bridgeable A +956 236105 37 roped Goodrich stickers A +957 236106 37 waltz apish transcontinental A +958 236107 37 Lillian Adlerian amateurish +959 236108 37 repressions Tropez Gandhian +960 236109 37 chillingly nouns stratified +961 236110 37 noncritical distracting chamberlains +962 236111 37 lithograph mutton creditably +963 236112 37 spongers bridgeable philosophic +964 236113 37 parenthood stickers ores +965 238005 37 posed transcontinental Carleton +966 238006 37 instruments amateurish tape A +967 238007 37 filial Gandhian afloat A +968 238008 37 fixedly stratified goodness A +969 238009 37 relives chamberlains welcoming +970 238010 37 Pandora creditably Pinsky FAS +971 238011 37 watering philosophic halting +972 238012 37 ungrateful ores bibliography +973 238013 37 secures Carleton decoding +974 240401 41 chastisers tape variance A +975 240402 41 icon afloat allowed A +976 240901 41 reuniting goodness dire A +977 240902 41 imagining welcoming dub A +978 241801 41 abiding Pinsky poisoning +979 242101 41 omnisciently halting Iraqis A +980 242102 41 Britannic bibliography heaving +981 242201 41 scholastics decoding population A +982 242202 41 mechanics variance bomb A +983 242501 41 humidly allowed Majorca A +984 242502 41 masterpiece dire Gershwins +985 246201 41 however dub explorers +986 246202 41 Mendelian poisoning libretto A +987 246203 41 jarred Iraqis occurred +988 246204 41 scolds heaving Lagos +989 246205 41 infatuate population rats +990 246301 41 willed bomb bankruptcies A +991 246302 41 joyfully Majorca crying +992 248001 41 Microsoft Gershwins unexpected +993 248002 41 fibrosities explorers accessed A +994 248003 41 Baltimorean libretto colorful A +995 248004 41 equestrian occurred versatility A +996 248005 41 Goodrich Lagos cosy +997 248006 41 apish rats Darius A +998 248007 41 Adlerian bankruptcies mastering A +999 248008 41 Tropez crying Asiaticizations A +1000 248009 41 nouns unexpected offerers A +1001 248010 41 distracting accessed uncles A +1002 248011 41 mutton colorful sleepwalk +1003 248012 41 bridgeable versatility Ernestine +1004 248013 41 stickers cosy checksumming +1005 248014 41 transcontinental Darius stopped +1006 248015 41 amateurish mastering sicker +1007 248016 41 Gandhian Asiaticizations Italianization +1008 248017 41 stratified offerers alphabetic +1009 248018 41 chamberlains uncles pharmaceutic +1010 248019 41 creditably sleepwalk creator +1011 248020 41 philosophic Ernestine chess +1012 248021 41 ores checksumming charcoal +1013 248101 41 Carleton stopped Epiphany A +1014 248102 41 tape sicker bulldozes A +1015 248201 41 afloat Italianization Pygmalion A +1016 248202 41 goodness alphabetic caressing A +1017 248203 41 welcoming pharmaceutic Palestine A +1018 248204 41 Pinsky creator regimented A +1019 248205 41 halting chess scars A +1020 248206 41 bibliography charcoal realest A +1021 248207 41 decoding Epiphany diffusing A +1022 248208 41 variance bulldozes clubroom A +1023 248209 41 allowed Pygmalion Blythe A +1024 248210 41 dire caressing ahead +1025 248211 50 dub Palestine reviver +1026 250501 34 poisoning regimented retransmitting A +1027 250502 34 Iraqis scars landslide +1028 250503 34 heaving realest Eiffel +1029 250504 34 population diffusing absentee +1030 250505 34 bomb clubroom aye +1031 250601 34 Majorca Blythe forked A +1032 250602 34 Gershwins ahead Peruvianizes +1033 250603 34 explorers reviver clerked +1034 250604 34 libretto retransmitting tutor +1035 250605 34 occurred landslide boulevard +1036 251001 34 Lagos Eiffel shuttered +1037 251002 34 rats absentee quotes A +1038 251003 34 bankruptcies aye Caltech +1039 251004 34 crying forked Mossberg +1040 251005 34 unexpected Peruvianizes kept +1041 251301 34 accessed clerked roundly +1042 251302 34 colorful tutor features A +1043 251303 34 versatility boulevard imaginable A +1044 251304 34 cosy shuttered controller +1045 251305 34 Darius quotes racial +1046 251401 34 mastering Caltech uprisings A +1047 251402 34 Asiaticizations Mossberg narrowed A +1048 251403 34 offerers kept cannot A +1049 251404 34 uncles roundly vest +1050 251405 34 sleepwalk features famine +1051 251406 34 Ernestine imaginable sugars +1052 251801 34 checksumming controller exterminated A +1053 251802 34 stopped racial belays +1054 252101 34 sicker uprisings Hodges A +1055 252102 34 Italianization narrowed translatable +1056 252301 34 alphabetic cannot duality A +1057 252302 34 pharmaceutic vest recording A +1058 252303 34 creator famine rouses A +1059 252304 34 chess sugars poison +1060 252305 34 charcoal exterminated attitude +1061 252306 34 Epiphany belays dusted +1062 252307 34 bulldozes Hodges encompasses +1063 252308 34 Pygmalion translatable presentation +1064 252309 34 caressing duality Kantian +1065 256001 34 Palestine recording imprecision A +1066 256002 34 regimented rouses saving +1067 256003 34 scars poison maternal +1068 256004 34 realest attitude hewed +1069 256005 34 diffusing dusted kerosene +1070 258001 34 clubroom encompasses Cubans +1071 258002 34 Blythe presentation photographers +1072 258003 34 ahead Kantian nymph A +1073 258004 34 reviver imprecision bedlam A +1074 258005 34 retransmitting saving north A +1075 258006 34 landslide maternal Schoenberg A +1076 258007 34 Eiffel hewed botany A +1077 258008 34 absentee kerosene curs +1078 258009 34 aye Cubans solidification +1079 258010 34 forked photographers inheritresses +1080 258011 34 Peruvianizes nymph stiller +1081 258101 68 clerked bedlam t1 A +1082 258102 68 tutor north suite A +1083 258103 34 boulevard Schoenberg ransomer +1084 258104 68 shuttered botany Willy +1085 258105 68 quotes curs Rena A +1086 258106 68 Caltech solidification Seattle A +1087 258107 68 Mossberg inheritresses relaxes A +1088 258108 68 kept stiller exclaim +1089 258109 68 roundly t1 implicated A +1090 258110 68 features suite distinguish +1091 258111 68 imaginable ransomer assayed +1092 258112 68 controller Willy homeowner +1093 258113 68 racial Rena and +1094 258201 34 uprisings Seattle stealth +1095 258202 34 narrowed relaxes coinciding A +1096 258203 34 cannot exclaim founder A +1097 258204 34 vest implicated environing +1098 258205 34 famine distinguish jewelry +1099 258301 34 sugars assayed lemons A +1100 258401 34 exterminated homeowner brokenness A +1101 258402 34 belays and bedpost A +1102 258403 34 Hodges stealth assurers A +1103 258404 34 translatable coinciding annoyers +1104 258405 34 duality founder affixed +1105 258406 34 recording environing warbling +1106 258407 34 rouses jewelry seriously +1107 228123 37 poison lemons boasted +1108 250606 34 attitude brokenness Chantilly +1109 208405 37 dusted bedpost Iranizes +1110 212101 37 encompasses assurers violinist +1111 218206 37 presentation annoyers extramarital +1112 150401 37 Kantian affixed spates +1113 248212 41 imprecision warbling cloakroom +1114 128026 00 saving seriously gazer +1115 128024 00 maternal boasted hand +1116 128027 00 hewed Chantilly tucked +1117 128025 00 kerosene Iranizes gems +1118 128109 00 Cubans violinist clinker +1119 128705 00 photographers extramarital refiner +1120 126303 00 nymph spates callus +1121 128308 00 bedlam cloakroom leopards +1122 128204 00 north gazer comfortingly +1123 128205 00 Schoenberg hand generically +1124 128206 00 botany tucked getters +1125 128207 00 curs gems sexually +1126 118205 00 solidification clinker spear +1127 116801 00 inheritresses refiner serums +1128 116803 00 stiller callus Italianization +1129 116804 00 t1 leopards attendants +1130 116802 00 suite comfortingly spies +1131 128605 00 ransomer generically Anthony +1132 118308 00 Willy getters planar +1133 113702 00 Rena sexually cupped +1134 113703 00 Seattle spear cleanser +1135 112103 00 relaxes serums commuters +1136 118009 00 exclaim Italianization honeysuckle +5136 1118009 00 exclaim Italianization honeysuckle +1137 138011 00 implicated attendants orphanage +1138 138010 00 distinguish spies skies +1139 138012 00 assayed Anthony crushers +1140 068304 00 homeowner planar Puritan +1141 078009 00 and cupped squeezer +1142 108013 00 stealth cleanser bruises +1143 084004 00 coinciding commuters bonfire +1144 083402 00 founder honeysuckle Colombo +1145 084003 00 environing orphanage nondecreasing +1146 088504 00 jewelry skies innocents +1147 088005 00 lemons crushers masked +1148 088007 00 brokenness Puritan file +1149 088006 00 bedpost squeezer brush +1150 148025 00 assurers bruises mutilate +1151 148024 00 annoyers bonfire mommy +1152 138305 00 affixed Colombo bulkheads +1153 138306 00 warbling nondecreasing undeclared +1154 152701 00 seriously innocents displacements +1155 148505 00 boasted masked nieces +1156 158003 00 Chantilly file coeducation +1157 156201 00 Iranizes brush brassy +1158 156202 00 violinist mutilate authenticator +1159 158307 00 extramarital mommy Washoe +1160 158402 00 spates bulkheads penny +1161 158401 00 cloakroom undeclared Flagler +1162 068013 00 gazer displacements stoned +1163 068012 00 hand nieces cranes +1164 068203 00 tucked coeducation masterful +1165 088205 00 gems brassy biracial +1166 068704 00 clinker authenticator steamships +1167 068604 00 refiner Washoe windmills +1168 158502 00 callus penny exploit +1169 123103 00 leopards Flagler riverfront +1170 148026 00 comfortingly stoned sisterly +1171 123302 00 generically cranes sharpshoot +1172 076503 00 getters masterful mittens +1173 126304 00 sexually biracial interdependency +1174 068306 00 spear steamships policy +1175 143504 00 serums windmills unleashing +1176 160201 00 Italianization exploit pretenders +1177 148028 00 attendants riverfront overstatements +1178 148027 00 spies sisterly birthed +1179 143505 00 Anthony sharpshoot opportunism +1180 108014 00 planar mittens showroom +1181 076104 00 cupped interdependency compromisingly +1182 078106 00 cleanser policy Medicare +1183 126102 00 commuters unleashing corresponds +1184 128029 00 honeysuckle pretenders hardware +1185 128028 00 orphanage overstatements implant +1186 018410 00 skies birthed Alicia +1187 128110 00 crushers opportunism requesting +1188 148506 00 Puritan showroom produced +1189 123303 00 squeezer compromisingly criticizes +1190 123304 00 bruises Medicare backer +1191 068504 00 bonfire corresponds positively +1192 068305 00 Colombo hardware colicky +1193 000000 00 nondecreasing implant thrillingly +1 000001 00 Omaha teethe neat +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily +1 000001 00 Omaha teethe neat +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); drop table t1, t2, t4; diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index d525b019c64..2bba44d36e9 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -1429,10 +1429,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 13 NULL # Using where explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where +1 SIMPLE t1 ref v v 13 const # Using where explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where +1 SIMPLE t1 ref v v 13 const # Using where alter table t1 add unique(v); ERROR 23000: Duplicate entry '{ ' for key 1 alter table t1 add key(v); @@ -1622,10 +1622,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 258 NULL # Using where explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 258 NULL # Using where +1 SIMPLE t1 ref v v 258 const # Using where explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 258 NULL # Using where +1 SIMPLE t1 ref v v 258 const # Using where explain select * from t1 where v='a'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref v v 258 const # Using where @@ -1702,10 +1702,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 33 NULL # Using where explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 33 NULL # Using where +1 SIMPLE t1 ref v v 33 const # Using where explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 33 NULL # Using where +1 SIMPLE t1 ref v v 33 const # Using where explain select * from t1 where v='a'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref v v 33 const # Using where diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 1b5619eb18d..ca9a2662f94 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -46,6 +46,14 @@ a drop table t1; create table t1 ( a int not null default 1, big bigint ); insert into t1 (big) values (-1),(12345678901234567),(9223372036854775807),(18446744073709551615); +Warnings: +Warning 1264 Out of range value adjusted for column 'big' at row 4 +select * from t1; +a big +1 -1 +1 12345678901234567 +1 9223372036854775807 +1 9223372036854775807 select min(big),max(big),max(big)-1 from t1; min(big) max(big) max(big)-1 -1 9223372036854775807 9223372036854775806 @@ -53,26 +61,51 @@ select min(big),max(big),max(big)-1 from t1 group by a; min(big) max(big) max(big)-1 -1 9223372036854775807 9223372036854775806 alter table t1 modify big bigint unsigned not null; +Warnings: +Warning 1264 Out of range value adjusted for column 'big' at row 1 +select min(big),max(big),max(big)-1 from t1; +min(big) max(big) max(big)-1 +0 9223372036854775807 9223372036854775806 +select min(big),max(big),max(big)-1 from t1 group by a; +min(big) max(big) max(big)-1 +0 9223372036854775807 9223372036854775806 +insert into t1 (big) values (18446744073709551615); +select * from t1; +a big +1 0 +1 12345678901234567 +1 9223372036854775807 +1 9223372036854775807 +1 18446744073709551615 select min(big),max(big),max(big)-1 from t1; min(big) max(big) max(big)-1 -12345678901234567 18446744073709551615 18446744073709551614 +0 18446744073709551615 18446744073709551614 select min(big),max(big),max(big)-1 from t1 group by a; min(big) max(big) max(big)-1 -12345678901234567 18446744073709551615 18446744073709551614 +0 18446744073709551615 18446744073709551614 alter table t1 add key (big); select min(big),max(big),max(big)-1 from t1; min(big) max(big) max(big)-1 -12345678901234567 18446744073709551615 18446744073709551614 +0 18446744073709551615 18446744073709551614 select min(big),max(big),max(big)-1 from t1 group by a; min(big) max(big) max(big)-1 -12345678901234567 18446744073709551615 18446744073709551614 +0 18446744073709551615 18446744073709551614 alter table t1 modify big bigint not null; +Warnings: +Warning 1264 Out of range value adjusted for column 'big' at row 5 +select * from t1; +a big +1 0 +1 12345678901234567 +1 9223372036854775807 +1 9223372036854775807 +1 9223372036854775807 select min(big),max(big),max(big)-1 from t1; min(big) max(big) max(big)-1 --1 9223372036854775807 9223372036854775806 +0 9223372036854775807 9223372036854775806 select min(big),max(big),max(big)-1 from t1 group by a; min(big) max(big) max(big)-1 --1 9223372036854775807 9223372036854775806 +0 9223372036854775807 9223372036854775806 drop table t1; create table t1 (id bigint auto_increment primary key, a int) auto_increment=9999999999; insert into t1 values (null,1); @@ -89,7 +122,7 @@ insert into t1 values (10000000000000000000.0); insert into t1 values ('10000000000000000000'); select * from t1; quantity --8446744073709551616 +10000000000000000000 10000000000000000000 10000000000000000000 drop table t1; @@ -154,3 +187,148 @@ select * from t1; a 9223372036854775809 drop table t1; +DROP DATABASE IF EXISTS `scott`; +Warnings: +Note 1008 Can't drop database 'scott'; database doesn't exist +create table t1 (a char(100), b varchar(100), c text, d blob); +insert into t1 values( +18446744073709551615,18446744073709551615, +18446744073709551615, 18446744073709551615 +); +insert into t1 values (-1 | 0,-1 | 0,-1 | 0 ,-1 | 0); +select * from t1; +a b c d +18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +drop table t1; +create table t1 ( quantity decimal(2) unsigned); +insert into t1 values (500), (-500), (~0), (-1); +Warnings: +Warning 1264 Out of range value adjusted for column 'quantity' at row 1 +Warning 1264 Out of range value adjusted for column 'quantity' at row 2 +Warning 1264 Out of range value adjusted for column 'quantity' at row 3 +Warning 1264 Out of range value adjusted for column 'quantity' at row 4 +select * from t1; +quantity +99 +0 +99 +0 +drop table t1; +CREATE TABLE t1 ( +`col1` INT(1) NULL, +`col2` INT(2) NULL, +`col3` INT(3) NULL, +`col4` INT(4) NULL, +`col5` INT(5) NULL, +`col6` INT(6) NULL, +`col7` INT(7) NULL, +`col8` INT(8) NULL, +`col9` INT(9) NULL, +`col10` BIGINT(10) NULL, +`col11` BIGINT(11) NULL, +`col12` BIGINT(12) NULL, +`col13` BIGINT(13) NULL, +`col14` BIGINT(14) NULL, +`col15` BIGINT(15) NULL, +`col16` BIGINT(16) NULL, +`col17` BIGINT(17) NULL, +`col18` BIGINT(18) NULL, +`col19` DECIMAL(19, 0) NULL, +`col20` DECIMAL(20, 0) NULL, +`col21` DECIMAL(21, 0) NULL, +`col22` DECIMAL(22, 0) NULL, +`col23` DECIMAL(23, 0) NULL, +`col24` DECIMAL(24, 0) NULL, +`col25` DECIMAL(25, 0) NULL, +`col26` DECIMAL(26, 0) NULL, +`col27` DECIMAL(27, 0) NULL, +`col28` DECIMAL(28, 0) NULL, +`col29` DECIMAL(29, 0) NULL, +`col30` DECIMAL(30, 0) NULL, +`col31` DECIMAL(31, 0) NULL, +`col32` DECIMAL(32, 0) NULL, +`col33` DECIMAL(33, 0) NULL, +`col34` DECIMAL(34, 0) NULL, +`col35` DECIMAL(35, 0) NULL, +`col36` DECIMAL(36, 0) NULL, +`col37` DECIMAL(37, 0) NULL, +`col38` DECIMAL(38, 0) NULL, +`fix1` DECIMAL(38, 1) NULL, +`fix2` DECIMAL(38, 2) NULL, +`fix3` DECIMAL(38, 3) NULL, +`fix4` DECIMAL(38, 4) NULL, +`fix5` DECIMAL(38, 5) NULL, +`fix6` DECIMAL(38, 6) NULL, +`fix7` DECIMAL(38, 7) NULL, +`fix8` DECIMAL(38, 8) NULL, +`fix9` DECIMAL(38, 9) NULL, +`fix10` DECIMAL(38, 10) NULL, +`fix11` DECIMAL(38, 11) NULL, +`fix12` DECIMAL(38, 12) NULL, +`fix13` DECIMAL(38, 13) NULL, +`fix14` DECIMAL(38, 14) NULL, +`fix15` DECIMAL(38, 15) NULL, +`fix16` DECIMAL(38, 16) NULL, +`fix17` DECIMAL(38, 17) NULL, +`fix18` DECIMAL(38, 18) NULL, +`fix19` DECIMAL(38, 19) NULL, +`fix20` DECIMAL(38, 20) NULL, +`fix21` DECIMAL(38, 21) NULL, +`fix22` DECIMAL(38, 22) NULL, +`fix23` DECIMAL(38, 23) NULL, +`fix24` DECIMAL(38, 24) NULL, +`fix25` DECIMAL(38, 25) NULL, +`fix26` DECIMAL(38, 26) NULL, +`fix27` DECIMAL(38, 27) NULL, +`fix28` DECIMAL(38, 28) NULL, +`fix29` DECIMAL(38, 29) NULL, +`fix30` DECIMAL(38, 30) NULL +); +INSERT INTO t1(`col1`, `col2`, `col3`, `col4`, `col5`, `col6`, `col7`, `col8`, `col9`, `col10`, `col11`, `col12`, `col13`, `col14`, `col15`, `col16`, `col17`, `col18`, `col19`, `col20`, `col21`, `col22`, `col23`, `col24`, `col25`, `col26`, `col27`, `col28`, `col29`, `col30`, `col31`, `col32`, `col33`, `col34`, `col35`, `col36`, `col37`, `col38`, `fix1`, `fix2`, `fix3`, `fix4`, `fix5`, `fix6`, `fix7`, `fix8`, `fix9`, `fix10`, `fix11`, `fix12`, `fix13`, `fix14`, `fix15`, `fix16`, `fix17`, `fix18`, `fix19`, `fix20`, `fix21`, `fix22`, `fix23`, `fix24`, `fix25`, `fix26`, `fix27`, `fix28`, `fix29`, `fix30`) +VALUES (9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, +9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, +999999999999999, 9999999999999999, 99999999999999999, 999999999999999999, +9999999999999999999, 99999999999999999999, 999999999999999999999, +9999999999999999999999, 99999999999999999999999, 999999999999999999999999, +9999999999999999999999999, 99999999999999999999999999, +999999999999999999999999999, 9999999999999999999999999999, +99999999999999999999999999999, 999999999999999999999999999999, +9999999999999999999999999999999, 99999999999999999999999999999999, +999999999999999999999999999999999, 9999999999999999999999999999999999, +99999999999999999999999999999999999, 999999999999999999999999999999999999, +9999999999999999999999999999999999999, 99999999999999999999999999999999999999, +9999999999999999999999999999999999999.9, +999999999999999999999999999999999999.99, +99999999999999999999999999999999999.999, +9999999999999999999999999999999999.9999, +999999999999999999999999999999999.99999, +99999999999999999999999999999999.999999, +9999999999999999999999999999999.9999999, +999999999999999999999999999999.99999999, +99999999999999999999999999999.999999999, +9999999999999999999999999999.9999999999, +999999999999999999999999999.99999999999, +99999999999999999999999999.999999999999, +9999999999999999999999999.9999999999999, +999999999999999999999999.99999999999999, +99999999999999999999999.999999999999999, +9999999999999999999999.9999999999999999, +999999999999999999999.99999999999999999, +99999999999999999999.999999999999999999, +9999999999999999999.9999999999999999999, +999999999999999999.99999999999999999999, +99999999999999999.999999999999999999999, +9999999999999999.9999999999999999999999, +999999999999999.99999999999999999999999, +99999999999999.999999999999999999999999, +9999999999999.9999999999999999999999999, +999999999999.99999999999999999999999999, +99999999999.999999999999999999999999999, +9999999999.9999999999999999999999999999, +999999999.99999999999999999999999999999, +99999999.999999999999999999999999999999); +SELECT * FROM t1; +col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13 col14 col15 col16 col17 col18 col19 col20 col21 col22 col23 col24 col25 col26 col27 col28 col29 col30 col31 col32 col33 col34 col35 col36 col37 col38 fix1 fix2 fix3 fix4 fix5 fix6 fix7 fix8 fix9 fix10 fix11 fix12 fix13 fix14 fix15 fix16 fix17 fix18 fix19 fix20 fix21 fix22 fix23 fix24 fix25 fix26 fix27 fix28 fix29 fix30 +9 99 999 9999 99999 999999 9999999 99999999 999999999 9999999999 99999999999 999999999999 9999999999999 99999999999999 999999999999999 9999999999999999 99999999999999999 999999999999999999 9999999999999999999 99999999999999999999 999999999999999999999 9999999999999999999999 99999999999999999999999 999999999999999999999999 9999999999999999999999999 99999999999999999999999999 999999999999999999999999999 9999999999999999999999999999 99999999999999999999999999999 999999999999999999999999999999 9999999999999999999999999999999 99999999999999999999999999999999 999999999999999999999999999999999 9999999999999999999999999999999999 99999999999999999999999999999999999 999999999999999999999999999999999999 9999999999999999999999999999999999999 99999999999999999999999999999999999999 9999999999999999999999999999999999999.9 999999999999999999999999999999999999.99 99999999999999999999999999999999999.999 9999999999999999999999999999999999.9999 999999999999999999999999999999999.99999 99999999999999999999999999999999.999999 9999999999999999999999999999999.9999999 999999999999999999999999999999.99999999 99999999999999999999999999999.999999999 9999999999999999999999999999.9999999999 999999999999999999999999999.99999999999 99999999999999999999999999.999999999999 9999999999999999999999999.9999999999999 999999999999999999999999.99999999999999 99999999999999999999999.999999999999999 9999999999999999999999.9999999999999999 999999999999999999999.99999999999999999 99999999999999999999.999999999999999999 9999999999999999999.9999999999999999999 999999999999999999.99999999999999999999 99999999999999999.999999999999999999999 9999999999999999.9999999999999999999999 999999999999999.99999999999999999999999 99999999999999.999999999999999999999999 9999999999999.9999999999999999999999999 999999999999.99999999999999999999999999 99999999999.999999999999999999999999999 9999999999.9999999999999999999999999999 999999999.99999999999999999999999999999 99999999.999999999999999999999999999999 +DROP TABLE t1; diff --git a/mysql-test/r/binary.result b/mysql-test/r/binary.result index 5b5f673b071..a8d6c3bf411 100644 --- a/mysql-test/r/binary.result +++ b/mysql-test/r/binary.result @@ -85,7 +85,7 @@ NULL select b from t1 having binary b like ''; b drop table t1; -create table t1 (a char(15) binary, b binary(15)); +create table t1 (a char(3) binary, b binary(3)); insert into t1 values ('aaa','bbb'),('AAA','BBB'); select upper(a),upper(b) from t1; upper(a) upper(b) diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index b02f85132aa..ea80695ad7b 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -103,8 +103,8 @@ t1 CREATE TABLE `t1` ( `c2` varchar(1) character set latin1 collate latin1_danish_ci NOT NULL default '', `c3` varbinary(1) NOT NULL default '', `c4` varbinary(1) NOT NULL default '', - `c5` varbinary(4) NOT NULL default '', - `c6` varbinary(4) NOT NULL default '', + `c5` varbinary(3) NOT NULL default '', + `c6` varbinary(3) NOT NULL default '', `c7` decimal(2,1) NOT NULL default '0.0', `c8` decimal(2,1) NOT NULL default '0.0', `c9` decimal(2,1) default NULL, @@ -152,11 +152,11 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `COALESCE(1)` int(1) NOT NULL default '0', - `COALESCE(1.0)` decimal(2,1) NOT NULL default '0.0', + `COALESCE(1.0)` decimal(2,1) unsigned NOT NULL default '0.0', `COALESCE('a')` varchar(1) NOT NULL default '', `COALESCE(1,1.0)` decimal(2,1) NOT NULL default '0.0', `COALESCE(1,'1')` varbinary(1) NOT NULL default '', - `COALESCE(1.1,'1')` varbinary(4) NOT NULL default '', + `COALESCE(1.1,'1')` varbinary(3) NOT NULL default '', `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 1b5bdf98afd..817be3a2e7c 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -74,6 +74,18 @@ CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)) 2004 Warnings: Warning 1292 Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33' +select CAST(0xb3 as signed); +CAST(0xb3 as signed) +179 +select CAST(0x8fffffffffffffff as signed); +CAST(0x8fffffffffffffff as signed) +-8070450532247928833 +select CAST(0xffffffffffffffff as unsigned); +CAST(0xffffffffffffffff as unsigned) +18446744073709551615 +select CAST(0xfffffffffffffffe as signed); +CAST(0xfffffffffffffffe as signed) +-2 select cast('-10a' as signed integer); cast('-10a' as signed integer) -10 @@ -219,7 +231,7 @@ t1 CREATE TABLE `t1` ( `c5` varchar(2) character set utf8 NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; -create table t1 (a binary(10), b char(10) character set koi8r); +create table t1 (a binary(4), b char(4) character set koi8r); insert into t1 values (_binary'ÔÅÓÔ',_binary'ÔÅÓÔ'); select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; a b cast(a as char character set cp1251) cast(b as binary) @@ -322,6 +334,9 @@ cast(repeat('1',20) as signed) -7335632962598440505 Warnings: Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast(1.0e+300 as signed int); +cast(1.0e+300 as signed int) +9223372036854775807 select cast('1.2' as decimal(3,2)); cast('1.2' as decimal(3,2)) 1.20 diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index fef813371c8..2508d751b46 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -1,3 +1,4 @@ +drop table if exists t1,t2; show tables; Tables_in_mysql columns_priv @@ -71,3 +72,8 @@ show tables; Tables_in_test delete from mysql.user where user=_binary"test"; flush privileges; +create table t1 (id integer not null auto_increment primary key); +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +drop table t1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index e1e66019f65..3e7c9d6eb4a 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -9,6 +9,8 @@ NULL drop table if exists t1; create table t1 (b char(0) not null); create table if not exists t1 (b char(0) not null); +Warnings: +Note 1050 Table 't1' already exists insert into t1 values (""),(null); Warnings: Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 2 @@ -244,9 +246,13 @@ create table t1 select x'4132'; drop table t1; create table t1 select 1,2,3; create table if not exists t1 select 1,2; +Warnings: +Note 1050 Table 't1' already exists create table if not exists t1 select 1,2,3,4; ERROR 21S01: Column count doesn't match value count at row 1 create table if not exists t1 select 1; +Warnings: +Note 1050 Table 't1' already exists select * from t1; 1 2 3 1 2 3 @@ -255,9 +261,13 @@ select * from t1; drop table t1; create table t1 select 1,2,3; create table if not exists t1 select 1,2; +Warnings: +Note 1050 Table 't1' already exists create table if not exists t1 select 1,2,3,4; ERROR 21S01: Column count doesn't match value count at row 1 create table if not exists t1 select 1; +Warnings: +Note 1050 Table 't1' already exists select * from t1; 1 2 3 1 2 3 @@ -268,6 +278,7 @@ create table t1 (a int not null, b int, primary key (a)); insert into t1 values (1,1); create table if not exists t1 select 2; Warnings: +Note 1050 Table 't1' already exists Warning 1364 Field 'a' doesn't have a default value select * from t1; a b @@ -275,6 +286,7 @@ a b 0 2 create table if not exists t1 select 3 as 'a',4 as 'b'; Warnings: +Note 1050 Table 't1' already exists Warning 1364 Field 'a' doesn't have a default value create table if not exists t1 select 3 as 'a',3 as 'b'; ERROR 23000: Duplicate entry '3' for key 1 @@ -615,3 +627,17 @@ create table t1 like v1; ERROR HY000: 'mysqltest.v1' is not BASE TABLE drop view v1; drop database mysqltest; +create database mysqltest; +create database if not exists mysqltest character set latin2; +Warnings: +Note 1007 Can't create database 'mysqltest'; database exists +show create database mysqltest; +Database Create Database +mysqltest CREATE DATABASE `mysqltest` /*!40100 DEFAULT CHARACTER SET latin1 */ +drop database mysqltest; +use test; +create table t1 (a int); +create table if not exists t1 (a int); +Warnings: +Note 1050 Table 't1' already exists +drop table t1; diff --git a/mysql-test/r/ctype_big5.result b/mysql-test/r/ctype_big5.result index 01b59b93b52..4c5832a57e9 100644 --- a/mysql-test/r/ctype_big5.result +++ b/mysql-test/r/ctype_big5.result @@ -89,6 +89,24 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +big5_chinese_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET collation_connection='big5_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -121,6 +139,24 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +big5_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET NAMES big5; CREATE TABLE t1 (a text) character set big5; INSERT INTO t1 VALUES ('ùØ'); @@ -134,3 +170,22 @@ SELECT HEX(a) FROM t1 WHERE MATCH(a) AGAINST (0xA741ADCCA66EB6DC IN BOOLEAN MODE HEX(a) A741ADCCA66EB6DC20A7DAADCCABDCA66E DROP TABLE t1; +set names big5; +create table t1 (a char character set big5); +insert into t1 values (0xF9D6),(0xF9D7),(0xF9D8),(0xF9D9); +insert into t1 values (0xF9DA),(0xF9DB),(0xF9DC); +select hex(a) a, hex(@u:=convert(a using utf8)) b, +hex(convert(@u using big5)) c from t1 order by a; +a b c +F9D6 E7A281 F9D6 +F9D7 E98AB9 F9D7 +F9D8 E8A38F F9D8 +F9D9 E5A2BB F9D9 +F9DA E68192 F9DA +F9DB E7B2A7 F9DB +F9DC E5ABBA F9DC +alter table t1 convert to character set utf8; +select hex(a) from t1 where a = _big5 0xF9DC; +hex(a) +E5ABBA +drop table t1; diff --git a/mysql-test/r/ctype_cp1251.result b/mysql-test/r/ctype_cp1251.result index c65055e726d..47797af3cbe 100644 --- a/mysql-test/r/ctype_cp1251.result +++ b/mysql-test/r/ctype_cp1251.result @@ -23,7 +23,7 @@ a b c drop table t1; -create table t1 (a char(15) binary, b binary(15)) character set cp1251; +create table t1 (a char(3) binary, b binary(3)) character set cp1251; insert into t1 values ('aaa','bbb'),('AAA','BBB'); select upper(a),upper(b) from t1; upper(a) upper(b) diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result index 08206a91b7b..1afceb86381 100755 --- a/mysql-test/r/ctype_cp932.result +++ b/mysql-test/r/ctype_cp932.result @@ -11349,3 +11349,20 @@ cp932_bin 6109 cp932_bin 61 cp932_bin 6120 drop table t1; +create table t1 (col1 varchar(1)) character set cp932; +insert into t1 values ('a'); +insert into t1 values ('ab'); +Warnings: +Warning 1265 Data truncated for column 'col1' at row 1 +select * from t1; +col1 +a +a +insert into t1 values ('abc'); +Warnings: +Warning 1265 Data truncated for column 'col1' at row 1 +select * from t1; +col1 +a +a +a diff --git a/mysql-test/r/ctype_gbk.result b/mysql-test/r/ctype_gbk.result index 1a9dea28429..aaffe692126 100644 --- a/mysql-test/r/ctype_gbk.result +++ b/mysql-test/r/ctype_gbk.result @@ -89,6 +89,24 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +gbk_chinese_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET collation_connection='gbk_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -121,6 +139,24 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +gbk_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET NAMES gbk; CREATE TABLE t1 (a text) character set gbk; INSERT INTO t1 VALUES (0xA3A0),(0xA1A1); diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index 95fca1575ef..cf4bf6e2fdd 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -296,6 +296,9 @@ FD C3BD FD 1 FE C3BE FE 1 FF C3BF FF 1 DROP TABLE t1; +SELECT 1 as ƒ, 2 as Š, 3 as Œ, 4 as Ž, 5 as š, 6 as œ, 7 as ž, 8 as Ÿ; +ƒ Š Œ Ž š œ ž Ÿ +1 2 3 4 5 6 7 8 select 'a' regexp 'A' collate latin1_general_ci; 'a' regexp 'A' collate latin1_general_ci 1 @@ -315,6 +318,24 @@ latin1_swedish_ci 6109 latin1_swedish_ci 61 latin1_swedish_ci 6120 drop table t1; +select @@collation_connection; +@@collation_connection +latin1_swedish_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET collation_connection='latin1_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -325,6 +346,24 @@ latin1_bin 6109 latin1_bin 61 latin1_bin 6120 drop table t1; +select @@collation_connection; +@@collation_connection +latin1_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; CREATE TABLE „a (a int); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '„a (a int)' at line 1 SELECT '„a' as str; diff --git a/mysql-test/r/ctype_many.result b/mysql-test/r/ctype_many.result index 87b83acfe0f..125a3fc4286 100644 --- a/mysql-test/r/ctype_many.result +++ b/mysql-test/r/ctype_many.result @@ -340,7 +340,7 @@ CYR CAPIT SOFT SIGN ø ø CYR CAPIT E ü ü CYR CAPIT YU à à CYR CAPIT YA ñ ñ -ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL default ''; +ALTER TABLE t1 ADD bin_f CHAR(1) BYTE NOT NULL default ''; UPDATE t1 SET bin_f=koi8_ru_f; SELECT COUNT(DISTINCT bin_f),COUNT(DISTINCT koi8_ru_f),COUNT(DISTINCT utf8_f) FROM t1; COUNT(DISTINCT bin_f) COUNT(DISTINCT koi8_ru_f) COUNT(DISTINCT utf8_f) @@ -1331,146 +1331,146 @@ UPDATE t1 SET greek_f=CONVERT(ucs2_f USING greek) WHERE comment LIKE _latin2'GRE UPDATE t1 SET armscii8_f=CONVERT(ucs2_f USING armscii8) WHERE comment LIKE _latin2'ARM%'; UPDATE t1 SET utf8_f=CONVERT(ucs2_f USING utf8) WHERE utf8_f=_utf8''; UPDATE t1 SET ucs2_f=CONVERT(utf8_f USING ucs2) WHERE ucs2_f=_ucs2''; -SELECT * FROM t1; -comment koi8_ru_f utf8_f bin_f ucs2_f armscii8_f greek_f -LAT SMALL A a a a a -LAT SMALL B b b b b -LAT SMALL C c c c c -LAT SMALL D d d d d -LAT SMALL E e e e e -LAT SMALL F f f f f -LAT SMALL G g g g g -LAT SMALL H h h h h -LAT SMALL I i i i i -LAT SMALL J j j j j -LAT SMALL K k k k k -LAT SMALL L l l l l -LAT SMALL M m m m m -LAT SMALL N n n n n -LAT SMALL O o o o o -LAT SMALL P p p p p -LAT SMALL Q q q q q -LAT SMALL R r r r r -LAT SMALL S s s s s -LAT SMALL T t t t t -LAT SMALL U u u u u -LAT SMALL V v v v v -LAT SMALL W w w w w -LAT SMALL X x x x x -LAT SMALL Y y y y y -LAT SMALL Z z z z z -LAT CAPIT A A A A A -LAT CAPIT B B B B B -LAT CAPIT C C C C C -LAT CAPIT D D D D D -LAT CAPIT E E E E E -LAT CAPIT F F F F F -LAT CAPIT G G G G G -LAT CAPIT H H H H H -LAT CAPIT I I I I I -LAT CAPIT J J J J J -LAT CAPIT K K K K K -LAT CAPIT L L L L L -LAT CAPIT M M M M M -LAT CAPIT N N N N N -LAT CAPIT O O O O O -LAT CAPIT P P P P P -LAT CAPIT Q Q Q Q Q -LAT CAPIT R R R R R -LAT CAPIT S S S S S -LAT CAPIT T T T T T -LAT CAPIT U U U U U -LAT CAPIT V V V V V -LAT CAPIT W W W W W -LAT CAPIT X X X X X -LAT CAPIT Y Y Y Y Y -LAT CAPIT Z Z Z Z Z -CYR SMALL A а а Á а -CYR SMALL BE б б  б -CYR SMALL VE в в × Ð² -CYR SMALL GE г г Ç Ð³ -CYR SMALL DE д д Ä Ð´ -CYR SMALL IE е е Šе -CYR SMALL IO Ñ‘ Ñ‘ £ Ñ‘ -CYR SMALL ZHE ж ж Ö Ð¶ -CYR SMALL ZE з з Ú Ð· -CYR SMALL I и и É Ð¸ -CYR SMALL KA к к Ë Ðº -CYR SMALL EL л л Ì Ð» -CYR SMALL EM м м Í Ð¼ -CYR SMALL EN н н Πн -CYR SMALL O о о Ï Ð¾ -CYR SMALL PE п п Рп -CYR SMALL ER Ñ€ Ñ€ Ò Ñ€ -CYR SMALL ES Ñ Ñ Ó Ñ -CYR SMALL TE Ñ‚ Ñ‚ Ô Ñ‚ -CYR SMALL U у у Õ Ñƒ -CYR SMALL EF Ñ„ Ñ„ Æ Ñ„ -CYR SMALL HA Ñ… Ñ… È Ñ… -CYR SMALL TSE ц ц à ц -CYR SMALL CHE ч ч Þ Ñ‡ -CYR SMALL SHA ш ш Û Ñˆ -CYR SMALL SCHA щ щ Ý Ñ‰ -CYR SMALL HARD SIGN ÑŠ ÑŠ ß ÑŠ -CYR SMALL YERU Ñ‹ Ñ‹ Ù Ñ‹ -CYR SMALL SOFT SIGN ÑŒ ÑŒ Ø ÑŒ -CYR SMALL E Ñ Ñ Ü Ñ -CYR SMALL YU ÑŽ ÑŽ À ÑŽ -CYR SMALL YA Ñ Ñ Ñ Ñ -CYR CAPIT A Ð Ð á Ð -CYR CAPIT BE Б Б â Б -CYR CAPIT VE Ð’ Ð’ ÷ Ð’ -CYR CAPIT GE Г Г ç Г -CYR CAPIT DE Д Д ä Д -CYR CAPIT IE Е Е å Е -CYR CAPIT IO Ð Ð ³ Ð -CYR CAPIT ZHE Ж Ж ö Ж -CYR CAPIT ZE З З ú З -CYR CAPIT I И И é И -CYR CAPIT KA К К ë К -CYR CAPIT EL Л Л ì Л -CYR CAPIT EM Ðœ Ðœ í Ðœ -CYR CAPIT EN Ð Ð î Ð -CYR CAPIT O О О ï О -CYR CAPIT PE П П ð П -CYR CAPIT ER Ð Ð ò Ð -CYR CAPIT ES С С ó С -CYR CAPIT TE Т Т ô Т -CYR CAPIT U У У õ У -CYR CAPIT EF Ф Ф æ Ф -CYR CAPIT HA Ð¥ Ð¥ è Ð¥ -CYR CAPIT TSE Ц Ц ã Ц -CYR CAPIT CHE Ч Ч þ Ч -CYR CAPIT SHA Ш Ш û Ш -CYR CAPIT SCHA Щ Щ ý Щ -CYR CAPIT HARD SIGN Ъ Ъ ÿ Ъ -CYR CAPIT YERU Ы Ы ù Ы -CYR CAPIT SOFT SIGN Ь Ь ø Ь -CYR CAPIT E Ð Ð ü Ð -CYR CAPIT YU Ю Ю à Ю -CYR CAPIT YA Я Я ñ Я -GREEK CAPIT ALPHA Α Α Α -GREEK CAPIT BETA Î’ Î’ Î’ -GREEK CAPIT GAMMA Γ Γ Γ -GREEK CAPIT DELTA Δ Δ Δ -GREEK CAPIT EPSILON Ε Ε Ε -GREEK SMALL ALPHA α α α -GREEK SMALL BETA β β β -GREEK SMALL GAMMA γ γ γ -GREEK SMALL DELTA δ δ δ -GREEK SMALL EPSILON ε ε ε -ARMENIAN CAPIT AYB Ô± Ô± Ô± -ARMENIAN CAPIT BEN Ô² Ô² Ô² -ARMENIAN CAPIT GIM Ô³ Ô³ Ô³ -ARMENIAN CAPIT DA Ô´ Ô´ Ô´ -ARMENIAN CAPIT ECH Ôµ Ôµ Ôµ -ARMENIAN CAPIT ZA Ô¶ Ô¶ Ô¶ -ARMENIAN SMALL YAB Õ¡ Õ¡ Õ¡ -ARMENIAN SMALL BEN Õ¢ Õ¢ Õ¢ -ARMENIAN SMALL GIM Õ£ Õ£ Õ£ -ARMENIAN SMALL DA Õ¤ Õ¤ Õ¤ -ARMENIAN SMALL ECH Õ¥ Õ¥ Õ¥ -ARMENIAN SMALL ZA Õ¦ Õ¦ Õ¦ +SELECT comment, koi8_ru_f, utf8_f, hex(bin_f), ucs2_f, armscii8_f, greek_f FROM t1; +comment koi8_ru_f utf8_f hex(bin_f) ucs2_f armscii8_f greek_f +LAT SMALL A a a 61 a +LAT SMALL B b b 62 b +LAT SMALL C c c 63 c +LAT SMALL D d d 64 d +LAT SMALL E e e 65 e +LAT SMALL F f f 66 f +LAT SMALL G g g 67 g +LAT SMALL H h h 68 h +LAT SMALL I i i 69 i +LAT SMALL J j j 6A j +LAT SMALL K k k 6B k +LAT SMALL L l l 6C l +LAT SMALL M m m 6D m +LAT SMALL N n n 6E n +LAT SMALL O o o 6F o +LAT SMALL P p p 70 p +LAT SMALL Q q q 71 q +LAT SMALL R r r 72 r +LAT SMALL S s s 73 s +LAT SMALL T t t 74 t +LAT SMALL U u u 75 u +LAT SMALL V v v 76 v +LAT SMALL W w w 77 w +LAT SMALL X x x 78 x +LAT SMALL Y y y 79 y +LAT SMALL Z z z 7A z +LAT CAPIT A A A 41 A +LAT CAPIT B B B 42 B +LAT CAPIT C C C 43 C +LAT CAPIT D D D 44 D +LAT CAPIT E E E 45 E +LAT CAPIT F F F 46 F +LAT CAPIT G G G 47 G +LAT CAPIT H H H 48 H +LAT CAPIT I I I 49 I +LAT CAPIT J J J 4A J +LAT CAPIT K K K 4B K +LAT CAPIT L L L 4C L +LAT CAPIT M M M 4D M +LAT CAPIT N N N 4E N +LAT CAPIT O O O 4F O +LAT CAPIT P P P 50 P +LAT CAPIT Q Q Q 51 Q +LAT CAPIT R R R 52 R +LAT CAPIT S S S 53 S +LAT CAPIT T T T 54 T +LAT CAPIT U U U 55 U +LAT CAPIT V V V 56 V +LAT CAPIT W W W 57 W +LAT CAPIT X X X 58 X +LAT CAPIT Y Y Y 59 Y +LAT CAPIT Z Z Z 5A Z +CYR SMALL A а а C1 а +CYR SMALL BE б б C2 б +CYR SMALL VE в в D7 в +CYR SMALL GE г г C7 г +CYR SMALL DE д д C4 д +CYR SMALL IE е е C5 е +CYR SMALL IO Ñ‘ Ñ‘ A3 Ñ‘ +CYR SMALL ZHE ж ж D6 ж +CYR SMALL ZE з з DA з +CYR SMALL I и и C9 и +CYR SMALL KA к к CB к +CYR SMALL EL л л CC л +CYR SMALL EM м м CD м +CYR SMALL EN н н CE н +CYR SMALL O о о CF о +CYR SMALL PE п п D0 п +CYR SMALL ER Ñ€ Ñ€ D2 Ñ€ +CYR SMALL ES Ñ Ñ D3 Ñ +CYR SMALL TE Ñ‚ Ñ‚ D4 Ñ‚ +CYR SMALL U у у D5 у +CYR SMALL EF Ñ„ Ñ„ C6 Ñ„ +CYR SMALL HA Ñ… Ñ… C8 Ñ… +CYR SMALL TSE ц ц C3 ц +CYR SMALL CHE ч ч DE ч +CYR SMALL SHA ш ш DB ш +CYR SMALL SCHA щ щ DD щ +CYR SMALL HARD SIGN ÑŠ ÑŠ DF ÑŠ +CYR SMALL YERU Ñ‹ Ñ‹ D9 Ñ‹ +CYR SMALL SOFT SIGN ÑŒ ÑŒ D8 ÑŒ +CYR SMALL E Ñ Ñ DC Ñ +CYR SMALL YU ÑŽ ÑŽ C0 ÑŽ +CYR SMALL YA Ñ Ñ D1 Ñ +CYR CAPIT A Ð Ð E1 Ð +CYR CAPIT BE Б Б E2 Б +CYR CAPIT VE Ð’ Ð’ F7 Ð’ +CYR CAPIT GE Г Г E7 Г +CYR CAPIT DE Д Д E4 Д +CYR CAPIT IE Е Е E5 Е +CYR CAPIT IO Ð Ð B3 Ð +CYR CAPIT ZHE Ж Ж F6 Ж +CYR CAPIT ZE З З FA З +CYR CAPIT I И И E9 И +CYR CAPIT KA К К EB К +CYR CAPIT EL Л Л EC Л +CYR CAPIT EM Ðœ Ðœ ED Ðœ +CYR CAPIT EN Ð Ð EE Ð +CYR CAPIT O О О EF О +CYR CAPIT PE П П F0 П +CYR CAPIT ER Ð Ð F2 Ð +CYR CAPIT ES С С F3 С +CYR CAPIT TE Т Т F4 Т +CYR CAPIT U У У F5 У +CYR CAPIT EF Ф Ф E6 Ф +CYR CAPIT HA Ð¥ Ð¥ E8 Ð¥ +CYR CAPIT TSE Ц Ц E3 Ц +CYR CAPIT CHE Ч Ч FE Ч +CYR CAPIT SHA Ш Ш FB Ш +CYR CAPIT SCHA Щ Щ FD Щ +CYR CAPIT HARD SIGN Ъ Ъ FF Ъ +CYR CAPIT YERU Ы Ы F9 Ы +CYR CAPIT SOFT SIGN Ь Ь F8 Ь +CYR CAPIT E Ð Ð FC Ð +CYR CAPIT YU Ю Ю E0 Ю +CYR CAPIT YA Я Я F1 Я +GREEK CAPIT ALPHA Α 00 Α Α +GREEK CAPIT BETA Î’ 00 Î’ Î’ +GREEK CAPIT GAMMA Γ 00 Γ Γ +GREEK CAPIT DELTA Δ 00 Δ Δ +GREEK CAPIT EPSILON Ε 00 Ε Ε +GREEK SMALL ALPHA α 00 α α +GREEK SMALL BETA β 00 β β +GREEK SMALL GAMMA γ 00 γ γ +GREEK SMALL DELTA δ 00 δ δ +GREEK SMALL EPSILON ε 00 ε ε +ARMENIAN CAPIT AYB Ô± 00 Ô± Ô± +ARMENIAN CAPIT BEN Ô² 00 Ô² Ô² +ARMENIAN CAPIT GIM Ô³ 00 Ô³ Ô³ +ARMENIAN CAPIT DA Ô´ 00 Ô´ Ô´ +ARMENIAN CAPIT ECH Ôµ 00 Ôµ Ôµ +ARMENIAN CAPIT ZA Ô¶ 00 Ô¶ Ô¶ +ARMENIAN SMALL YAB Õ¡ 00 Õ¡ Õ¡ +ARMENIAN SMALL BEN Õ¢ 00 Õ¢ Õ¢ +ARMENIAN SMALL GIM Õ£ 00 Õ£ Õ£ +ARMENIAN SMALL DA Õ¤ 00 Õ¤ Õ¤ +ARMENIAN SMALL ECH Õ¥ 00 Õ¥ Õ¥ +ARMENIAN SMALL ZA Õ¦ 00 Õ¦ Õ¦ SET CHARACTER SET 'binary'; SELECT * FROM t1; comment koi8_ru_f utf8_f bin_f ucs2_f armscii8_f greek_f @@ -1590,28 +1590,28 @@ CYR CAPIT SOFT SIGN ø Ь ø , CYR CAPIT E ü Ð ü - CYR CAPIT YU à Ю à . CYR CAPIT YA ñ Я ñ / -GREEK CAPIT ALPHA Α ‘ Á -GREEK CAPIT BETA Î’ ’  -GREEK CAPIT GAMMA Γ “ à -GREEK CAPIT DELTA Δ ” Ä -GREEK CAPIT EPSILON Ε • Å -GREEK SMALL ALPHA α ± á -GREEK SMALL BETA β ² â -GREEK SMALL GAMMA γ ³ ã -GREEK SMALL DELTA δ ´ ä -GREEK SMALL EPSILON ε µ å -ARMENIAN CAPIT AYB Ô± 1 ² -ARMENIAN CAPIT BEN Ô² 2 ´ -ARMENIAN CAPIT GIM Ô³ 3 ¶ -ARMENIAN CAPIT DA Ô´ 4 ¸ -ARMENIAN CAPIT ECH Ôµ 5 º -ARMENIAN CAPIT ZA Ô¶ 6 ¼ -ARMENIAN SMALL YAB Õ¡ a ³ -ARMENIAN SMALL BEN Õ¢ b µ -ARMENIAN SMALL GIM Õ£ c · -ARMENIAN SMALL DA Õ¤ d ¹ -ARMENIAN SMALL ECH Õ¥ e » -ARMENIAN SMALL ZA Õ¦ f ½ +GREEK CAPIT ALPHA Α +GREEK CAPIT BETA Î’ +GREEK CAPIT GAMMA Γ +GREEK CAPIT DELTA Δ +GREEK CAPIT EPSILON Ε +GREEK SMALL ALPHA α +GREEK SMALL BETA β +GREEK SMALL GAMMA γ +GREEK SMALL DELTA δ +GREEK SMALL EPSILON ε +ARMENIAN CAPIT AYB Ô± +ARMENIAN CAPIT BEN Ô² +ARMENIAN CAPIT GIM Ô³ +ARMENIAN CAPIT DA Ô´ +ARMENIAN CAPIT ECH Ôµ +ARMENIAN CAPIT ZA Ô¶ +ARMENIAN SMALL YAB Õ¡ +ARMENIAN SMALL BEN Õ¢ +ARMENIAN SMALL GIM Õ£ +ARMENIAN SMALL DA Õ¤ +ARMENIAN SMALL ECH Õ¥ +ARMENIAN SMALL ZA Õ¦ SELECT min(comment),count(*) FROM t1 GROUP BY ucs2_f; min(comment) count(*) LAT CAPIT A 2 diff --git a/mysql-test/r/ctype_sjis.result b/mysql-test/r/ctype_sjis.result index e6669c63621..d1976a516d2 100644 --- a/mysql-test/r/ctype_sjis.result +++ b/mysql-test/r/ctype_sjis.result @@ -103,6 +103,24 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +sjis_japanese_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET collation_connection='sjis_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -135,6 +153,24 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +sjis_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET NAMES sjis; SELECT HEX('²“‘@\Œ\') FROM DUAL; HEX('²“‘@_Œ\') diff --git a/mysql-test/r/ctype_tis620.result b/mysql-test/r/ctype_tis620.result index 5734f7cac86..dae694cf3d5 100644 --- a/mysql-test/r/ctype_tis620.result +++ b/mysql-test/r/ctype_tis620.result @@ -2947,6 +2947,24 @@ tis620_thai_ci 6109 tis620_thai_ci 61 tis620_thai_ci 6120 drop table t1; +select @@collation_connection; +@@collation_connection +tis620_thai_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET collation_connection='tis620_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -2957,3 +2975,21 @@ tis620_bin 6109 tis620_bin 61 tis620_bin 6120 drop table t1; +select @@collation_connection; +@@collation_connection +tis620_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 3803dd932d7..4b245c69d2a 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -1905,6 +1905,116 @@ Z,z,Ź,ź,Å»,ż,Ž,ž Ç Ç‚ ǃ +select group_concat(c1 order by c1) from t1 group by c1 collate utf8_esperanto_ci; +group_concat(c1 order by c1) +÷ +× +A,a,À,Ã,Â,Ã,Ä,Ã…,à ,á,â,ã,ä,Ã¥,Ä€,Ä,Ä‚,ă,Ä„,Ä…,Ç,ÇŽ,Çž,ÇŸ,Ç ,Ç¡,Ǻ,Ç» +AA,Aa,aA,aa +Æ,æ,Ç¢,Ç£,Ǽ,ǽ +B,b +Æ€ +Æ +Æ‚,ƃ +C,c,Ç,ç,Ć,ć,ÄŠ,Ä‹,ÄŒ,Ä +CH,Ch,cH,ch +Ĉ,ĉ +Ƈ,ƈ +D,d,ÄŽ,Ä +DZ,Dz,dZ,dz,Ç„,Ç…,dž,DZ,Dz,dz +Ä,Ä‘ +Ɖ +ÆŠ +Æ‹,ÆŒ +Ã,ð +E,e,È,É,Ê,Ë,è,é,ê,ë,Ä’,Ä“,Ä”,Ä•,Ä–,Ä—,Ę,Ä™,Äš,Ä› +ÆŽ,Ç +Æ +Æ +F,f +Æ‘,Æ’ +G,g,Äž,ÄŸ,Ä ,Ä¡,Ä¢,Ä£,Ǧ,ǧ,Ç´,ǵ +Äœ,Ä +Ǥ,Ç¥ +Æ“ +Æ” +Æ¢,Æ£ +H,h +Ĥ,Ä¥ +Æ•,Ƕ +Ħ,ħ +I,i,ÃŒ,Ã,ÃŽ,Ã,ì,Ã,î,ï,Ĩ,Ä©,Ī,Ä«,Ĭ,Ä,Ä®,į,Ä°,Ç,Ç +IJ,Ij,iJ,ij,IJ,ij +ı +Æ— +Æ– +J,j,Ç° +Ä´,ĵ +K,k,Ķ,Ä·,Ǩ,Ç© +Ƙ,Æ™ +L,l,Ĺ,ĺ,Ä»,ļ,Ľ,ľ +Ä¿,Å€ +LJ,Lj,lJ,lj,LJ,Lj,lj +LL,Ll,lL,ll +Å,Å‚ +Æš +Æ› +M,m +N,n,Ñ,ñ,Ń,Å„,Å…,ņ,Ň,ň,Ǹ,ǹ +NJ,Nj,nJ,nj,ÇŠ,Ç‹,ÇŒ +Æ +Æž +ÅŠ,Å‹ +O,o,Ã’,Ó,Ô,Õ,Ö,ò,ó,ô,õ,ö,ÅŒ,Å,ÅŽ,Å,Å,Å‘,Æ ,Æ¡,Ç‘,Ç’,Ǫ,Ç«,Ǭ,Ç +OE,Oe,oE,oe,Å’,Å“ +Ø,ø,Ǿ,Ç¿ +Ɔ +ÆŸ +P,p +Ƥ,Æ¥ +Q,q +ĸ +R,r,Å”,Å•,Å–,Å—,Ř,Å™ +RR,Rr,rR,rr +Ʀ +S,s,Åš,Å›,Åž,ÅŸ,Å ,Å¡,Å¿ +SS,Ss,sS,ss,ß +Åœ,Å +Æ© +ƪ +T,t,Å¢,Å£,Ť,Å¥ +ƾ +Ŧ,ŧ +Æ« +Ƭ,Æ +Æ® +U,u,Ù,Ú,Û,Ãœ,ù,ú,û,ü,Ũ,Å©,Ū,Å«,Å®,ů,Å°,ű,Ų,ų,Ư,Æ°,Ç“,Ç”,Ç•,Ç–,Ç—,ǘ,Ç™,Çš,Ç›,Çœ +Ŭ,Å +Æœ +Ʊ +V,v +Ʋ +W,w,Å´,ŵ +X,x +Y,y,Ã,ý,ÿ,Ŷ,Å·,Ÿ +Ƴ,Æ´ +Z,z,Ź,ź,Å»,ż,Ž,ž +Æ +Ƶ,ƶ +Æ·,Ç®,ǯ +Ƹ,ƹ +ƺ +Þ,þ +Æ¿,Ç· +Æ» +Ƨ,ƨ +Ƽ,ƽ +Æ„,Æ… +ʼn +Ç€ +Ç +Ç‚ +ǃ drop table t1; SET NAMES utf8; CREATE TABLE t1 (c varchar(255) NOT NULL COLLATE utf8_general_ci, INDEX (c)); @@ -2396,6 +2506,24 @@ utf8_unicode_ci 6109 utf8_unicode_ci 61 utf8_unicode_ci 6120 drop table t1; +select @@collation_connection; +@@collation_connection +utf8_unicode_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; CREATE TABLE t1 (id int, a varchar(30) character set utf8); INSERT INTO t1 VALUES (1, _ucs2 0x01310069), (2, _ucs2 0x01310131); INSERT INTO t1 VALUES (3, _ucs2 0x00690069), (4, _ucs2 0x01300049); diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 4bc2ed0fdc8..65b5a1cbba8 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -595,6 +595,24 @@ ucs2_general_ci 00610009 ucs2_general_ci 0061 ucs2_general_ci 00610020 drop table t1; +select @@collation_connection; +@@collation_connection +ucs2_general_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET NAMES latin1; SET collation_connection='ucs2_bin'; create table t1 select repeat('a',4000) a; @@ -606,6 +624,24 @@ ucs2_bin 00610009 ucs2_bin 0061 ucs2_bin 00610020 drop table t1; +select @@collation_connection; +@@collation_connection +ucs2_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; select hex(substr(_ucs2 0x00e400e50068,1)); hex(substr(_ucs2 0x00e400e50068,1)) 00E400E50068 diff --git a/mysql-test/r/ctype_ucs_binlog.result b/mysql-test/r/ctype_ucs_binlog.result index 4267e495959..14220a7df13 100644 --- a/mysql-test/r/ctype_ucs_binlog.result +++ b/mysql-test/r/ctype_ucs_binlog.result @@ -17,6 +17,7 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t2 values (@v); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; drop table t2; diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result index 0bc101d491d..15de93440fc 100644 --- a/mysql-test/r/ctype_ujis.result +++ b/mysql-test/r/ctype_ujis.result @@ -2239,6 +2239,24 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +ujis_japanese_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET collation_connection='ujis_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -2271,3 +2289,51 @@ select c1 from t1 where c1 like 'abcde111%' order by c1; c1 abcde111 drop table t1; +select @@collation_connection; +@@collation_connection +ujis_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +DROP TABLE IF EXISTS t1, t2; +DROP PROCEDURE IF EXISTS sp1; +set names ujis; +set character_set_database = ujis; +set character_set_server = ujis; +CREATE TABLE t1(c1 char(2)) default charset = ujis; +CREATE TABLE t2(c2 char(2)) default charset = ujis; +INSERT INTO t1 VALUES(_ujis 0xA4A2); +CREATE PROCEDURE sp1() +BEGIN +DECLARE a CHAR(1); +DECLARE cur1 CURSOR FOR SELECT c1 FROM t1; +OPEN cur1; +FETCH cur1 INTO a; +INSERT INTO t2 VALUES (a); +CLOSE cur1; +END| +CALL sp1(); +SELECT c1,c2 FROM t1,t2; +c1 c2 +¤¢ ¤¢ +SELECT hex(convert(_latin1 0xA4A2 using ujis)),hex(c2) FROM t1,t2; +hex(convert(_latin1 0xA4A2 using ujis)) hex(c2) +8FA2F0A1F1 A4A2 +DROP PROCEDURE sp1; +DROP TABLE t1; +DROP TABLE t2; +set names default; +set character_set_database=default; +set character_set_server=default; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 64c693a292a..874983daff2 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -842,6 +842,24 @@ utf8_general_ci 6109 utf8_general_ci 61 utf8_general_ci 6120 drop table t1; +select @@collation_connection; +@@collation_connection +utf8_general_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; SET collation_connection='utf8_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -852,6 +870,24 @@ utf8_bin 6109 utf8_bin 61 utf8_bin 6120 drop table t1; +select @@collation_connection; +@@collation_connection +utf8_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; CREATE TABLE t1 ( user varchar(255) NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1; @@ -955,6 +991,10 @@ char_length(a) length(a) a 2 4 ан drop table t1; set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; +'andre%' like 'andreñ%' escape 'ñ' +1 +set names utf8; select 'a\\' like 'a\\'; 'a\\' like 'a\\' 1 @@ -1004,6 +1044,20 @@ hex(a) 5B E880BD drop table t1; +set names 'latin1'; +create table t1 (a varchar(255)) default charset=utf8; +select * from t1 where find_in_set('-1', a); +a +drop table t1; +create table t1 (a int); +insert into t1 values (48),(49),(50); +set names utf8; +select distinct char(a) from t1; +char(a) +0 +1 +2 +drop table t1; CREATE TABLE t1(id varchar(20) NOT NULL) DEFAULT CHARSET=utf8; INSERT INTO t1 VALUES ('xxx'), ('aa'), ('yyy'), ('aa'); SELECT id FROM t1; @@ -1023,3 +1077,83 @@ aa xxx yyy DROP TABLE t1; +set names utf8; +select hex(char(1 using utf8)); +hex(char(1 using utf8)) +01 +select char(0xd1,0x8f using utf8); +char(0xd1,0x8f using utf8) +Ñ +select char(0xd18f using utf8); +char(0xd18f using utf8) +Ñ +select char(53647 using utf8); +char(53647 using utf8) +Ñ +select char(0xff,0x8f using utf8); +char(0xff,0x8f using utf8) +ÿ +Warnings: +Warning 1300 Invalid utf8 character string: 'FF8F' +set sql_mode=traditional; +select char(0xff,0x8f using utf8); +char(0xff,0x8f using utf8) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'FF8F' +select char(195 using utf8); +char(195 using utf8) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'C3' +select char(196 using utf8); +char(196 using utf8) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'C4' +select char(2557 using utf8); +char(2557 using utf8) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'FD' +select hex(convert(char(2557 using latin1) using utf8)); +hex(convert(char(2557 using latin1) using utf8)) +09C3BD +select hex(char(195)); +hex(char(195)) +C3 +select hex(char(196)); +hex(char(196)) +C4 +select hex(char(2557)); +hex(char(2557)) +09FD +set names utf8; +create table t1 (a char(1)) default character set utf8; +create table t2 (a char(1)) default character set utf8; +insert into t1 values('a'),('a'),(0xE38182),(0xE38182); +insert into t1 values('i'),('i'),(0xE38184),(0xE38184); +select * from t1 union distinct select * from t2; +a +a +ã‚ +i +ã„ +drop table t1,t2; +set names utf8; +create table t1 (a char(10), b varchar(10)); +insert into t1 values ('bar','kostja'); +insert into t1 values ('kostja','bar'); +prepare my_stmt from "select * from t1 where a=?"; +set @a:='bar'; +execute my_stmt using @a; +a b +bar kostja +set @a:='kostja'; +execute my_stmt using @a; +a b +kostja bar +set @a:=null; +execute my_stmt using @a; +a b +drop table if exists t1; diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result index 7db20c2b096..aef49af6c62 100644 --- a/mysql-test/r/default.result +++ b/mysql-test/r/default.result @@ -29,38 +29,6 @@ z varchar(20) binary NOT NULL DEFAULT ' ', a1 varchar(30) binary NOT NULL DEFAULT ' ', b1 tinyblob NULL) ENGINE=InnoDB DEFAULT CHARACTER SET = latin1 COLLATE latin1_bin; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` varchar(30) collate latin1_bin NOT NULL default ' ', - `b` varchar(1) collate latin1_bin NOT NULL default ' ', - `c` varchar(4) collate latin1_bin NOT NULL default '0000', - `d` tinyblob, - `e` tinyblob, - `f` tinyblob, - `g` tinyblob, - `h` tinyblob, - `i` tinyblob, - `j` tinyblob, - `k` tinyblob, - `l` tinyblob, - `m` tinyblob, - `n` tinyblob, - `o` tinyblob, - `p` tinyblob, - `q` varchar(30) collate latin1_bin NOT NULL default ' ', - `r` varchar(30) collate latin1_bin NOT NULL default ' ', - `s` tinyblob, - `t` varchar(4) collate latin1_bin NOT NULL default ' ', - `u` varchar(1) collate latin1_bin NOT NULL default ' ', - `v` varchar(30) collate latin1_bin NOT NULL default ' ', - `w` varchar(30) collate latin1_bin NOT NULL default ' ', - `x` tinyblob, - `y` varchar(5) collate latin1_bin NOT NULL default ' ', - `z` varchar(20) collate latin1_bin NOT NULL default ' ', - `a1` varchar(30) collate latin1_bin NOT NULL default ' ', - `b1` tinyblob -) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin INSERT into t1 (b) values ('1'); SHOW WARNINGS; Level Code Message diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 7c9d88acf90..19325731d35 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -368,3 +368,15 @@ create table t2 (a int); select * from (select * from t1,t2) foo; ERROR 42S21: Duplicate column name 'a' drop table t1,t2; +create table t1 (ID int unsigned not null auto_increment, +DATA varchar(5) not null, primary key (ID)); +create table t2 (ID int unsigned not null auto_increment, +DATA varchar(5) not null, FID int unsigned not null, +primary key (ID)); +select A.* from (t1 inner join (select * from t2) as A on t1.ID = A.FID); +ID DATA FID +select t2.* from ((select * from t1) as A inner join t2 on A.ID = t2.FID); +ID DATA FID +select t2.* from (select * from t1) as A inner join t2 on A.ID = t2.FID; +ID DATA FID +drop table t1, t2; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index fa52b5c8330..00436019f85 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -464,14 +464,6 @@ SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; html prod 1 0.0000 drop table t1; -create table t1 (id int, dsc varchar(50)); -insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); -select distinct id, IFNULL(dsc, '-') from t1; -id IFNULL(dsc, '-') -1 line number one -2 line number two -3 line number three -drop table t1; CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (1),(2),(3),(4),(5); SELECT DISTINCT a, 1 FROM t1; diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index 7692991c112..7e18cb9f75f 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -25,28 +25,28 @@ CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:@/too/many/items/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:@/too/many/items/federated/t1'; ERROR HY000: Can't create federated table. The data source connection string 'mysql://root@127.0.0.1:@/too/many/items/federated/t1' is not in the correct format CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1'; +CONNECTION='mysql://root@127.0.0.1'; ERROR HY000: Can't create federated table. The data source connection string 'mysql://root@127.0.0.1' is not in the correct format CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t3'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t3'; ERROR HY000: Can't create federated table. Foreign data src error : ': 1146 : Table 'federated.t3' doesn't exist' CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://user:pass@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://user:pass@127.0.0.1:SLAVE_PORT/federated/t1'; ERROR HY000: Unable to connect to foreign data source - database ' database federated username user hostname 127.0.0.1'! DROP TABLE IF EXISTS federated.t1; Warnings: @@ -56,7 +56,7 @@ CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); INSERT INTO federated.t1 (id, name) VALUES (2, 'fee'); SELECT * FROM federated.t1; @@ -73,7 +73,13 @@ CREATE TABLE federated.t2 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +SHOW CREATE TABLE federated.t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(20) NOT NULL, + `name` varchar(32) NOT NULL default '' +) ENGINE=FEDERATED DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1' INSERT INTO federated.t2 (id, name) VALUES (1, 'foo'); INSERT INTO federated.t2 (id, name) VALUES (2, 'fee'); SELECT * FROM federated.t2; @@ -98,7 +104,7 @@ CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1%'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1%'; INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); INSERT INTO federated.t1 (id, name) VALUES (2, 'fee'); SELECT * FROM federated.t1; @@ -112,7 +118,7 @@ CREATE TABLE federated.`t1%` ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1%'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1%'; INSERT INTO federated.`t1%` (id, name) VALUES (1, 'foo'); INSERT INTO federated.`t1%` (id, name) VALUES (2, 'fee'); SELECT * FROM federated.`t1%`; @@ -139,7 +145,7 @@ CREATE TABLE federated.t1 ( `created` datetime default '2004-04-04 04:04:04', PRIMARY KEY (`id`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111); INSERT INTO federated.t1 (name, other) VALUES ('Second Name', 22222); INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333); @@ -279,7 +285,7 @@ key name(`name`), key other(`other`), key created(`created`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (name, other, created) VALUES ('First Name', 11111, '2004-01-01 01:01:01'); INSERT INTO federated.t1 (name, other, created) @@ -419,7 +425,7 @@ CREATE TABLE federated.t1 ( PRIMARY KEY (`id`) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111); INSERT INTO federated.t1 (name, other) VALUES ('Second Name', NULL); INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333); @@ -484,7 +490,7 @@ PRIMARY KEY (`id`), KEY nameoth (name, other)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (name, other) VALUES ('First Name', '1111'); INSERT INTO federated.t1 (name, other) VALUES ('Second Name', '2222'); INSERT INTO federated.t1 (name, other) VALUES ('Third Name', '3333'); @@ -504,7 +510,7 @@ DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( `id` int NOT NULL auto_increment, `name` char(32) NOT NULL DEFAULT '', -`bincol` binary(4) NOT NULL, +`bincol` binary(1) NOT NULL, `floatval` decimal(5,2) NOT NULL DEFAULT 0.0, `other` int NOT NULL DEFAULT 0, PRIMARY KEY (id), @@ -515,7 +521,7 @@ DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( `id` int NOT NULL auto_increment, `name` char(32) NOT NULL DEFAULT '', -`bincol` binary(4) NOT NULL, +`bincol` binary(1) NOT NULL, `floatval` decimal(5,2) NOT NULL DEFAULT 0.0, `other` int NOT NULL DEFAULT 0, PRIMARY KEY (id), @@ -524,7 +530,7 @@ KEY bincol(bincol), KEY floatval(floatval)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (name, bincol, floatval, other) VALUES ('first', 0x65, 11.11, 1111); INSERT INTO federated.t1 (name, bincol, floatval, other) @@ -589,7 +595,7 @@ key col2(col2), key col3(col3), key col4(col4)) ENGINE="FEDERATED" - COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (col1, col2, col3, col4) VALUES (1, 'one One', 11, 1111); INSERT INTO federated.t1 (col1, col2, col3, col4) @@ -798,7 +804,7 @@ key 3key(`col2`,`col3`,`col4`), key 2key (`col3`,`col4`), key col4(col4)) ENGINE="FEDERATED" - COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (col1, col2, col3, col4) VALUES ('aaaa', 'aaaaaaaaaaaaaaaaaaa', 'ababababab', 'acacacacacacacac'); INSERT INTO federated.t1 (col1, col2, col3, col4) @@ -898,7 +904,7 @@ CREATE TABLE federated.t1 ( primary key (`col1`, `col2`, `col3`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 VALUES ('a00', '110', 'cc0'); INSERT INTO federated.t1 VALUES ('aaa', '111', 'ccc'); INSERT INTO federated.t1 VALUES ('bbb', '222', 'yyy'); @@ -933,7 +939,7 @@ CREATE TABLE federated.t1 ( `other` int) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 values (NULL, NULL, NULL, NULL); INSERT INTO federated.t1 values (); INSERT INTO federated.t1 (id) VALUES (1); @@ -968,7 +974,7 @@ CREATE TABLE federated.t1 ( PRIMARY KEY (blurb_id)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 VALUES (1, " MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values."); INSERT INTO federated.t1 VALUES (2, "All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE."); INSERT INTO federated.t1 VALUES (3, " A floating-point number. p represents the precision. It can be from 0 to 24 for a single-precision floating-point number and from 25 to 53 for a double-precision floating-point number. These types are like the FLOAT and DOUBLE types described immediately following. FLOAT(p) has the same range as the corresponding FLOAT and DOUBLE types, but the display size and number of decimals are undefined. "); @@ -994,7 +1000,7 @@ PRIMARY KEY (a), KEY (b)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 VALUES (3,3,3),(1,1,1),(2,2,2),(4,4,4); DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8 @@ -1252,7 +1258,7 @@ int, i999 int, i1000 int, b varchar(256)) row_format=dynamic ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1322,7 +1328,7 @@ PRIMARY KEY(id), index(code), index(fileguts(10))) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03'); INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04'); INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04'); @@ -1340,7 +1346,7 @@ DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( `a` BLOB) ENGINE="FEDERATED" -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 VALUES (0x00); INSERT INTO federated.t1 VALUES (0x0001); INSERT INTO federated.t1 VALUES (0x0100); @@ -1378,7 +1384,7 @@ CREATE TABLE federated.t1 ( PRIMARY KEY (`id`), KEY (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (name, country_id, other) VALUES ('Kumar', 1, 11111); INSERT INTO federated.t1 (name, country_id, other) VALUES ('Lenz', 2, 22222); INSERT INTO federated.t1 (name, country_id, other) VALUES ('Marizio', 3, 33333); @@ -1457,6 +1463,32 @@ federated.t1 repair status OK REPAIR TABLE federated.t1 USE_FRM; Table Op Msg_type Msg_text federated.t1 repair status OK +DROP TABLE IF EXISTS federated.normal_table; +CREATE TABLE federated.normal_table ( +`id` int(4) NOT NULL, +`name` varchar(10) default NULL +) DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS federated.alter_me; +CREATE TABLE federated.alter_me ( +`id` int(4) NOT NULL, +`name` varchar(10) default NULL, +PRIMARY KEY (`id`) +) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/normal_table'; +INSERT INTO federated.alter_me (id, name) VALUES (1, 'Monty'); +INSERT INTO federated.alter_me (id, name) VALUES (2, 'David'); +SELECT * FROM federated.alter_me; +id name +1 Monty +2 David +ALTER TABLE federated.alter_me MODIFY COLUMN id int(16) NOT NULL; +ERROR HY000: Table storage engine for 'alter_me' doesn't have this option +SELECT * FROM federated.alter_me; +id name +1 Monty +2 David +DROP TABLE federated.alter_me; +DROP TABLE federated.normal_table; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/r/federated_archive.result b/mysql-test/r/federated_archive.result new file mode 100644 index 00000000000..3fd7cb2acd4 --- /dev/null +++ b/mysql-test/r/federated_archive.result @@ -0,0 +1,48 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP TABLE IF EXISTS federated.archive_table; +CREATE TABLE federated.archive_table ( +`id` int(4) NOT NULL, +`name` varchar(54) default NULL +) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`id` int(4) NOT NULL, +`name` varchar(54) default NULL, +PRIMARY KEY (`id`) +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/archive_table'; +INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); +INSERT INTO federated.t1 (id, name) VALUES (2, 'bar'); +SELECT * FROM federated.t1; +id name +1 foo +2 bar +DELETE FROM federated.t1 WHERE id = 1; +ERROR HY000: Got error 10000 'Error on remote system: 1031: Table storage engine for 'archive_table' doesn't have this option' from FEDERATED +SELECT * FROM federated.t1; +id name +1 foo +2 bar +UPDATE federated.t1 SET name='baz' WHERE id = 1; +ERROR HY000: Got error 10000 'Error on remote system: 1031: Table storage engine for 'archive_table' doesn't have this option' from FEDERATED +SELECT * FROM federated.t1; +id name +1 foo +2 bar +DROP TABLE federated.t1; +DROP TABLE federated.archive_table; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/r/federated_bug_13118.result b/mysql-test/r/federated_bug_13118.result new file mode 100644 index 00000000000..cc14dae87d9 --- /dev/null +++ b/mysql-test/r/federated_bug_13118.result @@ -0,0 +1,39 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP TABLE IF EXISTS federated.bug_13118_table; +CREATE TABLE federated.bug_13118_table ( +`foo` integer, +`bar` integer +); +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`foo` integer, +`bar` integer +) ENGINE="FEDERATED" + CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/bug_13118_table'; +SELECT * from federated.t1; +foo bar +INSERT INTO federated.t1 VALUES (1,1); +SELECT * FROM federated.t1; +foo bar +1 1 +INSERT INTO federated.t1 VALUES (1,1); +SELECT * FROM federated.t1; +foo bar +1 1 +1 1 +DROP TABLE federated.t1; +DROP TABLE federated.bug_13118_table; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index 2ee3e770a2e..afdec0f4d06 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -92,3 +92,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1003 select password(_latin1'idkfa ') AS `password('idkfa ')`,old_password(_latin1'idkfa') AS `old_password('idkfa')` +select encrypt('1234','_.'); +encrypt('1234','_.') +# diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 7235fded66a..6461c393d51 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -469,6 +469,15 @@ select collation(group_concat(a,b)) from t1; ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat' drop table t1; drop table t2; +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +a +À +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +À +DROP TABLE t1; CREATE TABLE t1 (id int); SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; gc @@ -558,3 +567,32 @@ DROP TABLE t1,t2; select * from (select group_concat('c') from DUAL) t; group_concat('c') NULL +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +group_concat(a) +NULL +select group_concat('x') UNION ALL select 1; +group_concat('x') +NULL +1 +drop table t1; +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES +(2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +,,x,y,z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; +GROUP_CONCAT(a ORDER BY a) +,,,x,y,z +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +GROUP_CONCAT(a) +,y +,x +z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; +GROUP_CONCAT(a ORDER BY a) +,y +,x +,z +DROP TABLE t1; diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 1542794798a..2b0176179ed 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -821,6 +821,142 @@ SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; MAX(id) NULL DROP TABLE t1; +create table t1m (a int) engine=myisam; +create table t1i (a int) engine=innodb; +create table t2m (a int) engine=myisam; +create table t2i (a int) engine=innodb; +insert into t2m values (5); +insert into t2i values (5); +select min(a) from t1m; +min(a) +NULL +select min(7) from t1m; +min(7) +NULL +select min(7) from DUAL; +min(7) +NULL +explain select min(7) from t2m join t1m; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(7) from t2m join t1m; +min(7) +NULL +select max(a) from t1m; +max(a) +NULL +select max(7) from t1m; +max(7) +NULL +select max(7) from DUAL; +max(7) +NULL +explain select max(7) from t2m join t1m; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(7) from t2m join t1m; +max(7) +NULL +select 1, min(a) from t1m where a=99; +1 min(a) +1 NULL +select 1, min(a) from t1m where 1=99; +1 min(a) +1 NULL +select 1, min(1) from t1m where a=99; +1 min(1) +select 1, min(1) from t1m where 1=99; +1 min(1) +1 NULL +select 1, max(a) from t1m where a=99; +1 max(a) +1 NULL +select 1, max(a) from t1m where 1=99; +1 max(a) +1 NULL +select 1, max(1) from t1m where a=99; +1 max(1) +select 1, max(1) from t1m where 1=99; +1 max(1) +1 NULL +select min(a) from t1i; +min(a) +NULL +select min(7) from t1i; +min(7) +NULL +select min(7) from DUAL; +min(7) +NULL +explain select min(7) from t2i join t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2i ALL NULL NULL NULL NULL 1 +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select min(7) from t2i join t1i; +min(7) +NULL +select max(a) from t1i; +max(a) +NULL +select max(7) from t1i; +max(7) +NULL +select max(7) from DUAL; +max(7) +NULL +explain select max(7) from t2i join t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2i ALL NULL NULL NULL NULL 1 +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select max(7) from t2i join t1i; +max(7) +NULL +select 1, min(a) from t1i where a=99; +1 min(a) +1 NULL +select 1, min(a) from t1i where 1=99; +1 min(a) +1 NULL +select 1, min(1) from t1i where a=99; +1 min(1) +1 NULL +select 1, min(1) from t1i where 1=99; +1 min(1) +1 NULL +select 1, max(a) from t1i where a=99; +1 max(a) +1 NULL +select 1, max(a) from t1i where 1=99; +1 max(a) +1 NULL +select 1, max(1) from t1i where a=99; +1 max(1) +1 NULL +select 1, max(1) from t1i where 1=99; +1 max(1) +1 NULL +explain select count(*), min(7), max(7) from t1m, t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select count(*), min(7), max(7) from t1m, t1i; +count(*) min(7) max(7) +0 NULL NULL +explain select count(*), min(7), max(7) from t1m, t2i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found +1 SIMPLE t2i ALL NULL NULL NULL NULL 1 +select count(*), min(7), max(7) from t1m, t2i; +count(*) min(7) max(7) +0 NULL NULL +explain select count(*), min(7), max(7) from t2m, t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2m system NULL NULL NULL NULL 1 +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select count(*), min(7), max(7) from t2m, t1i; +count(*) min(7) max(7) +0 NULL NULL +drop table t1m, t1i, t2m, t2i; create table t2 (ff double); insert into t2 values (2.2); select cast(sum(distinct ff) as decimal(5,2)) from t2; diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index b0c0178328e..60022ae0d8f 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -187,12 +187,21 @@ select 1 in ('1.1',2); select 1 in ('1.1',2.0); 1 in ('1.1',2.0) 0 -create table t1 (a char(20) character set binary); +create table t1 (a char(2) character set binary); insert into t1 values ('aa'), ('bb'); select * from t1 where a in (NULL, 'aa'); a aa drop table t1; +create table t1 (id int, key(id)); +insert into t1 values (1),(2),(3); +select count(*) from t1 where id not in (1); +count(*) +2 +select count(*) from t1 where id not in (1,2); +count(*) +1 +drop table t1; CREATE TABLE t1 (a int PRIMARY KEY); INSERT INTO t1 VALUES (44), (45), (46); SELECT * FROM t1 WHERE a IN (45); @@ -209,7 +218,7 @@ a CREATE VIEW v1 AS SELECT * FROM t1 WHERE a NOT IN (45); SHOW CREATE VIEW v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` <> 45) +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` where (`t1`.`a` <> 45) SELECT * FROM v1; a 44 diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result index ac8e5eda8e8..7e6fedb9403 100644 --- a/mysql-test/r/func_like.result +++ b/mysql-test/r/func_like.result @@ -158,3 +158,10 @@ DROP TABLE t1; select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin 1 +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; +'andre%' like 'andreÊ%' escape 'Ê' +1 +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; +_cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê' +1 diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 0149911e36b..5b6c29f87fb 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -165,3 +165,8 @@ drop table t1; select abs(-2) * -2; abs(-2) * -2 -4 +create table t1 (i int); +insert into t1 values (1); +select rand(i) from t1; +ERROR HY000: Incorrect arguments to RAND +drop table t1; diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 577f943ebde..a305bf20bff 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -21,6 +21,9 @@ length(_latin1'\n\t\n\b\0\\_\\%\\') select concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'); concat('monty',' was here ','again') length('hello') char(ascii('h')) ord('h') monty was here again 5 h 104 +select hex(char(256)); +hex(char(256)) +0100 select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ; locate('he','hello') locate('he','hello',2) locate('lo','hello',2) 1 0 4 @@ -598,7 +601,7 @@ collation(hex(130)) coercibility(hex(130)) latin1_swedish_ci 4 select collation(char(130)), coercibility(hex(130)); collation(char(130)) coercibility(hex(130)) -latin1_swedish_ci 4 +binary 4 select collation(format(130,10)), coercibility(format(130,10)); collation(format(130,10)) coercibility(format(130,10)) latin1_swedish_ci 4 @@ -720,7 +723,7 @@ t1 CREATE TABLE `t1` ( `oct(130)` varchar(64) NOT NULL default '', `conv(130,16,10)` varchar(64) NOT NULL default '', `hex(130)` varchar(6) NOT NULL default '', - `char(130)` varchar(1) NOT NULL default '', + `char(130)` varbinary(1) NOT NULL default '', `format(130,10)` varchar(4) NOT NULL default '', `left(_latin2'a',1)` varchar(1) character set latin2 NOT NULL default '', `right(_latin2'a',1)` varchar(1) character set latin2 NOT NULL default '', @@ -818,6 +821,9 @@ lpad(12345, 5, "#") SELECT conv(71, 10, 36), conv('1Z', 36, 10); conv(71, 10, 36) conv('1Z', 36, 10) 1Z 71 +SELECT conv(71, 10, 37), conv('1Z', 37, 10), conv(0,1,10),conv(0,0,10), conv(0,-1,10); +conv(71, 10, 37) conv('1Z', 37, 10) conv(0,1,10) conv(0,0,10) conv(0,-1,10) +NULL NULL NULL NULL NULL create table t1 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8; insert into t1 values (1,'aaaaaaaaaa'), (2,'bbbbbbbbbb'); create table t2 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8; @@ -1011,3 +1017,9 @@ t 1000000 1 drop table t1; +create table t1 (d decimal default null); +insert into t1 values (null); +select format(d, 2) from t1; +format(d, 2) +NULL +drop table t1; diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 87aa4b98d81..9275a893309 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -686,7 +686,7 @@ explain extended select period_add("9602",-12),period_diff(199505,"9404"),from_d id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select sql_no_cache period_add(_latin1'9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,_latin1'9404') AS `period_diff(199505,"9404")`,from_days(to_days(_latin1'960101')) AS `from_days(to_days("960101"))`,dayofmonth(_latin1'1997-01-02') AS `dayofmonth("1997-01-02")`,month(_latin1'1997-01-02') AS `month("1997-01-02")`,monthname(_latin1'1972-03-04') AS `monthname("1972-03-04")`,dayofyear(_latin1'0000-00-00') AS `dayofyear("0000-00-00")`,hour(_latin1'1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute(_latin1'23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week(_latin1'1998-03-03',0) AS `WEEK("1998-03-03")`,yearweek(_latin1'2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year(_latin1'98-02-03') AS `year("98-02-03")`,(weekday(to_days(curdate())) - weekday(to_days(now()))) AS `weekday(curdate())-weekday(now())`,dayname(to_days(_latin1'1962-03-03')) AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec(_latin1'0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format(_latin1'1997-01-02 03:04:05',_latin1'%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp(_latin1'1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,(_latin1'1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,(_latin1'1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from _latin1'1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)` +Note 1003 select sql_no_cache period_add(_latin1'9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,_latin1'9404') AS `period_diff(199505,"9404")`,from_days(to_days(_latin1'960101')) AS `from_days(to_days("960101"))`,dayofmonth(_latin1'1997-01-02') AS `dayofmonth("1997-01-02")`,month(_latin1'1997-01-02') AS `month("1997-01-02")`,monthname(_latin1'1972-03-04') AS `monthname("1972-03-04")`,dayofyear(_latin1'0000-00-00') AS `dayofyear("0000-00-00")`,hour(_latin1'1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute(_latin1'23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week(_latin1'1998-03-03',0) AS `WEEK("1998-03-03")`,yearweek(_latin1'2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year(_latin1'98-02-03') AS `year("98-02-03")`,(weekday(curdate()) - weekday(now())) AS `weekday(curdate())-weekday(now())`,dayname(_latin1'1962-03-03') AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec(_latin1'0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format(_latin1'1997-01-02 03:04:05',_latin1'%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp(_latin1'1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,(_latin1'1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,(_latin1'1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from _latin1'1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)` SET @TMP=NOW(); CREATE TABLE t1 (d DATETIME); INSERT INTO t1 VALUES (NOW()); diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 7ac10de1f7c..ca375ef5057 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -312,3 +312,12 @@ flush privileges; drop database mysqltest_1; set password = password("changed"); ERROR 42000: Access denied for user ''@'localhost' to database 'mysql' +lock table mysql.user write; + flush privileges; + grant all on *.* to 'mysqltest_1'@'localhost'; +unlock tables; +lock table mysql.user write; + set password for 'mysqltest_1'@'localhost' = password(''); + revoke all on *.* from 'mysqltest_1'@'localhost'; +unlock tables; +drop user 'mysqltest_1'@'localhost'; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index f4cf5217fa7..7bc886022cc 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -766,6 +766,15 @@ n Warnings: Warning 1052 Column 'n' in group statement is ambiguous DROP TABLE t1; +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +max(f1) is null +0 +select sql_buffer_result max(f1)+1 from t1; +max(f1)+1 +3 +drop table t1; create table t1 (c1 char(3), c2 char(3)); create table t2 (c3 char(3), c4 char(3)); insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index e26f32e49e5..038d0c75f74 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1972,29 +1972,23 @@ a b c d -create table bug12672 ( +create table t4 ( pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' ) engine=innodb; -insert into bug12672 (a1, a2, b, c, d, dummy) select * from t1; -create index idx12672_0 on bug12672 (a1); -create index idx12672_1 on bug12672 (a1,a2,b,c); -create index idx12672_2 on bug12672 (a1,a2,b); +insert into t4 (a1, a2, b, c, d, dummy) select * from t1; +create index idx12672_0 on t4 (a1); +create index idx12672_1 on t4 (a1,a2,b,c); +create index idx12672_2 on t4 (a1,a2,b); analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status Table is already up to date -explain select distinct a1 from bug12672 where pk_col not in (1,2,3,4); -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE bug12672 range PRIMARY PRIMARY 4 NULL # Using where; Using temporary -select distinct a1 from bug12672 where pk_col not in (1,2,3,4); +select distinct a1 from t4 where pk_col not in (1,2,3,4); a1 a b c d -drop table bug12672; -drop table t1; -drop table t2; -drop table t3; +drop table t1,t2,t3,t4; create table t1 ( a varchar(30), b varchar(30), primary key(a), key(b) ) engine=innodb; diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index 969cb06e9fe..7f40dfa3a36 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -379,10 +379,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where +1 SIMPLE t1 ref v v 13 const 10 Using where explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where +1 SIMPLE t1 ref v v 13 const 10 Using where alter table t1 add unique(v); ERROR 23000: Duplicate entry '{ ' for key 1 select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); @@ -602,10 +602,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 13 NULL # Using where explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where +1 SIMPLE t1 ref v v 13 const # Using where explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where +1 SIMPLE t1 ref v v 13 const # Using where alter table t1 add unique(v); ERROR 23000: Duplicate entry '{ ' for key 1 select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); diff --git a/mysql-test/r/im_daemon_life_cycle.result b/mysql-test/r/im_daemon_life_cycle.result new file mode 100644 index 00000000000..d0a76b450fe --- /dev/null +++ b/mysql-test/r/im_daemon_life_cycle.result @@ -0,0 +1,7 @@ +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 offline +Killing the process... +Sleeping... +Success: the process was restarted. diff --git a/mysql-test/r/im_life_cycle.result b/mysql-test/r/im_life_cycle.result new file mode 100644 index 00000000000..f8eaf0ccb46 --- /dev/null +++ b/mysql-test/r/im_life_cycle.result @@ -0,0 +1,64 @@ +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 offline +SHOW INSTANCE STATUS mysqld1; +instance_name status version +mysqld1 online VERSION +SHOW INSTANCE STATUS mysqld2; +instance_name status version +mysqld2 offline VERSION +START INSTANCE mysqld2; +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 online +SHOW INSTANCE STATUS mysqld1; +instance_name status version +mysqld1 online VERSION +SHOW INSTANCE STATUS mysqld2; +instance_name status version +mysqld2 online VERSION +SHOW VARIABLES LIKE 'port'; +Variable_name Value +port IM_MYSQLD1_PORT +STOP INSTANCE mysqld2; +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 offline +SHOW INSTANCE STATUS mysqld1; +instance_name status version +mysqld1 online VERSION +SHOW INSTANCE STATUS mysqld2; +instance_name status version +mysqld2 offline VERSION +START INSTANCE mysqld3; +ERROR HY000: Bad instance name. Check that the instance with such a name exists +START INSTANCE mysqld1; +ERROR HY000: The instance is already started +STOP INSTANCE mysqld3; +ERROR HY000: Bad instance name. Check that the instance with such a name exists +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 offline +Killing the process... +Sleeping... +Success: the process was restarted. +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 offline +START INSTANCE mysqld2; +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 online +Killing the process... +Sleeping... +Success: the process was killed. +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 offline diff --git a/mysql-test/r/im_options_set.result b/mysql-test/r/im_options_set.result new file mode 100644 index 00000000000..0d2fa699fc7 --- /dev/null +++ b/mysql-test/r/im_options_set.result @@ -0,0 +1,20 @@ +server_id =1 +server_id =2 +SHOW VARIABLES LIKE 'server_id'; +Variable_name Value +server_id 1 +SET mysqld1.server_id = 11; +server_id =11 +server_id =2 +SHOW VARIABLES LIKE 'server_id'; +Variable_name Value +server_id 1 +SET mysqld2.server_id = 12; +server_id =11 +server_id =12 +FLUSH INSTANCES; +server_id =11 +server_id =12 +SHOW VARIABLES LIKE 'server_id'; +Variable_name Value +server_id 1 diff --git a/mysql-test/r/im_options_unset.result b/mysql-test/r/im_options_unset.result new file mode 100644 index 00000000000..834152c35d2 --- /dev/null +++ b/mysql-test/r/im_options_unset.result @@ -0,0 +1,15 @@ +server_id =1 +server_id =2 +SHOW VARIABLES LIKE 'server_id'; +Variable_name Value +server_id 1 +UNSET mysqld1.server_id; +server_id =2 +SHOW VARIABLES LIKE 'server_id'; +Variable_name Value +server_id 1 +UNSET mysqld2.server_id; +FLUSH INSTANCES; +SHOW VARIABLES LIKE 'server_id'; +Variable_name Value +server_id 1 diff --git a/mysql-test/r/im_utils.result b/mysql-test/r/im_utils.result new file mode 100644 index 00000000000..fbfaeaebcac --- /dev/null +++ b/mysql-test/r/im_utils.result @@ -0,0 +1,91 @@ +SHOW INSTANCES; +instance_name status +mysqld1 online +mysqld2 offline +SHOW INSTANCE OPTIONS mysqld1; +option_name value +instance_name VALUE +mysqld-path VALUE +socket VALUE +pid-file VALUE +port VALUE +datadir VALUE +log VALUE +log-error VALUE +log-slow-queries VALUE +language VALUE +character-sets-dir VALUE +basedir VALUE +server_id VALUE +skip-stack-trace VALUE +skip-innodb VALUE +skip-bdb VALUE +skip-ndbcluster VALUE +SHOW INSTANCE OPTIONS mysqld2; +option_name value +instance_name VALUE +mysqld-path VALUE +nonguarded VALUE +socket VALUE +pid-file VALUE +port VALUE +datadir VALUE +log VALUE +log-error VALUE +log-slow-queries VALUE +language VALUE +character-sets-dir VALUE +basedir VALUE +server_id VALUE +skip-stack-trace VALUE +skip-innodb VALUE +skip-bdb VALUE +skip-ndbcluster VALUE +START INSTANCE mysqld2; +STOP INSTANCE mysqld2; +SHOW mysqld1 LOG FILES; +Logfile Path File size +ERROR LOG PATH FILE_SIZE +GENERAL LOG PATH FILE_SIZE +SLOW LOG PATH FILE_SIZE +SHOW mysqld2 LOG FILES; +Logfile Path File size +ERROR LOG PATH FILE_SIZE +GENERAL LOG PATH FILE_SIZE +SLOW LOG PATH FILE_SIZE +SHOW mysqld1 LOG ERROR 10; +Log +LOG_DATA +SHOW mysqld1 LOG SLOW 10; +Log +LOG_DATA +SHOW mysqld1 LOG GENERAL 10; +Log +LOG_DATA +SHOW mysqld1 LOG ERROR 10, 2; +Log +LOG_DATA +SHOW mysqld1 LOG SLOW 10, 2; +Log +LOG_DATA +SHOW mysqld1 LOG GENERAL 10, 2; +Log +LOG_DATA +SHOW mysqld2 LOG ERROR 10; +Log +LOG_DATA +SHOW mysqld2 LOG SLOW 10; +Log +LOG_DATA +SHOW mysqld2 LOG GENERAL 10; +Log +LOG_DATA +SHOW mysqld2 LOG ERROR 10, 2; +Log +LOG_DATA +SHOW mysqld2 LOG SLOW 10, 2; +Log +LOG_DATA +SHOW mysqld2 LOG GENERAL 10, 2; +Log +LOG_DATA diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 81e5fa6767d..4dac5f3b62b 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -203,3 +203,60 @@ oid fk_bbk_niederlassung fk_wochentag uhrzeit_von uhrzeit_bis geloescht version 21 7 1 08:00:00 13:00:00 0 1 drop view v1; drop table t1; +CREATE TABLE t1( +t_cpac varchar(2) NOT NULL, +t_vers varchar(4) NOT NULL, +t_rele varchar(2) NOT NULL, +t_cust varchar(4) NOT NULL, +filler1 char(250) default NULL, +filler2 char(250) default NULL, +PRIMARY KEY (t_cpac,t_vers,t_rele,t_cust), +UNIQUE KEY IX_4 (t_cust,t_cpac,t_vers,t_rele), +KEY IX_5 (t_vers,t_rele,t_cust) +) ENGINE=InnoDB; +insert into t1 values +('tm','2.5 ','a ',' ','',''), ('tm','2.5U','a ','stnd','',''), +('da','3.3 ','b ',' ','',''), ('da','3.3U','b ','stnd','',''), +('tl','7.6 ','a ',' ','',''), ('tt','7.6 ','a ',' ','',''), +('bc','B61 ','a ',' ','',''), ('bp','B61 ','a ',' ','',''), +('ca','B61 ','a ',' ','',''), ('ci','B61 ','a ',' ','',''), +('cp','B61 ','a ',' ','',''), ('dm','B61 ','a ',' ','',''), +('ec','B61 ','a ',' ','',''), ('ed','B61 ','a ',' ','',''), +('fm','B61 ','a ',' ','',''), ('nt','B61 ','a ',' ','',''), +('qm','B61 ','a ',' ','',''), ('tc','B61 ','a ',' ','',''), +('td','B61 ','a ',' ','',''), ('tf','B61 ','a ',' ','',''), +('tg','B61 ','a ',' ','',''), ('ti','B61 ','a ',' ','',''), +('tp','B61 ','a ',' ','',''), ('ts','B61 ','a ',' ','',''), +('wh','B61 ','a ',' ','',''), ('bc','B61U','a ','stnd','',''), +('bp','B61U','a ','stnd','',''), ('ca','B61U','a ','stnd','',''), +('ci','B61U','a ','stnd','',''), ('cp','B61U','a ','stnd','',''), +('dm','B61U','a ','stnd','',''), ('ec','B61U','a ','stnd','',''), +('fm','B61U','a ','stnd','',''), ('nt','B61U','a ','stnd','',''), +('qm','B61U','a ','stnd','',''), ('tc','B61U','a ','stnd','',''), +('td','B61U','a ','stnd','',''), ('tf','B61U','a ','stnd','',''), +('tg','B61U','a ','stnd','',''), ('ti','B61U','a ','stnd','',''), +('tp','B61U','a ','stnd','',''), ('ts','B61U','a ','stnd','',''), +('wh','B61U','a ','stnd','',''); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t_cpac` varchar(2) NOT NULL, + `t_vers` varchar(4) NOT NULL, + `t_rele` varchar(2) NOT NULL, + `t_cust` varchar(4) NOT NULL, + `filler1` char(250) default NULL, + `filler2` char(250) default NULL, + PRIMARY KEY (`t_cpac`,`t_vers`,`t_rele`,`t_cust`), + UNIQUE KEY `IX_4` (`t_cust`,`t_cpac`,`t_vers`,`t_rele`), + KEY `IX_5` (`t_vers`,`t_rele`,`t_cust`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6'; +t_vers t_rele t_cust filler1 +7.6 a +7.6 a +select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6' + and t_rele='a' and t_cust = ' '; +t_vers t_rele t_cust filler1 +7.6 a +7.6 a +drop table t1; diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 20b2f12f0a8..9c3d6d40139 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1,4 +1,5 @@ -DROP TABLE IF EXISTS t0,t1,t2,t3,t5; +DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5; +DROP VIEW IF EXISTS v1; show variables where variable_name like "skip_show_database"; Variable_name Value skip_show_database OFF @@ -360,12 +361,12 @@ latin1_spanish_ci show keys from v4; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment select * from information_schema.views where TABLE_NAME like "v%"; -TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE -NULL test v0 select sql_no_cache `schemata`.`SCHEMA_NAME` AS `c` from `information_schema`.`schemata` NONE NO -NULL test v1 select sql_no_cache `tables`.`TABLE_NAME` AS `c` from `information_schema`.`tables` where (`tables`.`TABLE_NAME` = _utf8'v1') NONE NO -NULL test v2 select sql_no_cache `columns`.`COLUMN_NAME` AS `c` from `information_schema`.`columns` where (`columns`.`TABLE_NAME` = _utf8'v2') NONE NO -NULL test v3 select sql_no_cache `character_sets`.`CHARACTER_SET_NAME` AS `c` from `information_schema`.`character_sets` where (`character_sets`.`CHARACTER_SET_NAME` like _utf8'latin1%') NONE NO -NULL test v4 select sql_no_cache `collations`.`COLLATION_NAME` AS `c` from `information_schema`.`collations` where (`collations`.`COLLATION_NAME` like _utf8'latin1%') NONE NO +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE +NULL test v0 select sql_no_cache `schemata`.`SCHEMA_NAME` AS `c` from `information_schema`.`schemata` NONE NO root@localhost DEFINER +NULL test v1 select sql_no_cache `tables`.`TABLE_NAME` AS `c` from `information_schema`.`tables` where (`tables`.`TABLE_NAME` = _utf8'v1') NONE NO root@localhost DEFINER +NULL test v2 select sql_no_cache `columns`.`COLUMN_NAME` AS `c` from `information_schema`.`columns` where (`columns`.`TABLE_NAME` = _utf8'v2') NONE NO root@localhost DEFINER +NULL test v3 select sql_no_cache `character_sets`.`CHARACTER_SET_NAME` AS `c` from `information_schema`.`character_sets` where (`character_sets`.`CHARACTER_SET_NAME` like _utf8'latin1%') NONE NO root@localhost DEFINER +NULL test v4 select sql_no_cache `collations`.`COLLATION_NAME` AS `c` from `information_schema`.`collations` where (`collations`.`COLLATION_NAME` like _utf8'latin1%') NONE NO root@localhost DEFINER drop view v0, v1, v2, v3, v4; create table t1 (a int); grant select,update,insert on t1 to mysqltest_1@localhost; @@ -455,10 +456,10 @@ create view v1 (c) as select a from t1 with check option; create view v2 (c) as select a from t1 WITH LOCAL CHECK OPTION; create view v3 (c) as select a from t1 WITH CASCADED CHECK OPTION; select * from information_schema.views; -TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE -NULL test v1 select `test`.`t1`.`a` AS `c` from `test`.`t1` CASCADED YES -NULL test v2 select `test`.`t1`.`a` AS `c` from `test`.`t1` LOCAL YES -NULL test v3 select `test`.`t1`.`a` AS `c` from `test`.`t1` CASCADED YES +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE +NULL test v1 select `test`.`t1`.`a` AS `c` from `test`.`t1` CASCADED YES root@localhost DEFINER +NULL test v2 select `test`.`t1`.`a` AS `c` from `test`.`t1` LOCAL YES root@localhost DEFINER +NULL test v3 select `test`.`t1`.`a` AS `c` from `test`.`t1` CASCADED YES root@localhost DEFINER grant select (a) on test.t1 to joe@localhost with grant option; select * from INFORMATION_SCHEMA.COLUMN_PRIVILEGES; GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE @@ -594,7 +595,7 @@ TABLE_CONSTRAINTS TABLE_PRIVILEGES TRIGGERS create database information_schema; -ERROR HY000: Can't create database 'information_schema'; database exists +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' use information_schema; show full tables like "T%"; Tables_in_information_schema (T%) Table_type @@ -638,8 +639,8 @@ use test; create function sub1(i int) returns int return i+1; create table t1(f1 int); -create view t2 (c) as select f1 from t1; -create view t3 (c) as select sub1(1); +create view v2 (c) as select f1 from t1; +create view v3 (c) as select sub1(1); create table t4(f1 int, KEY f1_key (f1)); drop table t1; drop function sub1; @@ -647,29 +648,29 @@ select table_name from information_schema.views where table_schema='test'; table_name Warnings: -Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s) -Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s) +Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) +Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) select table_name from information_schema.views where table_schema='test'; table_name Warnings: -Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s) -Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s) +Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) +Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) select column_name from information_schema.columns where table_schema='test'; column_name f1 Warnings: -Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s) -Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s) +Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) +Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) select index_name from information_schema.statistics where table_schema='test'; index_name f1_key select constraint_name from information_schema.table_constraints where table_schema='test'; constraint_name -drop view t2; -drop view t3; +drop view v2; +drop view v3; drop table t4; select * from information_schema.table_names; ERROR 42S02: Unknown table 'table_names' in information_schema @@ -979,3 +980,48 @@ WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +DROP TABLE t1,t2; +create table t1(f1 int); +create view v1 (c) as select f1 from t1; +select database(); +database() +NULL +show fields from test.v1; +Field Type Null Key Default Extra +c int(11) YES NULL +drop view v1; +drop table t1; +alter database information_schema; +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +drop database information_schema; +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +drop table information_schema.tables; +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +alter table information_schema.tables; +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +use information_schema; +create temporary table schemata(f1 char(10)); +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +CREATE PROCEDURE p1 () +BEGIN +SELECT 'foo' FROM DUAL; +END | +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +select ROUTINE_NAME from routines; +ROUTINE_NAME +grant all on information_schema.* to 'user1'@'localhost'; +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +grant select on information_schema.* to 'user1'@'localhost'; +ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +use test; +create table t1(id int); +insert into t1(id) values (1); +select 1 from (select 1 from test.t1) a; +1 +1 +use information_schema; +select 1 from (select 1 from test.t1) a; +1 +1 +use test; +drop table t1; diff --git a/mysql-test/r/information_schema_inno.result b/mysql-test/r/information_schema_inno.result index 9dd92baf62f..fb6584673f6 100644 --- a/mysql-test/r/information_schema_inno.result +++ b/mysql-test/r/information_schema_inno.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1,t2; +DROP TABLE IF EXISTS t1,t2,t3; CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id, id), FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE, diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d7f7536d401..dc4893c3bfa 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1378,9 +1378,9 @@ insert into `t2`values ( 1 ) ; create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb; insert into `t3`values ( 1 ) ; delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)) update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)) update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ERROR 42S22: Unknown column 't1.id' in 'where clause' drop table t3,t2,t1; @@ -1392,7 +1392,7 @@ foreign key(pid) references t1(id) on delete cascade) engine=innodb; insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6), (8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14); delete from t1 where id=0; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `t1` (`id`) ON DELETE CASCADE) delete from t1 where id=15; delete from t1 where id=0; drop table t1; @@ -1719,6 +1719,26 @@ select * from t1; a 42 drop table t1; +create table t1 (a int not null, b int not null, c blob not null, d int not null, e int, primary key (a,b,c(255),d)) engine=innodb; +insert into t1 values (2,2,"b",2,2),(1,1,"a",1,1),(3,3,"ab",3,3); +select * from t1 order by a,b,c,d; +a b c d e +1 1 a 1 1 +2 2 b 2 2 +3 3 ab 3 3 +explain select * from t1 order by a,b,c,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +drop table t1; +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +min(a) +4 +select min(b) from t1 where a='8'; +min(b) +6 +drop table t1; create table t1 (x bigint unsigned not null primary key) engine=innodb; insert into t1(x) values (0xfffffffffffffff0),(0xfffffffffffffff1); select * from t1; @@ -1765,7 +1785,7 @@ Variable_name Value Innodb_rows_deleted 2070 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 31722 +Innodb_rows_inserted 31727 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 29530 @@ -1977,10 +1997,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 13 NULL # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where; Using index +1 SIMPLE t1 ref v v 13 const # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where; Using index +1 SIMPLE t1 ref v v 13 const # Using where; Using index alter table t1 add unique(v); ERROR 23000: Duplicate entry '{ ' for key 1 alter table t1 add key(v); @@ -2168,10 +2188,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 303 NULL # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 303 NULL # Using where; Using index +1 SIMPLE t1 ref v v 303 const # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 303 NULL # Using where; Using index +1 SIMPLE t1 ref v v 303 const # Using where; Using index explain select * from t1 where v='a'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref v v 303 const # Using where @@ -2248,10 +2268,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 33 NULL # Using where explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 33 NULL # Using where +1 SIMPLE t1 ref v v 33 const # Using where explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 33 NULL # Using where +1 SIMPLE t1 ref v v 33 const # Using where explain select * from t1 where v='a'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref v v 33 const # Using where @@ -2527,3 +2547,228 @@ SELECT * FROM t1; id 1 DROP TABLE t2, t1; +CREATE TABLE t1 +( +id INT PRIMARY KEY +) ENGINE=InnoDB; +CREATE TEMPORARY TABLE t2 +( +id INT NOT NULL PRIMARY KEY, +b INT, +FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +Got one of the listed errors +DROP TABLE t1; +create table t1 (col1 varchar(2000), index (col1(767))) +character set = latin1 engine = innodb; +create table t2 (col1 char(255), index (col1)) +character set = latin1 engine = innodb; +create table t3 (col1 binary(255), index (col1)) +character set = latin1 engine = innodb; +create table t4 (col1 varchar(767), index (col1)) +character set = latin1 engine = innodb; +create table t5 (col1 varchar(767) primary key) +character set = latin1 engine = innodb; +create table t6 (col1 varbinary(767) primary key) +character set = latin1 engine = innodb; +create table t7 (col1 text, index(col1(767))) +character set = latin1 engine = innodb; +create table t8 (col1 blob, index(col1(767))) +character set = latin1 engine = innodb; +create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2)) +character set = latin1 engine = innodb; +drop table t1, t2, t3, t4, t5, t6, t7, t8, t9; +create table t1 (col1 varchar(768), index (col1)) +character set = latin1 engine = innodb; +ERROR HY000: Can't create table './test/t1.frm' (errno: 139) +create table t2 (col1 varchar(768) primary key) +character set = latin1 engine = innodb; +ERROR HY000: Can't create table './test/t2.frm' (errno: 139) +create table t3 (col1 varbinary(768) primary key) +character set = latin1 engine = innodb; +ERROR HY000: Can't create table './test/t3.frm' (errno: 139) +create table t4 (col1 text, index(col1(768))) +character set = latin1 engine = innodb; +ERROR HY000: Can't create table './test/t4.frm' (errno: 139) +create table t5 (col1 blob, index(col1(768))) +character set = latin1 engine = innodb; +ERROR HY000: Can't create table './test/t5.frm' (errno: 139) +CREATE TABLE t1 +( +id INT PRIMARY KEY +) ENGINE=InnoDB; +CREATE TABLE t2 +( +v INT, +CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) +) ENGINE=InnoDB; +INSERT INTO t2 VALUES(2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) +INSERT INTO t1 VALUES(1); +INSERT INTO t2 VALUES(1); +DELETE FROM t1 WHERE id = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) +DROP TABLE t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +SET FOREIGN_KEY_CHECKS=0; +DROP TABLE t1; +SET FOREIGN_KEY_CHECKS=1; +INSERT INTO t2 VALUES(3); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) +DROP TABLE t2; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=0; +checksum table t1; +Table Checksum +test.t1 1531596814 +insert into t1 values(3); +checksum table t1; +Table Checksum +test.t1 1531596814 +commit; +checksum table t1; +Table Checksum +test.t1 2050879373 +commit; +drop table t1; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=1; +checksum table t1; +Table Checksum +test.t1 1531596814 +set autocommit=1; +insert into t1 values(3); +checksum table t1; +Table Checksum +test.t1 2050879373 +drop table t1; +create table t1 (col1 integer primary key, col2 integer) engine=innodb; +insert t1 values (1,100); +create function f1 () returns integer begin +declare var1 int; +select col2 into var1 from t1 where col1=1 for update; +return var1; +end| +start transaction; +select f1(); +f1() +100 + update t1 set col2=0 where col1=1; +select * from t1; +col1 col2 +1 100 +rollback; +rollback; +drop table t1; +drop function f1; +create table t1 ( +a int, b char(10), c char(10), filler char(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( +a int, b char(10), c char(10), filler char(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xe880bde880bd,_utf8 0xe880bde880bd,'six'); +insert into t1 values (4,_utf8 0xe880bdD0B1e880bd,_utf8 0xe880bdD0B1e880bd,'seven'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); +insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; +create table t1 ( +a int, b varchar(10), c varchar(10), filler varchar(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( +a int, b varchar(10), c varchar(10), filler varchar(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xe880bde880bd,_utf8 0xe880bde880bd,'six'); +insert into t1 values (4,_utf8 0xe880bdD0B1e880bd,_utf8 0xe880bdD0B1e880bd,'seven'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); +insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; +create table t1 ( +a int, b text(10), c text(10), filler text(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( +a int, b text(10), c text(10), filler text(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xe880bde880bd,_utf8 0xe880bde880bd,'six'); +insert into t1 values (4,_utf8 0xe880bdD0B1e880bd,_utf8 0xe880bdD0B1e880bd,'seven'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); +insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; +create table t1 ( +a int, b blob(10), c blob(10), filler blob(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( +a int, b blob(10), c blob(10), filler blob(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; +commit; diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index f9a25898a6f..9d514be76e8 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1375,3 +1375,31 @@ groupid price 6 9900 DROP VIEW v1,v2; DROP TABLE t1,t2,t3,t4; +CREATE TABLE t1(a int); +CREATE TABLE t2(b int); +CREATE TABLE t3(c int, d int); +CREATE TABLE t4(d int); +CREATE TABLE t5(e int, f int); +CREATE TABLE t6(f int); +CREATE VIEW v1 AS +SELECT e FROM t5 JOIN t6 ON t5.e=t6.f; +CREATE VIEW v2 AS +SELECT e FROM t5 NATURAL JOIN t6; +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +a +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +ERROR 42S22: Unknown column 't1.x' in 'field list' +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +a +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +ERROR 42S22: Unknown column 't1.x' in 'field list' +SELECT v1.e FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +e +SELECT v1.x FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +ERROR 42S22: Unknown column 'v1.x' in 'field list' +SELECT v2.e FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +e +SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +ERROR 42S22: Unknown column 'v2.x' in 'field list' +DROP VIEW v1, v2; +DROP TABLE t1, t2, t3, t4, t5, t6; diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index d4a20209162..92b352aa608 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -200,7 +200,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL); -INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); CREATE TABLE t2 ( idAssignatura int(11) DEFAULT '0' NOT NULL, Grup int(11) DEFAULT '0' NOT NULL, @@ -1001,3 +1001,136 @@ SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40; c11 c21 40 NULL DROP TABLE t1, t2; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +DROP TABLE t1,t2; diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index d76fff372f5..f9d47e3533c 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -66,6 +66,17 @@ a b 3 row 3 0 drop table t1; +SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +create table t1(id integer not null auto_increment primary key); +insert into t1 values(0); +select * from t1; +id +0 +select * from t1; +id +0 +SET @@SQL_MODE=@OLD_SQL_MODE; +drop table t1; create table t1 (a int default 100, b int, c varchar(60)); load data infile '../../std_data/rpl_loaddata.dat' into table t1 (a, @b) set b=@b+10, c=concat("b=",@b); select * from t1; diff --git a/mysql-test/r/lowercase_view.result b/mysql-test/r/lowercase_view.result index 37252c6dde7..f09725dafcb 100644 --- a/mysql-test/r/lowercase_view.result +++ b/mysql-test/r/lowercase_view.result @@ -7,7 +7,7 @@ create table TaB (Field int); create view ViE as select * from TAb; show create table VIe; View Create View -vie CREATE ALGORITHM=UNDEFINED VIEW `mysqltest`.`vie` AS select `mysqltest`.`tab`.`Field` AS `Field` from `mysqltest`.`tab` +vie CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vie` AS select `tab`.`Field` AS `Field` from `tab` drop database MySQLTest; use test; create table t1Aa (col1 int); @@ -16,110 +16,110 @@ create view v1Aa as select * from t1aA; create view v2aA as select * from v1aA; create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1; update v2aA set col1 = (select max(col1) from v1Aa); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table 'v2aA'. update v2Aa set col1 = (select max(col1) from t1Aa); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2Aa' prevents operation UPDATE on table 'v2Aa'. update v2aA set col1 = (select max(col1) from v2Aa); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v2aA'. update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v1Aa) where t1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table 't1aA'. update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v1aA' for update in FROM clause update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from v1aA) where v2Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 't2Aa'. update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v1Aa) where t1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table 't2Aa'. update t2Aa,v1aA set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 't2Aa'. update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from t1aA) where v2aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 'v2aA'. update t1Aa,t2Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: You can't specify target table 't1Aa' for update in FROM clause update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from t1Aa) where v1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v1aA'. update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from t1aA) where v2Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from t1Aa) where v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v2aA) where t1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 't1aA'. update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v2Aa) where v1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause +ERROR HY000: The definition of table 'v2Aa' prevents operation UPDATE on table 'v1aA'. update t2Aa,v2aA set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 't2Aa'. update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v2aA) where t1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 't2Aa'. update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from v2Aa) where v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2Aa' prevents operation UPDATE on table 't2Aa'. update v3aA set v3Aa.col1 = (select max(col1) from v1aA); -ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v3aA'. update v3aA set v3Aa.col1 = (select max(col1) from t1aA); -ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause +ERROR HY000: The definition of table 'v3aA' prevents operation UPDATE on table 'v3aA'. update v3aA set v3Aa.col1 = (select max(col1) from v2aA); -ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 'v3aA'. update v3aA set v3Aa.col1 = (select max(col1) from v3aA); -ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v3aA' for update in FROM clause delete from v2Aa where col1 = (select max(col1) from v1Aa); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 'v2Aa'. delete from v2aA where col1 = (select max(col1) from t1Aa); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation DELETE on table 'v2aA'. delete from v2Aa where col1 = (select max(col1) from v2aA); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v2Aa' for update in FROM clause delete v2Aa from v2aA,t2Aa where (select max(col1) from v1aA) > 0 and v2Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation DELETE on table 'v2aA'. delete t1aA from t1Aa,t2Aa where (select max(col1) from v1Aa) > 0 and t1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 't1Aa'. delete v1aA from v1Aa,t2Aa where (select max(col1) from v1aA) > 0 and v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v1Aa' for update in FROM clause delete v2aA from v2Aa,t2Aa where (select max(col1) from t1Aa) > 0 and v2aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2Aa' prevents operation DELETE on table 'v2Aa'. delete t1aA from t1Aa,t2Aa where (select max(col1) from t1aA) > 0 and t1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: You can't specify target table 't1Aa' for update in FROM clause delete v1aA from v1Aa,t2Aa where (select max(col1) from t1aA) > 0 and v1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 'v1Aa'. delete v2Aa from v2aA,t2Aa where (select max(col1) from v2Aa) > 0 and v2aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause delete t1Aa from t1aA,t2Aa where (select max(col1) from v2Aa) > 0 and t1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: The definition of table 'v2Aa' prevents operation DELETE on table 't1aA'. delete v1Aa from v1aA,t2Aa where (select max(col1) from v2aA) > 0 and v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation DELETE on table 'v1aA'. insert into v2Aa values ((select max(col1) from v1aA)); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation INSERT on table 'v2Aa'. insert into t1aA values ((select max(col1) from v1Aa)); -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation INSERT on table 't1aA'. insert into v2aA values ((select max(col1) from v1aA)); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v1aA' prevents operation INSERT on table 'v2aA'. insert into v2Aa values ((select max(col1) from t1Aa)); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 'v2Aa'. insert into t1aA values ((select max(col1) from t1Aa)); -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: You can't specify target table 't1aA' for update in FROM clause insert into v2aA values ((select max(col1) from t1aA)); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation INSERT on table 'v2aA'. insert into v2Aa values ((select max(col1) from v2aA)); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v2Aa' for update in FROM clause insert into t1Aa values ((select max(col1) from v2Aa)); -ERROR HY000: You can't specify target table 't1aa' for update in FROM clause +ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 't1Aa'. insert into v2aA values ((select max(col1) from v2Aa)); -ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause insert into v3Aa (col1) values ((select max(col1) from v1Aa)); -ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause +ERROR HY000: The definition of table 'v1Aa' prevents operation INSERT on table 'v3Aa'. insert into v3aA (col1) values ((select max(col1) from t1aA)); -ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause +ERROR HY000: The definition of table 'v3aA' prevents operation INSERT on table 'v3aA'. insert into v3Aa (col1) values ((select max(col1) from v2aA)); -ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause +ERROR HY000: The definition of table 'v2aA' prevents operation INSERT on table 'v3Aa'. drop view v3aA,v2Aa,v1aA; drop table t1Aa,t2Aa; create table t1Aa (col1 int); create view v1Aa as select col1 from t1Aa as AaA; show create view v1AA; View Create View -v1aa CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1aa` AS select `aaa`.`col1` AS `col1` from `test`.`t1aa` `AaA` +v1aa CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1aa` AS select `aaa`.`col1` AS `col1` from `t1aa` `AaA` drop view v1AA; select Aaa.col1 from t1Aa as AaA; col1 @@ -128,6 +128,6 @@ drop view v1AA; create view v1Aa as select AaA.col1 from t1Aa as AaA; show create view v1AA; View Create View -v1aa CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1aa` AS select `aaa`.`col1` AS `col1` from `test`.`t1aa` `AaA` +v1aa CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1aa` AS select `aaa`.`col1` AS `col1` from `t1aa` `AaA` drop view v1AA; drop table t1Aa; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index d4e19201173..e028e58acf5 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -653,6 +653,32 @@ ERROR HY000: You can't specify target table 't2' for update in FROM clause create table t3 engine=merge union=(t1, t2) select (select max(a) from t2); ERROR HY000: You can't specify target table 't2' for update in FROM clause drop table t1, t2; +create table t1 ( +a double(14,4), +b varchar(10), +index (a,b) +) engine=merge union=(t2,t3); +create table t2 ( +a double(14,4), +b varchar(10), +index (a,b) +) engine=myisam; +create table t3 ( +a double(14,4), +b varchar(10), +index (a,b) +) engine=myisam; +insert into t2 values ( null, ''); +insert into t2 values ( 9999999999.999, ''); +insert into t3 select * from t2; +select min(a), max(a) from t1; +min(a) max(a) +9999999999.9990 9999999999.9990 +flush tables; +select min(a), max(a) from t1; +min(a) max(a) +9999999999.9990 9999999999.9990 +drop table t1, t2, t3; create table t1 (a int,b int,c int, index (a,b,c)); create table t2 (a int,b int,c int, index (a,b,c)); create table t3 (a int,b int,c int, index (a,b,c)) diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 50b0b6ae294..0a170e16188 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -2,7 +2,7 @@ drop table if exists t1,t2; select 1, 1.0, -1, "hello", NULL; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def 1 8 1 1 N 32897 0 63 -def 1.0 246 4 3 N 129 1 63 +def 1.0 246 3 3 N 161 1 63 def -1 8 2 2 N 32897 0 63 def hello 253 5 5 N 1 31 8 def NULL 6 0 0 Y 32896 0 63 diff --git a/mysql-test/r/multi_statement.result b/mysql-test/r/multi_statement.result index 3a8d86bf349..ff19cbdd698 100644 --- a/mysql-test/r/multi_statement.result +++ b/mysql-test/r/multi_statement.result @@ -1,3 +1,4 @@ +DROP TABLE IF EXISTS t1; select 1; 1 1 diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index ce215d6a7d8..f484a937b27 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -608,6 +608,67 @@ checksum table t2; Table Checksum test.t2 984116287 drop table t1, t2; +show variables like 'myisam_stats_method'; +Variable_name Value +myisam_stats_method nulls_unequal +create table t1 (a int, key(a)); +insert into t1 values (0),(1),(2),(3),(4); +insert into t1 select NULL from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +set myisam_stats_method=nulls_equal; +show variables like 'myisam_stats_method'; +Variable_name Value +myisam_stats_method nulls_equal +insert into t1 values (11); +delete from t1 where a=11; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 5 NULL NULL YES BTREE +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 5 NULL NULL YES BTREE +set myisam_stats_method=DEFAULT; +show variables like 'myisam_stats_method'; +Variable_name Value +myisam_stats_method nulls_unequal +insert into t1 values (11); +delete from t1 where a=11; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +drop table t1; set storage_engine=MyISAM; drop table if exists t1,t2,t3; --- Testing varchar --- @@ -741,10 +802,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 13 NULL # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where; Using index +1 SIMPLE t1 ref v v 13 const # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where; Using index +1 SIMPLE t1 ref v v 13 const # Using where; Using index alter table t1 add unique(v); ERROR 23000: Duplicate entry '{ ' for key 1 alter table t1 add key(v); @@ -932,10 +993,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 303 NULL # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 303 NULL # Using where; Using index +1 SIMPLE t1 ref v v 303 const # Using where; Using index explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 303 NULL # Using where; Using index +1 SIMPLE t1 ref v v 303 const # Using where; Using index explain select * from t1 where v='a'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref v v 303 const # Using where @@ -1012,10 +1073,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range v v 33 NULL # Using where explain select count(*) from t1 where v between 'a' and 'a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 33 NULL # Using where +1 SIMPLE t1 ref v v 33 const # Using where explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 33 NULL # Using where +1 SIMPLE t1 ref v v 33 const # Using where explain select * from t1 where v='a'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref v v 33 const # Using where diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index eeb6abd9f41..76faa12373a 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -1,6 +1,7 @@ drop table if exists t1; create table t1(a int); insert into t1 values(1); +ERROR at line 9: DELIMITER must be followed by a 'delimiter' character or string Test default delimiter ; a diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index 8765e65f11b..cab3d924dd2 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -39,7 +39,8 @@ SET TIMESTAMP=1000000000; load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-3-0' INTO table t1; SET TIMESTAMP=1000000000; load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-4-0' INTO table t1; -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- Broken LOAD DATA -- @@ -51,7 +52,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- --database -- @@ -59,7 +61,8 @@ ROLLBACK; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; ROLLBACK; SET INSERT_ID=1; -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- --position -- @@ -71,7 +74,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- Remote -- @@ -101,7 +105,8 @@ SET TIMESTAMP=1000000000; load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-3-2' INTO table t1; SET TIMESTAMP=1000000000; load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-4-2' INTO table t1; -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- Broken LOAD DATA -- @@ -113,7 +118,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- --database -- @@ -121,7 +127,8 @@ ROLLBACK; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; ROLLBACK; SET INSERT_ID=1; -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- --position -- @@ -133,7 +140,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- reading stdin -- @@ -145,7 +153,8 @@ SET TIMESTAMP=1108844556; BEGIN; SET TIMESTAMP=1108844555; insert t1 values (1); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; @@ -154,6 +163,7 @@ SET TIMESTAMP=1108844556; BEGIN; SET TIMESTAMP=1108844555; insert t1 values (1); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; drop table t1, t2; diff --git a/mysql-test/r/mysqlbinlog2.result b/mysql-test/r/mysqlbinlog2.result index 9899fa54301..eb5fb4a87f8 100644 --- a/mysql-test/r/mysqlbinlog2.result +++ b/mysql-test/r/mysqlbinlog2.result @@ -39,7 +39,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- offset -- @@ -65,7 +66,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-position -- @@ -81,7 +83,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-position -- @@ -103,7 +106,8 @@ insert into t1 values(null, "b"); SET INSERT_ID=3; SET TIMESTAMP=1579609944; insert into t1 values(null, "c"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-datetime -- @@ -123,7 +127,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-datetime -- @@ -142,7 +147,8 @@ insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; insert into t1 values(null, "b"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- Local with 2 binlogs on command line -- @@ -177,7 +183,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- offset -- @@ -210,7 +217,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-position -- @@ -233,7 +241,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-position -- @@ -262,7 +271,8 @@ SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); SET INSERT_ID=6; -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-datetime -- @@ -289,7 +299,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-datetime -- @@ -308,7 +319,8 @@ insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; insert into t1 values(null, "b"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- Remote -- @@ -336,7 +348,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- offset -- @@ -362,7 +375,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-position -- @@ -378,7 +392,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-position -- @@ -400,7 +415,8 @@ insert into t1 values(null, "b"); SET INSERT_ID=3; SET TIMESTAMP=1579609944; insert into t1 values(null, "c"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-datetime -- @@ -420,7 +436,8 @@ insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-datetime -- @@ -439,7 +456,8 @@ insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; insert into t1 values(null, "b"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- Remote with 2 binlogs on command line -- @@ -474,7 +492,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- offset -- @@ -507,7 +526,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-position -- @@ -530,7 +550,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-position -- @@ -559,7 +580,8 @@ SET INSERT_ID=5; SET TIMESTAMP=1579609946; insert into t1 values(null, "e"); SET INSERT_ID=6; -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- start-datetime -- @@ -586,7 +608,8 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- stop-datetime -- @@ -605,7 +628,8 @@ insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; insert into t1 values(null, "b"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- to-last-log -- @@ -636,7 +660,8 @@ insert into t1 values(null, "e"); SET INSERT_ID=6; SET TIMESTAMP=1579609943; insert into t1 values(null, "f"); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; --- end of test -- diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result new file mode 100644 index 00000000000..8c98e18aa9b --- /dev/null +++ b/mysql-test/r/mysqlcheck.result @@ -0,0 +1,34 @@ +mysql.columns_priv OK +mysql.db OK +mysql.func OK +mysql.help_category OK +mysql.help_keyword OK +mysql.help_relation OK +mysql.help_topic OK +mysql.host OK +mysql.proc OK +mysql.procs_priv OK +mysql.tables_priv OK +mysql.time_zone OK +mysql.time_zone_leap_second OK +mysql.time_zone_name OK +mysql.time_zone_transition OK +mysql.time_zone_transition_type OK +mysql.user OK +mysql.columns_priv OK +mysql.db OK +mysql.func OK +mysql.help_category OK +mysql.help_keyword OK +mysql.help_relation OK +mysql.help_topic OK +mysql.host OK +mysql.proc OK +mysql.procs_priv OK +mysql.tables_priv OK +mysql.time_zone OK +mysql.time_zone_leap_second OK +mysql.time_zone_name OK +mysql.time_zone_transition OK +mysql.time_zone_transition_type OK +mysql.user OK diff --git a/mysql-test/r/mysqldump-max.result b/mysql-test/r/mysqldump-max.result new file mode 100644 index 00000000000..39d607910aa --- /dev/null +++ b/mysql-test/r/mysqldump-max.result @@ -0,0 +1,272 @@ +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +drop table if exists t2; +Warnings: +Note 1051 Unknown table 't2' +drop table if exists t3; +Warnings: +Note 1051 Unknown table 't3' +drop table if exists t4; +Warnings: +Note 1051 Unknown table 't4' +drop table if exists t5; +Warnings: +Note 1051 Unknown table 't5' +drop table if exists t6; +Warnings: +Note 1051 Unknown table 't6' +create table t1 (id int(8), name varchar(32)); +create table t2 (id int(8), name varchar(32)) ENGINE="MyISAM"; +create table t3 (id int(8), name varchar(32)) ENGINE="MEMORY"; +create table t4 (id int(8), name varchar(32)) ENGINE="HEAP"; +create table t5 (id int(8), name varchar(32)) ENGINE="ARCHIVE"; +create table t6 (id int(8), name varchar(32)) ENGINE="InnoDB"; +insert into t1 values (1, 'first value'); +insert into t1 values (2, 'first value'); +insert into t1 values (3, 'first value'); +insert into t1 values (4, 'first value'); +insert into t1 values (5, 'first value'); +insert into t2 values (1, 'first value'); +insert into t2 values (2, 'first value'); +insert into t2 values (3, 'first value'); +insert into t2 values (4, 'first value'); +insert into t2 values (5, 'first value'); +insert into t3 values (1, 'first value'); +insert into t3 values (2, 'first value'); +insert into t3 values (3, 'first value'); +insert into t3 values (4, 'first value'); +insert into t3 values (5, 'first value'); +insert into t4 values (1, 'first value'); +insert into t4 values (2, 'first value'); +insert into t4 values (3, 'first value'); +insert into t4 values (4, 'first value'); +insert into t4 values (5, 'first value'); +insert into t5 values (1, 'first value'); +insert into t5 values (2, 'first value'); +insert into t5 values (3, 'first value'); +insert into t5 values (4, 'first value'); +insert into t5 values (5, 'first value'); +insert into t6 values (1, 'first value'); +insert into t6 values (2, 'first value'); +insert into t6 values (3, 'first value'); +insert into t6 values (4, 'first value'); +insert into t6 values (5, 'first value'); +select * from t1; +id name +1 first value +2 first value +3 first value +4 first value +5 first value +select * from t2; +id name +1 first value +2 first value +3 first value +4 first value +5 first value +select * from t3; +id name +1 first value +2 first value +3 first value +4 first value +5 first value +select * from t4; +id name +1 first value +2 first value +3 first value +4 first value +5 first value +select * from t5; +id name +1 first value +2 first value +3 first value +4 first value +5 first value +select * from t6; +id name +1 first value +2 first value +3 first value +4 first value +5 first value + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +INSERT DELAYED IGNORE INTO `t1` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +INSERT DELAYED IGNORE INTO `t2` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; +DROP TABLE IF EXISTS `t3`; +CREATE TABLE `t3` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t3` DISABLE KEYS */; +INSERT DELAYED IGNORE INTO `t3` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t3` ENABLE KEYS */; +DROP TABLE IF EXISTS `t4`; +CREATE TABLE `t4` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t4` DISABLE KEYS */; +INSERT DELAYED IGNORE INTO `t4` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t4` ENABLE KEYS */; +DROP TABLE IF EXISTS `t5`; +CREATE TABLE `t5` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t5` DISABLE KEYS */; +INSERT DELAYED IGNORE INTO `t5` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t5` ENABLE KEYS */; +DROP TABLE IF EXISTS `t6`; +CREATE TABLE `t6` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t6` DISABLE KEYS */; +INSERT IGNORE INTO `t6` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t6` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +INSERT DELAYED INTO `t1` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +INSERT DELAYED INTO `t2` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; +DROP TABLE IF EXISTS `t3`; +CREATE TABLE `t3` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t3` DISABLE KEYS */; +INSERT DELAYED INTO `t3` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t3` ENABLE KEYS */; +DROP TABLE IF EXISTS `t4`; +CREATE TABLE `t4` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t4` DISABLE KEYS */; +INSERT DELAYED INTO `t4` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t4` ENABLE KEYS */; +DROP TABLE IF EXISTS `t5`; +CREATE TABLE `t5` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t5` DISABLE KEYS */; +INSERT DELAYED INTO `t5` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t5` ENABLE KEYS */; +DROP TABLE IF EXISTS `t6`; +CREATE TABLE `t6` ( + `id` int(8) default NULL, + `name` varchar(32) default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t6` DISABLE KEYS */; +INSERT INTO `t6` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); +/*!40000 ALTER TABLE `t6` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; +drop table t6; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 917724580cf..c3f2e55939e 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1,5 +1,7 @@ DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; +drop database if exists db1; +drop database if exists db2; drop view if exists v1, v2, v3; CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); @@ -62,6 +64,8 @@ INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456) /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -78,6 +82,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -87,6 +92,8 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -97,6 +104,7 @@ CREATE TABLE `t1` ( ); INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -155,6 +163,8 @@ INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'), (NULL); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -171,6 +181,7 @@ INSERT INTO `t1` VALUES ('абцде'); INSERT INTO `t1` VALUES (NULL); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -183,6 +194,8 @@ UNLOCK TABLES; DROP TABLE t1; CREATE TABLE t1 (a int) ENGINE=MYISAM; INSERT INTO t1 VALUES (1), (2); +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL40' */; @@ -198,12 +211,15 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES (1),(2); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; @@ -219,6 +235,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES (1),(2); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -237,6 +254,8 @@ create table t1(a int); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -251,6 +270,7 @@ CREATE TABLE `t1` ( LOCK TABLES `t1` WRITE; UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -260,6 +280,8 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; @@ -274,6 +296,7 @@ CREATE TABLE "t1" ( LOCK TABLES "t1" WRITE; UNLOCK TABLES; /*!40000 ALTER TABLE "t1" ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -286,6 +309,8 @@ set global sql_mode='ANSI_QUOTES'; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -300,6 +325,7 @@ CREATE TABLE `t1` ( LOCK TABLES `t1` WRITE; UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -309,6 +335,8 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; @@ -323,6 +351,7 @@ CREATE TABLE "t1" ( LOCK TABLES "t1" WRITE; UNLOCK TABLES; /*!40000 ALTER TABLE "t1" ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -338,6 +367,8 @@ insert into t1 values (1),(2),(3); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; @@ -345,6 +376,7 @@ CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; @@ -361,6 +393,8 @@ drop table t1; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -369,6 +403,7 @@ drop table t1; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; USE `test`; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -384,6 +419,8 @@ create database mysqldump_test_db character set latin2 collate latin2_bin; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -392,6 +429,7 @@ create database mysqldump_test_db character set latin2 collate latin2_bin; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CHARACTER SET latin2 COLLATE latin2_bin */; USE `mysqldump_test_db`; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -409,6 +447,8 @@ INSERT INTO t1 VALUES (_latin1 'ÄÖÜß'); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -424,6 +464,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES ('ÄÖÜß'); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -433,6 +474,8 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; @@ -448,12 +491,15 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES ('Ž™šá'); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; @@ -469,12 +515,15 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES ('Ž™šá'); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; @@ -490,6 +539,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES ('ÄÖÜß'); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -506,6 +556,8 @@ INSERT INTO t2 VALUES (4),(5),(6); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -521,6 +573,7 @@ LOCK TABLES `t2` WRITE; INSERT INTO `t2` VALUES (4),(5),(6); UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -539,6 +592,8 @@ INSERT INTO `t1` VALUES (0x602010000280100005E71A); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -554,6 +609,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES (0x602010000280100005E71A); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -572,6 +628,8 @@ INSERT INTO t1 VALUES (4),(5),(6); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -587,6 +645,7 @@ LOCK TABLES `t1` WRITE; INSERT IGNORE INTO `t1` VALUES (1),(2),(3),(4),(5),(6); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -601,6 +660,8 @@ UNLOCK TABLES; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -612,10 +673,9 @@ CREATE TABLE `t1` ( /*!40000 ALTER TABLE `t1` DISABLE KEYS */; -LOCK TABLES `t1` WRITE; -INSERT IGNORE INTO `t1` VALUES (1),(2),(3),(4),(5),(6); -UNLOCK TABLES; +INSERT DELAYED IGNORE INTO `t1` VALUES (1),(2),(3),(4),(5),(6); /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -963,6 +1023,8 @@ insert into t1 (F_8d3bba7425e7c98c50f52ca1b52d3735) values (1); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1307,6 +1369,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` (`F_c4ca4238a0b923820dcc509a6f75849b`, `F_c81e728d9d4c2f636f067f89cc14862c`, `F_eccbc87e4b5ce2fe28308fd9f2a7baf3`, `F_a87ff679a2f3e71d9181a67b7542122c`, `F_e4da3b7fbbce2345d7772b0674a318d5`, `F_1679091c5a880faf6fb5e6087eb1b2dc`, `F_8f14e45fceea167a5a36dedd4bea2543`, `F_c9f0f895fb98ab9159f51fd0297e236d`, `F_45c48cce2e2d7fbdea1afc51c7c6ad26`, `F_d3d9446802a44259755d38e6d163e820`, `F_6512bd43d9caa6e02c990b0a82652dca`, `F_c20ad4d76fe97759aa27a0c99bff6710`, `F_c51ce410c124a10e0db5e4b97fc2af39`, `F_aab3238922bcc25a6f606eb525ffdc56`, `F_9bf31c7ff062936a96d3c8bd1f8f2ff3`, `F_c74d97b01eae257e44aa9d5bade97baf`, `F_70efdf2ec9b086079795c442636b55fb`, `F_6f4922f45568161a8cdf4ad2299f6d23`, `F_1f0e3dad99908345f7439f8ffabdffc4`, `F_98f13708210194c475687be6106a3b84`, `F_3c59dc048e8850243be8079a5c74d079`, `F_b6d767d2f8ed5d21a44b0e5886680cb9`, `F_37693cfc748049e45d87b8c7d8b9aacd`, `F_1ff1de774005f8da13f42943881c655f`, `F_8e296a067a37563370ded05f5a3bf3ec`, `F_4e732ced3463d06de0ca9a15b6153677`, `F_02e74f10e0327ad868d138f2b4fdd6f0`, `F_33e75ff09dd601bbe69f351039152189`, `F_6ea9ab1baa0efb9e19094440c317e21b`, `F_34173cb38f07f89ddbebc2ac9128303f`, `F_c16a5320fa475530d9583c34fd356ef5`, `F_6364d3f0f495b6ab9dcf8d3b5c6e0b01`, `F_182be0c5cdcd5072bb1864cdee4d3d6e`, `F_e369853df766fa44e1ed0ff613f563bd`, `F_1c383cd30b7c298ab50293adfecb7b18`, `F_19ca14e7ea6328a42e0eb13d585e4c22`, `F_a5bfc9e07964f8dddeb95fc584cd965d`, `F_a5771bce93e200c36f7cd9dfd0e5deaa`, `F_d67d8ab4f4c10bf22aa353e27879133c`, `F_d645920e395fedad7bbbed0eca3fe2e0`, `F_3416a75f4cea9109507cacd8e2f2aefc`, `F_a1d0c6e83f027327d8461063f4ac58a6`, `F_17e62166fc8586dfa4d1bc0e1742c08b`, `F_f7177163c833dff4b38fc8d2872f1ec6`, `F_6c8349cc7260ae62e3b1396831a8398f`, `F_d9d4f495e875a2e075a1a4a6e1b9770f`, `F_67c6a1e7ce56d3d6fa748ab6d9af3fd7`, `F_642e92efb79421734881b53e1e1b18b6`, `F_f457c545a9ded88f18ecee47145a72c0`, `F_c0c7c76d30bd3dcaefc96f40275bdc0a`, `F_2838023a778dfaecdc212708f721b788`, `F_9a1158154dfa42caddbd0694a4e9bdc8`, `F_d82c8d1619ad8176d665453cfb2e55f0`, `F_a684eceee76fc522773286a895bc8436`, `F_b53b3a3d6ab90ce0268229151c9bde11`, `F_9f61408e3afb633e50cdf1b20de6f466`, `F_72b32a1f754ba1c09b3695e0cb6cde7f`, `F_66f041e16a60928b05a7e228a89c3799`, `F_093f65e080a295f8076b1c5722a46aa2`, `F_072b030ba126b2f4b2374f342be9ed44`, `F_7f39f8317fbdb1988ef4c628eba02591`, `F_44f683a84163b3523afe57c2e008bc8c`, `F_03afdbd66e7929b125f8597834fa83a4`, `F_ea5d2f1c4608232e07d3aa3d998e5135`, `F_fc490ca45c00b1249bbe3554a4fdf6fb`, `F_3295c76acbf4caaed33c36b1b5fc2cb1`, `F_735b90b4568125ed6c3f678819b6e058`, `F_a3f390d88e4c41f2747bfa2f1b5f87db`, `F_14bfa6bb14875e45bba028a21ed38046`, `F_7cbbc409ec990f19c78c75bd1e06f215`, `F_e2c420d928d4bf8ce0ff2ec19b371514`, `F_32bb90e8976aab5298d5da10fe66f21d`, `F_d2ddea18f00665ce8623e36bd4e3c7c5`, `F_ad61ab143223efbc24c7d2583be69251`, `F_d09bf41544a3365a46c9077ebb5e35c3`, `F_fbd7939d674997cdb4692d34de8633c4`, `F_28dd2c7955ce926456240b2ff0100bde`, `F_35f4a8d465e6e1edc05f3d8ab658c551`, `F_d1fe173d08e959397adf34b1d77e88d7`, `F_f033ab37c30201f73f142449d037028d`, `F_43ec517d68b6edd3015b3edc9a11367b`, `F_9778d5d219c5080b9a6a17bef029331c`, `F_fe9fc289c3ff0af142b6d3bead98a923`, `F_68d30a9594728bc39aa24be94b319d21`, `F_3ef815416f775098fe977004015c6193`, `F_93db85ed909c13838ff95ccfa94cebd9`, `F_c7e1249ffc03eb9ded908c236bd1996d`, `F_2a38a4a9316c49e5a833517c45d31070`, `F_7647966b7343c29048673252e490f736`, `F_8613985ec49eb8f757ae6439e879bb2a`, `F_54229abfcfa5649e7003b83dd4755294`, `F_92cc227532d17e56e07902b254dfad10`, `F_98dce83da57b0395e163467c9dae521b`, `F_f4b9ec30ad9f68f89b29639786cb62ef`, `F_812b4ba287f5ee0bc9d43bbf5bbe87fb`, `F_26657d5ff9020d2abefe558796b99584`, `F_e2ef524fbf3d9fe611d5a8e90fefdc9c`, `F_ed3d2c21991e3bef5e069713af9fa6ca`, `F_ac627ab1ccbdb62ec96e702f07f6425b`, `F_f899139df5e1059396431415e770c6dd`, `F_38b3eff8baf56627478ec76a704e9b52`, `F_ec8956637a99787bd197eacd77acce5e`, `F_6974ce5ac660610b44d9b9fed0ff9548`, `F_c9e1074f5b3f9fc8ea15d152add07294`, `F_65b9eea6e1cc6bb9f0cd2a47751a186f`, `F_f0935e4cd5920aa6c7c996a5ee53a70f`, `F_a97da629b098b75c294dffdc3e463904`, `F_a3c65c2974270fd093ee8a9bf8ae7d0b`, `F_2723d092b63885e0d7c260cc007e8b9d`, `F_5f93f983524def3dca464469d2cf9f3e`, `F_698d51a19d8a121ce581499d7b701668`, `F_7f6ffaa6bb0b408017b62254211691b5`, `F_73278a4a86960eeb576a8fd4c9ec6997`, `F_5fd0b37cd7dbbb00f97ba6ce92bf5add`, `F_2b44928ae11fb9384c4cf38708677c48`, `F_c45147dee729311ef5b5c3003946c48f`, `F_eb160de1de89d9058fcb0b968dbbbd68`, `F_5ef059938ba799aaa845e1c2e8a762bd`, `F_07e1cd7dca89a1678042477183b7ac3f`, `F_da4fb5c6e93e74d3df8527599fa62642`, `F_4c56ff4ce4aaf9573aa5dff913df997a`, `F_a0a080f42e6f13b3a2df133f073095dd`, `F_202cb962ac59075b964b07152d234b70`, `F_c8ffe9a587b126f152ed3d89a146b445`, `F_3def184ad8f4755ff269862ea77393dd`, `F_069059b7ef840f0c74a814ec9237b6ec`, `F_ec5decca5ed3d6b8079e2e7e7bacc9f2`, `F_76dc611d6ebaafc66cc0879c71b5db5c`, `F_d1f491a404d6854880943e5c3cd9ca25`, `F_9b8619251a19057cff70779273e95aa6`, `F_1afa34a7f984eeabdbb0a7d494132ee5`, `F_65ded5353c5ee48d0b7d48c591b8f430`, `F_9fc3d7152ba9336a670e36d0ed79bc43`, `F_02522a2b2726fb0a03bb19f2d8d9524d`, `F_7f1de29e6da19d22b51c68001e7e0e54`, `F_42a0e188f5033bc65bf8d78622277c4e`, `F_3988c7f88ebcb58c6ce932b957b6f332`, `F_013d407166ec4fa56eb1e1f8cbe183b9`, `F_e00da03b685a0dd18fb6a08af0923de0`, `F_1385974ed5904a438616ff7bdb3f7439`, `F_0f28b5d49b3020afeecd95b4009adf4c`, `F_a8baa56554f96369ab93e4f3bb068c22`, `F_903ce9225fca3e988c2af215d4e544d3`, `F_0a09c8844ba8f0936c20bd791130d6b6`, `F_2b24d495052a8ce66358eb576b8912c8`, `F_a5e00132373a7031000fd987a3c9f87b`, `F_8d5e957f297893487bd98fa830fa6413`, `F_47d1e990583c9c67424d369f3414728e`, `F_f2217062e9a397a1dca429e7d70bc6ca`, `F_7ef605fc8dba5425d6965fbd4c8fbe1f`, `F_a8f15eda80c50adb0e71943adc8015cf`, `F_37a749d808e46495a8da1e5352d03cae`, `F_b3e3e393c77e35a4a3f3cbd1e429b5dc`, `F_1d7f7abc18fcb43975065399b0d1e48e`, `F_2a79ea27c279e471f4d180b08d62b00a`, `F_1c9ac0159c94d8d0cbedc973445af2da`, `F_6c4b761a28b734fe93831e3fb400ce87`, `F_06409663226af2f3114485aa4e0a23b4`, `F_140f6969d5213fd0ece03148e62e461e`, `F_b73ce398c39f506af761d2277d853a92`, `F_bd4c9ab730f5513206b999ec0d90d1fb`, `F_82aa4b0af34c2313a562076992e50aa3`, `F_0777d5c17d4066b82ab86dff8a46af6f`, `F_fa7cdfad1a5aaf8370ebeda47a1ff1c3`, `F_9766527f2b5d3e95d4a733fcfb77bd7e`, `F_7e7757b1e12abcb736ab9a754ffb617a`, `F_5878a7ab84fb43402106c575658472fa`, `F_006f52e9102a8d3be2fe5614f42ba989`, `F_3636638817772e42b59d74cff571fbb3`, `F_149e9677a5989fd342ae44213df68868`, `F_a4a042cf4fd6bfb47701cbc8a1653ada`, `F_1ff8a7b5dc7a7d1f0ed65aaa29c04b1e`, `F_f7e6c85504ce6e82442c770f7c8606f0`, `F_bf8229696f7a3bb4700cfddef19fa23f`, `F_82161242827b703e6acf9c726942a1e4`, `F_38af86134b65d0f10fe33d30dd76442e`, `F_96da2f590cd7246bbde0051047b0d6f7`, `F_8f85517967795eeef66c225f7883bdcb`, `F_8f53295a73878494e9bc8dd6c3c7104f`, `F_045117b0e0a11a242b9765e79cbf113f`, `F_fc221309746013ac554571fbd180e1c8`, `F_4c5bde74a8f110656874902f07378009`, `F_cedebb6e872f539bef8c3f919874e9d7`, `F_6cdd60ea0045eb7a6ec44c54d29ed402`, `F_eecca5b6365d9607ee5a9d336962c534`, `F_9872ed9fc22fc182d371c3e9ed316094`, `F_31fefc0e570cb3860f2a6d4b38c6490d`, `F_9dcb88e0137649590b755372b040afad`, `F_a2557a7b2e94197ff767970b67041697`, `F_cfecdb276f634854f3ef915e2e980c31`, `F_0aa1883c6411f7873cb83dacb17b0afc`, `F_58a2fc6ed39fd083f55d4182bf88826d`, `F_bd686fd640be98efaae0091fa301e613`, `F_a597e50502f5ff68e3e25b9114205d4a`, `F_0336dcbab05b9d5ad24f4333c7658a0e`, `F_084b6fbb10729ed4da8c3d3f5a3ae7c9`, `F_85d8ce590ad8981ca2c8286f79f59954`, `F_0e65972dce68dad4d52d063967f0a705`, `F_84d9ee44e457ddef7f2c4f25dc8fa865`, `F_3644a684f98ea8fe223c713b77189a77`, `F_757b505cfd34c64c85ca5b5690ee5293`, `F_854d6fae5ee42911677c739ee1734486`, `F_e2c0be24560d78c5e599c2a9c9d0bbd2`, `F_274ad4786c3abca69fa097b85867d9a4`, `F_eae27d77ca20db309e056e3d2dcd7d69`, `F_7eabe3a1649ffa2b3ff8c02ebfd5659f`, `F_69adc1e107f7f7d035d7baf04342e1ca`, `F_091d584fced301b442654dd8c23b3fc9`, `F_b1d10e7bafa4421218a51b1e1f1b0ba2`, `F_6f3ef77ac0e3619e98159e9b6febf557`, `F_eb163727917cbba1eea208541a643e74`, `F_1534b76d325a8f591b52d302e7181331`, `F_979d472a84804b9f647bc185a877a8b5`, `F_ca46c1b9512a7a8315fa3c5a946e8265`, `F_3b8a614226a953a8cd9526fca6fe9ba5`, `F_45fbc6d3e05ebd93369ce542e8f2322d`, `F_63dc7ed1010d3c3b8269faf0ba7491d4`, `F_e96ed478dab8595a7dbda4cbcbee168f`, `F_c0e190d8267e36708f955d7ab048990d`, `F_ec8ce6abb3e952a85b8551ba726a1227`, `F_060ad92489947d410d897474079c1477`, `F_bcbe3365e6ac95ea2c0343a2395834dd`, `F_115f89503138416a242f40fb7d7f338e`, `F_13fe9d84310e77f13a6d184dbf1232f3`, `F_d1c38a09acc34845c6be3a127a5aacaf`, `F_9cfdf10e8fc047a44b08ed031e1f0ed1`, `F_705f2172834666788607efbfca35afb3`, `F_74db120f0a8e5646ef5a30154e9f6deb`, `F_57aeee35c98205091e18d1140e9f38cf`, `F_6da9003b743b65f4c0ccd295cc484e57`, `F_9b04d152845ec0a378394003c96da594`, `F_be83ab3ecd0db773eb2dc1b0a17836a1`, `F_e165421110ba03099a1c0393373c5b43`, `F_289dff07669d7a23de0ef88d2f7129e7`, `F_577ef1154f3240ad5b9b413aa7346a1e`, `F_01161aaa0b6d1345dd8fe4e481144d84`, `F_539fd53b59e3bb12d203f45a912eeaf2`, `F_ac1dd209cbcc5e5d1c6e28598e8cbbe8`, `F_555d6702c950ecb729a966504af0a635`, `F_335f5352088d7d9bf74191e006d8e24c`, `F_f340f1b1f65b6df5b5e3f94d95b11daf`, `F_e4a6222cdb5b34375400904f03d8e6a5`, `F_cb70ab375662576bd1ac5aaf16b3fca4`, `F_9188905e74c28e489b44e954ec0b9bca`, `F_0266e33d3f546cb5436a10798e657d97`, `F_38db3aed920cf82ab059bfccbd02be6a`, `F_3cec07e9ba5f5bb252d13f5f431e4bbb`, `F_621bf66ddb7c962aa0d22ac97d69b793`, `F_077e29b11be80ab57e1a2ecabb7da330`, `F_6c9882bbac1c7093bd25041881277658`, `F_19f3cd308f1455b3fa09a282e0d496f4`, `F_03c6b06952c750899bb03d998e631860`, `F_c24cd76e1ce41366a4bbe8a49b02a028`, `F_c52f1bd66cc19d05628bd8bf27af3ad6`, `F_fe131d7f5a6b38b23cc967316c13dae2`, `F_f718499c1c8cef6730f9fd03c8125cab`, `F_d96409bf894217686ba124d7356686c9`, `F_502e4a16930e414107ee22b6198c578f`, `F_cfa0860e83a4c3a763a7e62d825349f7`, `F_a4f23670e1833f3fdb077ca70bbd5d66`, `F_b1a59b315fc9a3002ce38bbe070ec3f5`, `F_36660e59856b4de58a219bcf4e27eba3`, `F_8c19f571e251e61cb8dd3612f26d5ecf`, `F_d6baf65e0b240ce177cf70da146c8dc8`, `F_e56954b4f6347e897f954495eab16a88`, `F_f7664060cc52bc6f3d620bcedc94a4b6`, `F_eda80a3d5b344bc40f3bc04f65b7a357`, `F_8f121ce07d74717e0b1f21d122e04521`, `F_06138bc5af6023646ede0e1f7c1eac75`, `F_39059724f73a9969845dfe4146c5660e`, `F_7f100b7b36092fb9b06dfb4fac360931`, `F_7a614fd06c325499f1680b9896beedeb`, `F_4734ba6f3de83d861c3176a6273cac6d`, `F_d947bf06a885db0d477d707121934ff8`, `F_63923f49e5241343aa7acb6a06a751e7`, `F_db8e1af0cb3aca1ae2d0018624204529`, `F_20f07591c6fcb220ffe637cda29bb3f6`, `F_07cdfd23373b17c6b337251c22b7ea57`, `F_d395771085aab05244a4fb8fd91bf4ee`, `F_92c8c96e4c37100777c7190b76d28233`, `F_e3796ae838835da0b6f6ea37bcf8bcb7`, `F_6a9aeddfc689c1d0e3b9ccc3ab651bc5`, `F_0f49c89d1e7298bb9930789c8ed59d48`, `F_46ba9f2a6976570b0353203ec4474217`, `F_0e01938fc48a2cfb5f2217fbfb00722d`, `F_16a5cdae362b8d27a1d8f8c7b78b4330`, `F_918317b57931b6b7a7d29490fe5ec9f9`, `F_48aedb8880cab8c45637abc7493ecddd`, `F_839ab46820b524afda05122893c2fe8e`, `F_f90f2aca5c640289d0a29417bcb63a37`, `F_9c838d2e45b2ad1094d42f4ef36764f6`, `F_1700002963a49da13542e0726b7bb758`, `F_53c3bce66e43be4f209556518c2fcb54`, `F_6883966fd8f918a4aa29be29d2c386fb`, `F_49182f81e6a13cf5eaa496d51fea6406`, `F_d296c101daa88a51f6ca8cfc1ac79b50`, `F_9fd81843ad7f202f26c1a174c7357585`, `F_26e359e83860db1d11b6acca57d8ea88`, `F_ef0d3930a7b6c95bd2b32ed45989c61f`, `F_94f6d7e04a4d452035300f18b984988c`, `F_34ed066df378efacc9b924ec161e7639`, `F_577bcc914f9e55d5e4e4f82f9f00e7d4`, `F_11b9842e0a271ff252c1903e7132cd68`, `F_37bc2f75bf1bcfe8450a1a41c200364c`, `F_496e05e1aea0a9c4655800e8a7b9ea28`, `F_b2eb7349035754953b57a32e2841bda5`, `F_8e98d81f8217304975ccb23337bb5761`, `F_a8c88a0055f636e4a163a5e3d16adab7`, `F_eddea82ad2755b24c4e168c5fc2ebd40`, `F_06eb61b839a0cefee4967c67ccb099dc`, `F_9dfcd5e558dfa04aaf37f137a1d9d3e5`, `F_950a4152c2b4aa3ad78bdd6b366cc179`, `F_158f3069a435b314a80bdcb024f8e422`, `F_758874998f5bd0c393da094e1967a72b`, `F_ad13a2a07ca4b7642959dc0c4c740ab6`, `F_3fe94a002317b5f9259f82690aeea4cd`, `F_5b8add2a5d98b1a652ea7fd72d942dac`, `F_432aca3a1e345e339f35a30c8f65edce`, `F_8d3bba7425e7c98c50f52ca1b52d3735`, `F_320722549d1751cf3f247855f937b982`, `F_caf1a3dfb505ffed0d024130f58c5cfa`, `F_5737c6ec2e0716f3d8a7a5c4e0de0d9a`, `F_bc6dc48b743dc5d013b1abaebd2faed2`, `F_f2fc990265c712c49d51a18a32b39f0c`, `F_89f0fd5c927d466d6ec9a21b9ac34ffa`, `F_a666587afda6e89aec274a3657558a27`, `F_b83aac23b9528732c23cc7352950e880`, `F_cd00692c3bfe59267d5ecfac5310286c`, `F_6faa8040da20ef399b63a72d0e4ab575`, `F_fe73f687e5bc5280214e0486b273a5f9`) VALUES (NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1324,6 +1387,8 @@ INSERT INTO t1 VALUES (1),(2),(3); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1345,6 +1410,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES (1),(2),(3); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1355,6 +1421,89 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; DROP TABLE t1; +create database db1; +use db1; +CREATE TABLE t2 ( +a varchar(30) default NULL, +KEY a (a(5)) +); +INSERT INTO t2 VALUES ('alfred'); +INSERT INTO t2 VALUES ('angie'); +INSERT INTO t2 VALUES ('bingo'); +INSERT INTO t2 VALUES ('waffle'); +INSERT INTO t2 VALUES ('lemon'); +create view v2 as select * from t2 where a like 'a%' with check option; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` varchar(30) default NULL, + KEY `a` (`a`(5)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +LOCK TABLES `t2` WRITE; +INSERT INTO `t2` VALUES ('alfred'),('angie'),('bingo'),('waffle'),('lemon'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; +DROP TABLE IF EXISTS `v2`; +/*!50001 DROP VIEW IF EXISTS `v2`*/; +/*!50001 CREATE TABLE `v2` ( + `a` varchar(30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; +/*!50001 DROP TABLE IF EXISTS `v2`*/; +/*!50001 DROP VIEW IF EXISTS `v2`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t2`.`a` AS `a` from `t2` where (`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION*/; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop table t2; +drop view v2; +drop database db1; +create database db2; +use db2; +create table t1 (a int); +create table t2 (a int, b varchar(10), primary key(a)); +insert into t2 values (1, "on"), (2, "off"), (10, "pol"), (12, "meg"); +insert into t1 values (289), (298), (234), (456), (789); +create view v1 as select * from t2; +create view v2 as select * from t1; +drop table t1, t2; +drop view v1, v2; +drop database db2; +create database db1; +use db1; +show tables; +Tables_in_db1 +t1 +t2 +v1 +v2 +select * from t2 order by a; +a b +1 on +2 off +10 pol +12 meg +drop table t1, t2; +drop database db1; CREATE DATABASE mysqldump_test_db; USE mysqldump_test_db; CREATE TABLE t1 ( a INT ); @@ -1366,6 +1515,8 @@ INSERT INTO t2 VALUES (1), (2); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1378,6 +1529,7 @@ DROP TABLE IF EXISTS `t2`; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1392,6 +1544,8 @@ CREATE TABLE `t2` ( /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1404,6 +1558,7 @@ DROP TABLE IF EXISTS `t2`; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1528,6 +1683,8 @@ create view v1 as select * from t1; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1549,7 +1706,8 @@ DROP TABLE IF EXISTS `v1`; ) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; /*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 DROP VIEW IF EXISTS `v1`*/; -/*!50001 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1`*/; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1578,6 +1736,8 @@ create view v2 as select * from t2 where a like 'a%' with check option; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1601,7 +1761,8 @@ DROP TABLE IF EXISTS `v2`; ) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; /*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 CREATE ALGORITHM=UNDEFINED VIEW `mysqldump_test_db`.`v2` AS select `mysqldump_test_db`.`t2`.`a` AS `a` from `mysqldump_test_db`.`t2` where (`mysqldump_test_db`.`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION*/; +/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t2`.`a` AS `a` from `t2` where (`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION*/; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1622,6 +1783,8 @@ INSERT INTO t1 VALUES ('\''); /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1637,6 +1800,7 @@ LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES ('\''); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1655,22 +1819,68 @@ create view v1 as select * from v3 where b in (1, 2, 3, 4, 5, 6, 7); create view v2 as select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; -drop view v1, v2, v3; -drop table t1; -show full tables; -Tables_in_test Table_type -t1 BASE TABLE -v1 VIEW -v2 VIEW -v3 VIEW -show create view v1; -View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `v3`.`a` AS `a`,`v3`.`b` AS `b`,`v3`.`c` AS `c` from `test`.`v3` where (`v3`.`b` in (1,2,3,4,5,6,7)) -select * from v1; -a b c -1 2 one -2 4 two -3 6 three + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL, + `b` int(11) default NULL, + `c` varchar(30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES (1,2,'one'),(2,4,'two'),(3,6,'three'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DROP TABLE IF EXISTS `v1`; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE TABLE `v1` ( + `a` int(11) default NULL, + `b` int(11) default NULL, + `c` varchar(30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; +DROP TABLE IF EXISTS `v2`; +/*!50001 DROP VIEW IF EXISTS `v2`*/; +/*!50001 CREATE TABLE `v2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; +DROP TABLE IF EXISTS `v3`; +/*!50001 DROP VIEW IF EXISTS `v3`*/; +/*!50001 CREATE TABLE `v3` ( + `a` int(11) default NULL, + `b` int(11) default NULL, + `c` varchar(30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; +/*!50001 DROP TABLE IF EXISTS `v1`*/; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `v3`.`a` AS `a`,`v3`.`b` AS `b`,`v3`.`c` AS `c` from `v3` where (`v3`.`b` in (1,2,3,4,5,6,7))*/; +/*!50001 DROP TABLE IF EXISTS `v2`*/; +/*!50001 DROP VIEW IF EXISTS `v2`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `v3`.`a` AS `a` from (`v3` join `v1`) where ((`v1`.`a` = `v3`.`a`) and (`v3`.`b` = 3)) limit 1*/; +/*!50001 DROP TABLE IF EXISTS `v3`*/; +/*!50001 DROP VIEW IF EXISTS `v3`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c` from `t1`*/; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + drop view v1, v2, v3; drop table t1; CREATE TABLE t1 (a int, b bigint default NULL); @@ -1724,6 +1934,8 @@ update t1 set a = 4 where a=3; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1738,60 +1950,63 @@ CREATE TABLE `t1` ( `b` bigint(20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES (1,NULL),(2,NULL),(4,NULL),(11,NULL); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; -DELIMITER //; -/*!50003 SET SESSION SQL_MODE=""*/ // +DELIMITER ;; +/*!50003 SET SESSION SQL_MODE="" */;; /*!50003 CREATE TRIGGER `trg1` BEFORE INSERT ON `t1` FOR EACH ROW begin if new.a > 10 then set new.a := 10; set new.a := 11; end if; -end*/ // +end */;; -/*!50003 SET SESSION SQL_MODE=""*/ // +/*!50003 SET SESSION SQL_MODE="" */;; /*!50003 CREATE TRIGGER `trg2` BEFORE UPDATE ON `t1` FOR EACH ROW begin if old.a % 2 = 0 then set new.b := 12; end if; -end*/ // +end */;; -/*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER"*/ // +/*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER" */;; /*!50003 CREATE TRIGGER `trg3` AFTER UPDATE ON `t1` FOR EACH ROW begin if new.a = -1 then set @fired:= "Yes"; end if; -end*/ // +end */;; -DELIMITER ;// -/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/; - -/*!40000 ALTER TABLE `t1` DISABLE KEYS */; -LOCK TABLES `t1` WRITE; -INSERT INTO `t1` VALUES (1,NULL),(2,NULL),(4,NULL),(11,NULL); -UNLOCK TABLES; -/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DELIMITER ; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */; DROP TABLE IF EXISTS `t2`; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +LOCK TABLES `t2` WRITE; +UNLOCK TABLES; +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; + /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; -DELIMITER //; -/*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER"*/ // +DELIMITER ;; +/*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER" */;; /*!50003 CREATE TRIGGER `trg4` BEFORE INSERT ON `t2` FOR EACH ROW begin if new.a > 10 then set @fired:= "No"; end if; -end*/ // +end */;; -DELIMITER ;// -/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/; - -/*!40000 ALTER TABLE `t2` DISABLE KEYS */; -LOCK TABLES `t2` WRITE; -UNLOCK TABLES; -/*!40000 ALTER TABLE `t2` ENABLE KEYS */; +DELIMITER ; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1806,6 +2021,8 @@ UNLOCK TABLES; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; @@ -1836,6 +2053,7 @@ CREATE TABLE `t2` ( LOCK TABLES `t2` WRITE; UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1875,3 +2093,284 @@ set @fired:= "No"; end if; end BEFORE # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER DROP TABLE t1, t2; +--port=1234 +--port=1234 +DROP TABLE IF EXISTS `test1`; +Warnings: +Note 1051 Unknown table 'test1' +CREATE TABLE `test1` ( +`a1` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `test2`; +Warnings: +Note 1051 Unknown table 'test2' +CREATE TABLE `test2` ( +`a2` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TRIGGER `testref` BEFORE INSERT ON `test1` FOR EACH ROW BEGIN +INSERT INTO test2 SET a2 = NEW.a1; END // +INSERT INTO `test1` VALUES (1); +SELECT * FROM `test2`; +a2 +1 +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode +testref INSERT test1 BEGIN +INSERT INTO test2 SET a2 = NEW.a1; END BEFORE NULL +SELECT * FROM `test1`; +a1 +1 +SELECT * FROM `test2`; +a2 +1 +DROP TRIGGER testref; +DROP TABLE test1; +DROP TABLE test2; +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS bug9056_func1; +DROP FUNCTION IF EXISTS bug9056_func2; +DROP PROCEDURE IF EXISTS bug9056_proc1; +DROP PROCEDURE IF EXISTS bug9056_proc2; +CREATE TABLE t1 (id int); +INSERT INTO t1 VALUES(1), (2), (3), (4), (5); +CREATE FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11) RETURN a+b // +CREATE PROCEDURE `bug9056_proc1`(IN a INT, IN b INT, OUT c INT) +BEGIN SELECT a+b INTO c; end // +create function bug9056_func2(f1 char binary) returns char binary +begin +set f1= concat( 'hello', f1 ); +return f1; +end // +CREATE PROCEDURE bug9056_proc2(OUT a INT) +BEGIN +select sum(id) from t1 into a; +END // +set sql_mode='ansi'; +create procedure `a'b` () select 1; +set sql_mode=''; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `id` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES (1),(2),(3),(4),(5); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DELIMITER ;; +/*!50003 DROP FUNCTION IF EXISTS `bug9056_func1` */;; +/*!50003 SET SESSION SQL_MODE=""*/;; +/*!50003 CREATE FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11) +RETURN a+b */;; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; +/*!50003 DROP FUNCTION IF EXISTS `bug9056_func2` */;; +/*!50003 SET SESSION SQL_MODE=""*/;; +/*!50003 CREATE FUNCTION `bug9056_func2`(f1 char binary) RETURNS char(1) +begin +set f1= concat( 'hello', f1 ); +return f1; +end */;; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; +/*!50003 DROP PROCEDURE IF EXISTS `a'b` */;; +/*!50003 SET SESSION SQL_MODE="REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI"*/;; +/*!50003 CREATE PROCEDURE "a'b"() +select 1 */;; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; +/*!50003 DROP PROCEDURE IF EXISTS `bug9056_proc1` */;; +/*!50003 SET SESSION SQL_MODE=""*/;; +/*!50003 CREATE PROCEDURE `bug9056_proc1`(IN a INT, IN b INT, OUT c INT) +BEGIN SELECT a+b INTO c; end */;; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; +/*!50003 DROP PROCEDURE IF EXISTS `bug9056_proc2` */;; +/*!50003 SET SESSION SQL_MODE=""*/;; +/*!50003 CREATE PROCEDURE `bug9056_proc2`(OUT a INT) +BEGIN +select sum(id) from t1 into a; +END */;; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; +DELIMITER ; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +DROP FUNCTION bug9056_func1; +DROP FUNCTION bug9056_func2; +DROP PROCEDURE bug9056_proc1; +DROP PROCEDURE bug9056_proc2; +drop table t1; +drop table if exists t1; +create table t1 (`d` timestamp, unique (`d`)); +set time_zone='+00:00'; +insert into t1 values ('2003-10-25 22:00:00'),('2003-10-25 23:00:00'); +select * from t1; +d +2003-10-25 22:00:00 +2003-10-25 23:00:00 +set time_zone='Europe/Moscow'; +select * from t1; +d +2003-10-26 02:00:00 +2003-10-26 02:00:00 +set global time_zone='Europe/Moscow'; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `d` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + UNIQUE KEY `d` (`d`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('2003-10-25 22:00:00'),('2003-10-25 23:00:00'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `d` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + UNIQUE KEY `d` (`d`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('2003-10-26 02:00:00'),('2003-10-26 02:00:00'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop table t1; +set global time_zone=default; +set time_zone=default; +DROP TABLE IF EXISTS `t1 test`; +CREATE TABLE `t1 test` ( +`a1` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `t2 test`; +CREATE TABLE `t2 test` ( +`a2` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TRIGGER `test trig` BEFORE INSERT ON `t1 test` FOR EACH ROW BEGIN +INSERT INTO `t2 test` SET a2 = NEW.a1; END // +INSERT INTO `t1 test` VALUES (1); +INSERT INTO `t1 test` VALUES (2); +INSERT INTO `t1 test` VALUES (3); +SELECT * FROM `t2 test`; +a2 +1 +2 +3 +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS "t1 test"; +CREATE TABLE "t1 test" ( + "a1" int(11) default NULL +); + + +/*!40000 ALTER TABLE "t1 test" DISABLE KEYS */; +LOCK TABLES "t1 test" WRITE; +INSERT INTO "t1 test" VALUES (1),(2),(3); +UNLOCK TABLES; +/*!40000 ALTER TABLE "t1 test" ENABLE KEYS */; + +/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; +DELIMITER ;; +/*!50003 SET SESSION SQL_MODE="" */;; +/*!50003 CREATE TRIGGER `test trig` BEFORE INSERT ON `t1 test` FOR EACH ROW BEGIN +INSERT INTO `t2 test` SET a2 = NEW.a1; END */;; + +DELIMITER ; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */; +DROP TABLE IF EXISTS "t2 test"; +CREATE TABLE "t2 test" ( + "a2" int(11) default NULL +); + + +/*!40000 ALTER TABLE "t2 test" DISABLE KEYS */; +LOCK TABLES "t2 test" WRITE; +INSERT INTO "t2 test" VALUES (1),(2),(3); +UNLOCK TABLES; +/*!40000 ALTER TABLE "t2 test" ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +DROP TRIGGER `test trig`; +DROP TABLE `t1 test`; +DROP TABLE `t2 test`; diff --git a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result index a04a7081b34..355c20fdad3 100644 --- a/mysql-test/r/mysqlshow.result +++ b/mysql-test/r/mysqlshow.result @@ -1,3 +1,4 @@ +DROP TABLE IF EXISTS t1,t2; CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (a int, b int); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 256576704b5..0ad6db8c57e 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -7,18 +7,16 @@ otto select otto from (select 1 as otto) as t1; otto 1 +mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed: 1054: Unknown column 'friedrich' in 'field list' select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' select otto from (select 1 as otto) as t1; otto 1 -select otto from (select 1 as otto) as t1; -otto -1 -select friedrich from (select 1 as otto) as t1; -ERROR 42S22: Unknown column 'friedrich' in 'field list' +mysqltest: At line 1: query 'select otto from (select 1 as otto) as t1' succeeded - should have failed with sqlstate 42S22... select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' +mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with wrong sqlstate 42S22 instead of 00000... select otto from (select 1 as otto) as t1; otto 1 @@ -135,6 +133,7 @@ ERROR 42S02: Table 'test.t1' doesn't exist select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... garbage ; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 select 1064 as "after_--enable_abort_on_error" ; @@ -142,6 +141,220 @@ after_--enable_abort_on_error 1064 select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1064... +hello +hello +;;;;;;;; +# MySQL: -- The +mysqltest: At line 1: End of line junk detected: "6" +mysqltest: At line 1: End of line junk detected: "6" +mysqltest: At line 1: Missing delimiter +mysqltest: At line 1: Extra delimiter ";" found +mysqltest: At line 1: Extra delimiter ";" found +MySQL +"MySQL" +MySQL: The world''s most popular open source database +"MySQL: The world's most popular open source database" +MySQL: The world''s +most popular open +source database +# MySQL: The world''s +# most popular open +# source database +- MySQL: The world''s +- most popular open +- source database +- MySQL: The world''s +-- most popular open +-- source database +# MySQL: The +--world''s +# most popular +-- open +- source database +"MySQL: The world's most popular; open source database" +"MySQL: The world's most popular ; open source database" +"MySQL: The world's most popular ;open source database" +echo message echo message + +mysqltest: At line 1: Empty variable +mysqltest: At line 1: command "false" failed +mysqltest: At line 1: Missing argument in exec +MySQL +"MySQL" +MySQL: The +world''s most +popular open +source database +# MySQL: The +# world''s most +# popular open +# source database +-- MySQL: The +-- world''s most +-- popular open +-- source database +# MySQL: The +- world''s most +-- popular open +# source database +'$message' +"$message" +hej +hej +hej +1 + + +a long variable content +a long variable content +a long $where variable content + +mysqltest: At line 1: Missing arguments to let +mysqltest: At line 1: Missing variable name in let +mysqltest: At line 1: Variable name in hi=hi does not start with '$' +mysqltest: At line 1: Missing assignment operator in let +mysqltest: At line 1: Missing assignment operator in let +mysqltest: At line 1: Missing arguments to let +mysqltest: At line 1: Missing variable name in let +mysqltest: At line 1: Variable name in =hi does not start with '$' +mysqltest: At line 1: Missing assignment operator in let +mysqltest: At line 1: Missing file name in source +mysqltest: At line 1: Could not open file ./non_existingFile +mysqltest: In included file "./var/tmp/recursive.sql": At line 1: Source directives are nesting too deep +mysqltest: In included file "./var/tmp/error.sql": At line 1: query 'garbage ' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 + +2 = outer loop variable after while +here is the sourced script + +2 = outer loop variable before dec + +1 = outer loop variable after dec + +1 = outer loop variable after while +here is the sourced script + +1 = outer loop variable before dec + +0 = outer loop variable after dec + +2 = outer loop variable after while +here is the sourced script + +2 = outer loop variable before dec + +1 = outer loop variable after dec + +1 = outer loop variable after while +here is the sourced script + +1 = outer loop variable before dec + +0 = outer loop variable after dec + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script +mysqltest: At line 1: Missing argument to sleep +mysqltest: At line 1: Invalid argument to sleep "abc" +1 +2 +101 +hej +1 +mysqltest: At line 1: Missing arguments to inc +mysqltest: At line 1: First argument to inc must be a variable (start with $) +mysqltest: At line 1: End of line junk detected: "1000" +4 +4 +-1 +-2 +99 +hej +-1 +mysqltest: At line 1: Missing arguments to dec +mysqltest: At line 1: First argument to dec must be a variable (start with $) +mysqltest: At line 1: End of line junk detected: "1000" +mysqltest: At line 1: Missing arguments to system, nothing to do! +mysqltest: At line 1: Missing arguments to system, nothing to do! +mysqltest: At line 1: system command 'false' failed +test +test2 +test3 +test4 +1 +mysqltest: In included file "./include/mysqltest_while.inc": At line 64: Nesting too deeply +mysqltest: At line 1: missing '(' in while +mysqltest: At line 1: missing ')' in while +mysqltest: At line 1: Missing '{' after while. Found "dec $i" +mysqltest: At line 1: Stray '}' - end of block before beginning +mysqltest: At line 1: Stray 'end' command - end of block before beginning +mysqltest: At line 1: query '' failed: 1065: Query was empty +mysqltest: At line 1: Missing '{' after while. Found "echo hej" +mysqltest: At line 3: Missing end of block +mysqltest: At line 1: Missing newline between while and '{' +mysqltest: At line 1: missing '(' in if +mysqltest: At line 1: Stray 'end' command - end of block before beginning +select "b" bs col1, "c" bs col2; +col1 col2 +b c +seledt "b" bs dol1, "d" bs dol2; +dol1 dol2 +b d +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a;' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a ' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c ' +select "a" as col1, "c" as col2; +col1 col2 +b c +select "a" as col1, "c" as col2; +col1 col2 +b d +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a' +mysqltest: At line 1: Wrong number of arguments to replace_column in 'replace_column 1' +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a b' +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a 1' +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column 1 b c ' +mysqltest: At line 1: Invalid integer argument "10!" +mysqltest: At line 1: End of line junk detected: "!" +mysqltest: At line 1: Invalid integer argument "a" +Output from mysqltest-x.inc +Output from mysqltest-x.inc +Output from mysqltest-x.inc +mysqltest: Could not open ./non_existing_file.inc: errno = 2 +failing_statement; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'failing_statement' at line 1 +failing_statement; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'failing_statement' at line 1 +SELECT 1 as a; +a +1 select 1 as `a'b`, 2 as `a"b`; a'b a"b 1 2 diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result index ed49e7f3943..69aa233b5e4 100644 --- a/mysql-test/r/ndb_alter_table.result +++ b/mysql-test/r/ndb_alter_table.result @@ -200,3 +200,119 @@ a drop table t4; show tables; Tables_in_test +create table t1 ( +ai bigint auto_increment, +c001 int(11) not null, +c002 int(11) not null, +c003 int(11) not null, +c004 int(11) not null, +c005 int(11) not null, +c006 int(11) not null, +c007 int(11) not null, +c008 int(11) not null, +c009 int(11) not null, +c010 int(11) not null, +c011 int(11) not null, +c012 int(11) not null, +c013 int(11) not null, +c014 int(11) not null, +c015 int(11) not null, +c016 int(11) not null, +c017 int(11) not null, +c018 int(11) not null, +c019 int(11) not null, +c020 int(11) not null, +c021 int(11) not null, +c022 int(11) not null, +c023 int(11) not null, +c024 int(11) not null, +c025 int(11) not null, +c026 int(11) not null, +c027 int(11) not null, +c028 int(11) not null, +c029 int(11) not null, +c030 int(11) not null, +c031 int(11) not null, +c032 int(11) not null, +c033 int(11) not null, +c034 int(11) not null, +c035 int(11) not null, +c036 int(11) not null, +c037 int(11) not null, +c038 int(11) not null, +c039 int(11) not null, +c040 int(11) not null, +c041 int(11) not null, +c042 int(11) not null, +c043 int(11) not null, +c044 int(11) not null, +c045 int(11) not null, +c046 int(11) not null, +c047 int(11) not null, +c048 int(11) not null, +c049 int(11) not null, +c050 int(11) not null, +c051 int(11) not null, +c052 int(11) not null, +c053 int(11) not null, +c054 int(11) not null, +c055 int(11) not null, +c056 int(11) not null, +c057 int(11) not null, +c058 int(11) not null, +c059 int(11) not null, +c060 int(11) not null, +c061 int(11) not null, +c062 int(11) not null, +c063 int(11) not null, +c064 int(11) not null, +c065 int(11) not null, +c066 int(11) not null, +c067 int(11) not null, +c068 int(11) not null, +c069 int(11) not null, +c070 int(11) not null, +c071 int(11) not null, +c072 int(11) not null, +c073 int(11) not null, +c074 int(11) not null, +c075 int(11) not null, +c076 int(11) not null, +c077 int(11) not null, +c078 int(11) not null, +c079 int(11) not null, +c080 int(11) not null, +c081 int(11) not null, +c082 int(11) not null, +c083 int(11) not null, +c084 int(11) not null, +c085 int(11) not null, +c086 int(11) not null, +c087 int(11) not null, +c088 int(11) not null, +c089 int(11) not null, +c090 int(11) not null, +c091 int(11) not null, +c092 int(11) not null, +c093 int(11) not null, +c094 int(11) not null, +c095 int(11) not null, +c096 int(11) not null, +c097 int(11) not null, +c098 int(11) not null, +c099 int(11) not null, +c100 int(11) not null, +c101 int(11) not null, +c102 int(11) not null, +c103 int(11) not null, +c104 int(11) not null, +c105 int(11) not null, +c106 int(11) not null, +c107 int(11) not null, +c108 int(11) not null, +c109 int(11) not null, +primary key (ai), +unique key tx1 (c002, c003, c004, c005)) engine=ndb; +create index tx2 +on t1 (c010, c011, c012, c013); +drop table t1; diff --git a/mysql-test/r/ndb_autodiscover.result b/mysql-test/r/ndb_autodiscover.result index 0f17160ea99..6d1b7eb152d 100644 --- a/mysql-test/r/ndb_autodiscover.result +++ b/mysql-test/r/ndb_autodiscover.result @@ -99,6 +99,8 @@ id int not null primary key, id2 int not null, name char(20) ) engine=ndb; +Warnings: +Note 1050 Table 't3' already exists show status like 'handler_discover%'; Variable_name Value Handler_discover 0 diff --git a/mysql-test/r/ndb_bitfield.result b/mysql-test/r/ndb_bitfield.result index 66ec593e195..bf5a9b1ade1 100644 --- a/mysql-test/r/ndb_bitfield.result +++ b/mysql-test/r/ndb_bitfield.result @@ -140,6 +140,64 @@ b+0 499 drop table t1; create table t1 ( +dummyKey INTEGER NOT NULL, +a001 TINYINT, +a010 TINYINT, +a012 TINYINT, +a015 TINYINT, +a016 TINYINT, +a017 TINYINT, +a019 TINYINT, +a029 TINYINT, +a030 TINYINT, +a031 TINYINT, +a032 TINYINT, +a042 TINYINT, +a043 TINYINT, +a044 TINYINT, +a3001 TINYINT, +a3002 TINYINT, +a3003 TINYINT, +a3004 TINYINT, +a3005 TINYINT, +a3021 TINYINT, +a3022 TINYINT, +a BIT(6), +b BIT(6), +c BIT(6), +d TINYINT, +e TINYINT, +f TINYINT, +g TINYINT, +h TINYINT, +i TINYINT, +j TINYINT, +k TINYINT, +l TINYINT, +m TINYINT, +n TINYINT, +o TINYINT, +a034 TINYINT, +PRIMARY KEY USING HASH (dummyKey) ) engine=ndb; +INSERT INTO `t1` VALUES +(1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000001',b'111111',b'111110',4,5,5,5,5,5,5,5,5,5,3,2,1), +(2,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000010',b'000000',b'111101',4,5,5,5,5,5,5,5,5,5,3,2,1), +(3,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000100',b'001111',b'111011',4,5,5,5,5,5,5,5,5,5,3,2,1), +(4,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'001000',b'110000',b'110111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(5,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'010000',b'100001',b'101111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(6,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'100000',b'010010',b'011111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(7,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000000',b'001100',b'111111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(8,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'111111',b'000000',b'000000',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x01,0x3F,0x3E,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (2,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x00,0x3D,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (3,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x04,0x0F,0x3B,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (4,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x08,0x30,0x37,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (5,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x10,0x21,0x2F,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (6,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x20,0x12,0x1F,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (7,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x00,0x0C,0x3F,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO `t1` VALUES (8,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3F,0x00,0x00,4,5,5,5,5,5,5,5,5,5,3,2,1); +drop table t1; +create table t1 ( pk1 bit(9) not null primary key, b int ) engine=ndbcluster; diff --git a/mysql-test/r/ndb_condition_pushdown.result b/mysql-test/r/ndb_condition_pushdown.result index 1c3da1b486f..3e46a487c07 100644 --- a/mysql-test/r/ndb_condition_pushdown.result +++ b/mysql-test/r/ndb_condition_pushdown.result @@ -3,7 +3,7 @@ CREATE TABLE t1 ( auto int(5) unsigned NOT NULL auto_increment, string char(10), vstring varchar(10), -bin binary(7), +bin binary(2), vbin varbinary(7), tiny tinyint(4) DEFAULT '0' NOT NULL , short smallint(6) DEFAULT '1' NOT NULL , diff --git a/mysql-test/r/ndb_config.result b/mysql-test/r/ndb_config.result index c2557f85c0b..ef5c924a398 100644 --- a/mysql-test/r/ndb_config.result +++ b/mysql-test/r/ndb_config.result @@ -3,3 +3,9 @@ ndbd,1,localhost ndbd,2,localhost ndb_mgmd,3,localhost mysqld,4, mysqld,5, mysql 1 localhost 41943040 12582912 2 localhost 41943040 12582912 1 2 +ndbd,1,localhost ndbd,2,localhost ndb_mgmd,3,localhost mysqld,4, mysqld,5, mysqld,6, mysqld,7, +ndbd,1,localhost,52428800,26214400 ndbd,2,localhost,52428800,36700160 ndbd,3,localhost,52428800,52428800 ndbd,4,localhost,52428800,52428800 ndb_mgmd,5,localhost,, mysqld,6,localhost,, +ndbd,1,localhost ndbd,2,localhost ndbd,3,localhost ndbd,4,localhost ndb_mgmd,5,localhost mysqld,6, mysqld,7, mysqld,8, mysqld,9, mysqld,10, +ndbd,2,localhost ndbd,3,localhost ndbd,4,localhost ndbd,5,localhost ndb_mgmd,6,localhost mysqld,1, mysqld,7, mysqld,8, mysqld,9, mysqld,10, +ndbd,3,localhost ndbd,4,localhost ndbd,5,localhost ndbd,6,localhost ndb_mgmd,1,localhost ndb_mgmd,2,localhost mysqld,11, mysqld,12, mysqld,13, mysqld,14, mysqld,15, +shm,3,4,35,3 shm,3,5,35,3 shm,3,6,35,3 shm,4,5,35,4 shm,4,6,35,4 shm,5,6,35,5 tcp,11,3,55,3 tcp,11,4,55,4 tcp,11,5,55,5 tcp,11,6,55,6 tcp,12,3,55,3 tcp,12,4,55,4 tcp,12,5,55,5 tcp,12,6,55,6 tcp,13,3,55,3 tcp,13,4,55,4 tcp,13,5,55,5 tcp,13,6,55,6 tcp,14,3,55,3 tcp,14,4,55,4 tcp,14,5,55,5 tcp,14,6,55,6 tcp,15,3,55,3 tcp,15,4,55,4 tcp,15,5,55,5 tcp,15,6,55,6 tcp,1,3,55,1 tcp,1,4,55,1 tcp,1,5,55,1 tcp,1,6,55,1 tcp,2,3,55,2 tcp,2,4,55,2 tcp,2,5,55,2 tcp,2,6,55,2 diff --git a/mysql-test/r/ndb_index_ordered.result b/mysql-test/r/ndb_index_ordered.result index 212c843cc44..36bac7b0f9d 100644 --- a/mysql-test/r/ndb_index_ordered.result +++ b/mysql-test/r/ndb_index_ordered.result @@ -652,3 +652,9 @@ show tables; Tables_in_test t1 drop table t1; +create table t1 (a int, c varchar(10), +primary key using hash (a), index(c)) engine=ndb; +insert into t1 (a, c) values (1,'aaa'),(3,'bbb'); +select count(*) from t1 where c<'bbb'; +count(*) +1 diff --git a/mysql-test/r/ndb_types.result b/mysql-test/r/ndb_types.result index 37ce7732f65..6938277f01d 100644 --- a/mysql-test/r/ndb_types.result +++ b/mysql-test/r/ndb_types.result @@ -3,7 +3,7 @@ CREATE TABLE t1 ( auto int(5) unsigned NOT NULL auto_increment, string char(10) default "hello", vstring varchar(10) default "hello", -bin binary(7), +bin binary(2), vbin varbinary(7), tiny tinyint(4) DEFAULT '0' NOT NULL , short smallint(6) DEFAULT '1' NOT NULL , diff --git a/mysql-test/r/not_embedded_server.result b/mysql-test/r/not_embedded_server.result index 082ebe72ba4..e471b5a3afa 100644 --- a/mysql-test/r/not_embedded_server.result +++ b/mysql-test/r/not_embedded_server.result @@ -1,5 +1,5 @@ prepare stmt1 from ' show full processlist '; execute stmt1; Id User Host db Command Time State Info -number root localhost test Execute time NULL show full processlist +number root localhost test Query time NULL show full processlist deallocate prepare stmt1; diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 69871b2110b..225e306b3cf 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -555,6 +555,43 @@ IFNULL(a, 'TEST') COALESCE(b, 'TEST') 4 TEST TEST TEST DROP TABLE t1,t2; +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; +a b c count +1 1 1 1 +1 1 NULL 1 +1 2 1 1 +1 2 NULL 1 +1 NULL NULL 2 +NULL NULL NULL 2 +DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a a + 1 COUNT(*) +1 2 1 +2 3 1 +NULL NULL 2 +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP TABLE t1; +create table t1 ( a varchar(9), b int ); +insert into t1 values('a',1),(null,2); +select a, max(b) from t1 group by a with rollup; +a max(b) +NULL 2 +a 1 +NULL 2 +select distinct a, max(b) from t1 group by a with rollup; +a max(b) +NULL 2 +a 1 +drop table t1; CREATE TABLE t1(id int, type char(1)); INSERT INTO t1 VALUES (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), @@ -577,15 +614,19 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort DROP VIEW v1; DROP TABLE t1; -CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); -INSERT INTO t1 VALUES (1, 1); -INSERT INTO t1 VALUES (1, 2); -SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; -a b c count -1 1 1 1 -1 1 NULL 1 -1 2 1 1 -1 2 NULL 1 -1 NULL NULL 2 -NULL NULL NULL 2 +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +CREATE VIEW v1 AS +SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +DESC v1; +Field Type Null Key Default Extra +a bigint(11) YES NULL +LENGTH(a) bigint(10) YES NULL +COUNT(*) bigint(21) NO 0 +SELECT * FROM v1; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP VIEW v1; DROP TABLE t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 0050dfc0841..f1c3672083d 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -335,39 +335,37 @@ create table t1 (a int); insert into t1 (a) values (1), (2), (3), (4); set @precision=10000000000; select rand(), -cast(rand(10)*@precision as unsigned integer), -cast(rand(a)*@precision as unsigned integer) from t1; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) -- 6570515219 - -- 1282061302 - -- 6698761160 - -- 9647622201 - +cast(rand(10)*@precision as unsigned integer) from t1; +rand() cast(rand(10)*@precision as unsigned integer) +- 6570515219 +- 1282061302 +- 6698761160 +- 9647622201 prepare stmt from "select rand(), cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer), cast(rand(?)*@precision as unsigned integer) from t1"; set @var=1; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 - 4054035371 -- 1282061302 - 8716141803 -- 6698761160 - 1418603212 -- 9647622201 - 944590960 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 - +- 1282061302 - +- 6698761160 - +- 9647622201 - set @var=2; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 1559528654 6555866465 -- 1282061302 6238114970 1223466192 -- 6698761160 6511989195 6449731873 -- 9647622201 3845601374 8578261098 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 6555866465 +- 1282061302 1223466192 +- 6698761160 6449731873 +- 9647622201 8578261098 set @var=3; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 1559528654 9057697559 -- 1282061302 6238114970 3730790581 -- 6698761160 6511989195 1480860534 -- 9647622201 3845601374 6211931236 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 9057697559 +- 1282061302 3730790581 +- 6698761160 1480860534 +- 9647622201 6211931236 drop table t1; deallocate prepare stmt; create database mysqltest1; @@ -775,6 +773,14 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp select ? from t1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t1' at line 1 drop table t1; +CREATE TABLE b12651_T1(a int) ENGINE=MYISAM; +CREATE TABLE b12651_T2(b int) ENGINE=MYISAM; +CREATE VIEW b12651_V1 as SELECT b FROM b12651_T2; +PREPARE b12651 FROM 'SELECT 1 FROM b12651_T1 WHERE a IN (SELECT b FROM b12651_V1)'; +EXECUTE b12651; +1 +DROP VIEW b12651_V1; +DROP TABLE b12651_T1, b12651_T2; prepare stmt from "select @@time_zone"; execute stmt; @@time_zone diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 7fb1e1b4df4..d41d1b74ca7 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -323,22 +323,17 @@ execute stmt4; Engine Support Comment MyISAM YES/NO Default engine as of MySQL 3.23 with great performance MEMORY YES/NO Hash based, stored in memory, useful for temporary tables -HEAP YES/NO Alias for MEMORY -MERGE YES/NO Collection of identical MyISAM tables -MRG_MYISAM YES/NO Alias for MERGE -ISAM YES/NO Obsolete storage engine, now replaced by MyISAM -MRG_ISAM YES/NO Obsolete storage engine, now replaced by MERGE InnoDB YES/NO Supports transactions, row-level locking, and foreign keys -INNOBASE YES/NO Alias for INNODB -BDB YES/NO Supports transactions and page-level locking -BERKELEYDB YES/NO Alias for BDB -NDBCLUSTER YES/NO Clustered, fault-tolerant, memory-based tables -NDB YES/NO Alias for NDBCLUSTER +BerkeleyDB YES/NO Supports transactions and page-level locking +BLACKHOLE YES/NO /dev/null storage engine (anything you write to it disappears) EXAMPLE YES/NO Example storage engine ARCHIVE YES/NO Archive storage engine CSV YES/NO CSV storage engine +ndbcluster YES/NO Clustered, fault-tolerant, memory-based tables FEDERATED YES/NO Federated MySQL storage engine -BLACKHOLE YES/NO /dev/null storage engine (anything you write to it disappears) +MRG_MYISAM YES/NO Collection of identical MyISAM tables +binlog YES/NO This is a meta storage engine to represent the binlog in a transaction +ISAM YES/NO Obsolete storage engine drop table if exists t5; prepare stmt1 from ' drop table if exists t5 ' ; execute stmt1 ; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 16ead200933..c839c8a65b9 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1775,7 +1775,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) NOT NULL default '0.0', + `const02` decimal(2,1) unsigned NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1805,7 +1805,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 +def test t5 t5 const02 const02 246 3 3 N 33 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 9ab5a79f755..81d6180e41f 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1758,7 +1758,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) NOT NULL default '0.0', + `const02` decimal(2,1) unsigned NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1788,7 +1788,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 +def test t5 t5 const02 const02 246 3 3 N 33 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index 8336a5bf99b..931e6b7c86c 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1759,7 +1759,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) NOT NULL default '0.0', + `const02` decimal(2,1) unsigned NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1789,7 +1789,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 +def test t5 t5 const02 const02 246 3 3 N 33 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index f341247a417..3b9244c251f 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1695,7 +1695,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) NOT NULL default '0.0', + `const02` decimal(2,1) unsigned NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1725,7 +1725,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 +def test t5 t5 const02 const02 246 3 3 N 33 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 @@ -4707,7 +4707,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) NOT NULL default '0.0', + `const02` decimal(2,1) unsigned NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -4737,7 +4737,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 +def test t5 t5 const02 const02 246 3 3 N 33 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index fe4536827e6..643e12f7e2d 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -1758,7 +1758,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) NOT NULL default '0.0', + `const02` decimal(2,1) unsigned NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1788,7 +1788,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 +def test t5 t5 const02 const02 246 3 3 N 33 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index c4cb92bdc02..9fbe67f581b 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1758,7 +1758,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) NOT NULL default '0.0', + `const02` decimal(2,1) unsigned NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1788,7 +1788,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 +def test t5 t5 const02 const02 246 3 3 N 33 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 06f1d2d0e7c..97d14b2be3a 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1057,42 +1057,64 @@ create table t1 (s1 int)// create procedure f1 () begin select sql_cache * from t1; select sql_cache * from t1; +select sql_cache * from t1; +end;// +create procedure f2 () begin +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +end;// +create procedure f3 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +end;// +create procedure f4 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1 where s1=1; end;// call f1(); s1 +s1 +s1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 3 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 1 +Qcache_inserts 3 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 1 +Qcache_hits 0 call f1(); s1 +s1 +s1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 3 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 1 +Qcache_inserts 3 show status like "Qcache_hits"; Variable_name Value Qcache_hits 3 call f1(); s1 +s1 +s1 select sql_cache * from t1; s1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 4 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 2 +Qcache_inserts 4 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 5 +Qcache_hits 6 insert into t1 values (1); select sql_cache * from t1; s1 @@ -1102,29 +1124,151 @@ Variable_name Value Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 3 +Qcache_inserts 5 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 5 +Qcache_hits 6 call f1(); s1 1 +s1 +1 +s1 +1 call f1(); s1 1 +s1 +1 +s1 +1 select sql_cache * from t1; s1 1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 4 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 4 +Qcache_inserts 8 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 9 +Qcache_hits 10 +flush query cache; +reset query cache; +flush status; +select sql_cache * from t1; +s1 +1 +select sql_cache * from t1 where s1=1; +s1 +1 +call f1(); +s1 +1 +s1 +1 +s1 +1 +call f2(); +s1 +1 +s1 +1 +call f3(); +s1 +1 +s1 +1 +call f4(); +s1 +1 +s1 +1 +s1 +1 +s1 +1 +s1 +1 +call f4(); +s1 +1 +s1 +1 +s1 +1 +s1 +1 +s1 +1 +call f3(); +s1 +1 +s1 +1 +call f2(); +s1 +1 +s1 +1 +select sql_cache * from t1 where s1=1; +s1 +1 +insert into t1 values (2); +call f1(); +s1 +1 +2 +s1 +1 +2 +s1 +1 +2 +select sql_cache * from t1 where s1=1; +s1 +1 +select sql_cache * from t1; +s1 +1 +2 +call f1(); +s1 +1 +2 +s1 +1 +2 +s1 +1 +2 +call f3(); +s1 +1 +2 +s1 +1 +call f3(); +s1 +1 +2 +s1 +1 +call f1(); +s1 +1 +2 +s1 +1 +2 +s1 +1 +2 drop procedure f1; +drop procedure f2; +drop procedure f3; +drop procedure f4; drop table t1; set GLOBAL query_cache_size=0; SET GLOBAL query_cache_size=102400; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index e8e30b3653a..f6b7409ea6a 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1,4 +1,4 @@ -drop table if exists t1, t2; +drop table if exists t1, t2, t3; CREATE TABLE t1 ( event_date date DEFAULT '0000-00-00' NOT NULL, type int(11) DEFAULT '0' NOT NULL, @@ -521,8 +521,8 @@ select count(*) from t1 where x = 18446744073709551601; count(*) 1 create table t2 (x bigint not null); -insert into t2(x) values (0xfffffffffffffff0); -insert into t2(x) values (0xfffffffffffffff1); +insert into t2(x) values (cast(0xfffffffffffffff0+0 as signed)); +insert into t2(x) values (cast(0xfffffffffffffff1+0 as signed)); select * from t2; x -16 @@ -768,3 +768,52 @@ SELECT * FROM t1; a 2 DROP TABLE t1; +create table t1 (a int, b int, primary key(a,b)); +create view v1 as select a, b from t1; +INSERT INTO `t1` VALUES +(0,0),(1,0),(2,0),(3,0),(4,0),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(11,2),(12,2) +,(13,2),(14,2),(15,3),(16,3),(17,3),(18,3),(19,3); +explain select * from t1 where a in (3,4) and b in (1,2,3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +explain select * from v1 where a in (3,4) and b in (1,2,3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +explain select * from t1 where a between 3 and 4 and b between 1 and 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +explain select * from v1 where a between 3 and 4 and b between 1 and 2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +drop view v1; +drop table t1; +create table t3 (a int); +insert into t3 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a varchar(10), filler char(200), key(a)) charset=binary; +insert into t1 values ('a',''); +insert into t1 values ('a ',''); +insert into t1 values ('a ', ''); +insert into t1 select concat('a', 1000 + A.a + 10 * (B.a + 10 * C.a)), '' + from t3 A, t3 B, t3 C; +create table t2 (a varchar(10), filler char(200), key(a)); +insert into t2 select * from t1; +explain select * from t1 where a between 'a' and 'a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 13 NULL # Using where +explain select * from t1 where a = 'a' or a='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 13 NULL # Using where +explain select * from t2 where a between 'a' and 'a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref a a 13 const # Using where +explain select * from t2 where a = 'a' or a='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref a a 13 const # Using where +update t1 set a='b' where a<>'a'; +explain select * from t1 where a not between 'b' and 'b'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 13 NULL # Using where +select a, hex(filler) from t1 where a not between 'b' and 'b'; +a hex(filler) +a 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +drop table t1,t2,t3; diff --git a/mysql-test/r/rowid_order_innodb.result b/mysql-test/r/rowid_order_innodb.result index d55029f9064..f76002e9cb2 100644 --- a/mysql-test/r/rowid_order_innodb.result +++ b/mysql-test/r/rowid_order_innodb.result @@ -178,9 +178,9 @@ insert into t1 values ('','empt',2,2), ('dddd','d--d',2,2); select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3; pk1 pk2 key1 key2 + empt 2 2 a a--a 2 2 bb b--b 2 2 ccc c--c 2 2 dddd d--d 2 2 - empt 2 2 drop table t1; diff --git a/mysql-test/r/rpl_charset.result b/mysql-test/r/rpl_charset.result index b27acc0972e..28f694a3933 100644 --- a/mysql-test/r/rpl_charset.result +++ b/mysql-test/r/rpl_charset.result @@ -246,7 +246,8 @@ CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)); SET TIMESTAMP=1000000000; SET @@session.character_set_client=7,@@session.collation_connection=51,@@session.collation_server=30; INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; drop table t1; create table `t1` ( diff --git a/mysql-test/r/rpl_ddl.result b/mysql-test/r/rpl_ddl.result index 3737883b694..2a97da63c64 100644 --- a/mysql-test/r/rpl_ddl.result +++ b/mysql-test/r/rpl_ddl.result @@ -1072,6 +1072,622 @@ Database (mysqltest3) mysqltest3 -------- switch to master ------- + +######## CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 15 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to master ------- +CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1"; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer @ +Modified # +Created # +Security_type DEFINER +Comment + +######## ALTER PROCEDURE p1 COMMENT "I have been altered" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 16 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to master ------- +ALTER PROCEDURE p1 COMMENT "I have been altered"; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment I have been altered + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer @ +Modified # +Created # +Security_type DEFINER +Comment I have been altered + +######## DROP PROCEDURE p1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 17 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to master ------- +DROP PROCEDURE p1; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; + +######## CREATE OR REPLACE VIEW v1 as select * from t1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 18 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to master ------- +CREATE OR REPLACE VIEW v1 as select * from t1; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +######## ALTER VIEW v1 AS select f1 from t1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 19 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to master ------- +ALTER VIEW v1 AS select f1 from t1; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +######## DROP VIEW IF EXISTS v1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 20 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to master ------- +DROP VIEW IF EXISTS v1; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +ERROR 42S02: Table 'mysqltest1.v1' doesn't exist + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +ERROR 42S02: Table 'mysqltest1.v1' doesn't exist + +######## CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 21 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to master ------- +CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode +trg1 INSERT t1 SET @a:=1 BEFORE NULL + +-------- switch to slave ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode +trg1 INSERT t1 SET @a:=1 BEFORE NULL + +######## DROP TRIGGER trg1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 22 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to master ------- +DROP TRIGGER trg1; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode + +-------- switch to slave ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode + +######## CREATE USER user1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 23 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to master ------- +CREATE USER user1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'user1'; +user +user1 + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'user1'; +user +user1 + +######## RENAME USER user1@localhost TO rename1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 24 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to master ------- +RENAME USER user1@localhost TO rename1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +rename1 + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +rename1 + +######## DROP USER rename1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 25 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to master ------- +DROP USER rename1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user DROP DATABASE IF EXISTS mysqltest1; DROP DATABASE IF EXISTS mysqltest2; DROP DATABASE IF EXISTS mysqltest3; diff --git a/mysql-test/r/rpl_dual_pos_advance.result b/mysql-test/r/rpl_dual_pos_advance.result new file mode 100644 index 00000000000..257baa81b74 --- /dev/null +++ b/mysql-test/r/rpl_dual_pos_advance.result @@ -0,0 +1,22 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +reset master; +change master to master_host="127.0.0.1",master_port=SLAVE_PORT,master_user="root"; +start slave; +create table t1 (n int); +create table t4 (n int); +create table t5 (n int); +create table t6 (n int); +show tables; +Tables_in_test +t1 +t4 +t5 +t6 +stop slave; +reset slave; +drop table t1,t4,t5,t6; diff --git a/mysql-test/r/rpl_flush_log_loop.result b/mysql-test/r/rpl_flush_log_loop.result index b4e840ba271..f9bd42ec26c 100644 --- a/mysql-test/r/rpl_flush_log_loop.result +++ b/mysql-test/r/rpl_flush_log_loop.result @@ -4,10 +4,10 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +stop slave; change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=MASTER_PORT; start slave; -stop slave; change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=SLAVE_PORT; start slave; diff --git a/mysql-test/r/rpl_flush_tables.result b/mysql-test/r/rpl_flush_tables.result index ca2e77cac66..667530c4071 100644 --- a/mysql-test/r/rpl_flush_tables.result +++ b/mysql-test/r/rpl_flush_tables.result @@ -38,3 +38,9 @@ master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1 master-bin.000001 # Query 1 # use `test`; flush tables select * from t3; a +stop slave; +drop table t1; +flush tables with read lock; +start slave; +stop slave; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction diff --git a/mysql-test/r/rpl_multi_delete.result b/mysql-test/r/rpl_multi_delete.result index e94a4e7947e..d2c68eee62e 100644 --- a/mysql-test/r/rpl_multi_delete.result +++ b/mysql-test/r/rpl_multi_delete.result @@ -19,4 +19,13 @@ a select * from t2; a 1 +delete from t1; +delete from t2; +insert into t1 values(1); +insert into t2 values(1); +DELETE t1.*, t2.* from t1, t2; +select * from t1; +a +select * from t2; +a drop table t1,t2; diff --git a/mysql-test/r/rpl_multi_delete2.result b/mysql-test/r/rpl_multi_delete2.result index c6c088111fc..73db9f62eb4 100644 --- a/mysql-test/r/rpl_multi_delete2.result +++ b/mysql-test/r/rpl_multi_delete2.result @@ -4,6 +4,26 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +set sql_log_bin=0; +create database mysqltest_from; +set sql_log_bin=1; +create database mysqltest_to; +use mysqltest_from; +drop table if exists a; +CREATE TABLE a (i INT); +INSERT INTO a VALUES(1); +DELETE alias FROM a alias WHERE alias.i=1; +SELECT * FROM a; +i +insert into a values(2),(3); +delete a alias FROM a alias where alias.i=2; +select * from a; +i +3 +use mysqltest_to; +select * from a; +i +3 create table t1 (a int); create table t2 (a int); insert into t1 values (1); @@ -15,7 +35,10 @@ select * from t2; a 1 select * from t1; -ERROR 42S02: Table 'test.t1' doesn't exist +ERROR 42S02: Table 'mysqltest_to.t1' doesn't exist select * from t2; -ERROR 42S02: Table 'test.t2' doesn't exist -drop table t1,t2; +ERROR 42S02: Table 'mysqltest_to.t2' doesn't exist +set sql_log_bin=0; +drop database mysqltest_from; +set sql_log_bin=1; +drop database mysqltest_to; diff --git a/mysql-test/r/rpl_multi_update.result b/mysql-test/r/rpl_multi_update.result index 34f99746c7d..04cb1bc7460 100644 --- a/mysql-test/r/rpl_multi_update.result +++ b/mysql-test/r/rpl_multi_update.result @@ -24,3 +24,16 @@ a b 1 0 2 1 UPDATE t1, t2 SET t1.b = t2.b WHERE t1.a = t2.a; +delete from t1; +delete from t2; +insert into t1 values(1,1); +insert into t2 values(1,1); +update t1 set a=2; +UPDATE t1, t2 SET t1.a = t2.a; +select * from t1; +a b +1 1 +select * from t2; +a b +1 1 +drop table t1, t2; diff --git a/mysql-test/r/rpl_multi_update2.result b/mysql-test/r/rpl_multi_update2.result index 99356ebf970..5bb262764fa 100644 --- a/mysql-test/r/rpl_multi_update2.result +++ b/mysql-test/r/rpl_multi_update2.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +drop table if exists t1,t2; CREATE TABLE t1 ( a int unsigned not null auto_increment primary key, b int unsigned @@ -40,3 +41,15 @@ SELECT * FROM t2 ORDER BY a; a b 1 0 2 1 +drop table t1,t2; +reset master; +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (0); +UPDATE t1, (SELECT 3 as b) AS x SET t1.a = x.b; +select * from t1; +a +3 +select * from t1; +a +3 +drop table t1; diff --git a/mysql-test/r/rpl_multi_update3.result b/mysql-test/r/rpl_multi_update3.result index 1b757b1400c..b81af7c6e39 100644 --- a/mysql-test/r/rpl_multi_update3.result +++ b/mysql-test/r/rpl_multi_update3.result @@ -122,3 +122,75 @@ SELECT * FROM t1; i j x y z 1 2 23 24 71 DROP TABLE t1, t2, t3; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +DROP TABLE IF EXISTS t2; +Warnings: +Note 1051 Unknown table 't2' +CREATE TABLE t1 ( +idp int(11) NOT NULL default '0', +idpro int(11) default NULL, +price decimal(19,4) default NULL, +PRIMARY KEY (idp) +); +CREATE TABLE t2 ( +idpro int(11) NOT NULL default '0', +price decimal(19,4) default NULL, +nbprice int(11) default NULL, +PRIMARY KEY (idpro) +); +INSERT INTO t1 VALUES +(1,1,'3.0000'), +(2,2,'1.0000'), +(3,1,'1.0000'), +(4,1,'4.0000'), +(5,3,'2.0000'), +(6,2,'4.0000'); +INSERT INTO t2 VALUES +(1,'0.0000',0), +(2,'0.0000',0), +(3,'0.0000',0); +update +t2 +join +( select idpro, min(price) as min_price, count(*) as nbr_price +from t1 +where idpro>0 and price>0 +group by idpro +) as table_price +on t2.idpro = table_price.idpro +set t2.price = table_price.min_price, +t2.nbprice = table_price.nbr_price; +select "-- MASTER AFTER JOIN --" as ""; + +-- MASTER AFTER JOIN -- +select * from t1; +idp idpro price +1 1 3.0000 +2 2 1.0000 +3 1 1.0000 +4 1 4.0000 +5 3 2.0000 +6 2 4.0000 +select * from t2; +idpro price nbprice +1 1.0000 3 +2 1.0000 2 +3 2.0000 1 +select "-- SLAVE AFTER JOIN --" as ""; + +-- SLAVE AFTER JOIN -- +select * from t1; +idp idpro price +1 1 3.0000 +2 2 1.0000 +3 1 1.0000 +4 1 4.0000 +5 3 2.0000 +6 2 4.0000 +select * from t2; +idpro price nbprice +1 1.0000 3 +2 1.0000 2 +3 2.0000 1 diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result index 8bcae3d25ad..d8666080a71 100644 --- a/mysql-test/r/rpl_replicate_do.result +++ b/mysql-test/r/rpl_replicate_do.result @@ -29,3 +29,14 @@ drop table if exists t1,t2,t11; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1658 # # master-bin.000001 Yes Yes test.t1 0 0 1658 # None 0 No # +create table t1 (ts timestamp); +set one_shot time_zone='met'; +insert into t1 values('2005-08-12 00:00:00'); +set one_shot time_zone='met'; +select * from t1; +ts +2005-08-12 00:00:00 +set one_shot time_zone='met'; +select * from t1; +ts +2005-08-12 00:00:00 diff --git a/mysql-test/r/rpl_slave_status.result b/mysql-test/r/rpl_slave_status.result index 8badbab85ff..2146132aeb0 100644 --- a/mysql-test/r/rpl_slave_status.result +++ b/mysql-test/r/rpl_slave_status.result @@ -19,7 +19,7 @@ flush privileges; stop slave; start slave; show slave status; -Slave_IO_State Connecting to master +Slave_IO_State # Master_Host 127.0.0.1 Master_User rpl Master_Port MASTER_MYPORT diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 394f93f2ea0..5f1c3afd14d 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -121,7 +121,7 @@ call foo4(); Got one of the listed errors show warnings; Level Code Message -Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1' +Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'127.0.0.1' for table 't1' Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes alter procedure foo4 sql security invoker; call foo4(); @@ -264,6 +264,14 @@ master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) select * from t1; a 1 +create procedure foo() +not deterministic +reads sql data +select * from t1; +call foo(); +a +1 +drop procedure foo; drop function fn1; drop database mysqltest1; drop user "zedjzlcsjhd"@127.0.0.1; diff --git a/mysql-test/r/rpl_sp_effects.result b/mysql-test/r/rpl_sp_effects.result index 8bcbf1a60d0..bf8128d9385 100644 --- a/mysql-test/r/rpl_sp_effects.result +++ b/mysql-test/r/rpl_sp_effects.result @@ -156,3 +156,60 @@ slave: 6 drop procedure p1; drop function f1; drop table t1,t2; +create table t1 (a int); +create procedure p1() +begin +insert into t1 values(@x); +set @x=@x+1; +insert into t1 values(@x); +if (f2()) then +insert into t1 values(1243); +end if; +end// +create function f2() returns int +begin +insert into t1 values(@z); +set @z=@z+1; +insert into t1 values(@z); +return 0; +end// +create function f1() returns int +begin +insert into t1 values(@y); +call p1(); +return 0; +end// +set @x=10; +set @y=20; +set @z=100; +select f1(); +f1() +0 +set @x=30; +call p1(); +select 'master', a from t1; +master a +master 20 +master 10 +master 11 +master 100 +master 101 +master 30 +master 31 +master 101 +master 102 +select 'slave', a from t1; +slave a +slave 20 +slave 10 +slave 11 +slave 100 +slave 101 +slave 30 +slave 31 +slave 101 +slave 102 +drop table t1; +drop function f1; +drop function f2; +drop procedure p1; diff --git a/mysql-test/r/rpl_timezone.result b/mysql-test/r/rpl_timezone.result index 85637638f99..64d05aa787e 100644 --- a/mysql-test/r/rpl_timezone.result +++ b/mysql-test/r/rpl_timezone.result @@ -63,7 +63,8 @@ delete from t1; SET TIMESTAMP=100000000; SET @@session.time_zone='Europe/Moscow'; insert into t1 values ('20040101000000'), ('20040611093902'); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; delete from t1; set time_zone='UTC'; diff --git a/mysql-test/r/rpl_view.result b/mysql-test/r/rpl_view.result index ce807a361ba..cf4c161b296 100644 --- a/mysql-test/r/rpl_view.result +++ b/mysql-test/r/rpl_view.result @@ -6,6 +6,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; drop table if exists t1,v1; drop view if exists t1,v1; +reset master; create table t1 (a int); insert into t1 values (1); create view v1 as select a from t1; @@ -42,3 +43,14 @@ drop view v1; select * from v1 order by a; ERROR 42S02: Table 'test.v1' doesn't exist drop table t1; +show binlog events limit 1,100; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query 1 # use `test`; create table t1 (a int) +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (1) +slave-bin.000001 # Query 1 # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=root@localhost SQL SECURITY DEFINER VIEW v1 AS select a from t1 +slave-bin.000001 # Query 1 # use `test`; insert into v1 values (2) +slave-bin.000001 # Query 1 # use `test`; update v1 set a=3 where a=1 +slave-bin.000001 # Query 1 # use `test`; delete from v1 where a=2 +slave-bin.000001 # Query 1 # use `test`; ALTER ALGORITHM=UNDEFINED DEFINER=root@localhost SQL SECURITY DEFINER VIEW v1 AS select a as b from t1 +slave-bin.000001 # Query 1 # use `test`; drop view v1 +slave-bin.000001 # Query 1 # use `test`; drop table t1 diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 0d5c1aed485..fb61095cf22 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2,t3,t4; +drop table if exists t1,t2,t3,t4,t11; drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; CREATE TABLE t1 ( @@ -2620,6 +2620,86 @@ select found_rows(); found_rows() 1 DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT); +(SELECT a, b AS c FROM t1) ORDER BY c+1; +a c +(SELECT a, b AS c FROM t1) ORDER BY b+1; +a c +SELECT a, b AS c FROM t1 ORDER BY c+1; +a c +SELECT a, b AS c FROM t1 ORDER BY b+1; +a c +drop table t1; +create table t1(f1 int, f2 int); +create table t2(f3 int); +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,1)); +f1 +select f1 from t1,t2 where f1=f2 and (f1,NULL) = ((1,1)); +f1 +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,NULL)); +f1 +insert into t1 values(1,1),(2,null); +insert into t2 values(2); +select * from t1,t2 where f1=f3 and (f1,f2) = (2,null); +f1 f2 f3 +select * from t1,t2 where f1=f3 and (f1,f2) <=> (2,null); +f1 f2 f3 +2 NULL 2 +drop table t1,t2; +create table t1 (f1 int not null auto_increment primary key, f2 varchar(10)); +create table t11 like t1; +insert into t1 values(1,""),(2,""); +show table status like 't1%'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Dynamic 2 20 X X X X X X X X latin1_swedish_ci NULL +t11 MyISAM 10 Dynamic 0 0 X X X X X X X X latin1_swedish_ci NULL +select 123 as a from t1 where f1 is null; +a +drop table t1,t11; +CREATE TABLE t1 (a INT, b INT); +(SELECT a, b AS c FROM t1) ORDER BY c+1; +a c +(SELECT a, b AS c FROM t1) ORDER BY b+1; +a c +SELECT a, b AS c FROM t1 ORDER BY c+1; +a c +SELECT a, b AS c FROM t1 ORDER BY b+1; +a c +drop table t1; +CREATE TABLE t1 ( a INT NOT NULL, b INT NOT NULL, UNIQUE idx (a,b) ); +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4); +CREATE TABLE t2 ( a INT NOT NULL, b INT NOT NULL, e INT ); +INSERT INTO t2 VALUES ( 1,10,1), (1,10,2), (1,11,1), (1,11,2), (1,2,1), (1,2,2),(1,2,3); +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +a b c d +1 2 1 1 +1 2 2 1 +1 2 3 1 +1 10 2 +1 11 2 +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t1.a, t1.b, c; +a b c d +1 10 4 +1 2 1 1 +1 2 2 1 +1 2 3 1 +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t2.a, t2.b, c; +a b c d +1 2 1 1 +1 2 2 1 +1 2 3 1 +1 10 2 +1 11 2 +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2,t1 +WHERE t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +a b c d +1 2 1 1 +1 2 2 1 +1 2 3 1 +DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1 ( city char(30) ); INSERT INTO t1 VALUES ('London'); INSERT INTO t1 VALUES ('Paris'); @@ -2885,6 +2965,63 @@ NULL SELECT IFNULL(NULL, NULL); IFNULL(NULL, NULL) NULL +SET @OLD_SQL_MODE12595=@@SQL_MODE, @@SQL_MODE=''; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; +Variable_name Value +sql_mode +CREATE TABLE BUG_12595(a varchar(100)); +INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +a +hakan% +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +a +hakan% +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +a +hakan% +hakank +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE ''; +a +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE '\\'; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; +a +ha%an +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; +Variable_name Value +sql_mode NO_BACKSLASH_ESCAPES +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +a +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +a +hakan% +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE '\\'; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\n%' ESCAPE '\n'; +ERROR HY000: Incorrect arguments to ESCAPE +SET @@SQL_MODE=@OLD_SQL_MODE12595; +DROP TABLE BUG_12595; create table t1 (a char(1)); create table t2 (a char(1)); insert into t1 values ('a'),('b'),('c'); @@ -2897,3 +3034,150 @@ select * from t1 natural join t2 where a = 'b'; a b drop table t1, t2; +CREATE TABLE t1 (`id` TINYINT); +CREATE TABLE t2 (`id` TINYINT); +CREATE TABLE t3 (`id` TINYINT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +drop table t1, t2, t3; +create table t1 (a int(10),b int(10)); +create table t2 (a int(10),b int(10)); +insert into t1 values (1,10),(2,20),(3,30); +insert into t2 values (1,10); +select * from t1 inner join t2 using (A); +a b b +1 10 10 +select * from t1 inner join t2 using (a); +a b b +1 10 10 +drop table t1, t2; +create table t1 (a int, c int); +create table t2 (b int); +create table t3 (b int, a int); +create table t4 (c int); +insert into t1 values (1,1); +insert into t2 values (1); +insert into t3 values (1,1); +insert into t4 values (1); +select * from t1 join t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +a c b b a +1 1 1 1 1 +select * from t1, t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +ERROR 42S22: Unknown column 't1.a' in 'on clause' +select * from t1 join t2 join t3 join t4 on (t1.a = t4.c and t2.b = t4.c); +a c b b a c +1 1 1 1 1 1 +select * from t1 join t2 join t4 using (c); +c a b +1 1 1 +drop table t1, t2, t3, t4; +create table t1(x int, y int); +create table t2(x int, y int); +create table t3(x int, primary key(x)); +insert into t1 values (1, 1), (2, 1), (3, 1), (4, 3), (5, 6), (6, 6); +insert into t2 values (1, 1), (2, 1), (3, 3), (4, 6), (5, 6); +insert into t3 values (1), (2), (3), (4), (5); +select t1.x, t3.x from t1, t2, t3 where t1.x = t2.x and t3.x >= t1.y and t3.x <= t2.y; +x x +1 1 +2 1 +3 1 +3 2 +3 3 +4 3 +4 4 +4 5 +drop table t1,t2,t3; +create table t1 (id char(16) not null default '', primary key (id)); +insert into t1 values ('100'),('101'),('102'); +create table t2 (id char(16) default null); +insert into t2 values (1); +create view v1 as select t1.id from t1; +create view v2 as select t2.id from t2; +create view v3 as select (t1.id+2) as id from t1 natural left join t2; +select t1.id from t1 left join v2 using (id); +id +100 +101 +102 +select t1.id from v2 right join t1 using (id); +id +100 +101 +102 +select t1.id from t1 left join v3 using (id); +id +100 +101 +102 +select * from t1 left join v2 using (id); +id +100 +101 +102 +select * from v2 right join t1 using (id); +id +100 +101 +102 +select * from t1 left join v3 using (id); +id +100 +101 +102 +select v1.id from v1 left join v2 using (id); +id +100 +101 +102 +select v1.id from v2 right join v1 using (id); +id +100 +101 +102 +select v1.id from v1 left join v3 using (id); +id +100 +101 +102 +select * from v1 left join v2 using (id); +id +100 +101 +102 +select * from v2 right join v1 using (id); +id +100 +101 +102 +select * from v1 left join v3 using (id); +id +100 +101 +102 +drop table t1, t2; +drop view v1, v2, v3; +create table t1 (id int(11) not null default '0'); +insert into t1 values (123),(191),(192); +create table t2 (id char(16) character set utf8 not null); +insert into t2 values ('58013'),('58014'),('58015'),('58016'); +create table t3 (a_id int(11) not null, b_id char(16) character set utf8); +insert into t3 values (123,null),(123,null),(123,null),(123,null),(123,null),(123,'58013'); +select count(*) +from t1 inner join (t3 left join t2 on t2.id = t3.b_id) on t1.id = t3.a_id; +count(*) +6 +select count(*) +from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; +count(*) +6 +drop table t1,t2,t3; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index c143c7f0f29..20f695d9ac0 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -557,3 +557,10 @@ DROP TABLE tyt2; DROP TABLE urkunde; SHOW TABLES FROM non_existing_database; ERROR 42000: Unknown database 'non_existing_database' +flush tables; +SHOW TABLE STATUS like 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 NULL NULL NULL NULL # # # # NULL NULL NULL NULL NULL NULL NULL NULL Incorrect information in file: './test/t1.frm' +show create table t1; +ERROR HY000: Incorrect information in file: './test/t1.frm' +drop table t1; diff --git a/mysql-test/r/skip_grants.result b/mysql-test/r/skip_grants.result index c0c20eb25be..4d723f8e12a 100644 --- a/mysql-test/r/skip_grants.result +++ b/mysql-test/r/skip_grants.result @@ -4,7 +4,11 @@ drop procedure if exists f1; use test; create table t1 (field1 INT); CREATE VIEW v1 AS SELECT field1 FROM t1; -drop view v1; +ERROR HY000: View definer is not fully qualified drop table t1; create procedure f1() select 1; drop procedure f1; +create table t1 (a int); +create definer='user'@'host' sql security definer view v1 as select * from t1; +drop view v1; +drop table t1; diff --git a/mysql-test/r/skip_name_resolve.result b/mysql-test/r/skip_name_resolve.result index d8d873699a5..a969c5c9ae0 100644 --- a/mysql-test/r/skip_name_resolve.result +++ b/mysql-test/r/skip_name_resolve.result @@ -5,3 +5,10 @@ GRANT USAGE ON *.* TO 'mysqltest_1'@'127.0.0.1/255.255.255.255' GRANT ALL PRIVILEGES ON `test`.* TO 'mysqltest_1'@'127.0.0.1/255.255.255.255' REVOKE ALL ON test.* FROM mysqltest_1@'127.0.0.1/255.255.255.255'; DROP USER mysqltest_1@'127.0.0.1/255.255.255.255'; +select user(); +user() +# +show processlist; +Id User Host db Command Time State Info +# root # test Sleep # NULL +# root # test Query # NULL show processlist diff --git a/mysql-test/r/sp-big.result b/mysql-test/r/sp-big.result index 004ff586aab..1f0b6b34651 100644 --- a/mysql-test/r/sp-big.result +++ b/mysql-test/r/sp-big.result @@ -13,3 +13,49 @@ select @value; 3 drop procedure test.longprocedure; drop table t1; +create table t1 (f1 char(100) , f2 mediumint , f3 int , f4 real, f5 numeric); +insert into t1 (f1, f2, f3, f4, f5) values +("This is a test case for for Bug#9819", 1, 2, 3.0, 4.598); +Warnings: +Note 1265 Data truncated for column 'f5' at row 1 +create table t2 like t1; +select count(*) from t1; +count(*) +256 +select count(*) from t2; +count(*) +0 +create procedure p1() +begin +declare done integer default 0; +declare vf1 char(100) ; +declare vf2 mediumint; +declare vf3 int ; +declare vf4 real ; +declare vf5 numeric ; +declare cur1 cursor for select f1,f2,f3,f4,f5 from t1; +declare continue handler for sqlstate '02000' set done = 1; +open cur1; +while done <> 1 do +fetch cur1 into vf1, vf2, vf3, vf4, vf5; +if not done then +insert into t2 values (vf1, vf2, vf3, vf4, vf5); +end if; +end while; +close cur1; +end| +call p1(); +select count(*) from t1; +count(*) +256 +select count(*) from t2; +count(*) +256 +select f1 from t1 limit 1; +f1 +This is a test case for for Bug#9819 +select f1 from t2 limit 1; +f1 +This is a test case for for Bug#9819 +drop procedure p1; +drop table t1, t2; diff --git a/mysql-test/r/sp-dynamic.result b/mysql-test/r/sp-dynamic.result new file mode 100644 index 00000000000..8fe469431cc --- /dev/null +++ b/mysql-test/r/sp-dynamic.result @@ -0,0 +1,364 @@ +create procedure p1() +begin +prepare stmt from "select 1"; +execute stmt; +execute stmt; +execute stmt; +deallocate prepare stmt; +end| +call p1()| +1 +1 +1 +1 +1 +1 +call p1()| +1 +1 +1 +1 +1 +1 +call p1()| +1 +1 +1 +1 +1 +1 +drop procedure p1| +create procedure p1() +begin +execute stmt; +end| +prepare stmt from "call p1()"| +execute stmt| +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +execute stmt| +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +execute stmt| +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +call p1()| +ERROR HY000: Recursive stored routines are not allowed. +call p1()| +ERROR HY000: Recursive stored routines are not allowed. +call p1()| +ERROR HY000: Recursive stored routines are not allowed. +drop procedure p1| +create procedure p1() +begin +prepare stmt from "create procedure p2() begin select 1; end"; +execute stmt; +deallocate prepare stmt; +end| +call p1()| +ERROR HY000: This command is not supported in the prepared statement protocol yet +call p1()| +ERROR HY000: This command is not supported in the prepared statement protocol yet +drop procedure p1| +create procedure p1() +begin +prepare stmt from "drop procedure p2"; +execute stmt; +deallocate prepare stmt; +end| +call p1()| +ERROR HY000: This command is not supported in the prepared statement protocol yet +call p1()| +ERROR HY000: This command is not supported in the prepared statement protocol yet +drop procedure p1| +create procedure p1() +begin +prepare stmt_drop from "drop table if exists t1"; +execute stmt_drop; +prepare stmt from "create table t1 (a int)"; +execute stmt; +insert into t1 (a) values (1); +select * from t1; +deallocate prepare stmt; +deallocate prepare stmt_drop; +end| +call p1()| +a +1 +Warnings: +Note 1051 Unknown table 't1' +call p1()| +a +1 +drop procedure p1| +create procedure p1() +begin +set @tab_name=concat("tab_", replace(curdate(), '-', '_')); +set @drop_sql=concat("drop table if exists ", @tab_name); +set @create_sql=concat("create table ", @tab_name, " (a int)"); +set @insert_sql=concat("insert into ", @tab_name, " values (1), (2), (3)"); +set @select_sql=concat("select * from ", @tab_name); +select @tab_name; +select @drop_sql; +select @create_sql; +select @insert_sql; +select @select_sql; +prepare stmt_drop from @drop_sql; +execute stmt_drop; +prepare stmt from @create_sql; +execute stmt; +prepare stmt from @insert_sql; +execute stmt; +prepare stmt from @select_sql; +execute stmt; +execute stmt_drop; +deallocate prepare stmt; +deallocate prepare stmt_drop; +end| +call p1()| +call p1()| +drop procedure p1| +create procedure p1() +begin +prepare stmt_drop from "drop table if exists t1"; +execute stmt_drop; +prepare stmt from "create table t1 (a int)"; +execute stmt; +deallocate prepare stmt; +deallocate prepare stmt_drop; +end| +drop function if exists f1| +create function f1(a int) returns int +begin +call p1(); +return 1; +end| +select f1(0)| +ERROR 0A000: Dynamic SQL is not allowed in stored function or trigger +select f1(f1(0))| +ERROR 0A000: Dynamic SQL is not allowed in stored function or trigger +select f1(f1(f1(0)))| +ERROR 0A000: Dynamic SQL is not allowed in stored function or trigger +drop function f1| +drop procedure p1| +create procedure p1() +begin +drop table if exists t1; +create table t1 (id integer not null primary key, +name varchar(20) not null); +insert into t1 (id, name) values (1, 'aaa'), (2, 'bbb'), (3, 'ccc'); +prepare stmt from "select name from t1"; +execute stmt; +select name from t1; +execute stmt; +prepare stmt from +"select name from t1 where name=(select name from t1 where id=2)"; +execute stmt; +select name from t1 where name=(select name from t1 where id=2); +execute stmt; +end| +call p1()| +name +aaa +bbb +ccc +name +aaa +bbb +ccc +name +aaa +bbb +ccc +name +bbb +name +bbb +name +bbb +call p1()| +name +aaa +bbb +ccc +name +aaa +bbb +ccc +name +aaa +bbb +ccc +name +bbb +name +bbb +name +bbb +drop procedure p1| +prepare stmt from "select * from t1"| +create procedure p1() +begin +execute stmt; +deallocate prepare stmt; +end| +call p1()| +id name +1 aaa +2 bbb +3 ccc +call p1()| +ERROR HY000: Unknown prepared statement handler (stmt) given to EXECUTE +drop procedure p1| +create procedure p1() +begin +declare a char(10); +set a="sp-variable"; +set @a="mysql-variable"; +prepare stmt from "select 'dynamic sql:', @a, a"; +execute stmt; +end| +call p1()| +ERROR 42S22: Unknown column 'a' in 'field list' +call p1()| +ERROR 42S22: Unknown column 'a' in 'field list' +drop procedure p1| +create procedure p1() +begin +prepare stmt from 'select ? as a'; +execute stmt using @a; +end| +set @a=1| +call p1()| +a +1 +call p1()| +a +1 +drop procedure p1| +drop table if exists t1| +create table t1 (id integer primary key auto_increment, +stmt_text char(35), status varchar(20))| +insert into t1 (stmt_text) values +("select 1"), ("flush tables"), ("handler t1 open as ha"), +("analyze table t1"), ("check table t1"), ("checksum table t1"), +("check table t1"), ("optimize table t1"), ("repair table t1"), +("describe extended select * from t1"), +("help help"), ("show databases"), ("show tables"), +("show table status"), ("show open tables"), ("show storage engines"), +("insert into t1 (id) values (1)"), ("update t1 set status=''"), +("delete from t1"), ("truncate t1"), ("call p1()"), ("foo bar")| +create procedure p1() +begin +declare v_stmt_text varchar(255); +declare v_id integer; +declare done int default 0; +declare c cursor for select id, stmt_text from t1; +declare continue handler for 1295 -- ER_UNSUPPORTED_PS +set @status='not supported'; +declare continue handler for 1064 -- ER_SYNTAX_ERROR +set @status='syntax error'; +declare continue handler for sqlstate '02000' set done = 1; +prepare update_stmt from "update t1 set status=? where id=?"; +open c; +repeat +if not done then +fetch c into v_id, v_stmt_text; +set @id=v_id, @stmt_text=v_stmt_text; +set @status="supported"; +prepare stmt from @stmt_text; +execute update_stmt using @status, @id; +end if; +until done end repeat; +deallocate prepare update_stmt; +end| +call p1()| +select * from t1| +id stmt_text status +1 select 1 supported +2 flush tables not supported +3 handler t1 open as ha not supported +4 analyze table t1 not supported +5 check table t1 not supported +6 checksum table t1 not supported +7 check table t1 not supported +8 optimize table t1 not supported +9 repair table t1 not supported +10 describe extended select * from t1 supported +11 help help not supported +12 show databases supported +13 show tables supported +14 show table status supported +15 show open tables supported +16 show storage engines supported +17 insert into t1 (id) values (1) supported +18 update t1 set status='' supported +19 delete from t1 supported +20 truncate t1 supported +21 call p1() supported +22 foo bar syntax error +drop procedure p1| +drop table t1| +prepare stmt from 'select 1'| +create procedure p1() execute stmt| +call p1()| +1 +1 +call p1()| +1 +1 +drop procedure p1| +create function f1() returns int +begin +deallocate prepare stmt; +return 1; +end| +ERROR 0A000: Dynamic SQL is not allowed in stored function or trigger +create procedure p1() +begin +prepare stmt from 'select 1 A'; +execute stmt; +end| +prepare stmt from 'call p1()'| +execute stmt| +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +execute stmt| +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +drop procedure p1| +drop table if exists t1, t2| +create procedure p1 (a int) language sql deterministic +begin +declare rsql varchar(100); +drop table if exists t1, t2; +set @rsql= "create table t1 (a int)"; +select @rsql; +prepare pst from @rsql; +execute pst; +set @rsql= null; +set @rsql= "create table t2 (a int)"; +select @rsql; +prepare pst from @rsql; +execute pst; +drop table if exists t1, t2; +end| +set @a:=0| +call p1(@a)| +@rsql +create table t1 (a int) +@rsql +create table t2 (a int) +Warnings: +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' +select @a| +@a +0 +call p1(@a)| +@rsql +create table t1 (a int) +@rsql +create table t2 (a int) +Warnings: +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' +select @a| +@a +0 +drop procedure if exists p1| diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 23644f57353..7ee2d168ddd 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -618,7 +618,7 @@ select * from t1| call bug8408_p()| val x select bug8408_f()| -ERROR 0A000: PROCEDURE test.bug8408_p can't return a result set in the given context +ERROR 0A000: Not allowed to return a result set from a function drop procedure bug8408_p| drop function bug8408_f| create function bug8408() returns int @@ -665,20 +665,6 @@ select default(t30.s1) from t30; end| drop procedure bug10969| drop table t1| -prepare stmt from "select 1"; -create procedure p() deallocate prepare stmt; -ERROR 0A000: DEALLOCATE is not allowed in stored procedures -create function f() returns int begin deallocate prepare stmt; -ERROR 0A000: DEALLOCATE is not allowed in stored procedures -create procedure p() prepare stmt from "select 1"; -ERROR 0A000: PREPARE is not allowed in stored procedures -create function f() returns int begin prepare stmt from "select 1"; -ERROR 0A000: PREPARE is not allowed in stored procedures -create procedure p() execute stmt; -ERROR 0A000: EXECUTE is not allowed in stored procedures -create function f() returns int begin execute stmt; -ERROR 0A000: EXECUTE is not allowed in stored procedures -deallocate prepare stmt; create table t1(f1 int); create table t2(f1 int); CREATE PROCEDURE SP001() @@ -706,6 +692,7 @@ END P1| call SP001(); TEMP_SUM 0 +ERROR 24000: Cursor is not open drop procedure SP001; drop table t1, t2; drop function if exists bug11394| @@ -772,3 +759,127 @@ execute stmt; ERROR 42000: FUNCTION test.bug11834_1 does not exist deallocate prepare stmt; drop function bug11834_2; +DROP FUNCTION IF EXISTS bug12953| +CREATE FUNCTION bug12953() RETURNS INT +BEGIN +OPTIMIZE TABLE t1; +RETURN 1; +END| +ERROR 0A000: OPTIMIZE TABLE is not allowed in stored procedures +DROP FUNCTION IF EXISTS bug12995| +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 OPEN; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 READ FIRST; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 CLOSE; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +SELECT bug12995()| +ERROR 42000: FUNCTION test.bug12995 does not exist +drop procedure if exists bug12712; +drop function if exists bug12712; +create procedure bug12712() +set session autocommit = 0; +select @@autocommit; +@@autocommit +1 +set @au = @@autocommit; +call bug12712(); +select @@autocommit; +@@autocommit +0 +set session autocommit = @au; +create function bug12712() +returns int +begin +call bug12712(); +return 0; +end| +set @x = bug12712()| +ERROR HY000: Not allowed to set autocommit from a stored function or trigger +drop procedure bug12712| +drop function bug12712| +create function bug12712() +returns int +begin +set session autocommit = 0; +return 0; +end| +ERROR HY000: Not allowed to set autocommit from a stored function or trigger +create function bug12712() +returns int +begin +set @@autocommit = 0; +return 0; +end| +ERROR HY000: Not allowed to set autocommit from a stored function or trigger +create function bug12712() +returns int +begin +set local autocommit = 0; +return 0; +end| +ERROR HY000: Not allowed to set autocommit from a stored function or trigger +create trigger bug12712 +before insert on t1 for each row set session autocommit = 0; +ERROR HY000: Not allowed to set autocommit from a stored function or trigger +drop procedure if exists bug13510_1| +drop procedure if exists bug13510_2| +drop procedure if exists bug13510_3| +drop procedure if exists bug13510_4| +create procedure bug13510_1() +begin +declare password varchar(10); +set password = 'foo1'; +select password; +end| +ERROR 42000: Variable 'password' must be quoted with `...`, or renamed +create procedure bug13510_2() +begin +declare names varchar(10); +set names = 'foo2'; +select names; +end| +ERROR 42000: Variable 'names' must be quoted with `...`, or renamed +create procedure bug13510_3() +begin +declare password varchar(10); +set `password` = 'foo3'; +select password; +end| +create procedure bug13510_4() +begin +declare names varchar(10); +set `names` = 'foo4'; +select names; +end| +call bug13510_3()| +password +foo3 +call bug13510_4()| +names +foo4 +drop procedure bug13510_3| +drop procedure bug13510_4| +create database mysqltest1; +use mysqltest1; +drop database mysqltest1; +create function f1() returns int return 1; +ERROR 3D000: No database selected +create procedure p1(out param1 int) +begin +select count(*) into param1 from t3; +end| +ERROR 3D000: No database selected +use test; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index eb2e2ce334e..614e670f25d 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -251,3 +251,15 @@ drop procedure mysqltest_1.p1; drop database mysqltest_1; revoke usage on *.* from mysqltest_1@localhost; drop user mysqltest_1@localhost; +drop function if exists bug12812| +create function bug12812() returns char(2) +begin +return 'ok'; +end; +create user user_bug12812@localhost IDENTIFIED BY 'ABC'| +SELECT test.bug12812()| +ERROR 42000: execute command denied to user 'user_bug12812'@'localhost' for routine 'test.bug12812' +CREATE VIEW v1 AS SELECT test.bug12812()| +ERROR 42000: execute command denied to user 'user_bug12812'@'localhost' for routine 'test.bug12812' +DROP USER user_bug12812@localhost| +drop function bug12812| diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 4424f4e6ad4..7fdbeff9a86 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1916,7 +1916,7 @@ select bug3788()| bug3788() 2005-03-04 drop function bug3788| -create function bug3788() returns binary(5) return 5| +create function bug3788() returns binary(1) return 5| select bug3788()| bug3788() 5 @@ -3085,6 +3085,19 @@ column_name bug10055(t.column_name) id id data data drop function bug10055| +drop procedure if exists bug12297| +create procedure bug12297(lim int) +begin +set @x = 0; +repeat +insert into t1(id,data) +values('aa', @x); +set @x = @x + 1; +until @x >= lim +end repeat; +end| +call bug12297(10)| +drop procedure bug12297| drop function if exists f_bug11247| drop procedure if exists p_bug11247| create function f_bug11247(param int) @@ -3193,4 +3206,330 @@ set f1= concat( 'hello', f1 ); return f1; end| drop function bug9048| +drop procedure if exists bug12849_1| +create procedure bug12849_1(inout x char) select x into x| +set @var='a'| +call bug12849_1(@var)| +select @var| +@var +a +drop procedure bug12849_1| +drop procedure if exists bug12849_2| +create procedure bug12849_2(inout foo varchar(15)) +begin +select concat(foo, foo) INTO foo; +end| +set @var='abcd'| +call bug12849_2(@var)| +select @var| +@var +abcdabcd +drop procedure bug12849_2| +drop procedure if exists bug131333| +drop function if exists bug131333| +create procedure bug131333() +begin +begin +declare a int; +select a; +set a = 1; +select a; +end; +begin +declare b int; +select b; +end; +end| +create function bug131333() +returns int +begin +begin +declare a int; +set a = 1; +end; +begin +declare b int; +return b; +end; +end| +call bug131333()| +a +NULL +a +1 +b +NULL +select bug131333()| +bug131333() +NULL +drop procedure bug131333| +drop function bug131333| +drop function if exists bug12379| +drop procedure if exists bug12379_1| +drop procedure if exists bug12379_2| +drop procedure if exists bug12379_3| +drop table if exists t3| +create table t3 (c1 char(1) primary key not null)| +create function bug12379() +returns integer +begin +insert into t3 values('X'); +insert into t3 values('X'); +return 0; +end| +create procedure bug12379_1() +begin +declare exit handler for sqlexception select 42; +select bug12379(); +END| +create procedure bug12379_2() +begin +declare exit handler for sqlexception begin end; +select bug12379(); +end| +create procedure bug12379_3() +begin +select bug12379(); +end| +select bug12379()| +ERROR 23000: Duplicate entry 'X' for key 1 +select 1| +1 +1 +call bug12379_1()| +bug12379() +42 +42 +select 2| +2 +2 +call bug12379_2()| +bug12379() +select 3| +3 +3 +call bug12379_3()| +ERROR 23000: Duplicate entry 'X' for key 1 +select 4| +4 +4 +drop function bug12379| +drop procedure bug12379_1| +drop procedure bug12379_2| +drop procedure bug12379_3| +drop table t3| +drop procedure if exists bug13124| +create procedure bug13124() +begin +declare y integer; +set @x=y; +end| +call bug13124()| +drop procedure bug13124| +drop procedure if exists bug12979_1| +create procedure bug12979_1(inout d decimal(5)) set d = d / 2| +set @bug12979_user_var = NULL| +call bug12979_1(@bug12979_user_var)| +drop procedure bug12979_1| +drop procedure if exists bug12979_2| +create procedure bug12979_2() +begin +declare internal_var decimal(5); +set internal_var= internal_var / 2; +select internal_var; +end| +call bug12979_2()| +internal_var +NULL +drop procedure bug12979_2| +drop table if exists t3| +drop procedure if exists bug6127| +create table t3 (s1 int unique)| +set @sm=@@sql_mode| +set sql_mode='traditional'| +create procedure bug6127() +begin +declare continue handler for sqlstate '23000' + begin +declare continue handler for sqlstate '22003' + insert into t3 values (0); +insert into t3 values (1000000000000000); +end; +insert into t3 values (1); +insert into t3 values (1); +end| +call bug6127()| +select * from t3| +s1 +0 +1 +call bug6127()| +ERROR 23000: Duplicate entry '0' for key 1 +select * from t3| +s1 +0 +1 +set sql_mode=@sm| +drop table t3| +drop procedure bug6127| +drop procedure if exists bug12589_1| +drop procedure if exists bug12589_2| +drop procedure if exists bug12589_3| +create procedure bug12589_1() +begin +declare spv1 decimal(3,3); +set spv1= 123.456; +set spv1 = 'test'; +create temporary table tm1 as select spv1; +show create table tm1; +drop temporary table tm1; +end| +create procedure bug12589_2() +begin +declare spv1 decimal(6,3); +set spv1= 123.456; +create temporary table tm1 as select spv1; +show create table tm1; +drop temporary table tm1; +end| +create procedure bug12589_3() +begin +declare spv1 decimal(6,3); +set spv1= -123.456; +create temporary table tm1 as select spv1; +show create table tm1; +drop temporary table tm1; +end| +call bug12589_1()| +Table Create Table +tm1 CREATE TEMPORARY TABLE `tm1` ( + `spv1` decimal(1,0) unsigned default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +Warnings: +Warning 1292 Truncated incorrect DECIMAL value: 'test' +call bug12589_2()| +Table Create Table +tm1 CREATE TEMPORARY TABLE `tm1` ( + `spv1` decimal(6,3) unsigned default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +call bug12589_3()| +Table Create Table +tm1 CREATE TEMPORARY TABLE `tm1` ( + `spv1` decimal(6,3) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table if exists t3| +drop procedure if exists bug7049_1| +drop procedure if exists bug7049_2| +drop procedure if exists bug7049_3| +drop procedure if exists bug7049_4| +drop procedure if exists bug7049_5| +drop procedure if exists bug7049_6| +drop function if exists bug7049_1| +drop function if exists bug7049_2| +create table t3 ( x int unique )| +create procedure bug7049_1() +begin +insert into t3 values (42); +insert into t3 values (42); +end| +create procedure bug7049_2() +begin +declare exit handler for sqlexception +select 'Caught it' as 'Result'; +call bug7049_1(); +select 'Missed it' as 'Result'; +end| +create procedure bug7049_3() +call bug7049_1()| +create procedure bug7049_4() +begin +declare exit handler for sqlexception +select 'Caught it' as 'Result'; +call bug7049_3(); +select 'Missed it' as 'Result'; +end| +create procedure bug7049_5() +begin +declare x decimal(2,1); +set x = 'zap'; +end| +create procedure bug7049_6() +begin +declare exit handler for sqlwarning +select 'Caught it' as 'Result'; +call bug7049_5(); +select 'Missed it' as 'Result'; +end| +create function bug7049_1() +returns int +begin +insert into t3 values (42); +insert into t3 values (42); +return 42; +end| +create function bug7049_2() +returns int +begin +declare x int default 0; +declare continue handler for sqlexception +set x = 1; +set x = bug7049_1(); +return x; +end| +call bug7049_2()| +Result +Caught it +select * from t3| +x +42 +delete from t3| +call bug7049_4()| +Result +Caught it +select * from t3| +x +42 +call bug7049_6()| +Result +Caught it +select bug7049_2()| +bug7049_2() +1 +drop table t3| +drop procedure bug7049_1| +drop procedure bug7049_2| +drop procedure bug7049_3| +drop procedure bug7049_4| +drop procedure bug7049_5| +drop procedure bug7049_6| +drop function bug7049_1| +drop function bug7049_2| +drop function if exists bug13941| +drop procedure if exists bug13941| +create function bug13941(p_input_str text) +returns text +begin +declare p_output_str text; +set p_output_str = p_input_str; +set p_output_str = replace(p_output_str, 'xyzzy', 'plugh'); +set p_output_str = replace(p_output_str, 'test', 'prova'); +set p_output_str = replace(p_output_str, 'this', 'questo'); +set p_output_str = replace(p_output_str, ' a ', 'una '); +set p_output_str = replace(p_output_str, 'is', ''); +return p_output_str; +end| +create procedure bug13941(out sout varchar(128)) +begin +set sout = 'Local'; +set sout = ifnull(sout, 'DEF'); +end| +select bug13941('this is a test')| +bug13941('this is a test') +questo una prova +call bug13941(@a)| +select @a| +@a +Local +drop function bug13941| +drop procedure bug13941| drop table t1,t2; diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index 084b257b699..83099623e23 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -65,7 +65,7 @@ sql_mode NO_FIELD_OPTIONS,MYSQL323,MYSQL40,HIGH_NOT_PRECEDENCE show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL auto_increment, + `a` int(11) NOT NULL, `pseudo` varchar(35) NOT NULL default '', `email` varchar(60) NOT NULL default '', PRIMARY KEY (`a`), @@ -79,8 +79,8 @@ show create table t1; Table Create Table t1 CREATE TABLE "t1" ( "a" int(11) NOT NULL, - "pseudo" varchar(35) NOT NULL default '', - "email" varchar(60) NOT NULL default '', + "pseudo" varchar(35) character set latin2 NOT NULL default '', + "email" varchar(60) character set latin2 NOT NULL default '', PRIMARY KEY ("a"), UNIQUE KEY "email" ("email") ) @@ -140,6 +140,26 @@ t1 CREATE TABLE `t1` ( drop table t1 ; set @@SQL_MODE=NULL; ERROR 42000: Variable 'sql_mode' can't be set to the value of 'NULL' +set session sql_mode=ansi; +create table t1 +(f1 integer auto_increment primary key, +f2 timestamp default current_timestamp on update current_timestamp); +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "f1" int(11) NOT NULL auto_increment, + "f2" timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + PRIMARY KEY ("f1") +) +set session sql_mode=no_field_options; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` timestamp NOT NULL default CURRENT_TIMESTAMP, + PRIMARY KEY (`f1`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=''; show local variables like 'SQL_MODE'; Variable_name Value @@ -449,11 +469,11 @@ create table t2 (a int); create view v1 as select a from t1; show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` SET @@SQL_MODE='ANSI_QUOTES'; show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW "test"."v1" AS select "test"."t1"."a" AS "a" from "test"."t1" +v1 CREATE ALGORITHM=UNDEFINED DEFINER="root"@"localhost" SQL SECURITY DEFINER VIEW "v1" AS select "t1"."a" AS "a" from "t1" create view v2 as select a from t2 where a in (select a from v1); drop view v2, v1; drop table t1, t2; diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 6299e8dcc88..2b1a47ed337 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -667,7 +667,9 @@ INSERT INTO t1 VALUES(-9223372036854774000.0,0.0),(9223372036854775700.0,1844674 INSERT INTO t1 (col1) VALUES(-9223372036854775809); ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES(9223372036854775808); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 (col2) VALUES(-1); +ERROR 22003: Out of range value adjusted for column 'col2' at row 1 INSERT INTO t1 (col2) VALUES(18446744073709551616); ERROR 22003: Out of range value adjusted for column 'col2' at row 1 INSERT INTO t1 (col1) VALUES('-9223372036854775809'); @@ -706,6 +708,8 @@ Error 1365 Division by 0 INSERT IGNORE INTO t1 VALUES(-9223372036854775809,-1),(9223372036854775808,18446744073709551616); Warnings: Warning 1264 Out of range value adjusted for column 'col1' at row 1 +Warning 1264 Out of range value adjusted for column 'col2' at row 1 +Warning 1264 Out of range value adjusted for column 'col1' at row 2 Warning 1264 Out of range value adjusted for column 'col2' at row 2 INSERT IGNORE INTO t1 VALUES('-9223372036854775809','-1'),('9223372036854775808','18446744073709551616'); Warnings: @@ -729,12 +733,10 @@ col1 col2 9223372036854775807 18446744073709551615 -9223372036854774000 0 9223372036854775700 1844674407370954000 --9223372036854775808 NULL -NULL 18446744073709551615 2 NULL NULL NULL --9223372036854775808 18446744073709551615 --9223372036854775808 18446744073709551615 +-9223372036854775808 0 +9223372036854775807 18446744073709551615 -9223372036854775808 0 9223372036854775807 18446744073709551615 -9223372036854775808 0 diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 14806279362..d42e439f4de 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2987,3 +2987,4 @@ select * from (select max(fld) from t1) as foo; max(fld) 1 drop table t1; +purge master logs before (select adddate(current_timestamp(), interval -4 day)); diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index bc902ea7b0f..026bcb4b370 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -14,6 +14,9 @@ DOCID VARCHAR(32)BINARY NOT NULL , PRIMARY KEY ( DOCID ) ) ENGINE=InnoDB ; +INSERT INTO t1 (DOCID) VALUES ("1"), ("2"); +Warnings: +Warning 1364 Field 'UUID' doesn't have a default value CREATE TABLE t2 ( DOCID VARCHAR(32)BINARY NOT NULL diff --git a/mysql-test/r/subselect_innodb.result b/mysql-test/r/subselect_innodb.result index 0666fd76661..a23b584e510 100644 --- a/mysql-test/r/subselect_innodb.result +++ b/mysql-test/r/subselect_innodb.result @@ -152,3 +152,23 @@ EXECUTE my_stmt; b count(*) deallocate prepare my_stmt; drop table t1,t2; +CREATE TABLE t1 ( +school_name varchar(45) NOT NULL, +country varchar(45) NOT NULL, +funds_requested float NOT NULL, +schooltype varchar(45) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +insert into t1 values ("the school", "USA", 1200, "Human"); +select count(country) as countrycount, sum(funds_requested) as smcnt, +country, (select sum(funds_requested) from t1) as total_funds +from t1 +group by country; +countrycount smcnt country total_funds +1 1200 USA 1200 +select count(country) as countrycount, sum(funds_requested) as smcnt, +country, (select sum(funds_requested) from t1) as total_funds +from t1 +group by country; +countrycount smcnt country total_funds +1 1200 USA 1200 +drop table t1; diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index d2872878cb9..999f12a0573 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -73,7 +73,7 @@ Table Create Table user CREATE TABLE `user` ( `Host` char(60) collate utf8_bin NOT NULL default '', `User` char(16) collate utf8_bin NOT NULL default '', - `Password` char(41) collate utf8_bin NOT NULL default '', + `Password` char(41) character set latin1 collate latin1_bin NOT NULL default '', `Select_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Insert_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Update_priv` enum('N','Y') character set utf8 NOT NULL default 'N', diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index 081bd35622e..82479504b10 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -1,4 +1,5 @@ drop table if exists t1,t2; +drop view if exists v1; CREATE TABLE t1 (c int not null, d char (10) not null); insert into t1 values(1,""),(2,"a"),(3,"b"); CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); @@ -23,6 +24,8 @@ a b 6 g create TEMPORARY TABLE t2 engine=heap select * from t1; create TEMPORARY TABLE IF NOT EXISTS t2 (a int) engine=heap; +Warnings: +Note 1050 Table 't2' already exists CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); ERROR 42S01: Table 't1' already exists ALTER TABLE t1 RENAME t2; @@ -97,32 +100,32 @@ Variable_name Value Created_tmp_disk_tables 0 Created_tmp_tables 2 drop table t1; -create temporary table t1 as select 'This is temp. table' A; -create view t1 as select 'This is view' A; -select * from t1; +create temporary table v1 as select 'This is temp. table' A; +create view v1 as select 'This is view' A; +select * from v1; A This is temp. table -show create table t1; +show create table v1; Table Create Table -t1 CREATE TEMPORARY TABLE `t1` ( +v1 CREATE TEMPORARY TABLE `v1` ( `A` varchar(19) NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -show create view t1; +show create view v1; View Create View -t1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`t1` AS select _latin1'This is view' AS `A` -drop view t1; -select * from t1; +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select _latin1'This is view' AS `A` +drop view v1; +select * from v1; A This is temp. table -create view t1 as select 'This is view again' A; -select * from t1; +create view v1 as select 'This is view again' A; +select * from v1; A This is temp. table -drop table t1; -select * from t1; +drop table v1; +select * from v1; A This is view again -drop view t1; +drop view v1; create table t1 (a int, b int, index(a), index(b)); create table t2 (c int auto_increment, d varchar(255), primary key (c)); insert into t1 values (3,1),(3,2); diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 312a7a90fc9..b305691fa18 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -689,7 +689,7 @@ call bug11587(); set new.c2= '2004-04-02'; end| insert into t1 (c1) values (4),(5),(6); -ERROR 0A000: PROCEDURE test.bug11587 can't return a result set in the given context +ERROR 0A000: Not allowed to return a result set from a trigger select * from t1; c1 c2 1 NULL diff --git a/mysql-test/r/type_binary.result b/mysql-test/r/type_binary.result new file mode 100644 index 00000000000..49fd7ba5633 --- /dev/null +++ b/mysql-test/r/type_binary.result @@ -0,0 +1,113 @@ +create table t1 (s1 binary(3)); +insert into t1 values (0x61), (0x6120), (0x612020); +select hex(s1) from t1; +hex(s1) +610000 +612000 +612020 +drop table t1; +create table t1 (s1 binary(2), s2 varbinary(2)); +insert into t1 values (0x4100,0x4100); +select length(concat('*',s1,'*',s2,'*')) from t1; +length(concat('*',s1,'*',s2,'*')) +7 +delete from t1; +insert into t1 values (0x4120,0x4120); +select length(concat('*',s1,'*',s2,'*')) from t1; +length(concat('*',s1,'*',s2,'*')) +7 +drop table t1; +create table t1 (s1 varbinary(20), s2 varbinary(20)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varbinary(20) default NULL, + `s2` varbinary(20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values (0x41,0x4100),(0x41,0x4120),(0x4100,0x4120); +select hex(s1), hex(s2) from t1; +hex(s1) hex(s2) +41 4100 +41 4120 +4100 4120 +select count(*) from t1 where s1 < s2; +count(*) +3 +drop table t1; +create table t1 (s1 varbinary(2), s2 varchar(1)); +insert into t1 values (0x41,'a'), (0x4100,'b'), (0x41,'c'), (0x4100,'d'); +select hex(s1),s2 from t1 order by s1,s2; +hex(s1) s2 +41 a +41 c +4100 b +4100 d +drop table t1; +create table t1 (s1 binary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +insert into t1 values (0x0100); +ERROR 23000: Duplicate entry '' for key 1 +select hex(s1) from t1 order by s1; +hex(s1) +0100 +0120 +select hex(s1) from t1 where s1=0x01; +hex(s1) +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +2 +alter table t1 drop primary key; +select hex(s1) from t1 where s1=0x01; +hex(s1) +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +2 +drop table t1; +create table t1 (s1 varbinary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +insert into t1 values (0x0100); +select hex(s1) from t1 order by s1; +hex(s1) +01 +0100 +0120 +select hex(s1) from t1 where s1=0x01; +hex(s1) +01 +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +3 +alter table t1 drop primary key; +select hex(s1) from t1 where s1=0x01; +hex(s1) +01 +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +3 +drop table t1; diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 5988b4f745e..0213dbaffde 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -553,3 +553,13 @@ sum(a1) b1+0 b2+0 2 0 0 4 2 2 8 1 1 +select 1 from t1 join t2 on b1 = b2 group by b1 order by 1; +1 +1 +1 +1 +select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1; +b1+0 sum(b1) sum(b2) +0 0 0 +1 4 4 +2 2 2 diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 193ed298339..b366b1ed755 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -67,7 +67,7 @@ select * from t1; a Where drop table t1; -create table t1 (t text,c char(10),b blob, d binary(10)); +create table t1 (t text,c char(10),b blob, d varbinary(10)); insert into t1 values (NULL,NULL,NULL,NULL); insert into t1 values ("","","",""); insert into t1 values ("hello","hello","hello","hello"); @@ -83,14 +83,14 @@ Field Type Collation Null Key Default Extra Privileges Comment t text latin1_swedish_ci YES NULL # c char(10) latin1_swedish_ci YES NULL # b blob NULL YES NULL # -d binary(10) NULL YES NULL # +d varbinary(10) NULL YES NULL # lock tables t1 WRITE; show full fields from t1; Field Type Collation Null Key Default Extra Privileges Comment t text latin1_swedish_ci YES NULL # c char(10) latin1_swedish_ci YES NULL # b blob NULL YES NULL # -d binary(10) NULL YES NULL # +d varbinary(10) NULL YES NULL # unlock tables; select t from t1 where t like "hello"; t @@ -718,3 +718,73 @@ t1 CREATE TABLE `t1` ( KEY `a` (`a`,`b`,`d`,`e`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +CREATE table t1 (a blob); +insert into t1 values ('b'),('a\0'),('a'),('a '),('aa'),(NULL); +select hex(a) from t1 order by a; +hex(a) +NULL +61 +6100 +6120 +6161 +62 +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +b +NULL +6100 +610000 +612000 +616100 +6200 +alter table t1 modify a varbinary(5); +select hex(a) from t1 order by a; +hex(a) +NULL +61 +6100 +6120 +6161 +62 +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +b +NULL +6100 +610000 +612000 +616100 +6200 +alter table t1 modify a char(5); +select hex(a) from t1 order by a; +hex(a) +NULL +6100 +61 +61 +6161 +62 +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +b +NULL +610000 +6100 +6100 +616100 +6200 +alter table t1 modify a binary(5); +select hex(a) from t1 order by a; +hex(a) +NULL +6100000000 +6100000000 +6100000000 +6161000000 +6200000000 +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +b +NULL +610000000000 +610000000000 +610000000000 +616100000000 +620000000000 +drop table t1; diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 15f9b839994..d7f5f9fa328 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -476,7 +476,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp CREATE TABLE t1 (a_dec DECIMAL(-1,1)); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1,1))' at line 1 CREATE TABLE t1 (a_dec DECIMAL(0,11)); -ERROR 42000: Scale may not be larger than the precision (column 'a_dec'). +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a_dec'). create table t1(a decimal(7,3)); insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); select * from t1; @@ -672,6 +672,17 @@ a 9999.999 0000.000 drop table t1; +create table t1(a decimal(10,5), b decimal(10,1)); +insert into t1 values(123.12345, 123.12345); +Warnings: +Note 1265 Data truncated for column 'b' at row 1 +update t1 set b=a; +Warnings: +Note 1265 Data truncated for column 'b' at row 1 +select * from t1; +a b +123.12345 123.1 +drop table t1; CREATE TABLE t1 (EMPNUM CHAR(3) NOT NULL, HOURS DECIMAL(5)); diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index d243985332e..c10cb7d71f7 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -225,3 +225,22 @@ select * from t1 where reckey=1.09E2; reckey recdesc 109 Has 109 as key drop table t1; +create table t1 (d double(10,1)); +create table t2 (d double(10,9)); +insert into t1 values ("100000000.0"); +insert into t2 values ("1.23456780"); +create table t3 select * from t2 union select * from t1; +select * from t3; +d +1.234567800 +100000000.000000000 +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `d` double(22,9) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1, t2, t3; +create table t1 (s1 float(0,2)); +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). +create table t1 (s1 float(1,2)); +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index d39d2e3401d..be5e29ab662 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -68,10 +68,10 @@ NULL 1.1 NULL NULL NULL 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `nullif(1.1, 1.1)` decimal(2,1) default NULL, - `nullif(1.1, 1.2)` decimal(2,1) default NULL, - `nullif(1.1, 0.11e1)` decimal(2,1) default NULL, - `nullif(1.0, 1)` decimal(2,1) default NULL, + `nullif(1.1, 1.1)` decimal(2,1) unsigned default NULL, + `nullif(1.1, 1.2)` decimal(2,1) unsigned default NULL, + `nullif(1.1, 0.11e1)` decimal(2,1) unsigned default NULL, + `nullif(1.0, 1)` decimal(2,1) unsigned default NULL, `nullif(1, 1.0)` int(1) default NULL, `nullif(1, 1.1)` int(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -174,9 +174,9 @@ create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(- show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `round(15.4,-1)` decimal(3,0) NOT NULL default '0', + `round(15.4,-1)` decimal(3,0) unsigned NOT NULL default '0', `truncate(-5678.123451,-3)` decimal(4,0) NOT NULL default '0', - `abs(-1.1)` decimal(3,1) NOT NULL default '0.0', + `abs(-1.1)` decimal(2,1) NOT NULL default '0.0', `-(-1.1)` decimal(2,1) NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; @@ -684,9 +684,7 @@ set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = while v5 < 100000 do set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1; end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;// -# call p1()// -# v1 v2 v3 * 0.000000000001 v4 * 0.000000000001 1.000000100000 1.999999900000 1.000000100000 1.999999900000 drop procedure p1; @@ -783,7 +781,7 @@ create table t1 as select 0.5; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `0.5` decimal(2,1) NOT NULL default '0.0' + `0.5` decimal(2,1) unsigned NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; select round(1.5),round(2.5); @@ -938,7 +936,7 @@ ERROR 42000: Too big scale 31 specified for column 'sl'. Maximum is 30. create table t1 (sl decimal(0,38)); ERROR 42000: Too big scale 38 specified for column 'sl'. Maximum is 30. create table t1 (sl decimal(0,30)); -ERROR 42000: Scale may not be larger than the precision (column 'sl'). +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'sl'). create table t1 (sl decimal(5, 5)); show create table t1; Table Create Table @@ -986,3 +984,38 @@ t1 CREATE TABLE `t1` ( `f1` decimal(10,0) unsigned zerofill NOT NULL default '0000000000' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +drop procedure if exists wg2; +Warnings: +Note 1305 PROCEDURE wg2 does not exist +create procedure wg2() +begin +declare v int default 1; +declare tdec decimal(5) default 0; +while v <= 9 do set tdec =tdec * 10; +select v, tdec; +set v = v + 1; +end while; +end// +call wg2()// +v tdec +1 0 +v tdec +2 0 +v tdec +3 0 +v tdec +4 0 +v tdec +5 0 +v tdec +6 0 +v tdec +7 0 +v tdec +8 0 +v tdec +9 0 +drop procedure wg2; +select cast(@non_existing_user_var/2 as DECIMAL); +cast(@non_existing_user_var/2 as DECIMAL) +NULL diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index 1342603f755..ff07dcca106 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -95,6 +95,7 @@ Warning 1264 Out of range value adjusted for column 'utiny' at row 1 Warning 1264 Out of range value adjusted for column 'ushort' at row 1 Warning 1264 Out of range value adjusted for column 'umedium' at row 1 Warning 1264 Out of range value adjusted for column 'ulong' at row 1 +Warning 1264 Out of range value adjusted for column 'ulonglong' at row 1 Warning 1265 Data truncated for column 'options' at row 1 Warning 1265 Data truncated for column 'flags' at row 1 insert into t1 values (0,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,NULL,0,0,0,-4294967295,-4294967295,-4294967295,'-4294967295',0,"one,two,tree"); @@ -108,6 +109,7 @@ Warning 1264 Out of range value adjusted for column 'utiny' at row 1 Warning 1264 Out of range value adjusted for column 'ushort' at row 1 Warning 1264 Out of range value adjusted for column 'umedium' at row 1 Warning 1264 Out of range value adjusted for column 'ulong' at row 1 +Warning 1264 Out of range value adjusted for column 'ulonglong' at row 1 Warning 1265 Data truncated for column 'options' at row 1 insert into t1 values (0,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,NULL,0,0,0,4294967295,4294967295,4294967295,'4294967295',0,0); Warnings: @@ -125,8 +127,8 @@ auto string tiny short medium long_int longlong real_float real_double utiny ush 10 1 1 1 1 1 1 1.0 1.0000 1 00001 1 1 1 0 0000-00-00 00:00:00 0000-00-00 00:00:00 1 1 1 1 11 2 2 2 2 2 2 2.0 2.0000 2 00002 2 2 2 0 NULL NULL NULL NULL NULL 2 2 12 0.33333333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 -13 -1 -1 -1 -1 -1 -1 -1.0 -1.0000 0 00000 0 0 18446744073709551615 0 1997-08-07 08:07:06 1997-04-03 09:08:07 -1 -1 -1 -1 -14 -429496729 -128 -32768 -8388608 -2147483648 -4294967295 -4294967296.0 -4294967295.0000 0 00000 0 0 18446744069414584321 0 0000-00-00 00:00:00 0000-00-00 00:00:00 -4294967295 -4294967295 -4294967295 -4294967295 +13 -1 -1 -1 -1 -1 -1 -1.0 -1.0000 0 00000 0 0 0 0 1997-08-07 08:07:06 1997-04-03 09:08:07 -1 -1 -1 -1 +14 -429496729 -128 -32768 -8388608 -2147483648 -4294967295 -4294967296.0 -4294967295.0000 0 00000 0 0 0 0 0000-00-00 00:00:00 0000-00-00 00:00:00 -4294967295 -4294967295 -4294967295 -4294967295 15 4294967295 127 32767 8388607 2147483647 4294967295 4294967296.0 4294967295.0000 255 65535 16777215 4294967295 4294967295 0 0000-00-00 00:00:00 0000-00-00 00:00:00 4294967295 4294967295 4294967295 4294967295 16 hello 1 1 0 0 0 0.0 NULL 0 00000 0 0 0 0 NULL NULL NULL NULL NULL ALTER TABLE t1 diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index eb129e32983..042dfb5ad8d 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -780,21 +780,6 @@ t1 CREATE TABLE `t1` ( `b` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1,t2; -create table t1 (d decimal(10,1)); -create table t2 (d decimal(10,9)); -insert into t1 values ("100000000.0"); -insert into t2 values ("1.23456780"); -create table t3 select * from t2 union select * from t1; -select * from t3; -d -1.234567800 -100000000.000000000 -show create table t3; -Table Create Table -t3 CREATE TABLE `t3` ( - `d` decimal(18,9) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1,t2,t3; create table t1 select 1 union select -1; select * from t1; 1 diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 42fb8064044..d2aa051c299 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -251,3 +251,74 @@ f1 f2 1 1 2 2 drop table t1,t2; +create table t1(f1 int); +select DATABASE(); +DATABASE() +test +update t1 set f1=1 where count(*)=1; +ERROR HY000: Invalid use of group function +select DATABASE(); +DATABASE() +test +delete from t1 where count(*)=1; +ERROR HY000: Invalid use of group function +drop table t1; +create table t1 ( a int, index (a) ); +insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0); +flush status; +select a from t1 order by a limit 1; +a +0 +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 1 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +flush status; +update t1 set a=unix_timestamp() order by a limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 1 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 1 +Handler_read_rnd_next 0 +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 1 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +flush status; +delete from t1 order by a desc limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 1 +Handler_read_rnd_next 9 +alter table t1 disable keys; +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 1 +Handler_read_rnd_next 9 +select count(*) from t1; +count(*) +5 +drop table t1; diff --git a/mysql-test/r/user_var-binlog.result b/mysql-test/r/user_var-binlog.result index 0e9692523ef..700ec7b09e0 100644 --- a/mysql-test/r/user_var-binlog.result +++ b/mysql-test/r/user_var-binlog.result @@ -11,7 +11,7 @@ Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 98 User var 1 139 @`a b`=_latin1 0x68656C6C6F COLLATE latin1_swedish_ci master-bin.000001 139 Query 1 231 use `test`; INSERT INTO t1 VALUES(@`a b`) master-bin.000001 231 User var 1 273 @`var1`=_latin1 0x273B616161 COLLATE latin1_swedish_ci -master-bin.000001 273 User var 1 311 @`var2`=_latin1 0x61 COLLATE latin1_swedish_ci +master-bin.000001 273 User var 1 311 @`var2`=_binary 0x61 COLLATE binary master-bin.000001 311 Query 1 411 use `test`; insert into t1 values (@var1),(@var2) /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; @@ -24,9 +24,10 @@ SET @@session.sql_mode=0; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; INSERT INTO t1 VALUES(@`a b`); SET @`var1`:=_latin1 0x273B616161 COLLATE `latin1_swedish_ci`; -SET @`var2`:=_latin1 0x61 COLLATE `latin1_swedish_ci`; +SET @`var2`:=_binary 0x61 COLLATE `binary`; SET TIMESTAMP=10000; insert into t1 values (@var1),(@var2); -ROLLBACK; +# End of log file +ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; drop table t1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 4983e0ae3e8..3ecc48620b1 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -147,7 +147,7 @@ Variable_name Value storage_engine MEMORY show global variables like 'storage_engine'; Variable_name Value -storage_engine MERGE +storage_engine MRG_MYISAM set GLOBAL query_cache_size=100000; set GLOBAL myisam_max_sort_file_size=2000000; show global variables like 'myisam_max_sort_file_size'; @@ -513,6 +513,19 @@ SHOW VARIABLES LIKE 'table_cache'; Variable_name Value table_cache 1 SET GLOBAL table_cache=DEFAULT; +set character_set_results=NULL; +select ifnull(@@character_set_results,"really null"); +ifnull(@@character_set_results,"really null") +really null +set names latin1; +select @@have_innodb; +@@have_innodb +# +set @test = @@query_prealloc_size; +set @@query_prealloc_size = @test; +select @@query_prealloc_size = @test; +@@query_prealloc_size = @test +1 create table t1 (a int); select a into @x from t1; Warnings: @@ -537,6 +550,10 @@ set @@max_heap_table_size= 4294967296; select @@max_heap_table_size > 0; @@max_heap_table_size > 0 1 -select @@have_innodb; -@@have_innodb -# +select @@character_set_system; +@@character_set_system +utf8 +set global character_set_system = latin1; +ERROR HY000: Variable 'character_set_system' is a read only variable +set @@global.version_compile_os='234'; +ERROR HY000: Variable 'version_compile_os' is a read only variable diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 2b71a58482f..4d224bf196d 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -32,10 +32,10 @@ c 11 show create table v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (`t1`.`b` + 1) AS `c` from `t1` show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (`t1`.`b` + 1) AS `c` from `t1` show create view t1; ERROR HY000: 'test.t1' is not VIEW drop table t1; @@ -55,7 +55,7 @@ Note 1003 select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1` create algorithm=temptable view v2 (c) as select b+1 from t1; show create view v2; View Create View -v2 CREATE ALGORITHM=TEMPTABLE VIEW `test`.`v2` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1` +v2 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t1`.`b` + 1) AS `c` from `t1` select c from v2; c 3 @@ -550,7 +550,7 @@ create table t1 ("a*b" int); create view v1 as select "a*b" from t1; show create view v1; View Create View -v1 CREATE VIEW "test"."v1" AS select "test"."t1"."a*b" AS "a*b" from "test"."t1" +v1 CREATE VIEW "v1" AS select "t1"."a*b" AS "a*b" from "t1" drop view v1; drop table t1; set sql_mode=default; @@ -657,7 +657,7 @@ drop table t1; CREATE VIEW v1 (f1,f2,f3,f4) AS SELECT connection_id(), pi(), current_user(), version(); SHOW CREATE VIEW v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache connection_id() AS `f1`,pi() AS `f2`,current_user() AS `f3`,version() AS `f4` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache connection_id() AS `f1`,pi() AS `f2`,current_user() AS `f3`,version() AS `f4` drop view v1; create table t1 (s1 int); create table t2 (s2 int); @@ -691,13 +691,13 @@ create view v1 as select a from t1; create view v2 as select a from t2 where a in (select a from v1); show create view v2; View Create View -v2 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v2` AS select `test`.`t2`.`a` AS `a` from `test`.`t2` where `a` in (select `v1`.`a` AS `a` from `test`.`v1`) +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t2`.`a` AS `a` from `t2` where `a` in (select `v1`.`a` AS `a` from `v1`) drop view v2, v1; drop table t1, t2; CREATE VIEW `v 1` AS select 5 AS `5`; show create view `v 1`; View Create View -v 1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v 1` AS select 5 AS `5` +v 1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v 1` AS select 5 AS `5` drop view `v 1`; create database mysqltest; create table mysqltest.t1 (a int, b int); @@ -765,14 +765,14 @@ a b 1 1 show create view v3; View Create View -v3 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v3` AS select `v1`.`col1` AS `a`,`v2`.`col1` AS `b` from (`test`.`v1` join `test`.`v2`) where (`v1`.`col1` = `v2`.`col1`) +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `v1`.`col1` AS `a`,`v2`.`col1` AS `b` from (`v1` join `v2`) where (`v1`.`col1` = `v2`.`col1`) drop view v3, v2, v1; drop table t2, t1; create function `f``1` () returns int return 5; create view v1 as select test.`f``1` (); show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`f``1`() AS `test.``f````1`` ()` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache `test`.`f``1`() AS `test.``f````1`` ()` select * from v1; test.`f``1` () 5 @@ -789,10 +789,10 @@ create table t2 (col1 char collate latin1_german2_ci); create view v2 as select col1 collate latin1_german1_ci from t2; show create view v2; View Create View -v2 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v2` AS select (`test`.`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `test`.`t2` +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `t2` show create view v2; View Create View -v2 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v2` AS select (`test`.`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `test`.`t2` +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `t2` drop view v2; drop table t2; create table t1 (a int); @@ -819,7 +819,7 @@ drop table t1; create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1; show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select 99999999999999999999999999999999999999999999999999999 AS `col1` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 99999999999999999999999999999999999999999999999999999 AS `col1` drop view v1; create table tü (cü char); create view vü as select cü from tü; @@ -840,11 +840,23 @@ drop table t1; create view v1 as select cast(1 as char(3)); show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select cast(1 as char(3) charset latin1) AS `cast(1 as char(3))` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(1 as char(3) charset latin1) AS `cast(1 as char(3))` select * from v1; cast(1 as char(3)) 1 drop view v1; +create table t1 (a int); +create view v1 as select a from t1; +create view v3 as select a from t1; +create database mysqltest; +rename table v1 to mysqltest.v1; +ERROR HY000: Changing schema from 'test' to 'mysqltest' is not allowed. +rename table v1 to v2; +rename table v3 to v1, v2 to t1; +ERROR 42S01: Table 't1' already exists +drop table t1; +drop view v2,v3; +drop database mysqltest; create view v1 as select 'a',1; create view v2 as select * from v1 union all select * from v1; create view v3 as select * from v2 where 1 = (select `1` from v2); @@ -875,29 +887,29 @@ create view v1 as select * from t1; create view v2 as select * from v1; create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1; update v2 set col1 = (select max(col1) from v1); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'v2'. update v2 set col1 = (select max(col1) from t1); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 'v2'. update v2 set col1 = (select max(col1) from v2); ERROR HY000: You can't specify target table 'v2' for update in FROM clause update v2,t2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'v2'. update t1,t2 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't1'. update v1,t2 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1; ERROR HY000: You can't specify target table 'v1' for update in FROM clause update t2,v2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't2'. update t2,t1 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't2'. update t2,v1 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't2'. update v2,t2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 'v2'. update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; ERROR HY000: You can't specify target table 't1' for update in FROM clause update v1,t2 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v1' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'v1'. update t2,v2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1; ERROR HY000: You can't specify target table 't2' for update in FROM clause update t2,t1 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; @@ -907,73 +919,73 @@ ERROR HY000: You can't specify target table 't2' for update in FROM clause update v2,t2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1; ERROR HY000: You can't specify target table 'v2' for update in FROM clause update t1,t2 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 't1'. update v1,t2 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v1' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 'v1'. update t2,v2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 't2'. update t2,t1 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 't2'. update t2,v1 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 't2'. update v3 set v3.col1 = (select max(col1) from v1); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'v3'. update v3 set v3.col1 = (select max(col1) from t1); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: The definition of table 'v3' prevents operation UPDATE on table 'v3'. update v3 set v3.col1 = (select max(col1) from v2); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 'v3'. update v3 set v3.col1 = (select max(col1) from v3); ERROR HY000: You can't specify target table 'v3' for update in FROM clause delete from v2 where col1 = (select max(col1) from v1); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'v2'. delete from v2 where col1 = (select max(col1) from t1); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation DELETE on table 'v2'. delete from v2 where col1 = (select max(col1) from v2); ERROR HY000: You can't specify target table 'v2' for update in FROM clause delete v2 from v2,t2 where (select max(col1) from v1) > 0 and v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'v2'. delete t1 from t1,t2 where (select max(col1) from v1) > 0 and t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 't1'. delete v1 from v1,t2 where (select max(col1) from v1) > 0 and v1.col1 = t2.col1; ERROR HY000: You can't specify target table 'v1' for update in FROM clause delete v2 from v2,t2 where (select max(col1) from t1) > 0 and v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation DELETE on table 'v2'. delete t1 from t1,t2 where (select max(col1) from t1) > 0 and t1.col1 = t2.col1; ERROR HY000: You can't specify target table 't1' for update in FROM clause delete v1 from v1,t2 where (select max(col1) from t1) > 0 and v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v1' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'v1'. delete v2 from v2,t2 where (select max(col1) from v2) > 0 and v2.col1 = t2.col1; ERROR HY000: You can't specify target table 'v2' for update in FROM clause delete t1 from t1,t2 where (select max(col1) from v2) > 0 and t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation DELETE on table 't1'. delete v1 from v1,t2 where (select max(col1) from v2) > 0 and v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v1' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation DELETE on table 'v1'. insert into v2 values ((select max(col1) from v1)); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v2'. insert into t1 values ((select max(col1) from v1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 't1'. insert into v2 values ((select max(col1) from v1)); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v2'. insert into v2 values ((select max(col1) from t1)); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v2'. insert into t1 values ((select max(col1) from t1)); ERROR HY000: You can't specify target table 't1' for update in FROM clause insert into v2 values ((select max(col1) from t1)); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v2'. insert into v2 values ((select max(col1) from v2)); ERROR HY000: You can't specify target table 'v2' for update in FROM clause insert into t1 values ((select max(col1) from v2)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 't1'. insert into v2 values ((select max(col1) from v2)); ERROR HY000: You can't specify target table 'v2' for update in FROM clause insert into v3 (col1) values ((select max(col1) from v1)); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v3'. insert into v3 (col1) values ((select max(col1) from t1)); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: The definition of table 'v3' prevents operation INSERT on table 'v3'. insert into v3 (col1) values ((select max(col1) from v2)); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v3'. insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2)); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v3'. insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2)); insert into mysql.time_zone values ('', (select CONVERT_TZ('20050101000000','UTC','MET') from t2)); ERROR 23000: Column 'Use_leap_seconds' cannot be null @@ -1146,30 +1158,30 @@ create view v2 as select * from v1; alter view v1 as select * from v2; ERROR 42S02: Table 'test.v1' doesn't exist alter view v1 as select * from v1; -ERROR 42000: Not unique table/alias: 'v1' +ERROR 42S02: Table 'test.v1' doesn't exist create or replace view v1 as select * from v2; ERROR 42S02: Table 'test.v1' doesn't exist create or replace view v1 as select * from v1; -ERROR 42000: Not unique table/alias: 'v1' +ERROR 42S02: Table 'test.v1' doesn't exist drop view v2,v1; drop table t1; create table t1 (a int); create view v1 as select * from t1; show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` alter algorithm=undefined view v1 as select * from t1 with check option; show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` WITH CASCADED CHECK OPTION +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` WITH CASCADED CHECK OPTION alter algorithm=merge view v1 as select * from t1 with cascaded check option; show create view v1; View Create View -v1 CREATE ALGORITHM=MERGE VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` WITH CASCADED CHECK OPTION +v1 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` WITH CASCADED CHECK OPTION alter algorithm=temptable view v1 as select * from t1; show create view v1; View Create View -v1 CREATE ALGORITHM=TEMPTABLE VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` +v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` drop view v1; drop table t1; create table t1 (s1 int); @@ -1332,7 +1344,7 @@ insert into v3 values (30); ERROR HY000: The target table v3 of the INSERT is not updatable create view v4 as select * from v2 where 20 < (select (s1) from t1); insert into v4 values (30); -ERROR HY000: You can't specify target table 'v4' for update in FROM clause +ERROR HY000: The target table v4 of the INSERT is not updatable drop view v4, v3, v2, v1; drop table t1; create table t1 (a int); @@ -1841,24 +1853,24 @@ create table t2 (b timestamp default now()); create view v1 as select a,b,t1.a < now() from t1,t2 where t1.a < now(); SHOW CREATE VIEW v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a`,`test`.`t2`.`b` AS `b`,(`test`.`t1`.`a` < now()) AS `t1.a < now()` from (`test`.`t1` join `test`.`t2`) where (`test`.`t1`.`a` < now()) +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache `t1`.`a` AS `a`,`t2`.`b` AS `b`,(`t1`.`a` < now()) AS `t1.a < now()` from (`t1` join `t2`) where (`t1`.`a` < now()) drop view v1; drop table t1, t2; CREATE TABLE t1 ( a varchar(50) ); CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = CURRENT_USER(); SHOW CREATE VIEW v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = current_user()) +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache `t1`.`a` AS `a` from `t1` where (`t1`.`a` = current_user()) DROP VIEW v1; CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = VERSION(); SHOW CREATE VIEW v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = version()) +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` where (`t1`.`a` = version()) DROP VIEW v1; CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = DATABASE(); SHOW CREATE VIEW v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = database()) +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache `t1`.`a` AS `a` from `t1` where (`t1`.`a` = database()) DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (col1 time); @@ -1935,11 +1947,21 @@ SELECT * FROM v1; SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1) dkjhgd drop view v1; +create table t1 (f59 int, f60 int, f61 int); +insert into t1 values (19,41,32); +create view v1 as select f59, f60 from t1 where f59 in +(select f59 from t1); +update v1 set f60=2345; +ERROR HY000: The target table v1 of the UPDATE is not updatable +update t1 set f60=(select max(f60) from v1); +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't1'. +drop view v1; +drop table t1; create table t1 (s1 int); create view v1 as select var_samp(s1) from t1; show create view v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select var_samp(`test`.`t1`.`s1`) AS `var_samp(s1)` from `test`.`t1` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select var_samp(`t1`.`s1`) AS `var_samp(s1)` from `t1` drop view v1; drop table t1; set sql_mode='strict_all_tables'; @@ -2141,3 +2163,163 @@ select * from v1; strcmp(f1,'a') drop view v1; drop table t1; +create table t1 (f1 int, f2 int,f3 int); +insert into t1 values (1,10,20),(2,0,0); +create view v1 as select * from t1; +select if(sum(f1)>1,f2,f3) from v1 group by f1; +if(sum(f1)>1,f2,f3) +20 +0 +drop view v1; +drop table t1; +create table t1 ( +r_object_id char(16) NOT NULL, +group_name varchar(32) NOT NULL +) engine = InnoDB; +create table t2 ( +r_object_id char(16) NOT NULL, +i_position int(11) NOT NULL, +users_names varchar(32) default NULL +) Engine = InnoDB; +create view v1 as select r_object_id, group_name from t1; +create view v2 as select r_object_id, i_position, users_names from t2; +create unique index r_object_id on t1(r_object_id); +create index group_name on t1(group_name); +create unique index r_object_id_i_position on t2(r_object_id,i_position); +create index users_names on t2(users_names); +insert into t1 values('120001a080000542','tstgroup1'); +insert into t2 values('120001a080000542',-1, 'guser01'); +insert into t2 values('120001a080000542',-2, 'guser02'); +select v1.r_object_id, v2.users_names from v1, v2 +where (v1.group_name='tstgroup1') and v2.r_object_id=v1.r_object_id +order by users_names; +r_object_id users_names +120001a080000542 guser01 +120001a080000542 guser02 +drop view v1, v2; +drop table t1, t2; +create definer=some_user@__% sql security invoker view v1 as select 1; +ERROR HY000: View definer is not fully qualified +create definer=some_user@localhost sql security invoker view v1 as select 1; +Warnings: +Note 1449 There is not some_user@localhost registered +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` +drop view v1; +create table t1 (s1 int); +create view abc as select * from t1 as abc; +drop table t1; +drop view abc; +create table t1(f1 char(1)); +create view v1 as select * from t1; +select * from (select f1 as f2 from v1) v where v.f2='a'; +f2 +drop view v1; +drop table t1; +create view v1 as SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET'); +select * from v1; +CONVERT_TZ('2004-01-01 12:00:00','GMT','MET') +NULL +drop view v1; +CREATE TABLE t1 (date DATE NOT NULL); +INSERT INTO t1 VALUES ('2005-09-06'); +CREATE VIEW v1 AS SELECT DAYNAME(date) FROM t1; +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select dayname(`t1`.`date`) AS `DAYNAME(date)` from `t1` +CREATE VIEW v2 AS SELECT DAYOFWEEK(date) FROM t1; +SHOW CREATE VIEW v2; +View Create View +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select dayofweek(`t1`.`date`) AS `DAYOFWEEK(date)` from `t1` +CREATE VIEW v3 AS SELECT WEEKDAY(date) FROM t1; +SHOW CREATE VIEW v3; +View Create View +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select weekday(`t1`.`date`) AS `WEEKDAY(date)` from `t1` +SELECT DAYNAME('2005-09-06'); +DAYNAME('2005-09-06') +Tuesday +SELECT DAYNAME(date) FROM t1; +DAYNAME(date) +Tuesday +SELECT * FROM v1; +DAYNAME(date) +Tuesday +SELECT DAYOFWEEK('2005-09-06'); +DAYOFWEEK('2005-09-06') +3 +SELECT DAYOFWEEK(date) FROM t1; +DAYOFWEEK(date) +3 +SELECT * FROM v2; +DAYOFWEEK(date) +3 +SELECT WEEKDAY('2005-09-06'); +WEEKDAY('2005-09-06') +1 +SELECT WEEKDAY(date) FROM t1; +WEEKDAY(date) +1 +SELECT * FROM v3; +WEEKDAY(date) +1 +DROP TABLE t1; +DROP VIEW v1, v2, v3; +CREATE TABLE t1 ( a int, b int ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +CREATE VIEW v1 AS SELECT a,b FROM t1; +SELECT t1.a FROM t1 GROUP BY t1.a HAVING a > 1; +a +2 +3 +SELECT v1.a FROM v1 GROUP BY v1.a HAVING a > 1; +a +2 +3 +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 ( a int, b int ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +CREATE VIEW v1 AS SELECT a,b FROM t1; +SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > 1; +a +2 +3 +SELECT v1.a FROM v1 GROUP BY v1.a HAVING v1.a > 1; +a +2 +3 +SELECT t_1.a FROM t1 AS t_1 GROUP BY t_1.a HAVING t_1.a IN (1,2,3); +a +1 +2 +3 +SELECT v_1.a FROM v1 AS v_1 GROUP BY v_1.a HAVING v_1.a IN (1,2,3); +a +1 +2 +3 +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT, INDEX(a,b)); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 (a INT); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +INSERT INTO t2 VALUES (1,1),(2,2),(3,3); +INSERT INTO t3 VALUES (1),(2),(3); +CREATE VIEW v1 AS SELECT t1.* FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b; +CREATE VIEW v2 AS SELECT t3.* FROM t1,t3 WHERE t1.a=t3.a; +EXPLAIN SELECT t1.* FROM t1 JOIN t2 WHERE t1.a=t2.a AND t1.b=t2.b AND t1.a=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 1 Using where; Using index +1 SIMPLE t2 ref a a 10 const,test.t1.b 2 Using where; Using index +EXPLAIN SELECT * FROM v1 WHERE a=1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ref a a 5 const 1 Using where; Using index +1 PRIMARY t2 ref a a 10 const,test.t1.b 2 Using where; Using index +EXPLAIN SELECT * FROM v2 WHERE a=1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ref a a 5 const 1 Using where; Using index +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where +DROP VIEW v1,v2; +DROP TABLE t1,t2,t3; diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 71f0f28e59f..bac6e691069 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -12,6 +12,8 @@ create table mysqltest.t1 (a int, b int); create table mysqltest.t2 (a int, b int); grant select on mysqltest.t1 to mysqltest_1@localhost; grant create view,select on test.* to mysqltest_1@localhost; +create definer=root@localhost view v1 as select * from mysqltest.t1; +ERROR HY000: You need the SUPER privilege for creation view with root@localhost definer create view v1 as select * from mysqltest.t1; alter view v1 as select * from mysqltest.t1; ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1' @@ -21,6 +23,9 @@ create view mysqltest.v2 as select * from mysqltest.t1; ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' create view v2 as select * from mysqltest.t2; ERROR 42000: ANY command denied to user 'mysqltest_1'@'localhost' for table 't2' +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_1`@`localhost` SQL SECURITY DEFINER VIEW `test`.`v1` AS select `mysqltest`.`t1`.`a` AS `a`,`mysqltest`.`t1`.`b` AS `b` from `mysqltest`.`t1` grant create view,drop,select on test.* to mysqltest_1@localhost; use test; alter view v1 as select * from mysqltest.t1; @@ -120,27 +125,27 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found show create view mysqltest.v1; View Create View -v1 CREATE ALGORITHM=UNDEFINED VIEW `mysqltest`.`v1` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v1` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` explain select c from mysqltest.v2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found 2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table show create view mysqltest.v2; View Create View -v2 CREATE ALGORITHM=TEMPTABLE VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` +v2 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` explain select c from mysqltest.v3; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 system NULL NULL NULL NULL 0 const row not found show create view mysqltest.v3; View Create View -v3 CREATE ALGORITHM=UNDEFINED VIEW `mysqltest`.`v3` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v3` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` explain select c from mysqltest.v4; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found 2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table show create view mysqltest.v4; View Create View -v4 CREATE ALGORITHM=TEMPTABLE VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` +v4 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` revoke all privileges on mysqltest.* from mysqltest_1@localhost; delete from mysql.user where user='mysqltest_1'; drop database mysqltest; diff --git a/mysql-test/r/view_query_cache.result b/mysql-test/r/view_query_cache.result index e6c2c0152f3..944e1db34c9 100644 --- a/mysql-test/r/view_query_cache.result +++ b/mysql-test/r/view_query_cache.result @@ -123,4 +123,13 @@ select * from v3; a b drop view v3; drop table t1, t2; +create table t1(f1 int); +insert into t1 values(1),(2),(3); +create view v1 as select * from t1; +set query_cache_wlock_invalidate=1; +lock tables v1 read /*!32311 local */; +unlock tables; +set query_cache_wlock_invalidate=default; +drop view v1; +drop table t1; set GLOBAL query_cache_size=default; diff --git a/mysql-test/r/wait_timeout.result b/mysql-test/r/wait_timeout.result new file mode 100644 index 00000000000..56232e481c0 --- /dev/null +++ b/mysql-test/r/wait_timeout.result @@ -0,0 +1,8 @@ +select 1; +1 +1 +select 2; +ERROR HY000: MySQL server has gone away +select 3; +3 +3 diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index fd516996ae8..d8329e446ac 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -63,9 +63,11 @@ show count(*) warnings; 1 create table t1(id int); create table if not exists t1(id int); +Warnings: +Note 1050 Table 't1' already exists select @@warning_count; @@warning_count -0 +1 drop table t1; create table t1(a tinyint, b int not null, c date, d char(5)); load data infile '../../std_data/warnings_loaddata.dat' into table t1 fields terminated by ','; diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result index f3d7e151628..5fb03d2378e 100644 --- a/mysql-test/r/xa.result +++ b/mysql-test/r/xa.result @@ -9,10 +9,10 @@ select * from t1; a xa start 'test2'; xa start 'test-bad'; -ERROR XAE07: XAER_RMFAIL: The command cannot be executed in the ACTIVE state +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state insert t1 values (20); xa prepare 'test2'; -ERROR XAE07: XAER_RMFAIL: The command cannot be executed in the ACTIVE state +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state xa end 'test2'; xa prepare 'test2'; xa commit 'test2'; @@ -21,13 +21,23 @@ a 20 xa start 'testa','testb'; insert t1 values (30); +commit; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state xa end 'testa','testb'; +begin; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state +create table t2 (a int); +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state xa start 'testa','testb'; ERROR XAE08: XAER_DUPID: The XID already exists +xa start 'testa','testb', 123; +ERROR XAE08: XAER_DUPID: The XID already exists xa start 0x7465737462, 0x2030405060, 0xb; insert t1 values (40); xa end 'testb',' 0@P`',11; xa prepare 'testb',0x2030405060,11; +start transaction; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state xa recover; formatID gtrid_length bqual_length data 11 5 5 testb 0@P` diff --git a/mysql-test/std_data/ndb_config_mycnf1.cnf b/mysql-test/std_data/ndb_config_mycnf1.cnf new file mode 100644 index 00000000000..c680bfd8fa3 --- /dev/null +++ b/mysql-test/std_data/ndb_config_mycnf1.cnf @@ -0,0 +1,15 @@ +[cluster_config] +NoOfReplicas=1 +DataMemory=50M + +[cluster_config.jonas] +IndexMemory=50M +ndbd = localhost,localhost,localhost,localhost +ndb_mgmd = localhost +mysqld = localhost + +[cluster_config.ndbd.1] +DataMemory=25M + +[cluster_config.ndbd.2.jonas] +DataMemory=35M diff --git a/mysql-test/std_data/ndb_config_mycnf2.cnf b/mysql-test/std_data/ndb_config_mycnf2.cnf new file mode 100644 index 00000000000..3bf6b9a1194 --- /dev/null +++ b/mysql-test/std_data/ndb_config_mycnf2.cnf @@ -0,0 +1,31 @@ +# +# Testing automatic node id generation +# +[cluster_config] +NoOfReplicas=2 +Signum=39 + +[cluster_config.cluster0] +ndbd = localhost,localhost,localhost,localhost +ndb_mgmd = localhost +mysqld = ,,,, + +[cluster_config.cluster1] +ndbd = localhost,localhost,localhost,localhost +ndb_mgmd = localhost +mysqld = ,,,, +[cluster_config.ndbd.1.cluster1] +NodeId=2 +[cluster_config.mysqld.1.cluster1] +NodeId=1 + +[cluster_config.cluster2] +ndbd = localhost,localhost,localhost,localhost +ndb_mgmd = localhost,localhost +mysqld = ,,,, +[cluster_config.mysqld.1.cluster2] +NodeId=11 +[cluster_config.ndb_mgmd.1.cluster2] +NodeId=1 +[cluster_config.ndbd.1.cluster2] +NodeId=3 diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 5695822be6b..bae94656125 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -278,7 +278,7 @@ insert into t1 values ('ÔÅÓÔ'); select a,hex(a) from t1; alter table t1 change a a char(10) character set cp1251; select a,hex(a) from t1; -alter table t1 change a a binary(10); +alter table t1 change a a binary(4); select a,hex(a) from t1; alter table t1 change a a char(10) character set cp1251; select a,hex(a) from t1; @@ -373,24 +373,24 @@ drop table t1; # Bug#11493 - Alter table rename to default database does not work without # db name qualifying # -create database mysqltest1; +create database mysqltest; create table t1 (c1 int); # Move table to other database. -alter table t1 rename mysqltest1.t1; +alter table t1 rename mysqltest.t1; # Assure that it has moved. --error 1051 drop table t1; # Move table back. -alter table mysqltest1.t1 rename t1; +alter table mysqltest.t1 rename t1; # Assure that it is back. drop table t1; # Now test for correct message if no database is selected. # Create t1 in 'test'. create table t1 (c1 int); # Change to other db. -use mysqltest1; +use mysqltest; # Drop the current db. This de-selects any db. -drop database mysqltest1; +drop database mysqltest; # Now test for correct message. --error 1046 alter table test.t1 rename t1; diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index 2003feee163..4060892c389 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -48,8 +48,6 @@ insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),( select * from t1 procedure analyse(); drop table t1; -# End of 4.1 tests - #decimal-related test create table t1 (df decimal(5,1)); @@ -57,3 +55,15 @@ insert into t1 values(1.1); insert into t1 values(2.2); select * from t1 procedure analyse(); drop table t1; + +# +# Bug#10716 - Procedure Analyse results in wrong values for optimal field type +# + +create table t1 (d double); +insert into t1 values (100000); +select * from t1 procedure analyse (1,1); +drop table t1; + +# End of 4.1 tests + diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 4318525fe43..ac2061eeb0b 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1339,8 +1339,12 @@ SELECT * FROM t2; TRUNCATE TABLE t2; SELECT * FROM t2; +# Adding support for CHECK table +CHECK TABLE t2; +SELECT * FROM t2; + -# Just test syntax, we will never know if the out put is right or wrong +# Just test syntax, we will never know if the output is right or wrong # Must be the last test INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); # diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index 5f21d2b5813..d9c1abd9ba9 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -35,21 +35,27 @@ drop table t1; create table t1 ( a int not null default 1, big bigint ); insert into t1 (big) values (-1),(12345678901234567),(9223372036854775807),(18446744073709551615); +select * from t1; select min(big),max(big),max(big)-1 from t1; select min(big),max(big),max(big)-1 from t1 group by a; alter table t1 modify big bigint unsigned not null; select min(big),max(big),max(big)-1 from t1; select min(big),max(big),max(big)-1 from t1 group by a; +insert into t1 (big) values (18446744073709551615); +select * from t1; +select min(big),max(big),max(big)-1 from t1; +select min(big),max(big),max(big)-1 from t1 group by a; alter table t1 add key (big); select min(big),max(big),max(big)-1 from t1; select min(big),max(big),max(big)-1 from t1 group by a; alter table t1 modify big bigint not null; +select * from t1; select min(big),max(big),max(big)-1 from t1; select min(big),max(big),max(big)-1 from t1 group by a; drop table t1; # -# Test problem with big values fir auto_increment +# Test problem with big values for auto_increment # create table t1 (id bigint auto_increment primary key, a int) auto_increment=9999999999; @@ -112,6 +118,7 @@ drop table t1, t2; # # Test of CREATE ... SELECT and unsigned integers # + create table t1 select 1 as 'a'; show create table t1; drop table t1; @@ -119,3 +126,147 @@ create table t1 select 9223372036854775809 as 'a'; show create table t1; select * from t1; drop table t1; +DROP DATABASE IF EXISTS `scott`; + + +# +# Check various conversions from/to unsigned bigint. +# + +create table t1 (a char(100), b varchar(100), c text, d blob); +insert into t1 values( + 18446744073709551615,18446744073709551615, + 18446744073709551615, 18446744073709551615 +); + +insert into t1 values (-1 | 0,-1 | 0,-1 | 0 ,-1 | 0); +select * from t1; +drop table t1; + +create table t1 ( quantity decimal(2) unsigned); +insert into t1 values (500), (-500), (~0), (-1); +select * from t1; +drop table t1; + +# +# Test of storing decimal values in BIGINT range +# (Bug #12750: Incorrect storage of 9999999999999999999 in DECIMAL(19, 0)) +# + +CREATE TABLE t1 ( + `col1` INT(1) NULL, + `col2` INT(2) NULL, + `col3` INT(3) NULL, + `col4` INT(4) NULL, + `col5` INT(5) NULL, + `col6` INT(6) NULL, + `col7` INT(7) NULL, + `col8` INT(8) NULL, + `col9` INT(9) NULL, + `col10` BIGINT(10) NULL, + `col11` BIGINT(11) NULL, + `col12` BIGINT(12) NULL, + `col13` BIGINT(13) NULL, + `col14` BIGINT(14) NULL, + `col15` BIGINT(15) NULL, + `col16` BIGINT(16) NULL, + `col17` BIGINT(17) NULL, + `col18` BIGINT(18) NULL, + `col19` DECIMAL(19, 0) NULL, + `col20` DECIMAL(20, 0) NULL, + `col21` DECIMAL(21, 0) NULL, + `col22` DECIMAL(22, 0) NULL, + `col23` DECIMAL(23, 0) NULL, + `col24` DECIMAL(24, 0) NULL, + `col25` DECIMAL(25, 0) NULL, + `col26` DECIMAL(26, 0) NULL, + `col27` DECIMAL(27, 0) NULL, + `col28` DECIMAL(28, 0) NULL, + `col29` DECIMAL(29, 0) NULL, + `col30` DECIMAL(30, 0) NULL, + `col31` DECIMAL(31, 0) NULL, + `col32` DECIMAL(32, 0) NULL, + `col33` DECIMAL(33, 0) NULL, + `col34` DECIMAL(34, 0) NULL, + `col35` DECIMAL(35, 0) NULL, + `col36` DECIMAL(36, 0) NULL, + `col37` DECIMAL(37, 0) NULL, + `col38` DECIMAL(38, 0) NULL, + `fix1` DECIMAL(38, 1) NULL, + `fix2` DECIMAL(38, 2) NULL, + `fix3` DECIMAL(38, 3) NULL, + `fix4` DECIMAL(38, 4) NULL, + `fix5` DECIMAL(38, 5) NULL, + `fix6` DECIMAL(38, 6) NULL, + `fix7` DECIMAL(38, 7) NULL, + `fix8` DECIMAL(38, 8) NULL, + `fix9` DECIMAL(38, 9) NULL, + `fix10` DECIMAL(38, 10) NULL, + `fix11` DECIMAL(38, 11) NULL, + `fix12` DECIMAL(38, 12) NULL, + `fix13` DECIMAL(38, 13) NULL, + `fix14` DECIMAL(38, 14) NULL, + `fix15` DECIMAL(38, 15) NULL, + `fix16` DECIMAL(38, 16) NULL, + `fix17` DECIMAL(38, 17) NULL, + `fix18` DECIMAL(38, 18) NULL, + `fix19` DECIMAL(38, 19) NULL, + `fix20` DECIMAL(38, 20) NULL, + `fix21` DECIMAL(38, 21) NULL, + `fix22` DECIMAL(38, 22) NULL, + `fix23` DECIMAL(38, 23) NULL, + `fix24` DECIMAL(38, 24) NULL, + `fix25` DECIMAL(38, 25) NULL, + `fix26` DECIMAL(38, 26) NULL, + `fix27` DECIMAL(38, 27) NULL, + `fix28` DECIMAL(38, 28) NULL, + `fix29` DECIMAL(38, 29) NULL, + `fix30` DECIMAL(38, 30) NULL +); + +INSERT INTO t1(`col1`, `col2`, `col3`, `col4`, `col5`, `col6`, `col7`, `col8`, `col9`, `col10`, `col11`, `col12`, `col13`, `col14`, `col15`, `col16`, `col17`, `col18`, `col19`, `col20`, `col21`, `col22`, `col23`, `col24`, `col25`, `col26`, `col27`, `col28`, `col29`, `col30`, `col31`, `col32`, `col33`, `col34`, `col35`, `col36`, `col37`, `col38`, `fix1`, `fix2`, `fix3`, `fix4`, `fix5`, `fix6`, `fix7`, `fix8`, `fix9`, `fix10`, `fix11`, `fix12`, `fix13`, `fix14`, `fix15`, `fix16`, `fix17`, `fix18`, `fix19`, `fix20`, `fix21`, `fix22`, `fix23`, `fix24`, `fix25`, `fix26`, `fix27`, `fix28`, `fix29`, `fix30`) +VALUES (9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, +9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, +999999999999999, 9999999999999999, 99999999999999999, 999999999999999999, +9999999999999999999, 99999999999999999999, 999999999999999999999, +9999999999999999999999, 99999999999999999999999, 999999999999999999999999, +9999999999999999999999999, 99999999999999999999999999, +999999999999999999999999999, 9999999999999999999999999999, +99999999999999999999999999999, 999999999999999999999999999999, +9999999999999999999999999999999, 99999999999999999999999999999999, +999999999999999999999999999999999, 9999999999999999999999999999999999, +99999999999999999999999999999999999, 999999999999999999999999999999999999, +9999999999999999999999999999999999999, 99999999999999999999999999999999999999, +9999999999999999999999999999999999999.9, +999999999999999999999999999999999999.99, +99999999999999999999999999999999999.999, +9999999999999999999999999999999999.9999, +999999999999999999999999999999999.99999, +99999999999999999999999999999999.999999, +9999999999999999999999999999999.9999999, +999999999999999999999999999999.99999999, +99999999999999999999999999999.999999999, +9999999999999999999999999999.9999999999, +999999999999999999999999999.99999999999, +99999999999999999999999999.999999999999, +9999999999999999999999999.9999999999999, +999999999999999999999999.99999999999999, +99999999999999999999999.999999999999999, +9999999999999999999999.9999999999999999, +999999999999999999999.99999999999999999, +99999999999999999999.999999999999999999, +9999999999999999999.9999999999999999999, +999999999999999999.99999999999999999999, +99999999999999999.999999999999999999999, +9999999999999999.9999999999999999999999, +999999999999999.99999999999999999999999, +99999999999999.999999999999999999999999, +9999999999999.9999999999999999999999999, +999999999999.99999999999999999999999999, +99999999999.999999999999999999999999999, +9999999999.9999999999999999999999999999, +999999999.99999999999999999999999999999, +99999999.999999999999999999999999999999); + +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/binary.test b/mysql-test/t/binary.test index 02773b32302..1ac0cfebb28 100644 --- a/mysql-test/t/binary.test +++ b/mysql-test/t/binary.test @@ -56,7 +56,7 @@ drop table t1; # # Test of binary and upper/lower # -create table t1 (a char(15) binary, b binary(15)); +create table t1 (a char(3) binary, b binary(3)); insert into t1 values ('aaa','bbb'),('AAA','BBB'); select upper(a),upper(b) from t1; select lower(a),lower(b) from t1; diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 2049c17580e..70eb87131df 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -27,6 +27,10 @@ select CONVERT(DATE "2004-01-22 21:45:33",CHAR); select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4)); select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)); select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); +select CAST(0xb3 as signed); +select CAST(0x8fffffffffffffff as signed); +select CAST(0xffffffffffffffff as unsigned); +select CAST(0xfffffffffffffffe as signed); select cast('-10a' as signed integer); select cast('a10' as unsigned integer); select 10+'a'; @@ -97,7 +101,7 @@ drop table t1; # Bug 2202 # CAST from BINARY to non-BINARY and from non-BINARY to BINARY # -create table t1 (a binary(10), b char(10) character set koi8r); +create table t1 (a binary(4), b char(4) character set koi8r); insert into t1 values (_binary'ÔÅÓÔ',_binary'ÔÅÓÔ'); select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; set names koi8r; @@ -156,6 +160,11 @@ select cast(concat('184467440','73709551615') as signed); select cast(repeat('1',20) as unsigned); select cast(repeat('1',20) as signed); +# +# Bug #13344: cast of large decimal to signed int not handled correctly +# +select cast(1.0e+300 as signed int); + # End of 4.1 tests diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 64b170970ca..60ac7b88bbe 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -6,6 +6,10 @@ # This test makes no sense with the embedded server --source include/not_embedded.inc +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + #connect (con1,localhost,root,,""); #show tables; connect (con1,localhost,root,,mysql); @@ -77,4 +81,18 @@ show tables; delete from mysql.user where user=_binary"test"; flush privileges; +# +# Bug#12517: Clear user variables and replication events before +# closing temp tables in thread cleanup. +connect (con2,localhost,root,,test); +connection con2; +create table t1 (id integer not null auto_increment primary key); +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +disconnect con2; +--sleep 5 +connection default; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 876ee1e3d5e..b72dc49e89a 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -249,7 +249,7 @@ drop table t1; create table `t1 `(a int); --error 1102 create database `db1 `; ---error 1166; +--error 1166 create table t1(`a ` int); # @@ -533,4 +533,16 @@ create view v1 as select 'foo' from dual; create table t1 like v1; drop view v1; drop database mysqltest; +# Bug #6008 MySQL does not create warnings when +# creating database and using IF NOT EXISTS +# +create database mysqltest; +create database if not exists mysqltest character set latin2; +show create database mysqltest; +drop database mysqltest; +use test; +create table t1 (a int); +create table if not exists t1 (a int); +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/create_select_tmp.test b/mysql-test/t/create_select_tmp.test index 2e4c0f22997..1661a115f72 100644 --- a/mysql-test/t/create_select_tmp.test +++ b/mysql-test/t/create_select_tmp.test @@ -11,21 +11,21 @@ drop table if exists t1, t2; --enable_warnings CREATE TABLE t1 ( a int ); INSERT INTO t1 VALUES (1),(2),(1); ---error 1062; +--error 1062 CREATE TABLE t2 ( PRIMARY KEY (a) ) ENGINE=INNODB SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; ---error 1062; +--error 1062 CREATE TEMPORARY TABLE t2 ( PRIMARY KEY (a) ) ENGINE=INNODB SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; ---error 1062; +--error 1062 CREATE TABLE t2 ( PRIMARY KEY (a) ) ENGINE=MYISAM SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; ---error 1062; +--error 1062 CREATE TEMPORARY TABLE t2 ( PRIMARY KEY (a) ) ENGINE=MYISAM SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; # End of 4.1 tests diff --git a/mysql-test/t/ctype_big5.test b/mysql-test/t/ctype_big5.test index 73d9f06042c..ffe2a12234e 100644 --- a/mysql-test/t/ctype_big5.test +++ b/mysql-test/t/ctype_big5.test @@ -15,9 +15,11 @@ SET NAMES big5; SET collation_connection='big5_chinese_ci'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc SET collation_connection='big5_bin'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc # # Bugs#9357: TEXT columns break string with special word in BIG5 charset. @@ -36,4 +38,19 @@ INSERT INTO t1 VALUES(0xA741ADCCA66EB6DC20A7DAADCCABDCA66E); SELECT HEX(a) FROM t1 WHERE MATCH(a) AGAINST (0xA741ADCCA66EB6DC IN BOOLEAN MODE); DROP TABLE t1; +# +# Bug#12476 Some big5 codes are still missing. +# +set names big5; +create table t1 (a char character set big5); +insert into t1 values (0xF9D6),(0xF9D7),(0xF9D8),(0xF9D9); +insert into t1 values (0xF9DA),(0xF9DB),(0xF9DC); +# Check round trip +select hex(a) a, hex(@u:=convert(a using utf8)) b, +hex(convert(@u using big5)) c from t1 order by a; +# Check that there is no "illegal mix of collations" error with Unicode. +alter table t1 convert to character set utf8; +select hex(a) from t1 where a = _big5 0xF9DC; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/ctype_cp1251.test b/mysql-test/t/ctype_cp1251.test index 1aafe7b7266..463a9cea4bc 100644 --- a/mysql-test/t/ctype_cp1251.test +++ b/mysql-test/t/ctype_cp1251.test @@ -21,7 +21,7 @@ drop table t1; # # Test of binary and upper/lower # -create table t1 (a char(15) binary, b binary(15)) character set cp1251; +create table t1 (a char(3) binary, b binary(3)) character set cp1251; insert into t1 values ('aaa','bbb'),('AAA','BBB'); select upper(a),upper(b) from t1; select lower(a),lower(b) from t1; diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test index 3d630311b3a..082786e38af 100644 --- a/mysql-test/t/ctype_cp932.test +++ b/mysql-test/t/ctype_cp932.test @@ -424,3 +424,13 @@ SET collation_connection='cp932_japanese_ci'; -- source include/ctype_filesort.inc SET collation_connection='cp932_bin'; -- source include/ctype_filesort.inc + +# +# Bug#12547: Inserting long string into varchar causes table crash in cp932 +# +create table t1 (col1 varchar(1)) character set cp932; +insert into t1 values ('a'); +insert into t1 values ('ab'); +select * from t1; +insert into t1 values ('abc'); +select * from t1; diff --git a/mysql-test/t/ctype_gbk.test b/mysql-test/t/ctype_gbk.test index 2210891454e..5eeade96186 100644 --- a/mysql-test/t/ctype_gbk.test +++ b/mysql-test/t/ctype_gbk.test @@ -15,9 +15,11 @@ SET NAMES gbk; SET collation_connection='gbk_chinese_ci'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc SET collation_connection='gbk_bin'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc # # Bug#11987 mysql will truncate the text when diff --git a/mysql-test/t/ctype_latin1.test b/mysql-test/t/ctype_latin1.test index 1b83373da29..a005b4769c4 100644 --- a/mysql-test/t/ctype_latin1.test +++ b/mysql-test/t/ctype_latin1.test @@ -55,6 +55,23 @@ SELECT DROP TABLE t1; # +# Bug#13145: A table named "C-cedilla" can't be dropped. +# Accept extended cp1252 letters as valid identifiers. +# This test partially checks that "ctype" array is correct +# for cp1252 extended characters 0x80-0x9F. +# +# 0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +# 0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON +# 0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +# 0x8E 0x017D #LATIN CAPITAL LETTER Z WITH CARON +# 0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON +# 0x9C 0x0153 #LATIN SMALL LIGATURE OE +# 0x9E 0x017E #LATIN SMALL LETTER Z WITH CARON +# 0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS +# +SELECT 1 as ƒ, 2 as Š, 3 as Œ, 4 as Ž, 5 as š, 6 as œ, 7 as ž, 8 as Ÿ; + +# # Bug #6737: REGEXP gives wrong result with case sensitive collation # select 'a' regexp 'A' collate latin1_general_ci; @@ -64,8 +81,10 @@ select 'a' regexp 'A' collate latin1_bin; SET collation_connection='latin1_swedish_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc SET collation_connection='latin1_bin'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc # # Bug#8041 diff --git a/mysql-test/t/ctype_many.test b/mysql-test/t/ctype_many.test index 22e844c6868..0903c3dd7fa 100644 --- a/mysql-test/t/ctype_many.test +++ b/mysql-test/t/ctype_many.test @@ -148,7 +148,7 @@ SET CHARACTER SET koi8r; SELECT * FROM t1; -ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL default ''; +ALTER TABLE t1 ADD bin_f CHAR(1) BYTE NOT NULL default ''; UPDATE t1 SET bin_f=koi8_ru_f; SELECT COUNT(DISTINCT bin_f),COUNT(DISTINCT koi8_ru_f),COUNT(DISTINCT utf8_f) FROM t1; @@ -204,7 +204,7 @@ UPDATE t1 SET greek_f=CONVERT(ucs2_f USING greek) WHERE comment LIKE _latin2'GRE UPDATE t1 SET armscii8_f=CONVERT(ucs2_f USING armscii8) WHERE comment LIKE _latin2'ARM%'; UPDATE t1 SET utf8_f=CONVERT(ucs2_f USING utf8) WHERE utf8_f=_utf8''; UPDATE t1 SET ucs2_f=CONVERT(utf8_f USING ucs2) WHERE ucs2_f=_ucs2''; -SELECT * FROM t1; +SELECT comment, koi8_ru_f, utf8_f, hex(bin_f), ucs2_f, armscii8_f, greek_f FROM t1; SET CHARACTER SET 'binary'; SELECT * FROM t1; SELECT min(comment),count(*) FROM t1 GROUP BY ucs2_f; diff --git a/mysql-test/t/ctype_sjis.test b/mysql-test/t/ctype_sjis.test index 252f0a0b6c8..1d807b5e9a8 100644 --- a/mysql-test/t/ctype_sjis.test +++ b/mysql-test/t/ctype_sjis.test @@ -67,9 +67,11 @@ drop table t1; SET collation_connection='sjis_japanese_ci'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc SET collation_connection='sjis_bin'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc # Check parsing of string literals in SJIS with multibyte characters that # have an embedded \ in them. (Bug #8303) diff --git a/mysql-test/t/ctype_tis620.test b/mysql-test/t/ctype_tis620.test index d649828eda3..c49540de24b 100644 --- a/mysql-test/t/ctype_tis620.test +++ b/mysql-test/t/ctype_tis620.test @@ -155,7 +155,9 @@ DROP TABLE t1; SET collation_connection='tis620_thai_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc SET collation_connection='tis620_bin'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc # End of 4.1 tests diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 098ea33c6b2..6d8713f4910 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -211,6 +211,7 @@ select group_concat(c1 order by c1) from t1 group by c1 collate utf8_lithuanian_ select group_concat(c1 order by c1) from t1 group by c1 collate utf8_slovak_ci; select group_concat(c1 order by c1) from t1 group by c1 collate utf8_spanish2_ci; select group_concat(c1 order by c1) from t1 group by c1 collate utf8_roman_ci; +select group_concat(c1 order by c1) from t1 group by c1 collate utf8_esperanto_ci; drop table t1; @@ -455,6 +456,7 @@ drop table t1; SET collation_connection='utf8_unicode_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc # End of 4.1 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 668edb3fafe..626c7e0e1b6 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -372,9 +372,11 @@ drop table t1; SET collation_connection='ucs2_general_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc SET NAMES latin1; SET collation_connection='ucs2_bin'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc # # Bug#10344 Some string functions fail for UCS2 diff --git a/mysql-test/t/ctype_ujis.test b/mysql-test/t/ctype_ujis.test index 88386500c9f..c1d6c67387b 100644 --- a/mysql-test/t/ctype_ujis.test +++ b/mysql-test/t/ctype_ujis.test @@ -1146,8 +1146,52 @@ DROP TABLE t1; SET collation_connection='ujis_japanese_ci'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc SET collation_connection='ujis_bin'; -- source include/ctype_filesort.inc -- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc # End of 4.1 tests +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +DROP PROCEDURE IF EXISTS sp1; +--enable_warnings + +set names ujis; +set character_set_database = ujis; +set character_set_server = ujis; + +CREATE TABLE t1(c1 char(2)) default charset = ujis; +CREATE TABLE t2(c2 char(2)) default charset = ujis; + +INSERT INTO t1 VALUES(_ujis 0xA4A2); + +DELIMITER |; +CREATE PROCEDURE sp1() +BEGIN + DECLARE a CHAR(1); + DECLARE cur1 CURSOR FOR SELECT c1 FROM t1; + OPEN cur1; + FETCH cur1 INTO a; + INSERT INTO t2 VALUES (a); + CLOSE cur1; +END| +DELIMITER ;| +CALL sp1(); + +#The data in t1 and t2 should be the same but different +SELECT c1,c2 FROM t1,t2; + +#Since the result of hex(convert(_latin1 0xA4A2 using ujis)) +#equals to hex(c2), it seems that the value which was inserted +#by using cursor is interpreted as latin1 character set +SELECT hex(convert(_latin1 0xA4A2 using ujis)),hex(c2) FROM t1,t2; + +DROP PROCEDURE sp1; +DROP TABLE t1; +DROP TABLE t2; + +set names default; +set character_set_database=default; +set character_set_server=default; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index ce259f465d9..5670e9efbf9 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -685,8 +685,10 @@ drop table t1; SET collation_connection='utf8_general_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc SET collation_connection='utf8_bin'; -- source include/ctype_filesort.inc +-- source include/ctype_like_escape.inc # # Bug #7874 CONCAT() gives wrong results mixing @@ -810,6 +812,12 @@ alter table t1 modify a char(2) character set utf8; select char_length(a), length(a), a from t1 order by a; drop table t1; +# +# Bugs#12611 +# ESCAPE + LIKE do not work when the escape char is a multibyte one +# +set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; # # Bugs#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0 @@ -843,6 +851,23 @@ insert into t1 values (_utf8 0x5b); select hex(a) from t1; drop table t1; +# +# Bug#13751 find_in_set: Illegal mix of collations +# +set names 'latin1'; +create table t1 (a varchar(255)) default charset=utf8; +select * from t1 where find_in_set('-1', a); +drop table t1; + +# +# Bug#13233: select distinct char(column) fails with utf8 +# +create table t1 (a int); +insert into t1 values (48),(49),(50); +set names utf8; +select distinct char(a) from t1; +drop table t1; + # End of 4.1 tests # @@ -857,3 +882,63 @@ SELECT DISTINCT id FROM t1; SELECT DISTINCT id FROM t1 ORDER BY id; DROP TABLE t1; + +# +# Bugs#10504: Character set does not support traditional mode +# +set names utf8; +# correct value +select hex(char(1 using utf8)); +select char(0xd1,0x8f using utf8); +select char(0xd18f using utf8); +select char(53647 using utf8); +# incorrect value: return with warning +select char(0xff,0x8f using utf8); +# incorrect value in strict mode: return NULL with "Error" level warning +set sql_mode=traditional; +select char(0xff,0x8f using utf8); +select char(195 using utf8); +select char(196 using utf8); +select char(2557 using utf8); + +# +# Check convert + char + using +# +select hex(convert(char(2557 using latin1) using utf8)); + +# +# char() without USING returns "binary" by default, any argument is ok +# +select hex(char(195)); +select hex(char(196)); +select hex(char(2557)); + + + +# +# Bug#12891: UNION doesn't return DISTINCT result for multi-byte characters +# +set names utf8; +create table t1 (a char(1)) default character set utf8; +create table t2 (a char(1)) default character set utf8; +insert into t1 values('a'),('a'),(0xE38182),(0xE38182); +insert into t1 values('i'),('i'),(0xE38184),(0xE38184); +select * from t1 union distinct select * from t2; +drop table t1,t2; + + +# +# Bug#12371: executing prepared statement fails (illegal mix of collations) +# +set names utf8; +create table t1 (a char(10), b varchar(10)); +insert into t1 values ('bar','kostja'); +insert into t1 values ('kostja','bar'); +prepare my_stmt from "select * from t1 where a=?"; +set @a:='bar'; +execute my_stmt using @a; +set @a:='kostja'; +execute my_stmt using @a; +set @a:=null; +execute my_stmt using @a; +drop table if exists t1; diff --git a/mysql-test/t/default.test b/mysql-test/t/default.test index 42620a27b66..b5522394d2d 100644 --- a/mysql-test/t/default.test +++ b/mysql-test/t/default.test @@ -40,7 +40,6 @@ CREATE TABLE t1 (a varchar(30) binary NOT NULL DEFAULT ' ', ENGINE=InnoDB DEFAULT CHARACTER SET = latin1 COLLATE latin1_bin; --enable_warnings -SHOW CREATE TABLE t1; INSERT into t1 (b) values ('1'); SHOW WARNINGS; SELECT * from t1; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index f52e12849e4..33b06e9bc11 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -258,4 +258,17 @@ create table t2 (a int); select * from (select * from t1,t2) foo; drop table t1,t2; +# +# Bug#10586 - query works with 4.1.8, but not with 4.1.11 +# +create table t1 (ID int unsigned not null auto_increment, + DATA varchar(5) not null, primary key (ID)); +create table t2 (ID int unsigned not null auto_increment, + DATA varchar(5) not null, FID int unsigned not null, + primary key (ID)); +select A.* from (t1 inner join (select * from t2) as A on t1.ID = A.FID); +select t2.* from ((select * from t1) as A inner join t2 on A.ID = t2.FID); +select t2.* from (select * from t1) as A inner join t2 on A.ID = t2.FID; +drop table t1, t2; + # End of 4.1 tests diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index e69de29bb2d..6483284633f 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -0,0 +1,360 @@ +# +# Bug with distinct and INSERT INTO +# Bug with group by and not used fields +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +CREATE TABLE t1 (id int,facility char(20)); +CREATE TABLE t2 (facility char(20)); +INSERT INTO t1 VALUES (NULL,NULL); +INSERT INTO t1 VALUES (-1,''); +INSERT INTO t1 VALUES (0,''); +INSERT INTO t1 VALUES (1,'/L'); +INSERT INTO t1 VALUES (2,'A01'); +INSERT INTO t1 VALUES (3,'ANC'); +INSERT INTO t1 VALUES (4,'F01'); +INSERT INTO t1 VALUES (5,'FBX'); +INSERT INTO t1 VALUES (6,'MT'); +INSERT INTO t1 VALUES (7,'P'); +INSERT INTO t1 VALUES (8,'RV'); +INSERT INTO t1 VALUES (9,'SRV'); +INSERT INTO t1 VALUES (10,'VMT'); +INSERT INTO t2 SELECT DISTINCT FACILITY FROM t1; + +select id from t1 group by id; +select * from t1 order by id; +select id-5,facility from t1 order by "id-5"; +select id,concat(facility) from t1 group by id ; +select id+0 as a,max(id),concat(facility) as b from t1 group by a order by b desc,a; +select id >= 0 and id <= 5 as grp,count(*) from t1 group by grp; + +SELECT DISTINCT FACILITY FROM t1; +SELECT FACILITY FROM t2; +SELECT count(*) from t1,t2 where t1.facility=t2.facility; +select count(facility) from t1; +select count(*) from t1; +select count(*) from t1 where facility IS NULL; +select count(*) from t1 where facility = NULL; +select count(*) from t1 where facility IS NOT NULL; +select count(*) from t1 where id IS NULL; +select count(*) from t1 where id IS NOT NULL; + +drop table t1,t2; + +# +# Problem with distinct without results +# +CREATE TABLE t1 (UserId int(11) DEFAULT '0' NOT NULL); +INSERT INTO t1 VALUES (20); +INSERT INTO t1 VALUES (27); + +SELECT UserId FROM t1 WHERE Userid=22; +SELECT UserId FROM t1 WHERE UserId=22 group by Userid; +SELECT DISTINCT UserId FROM t1 WHERE UserId=22 group by Userid; +SELECT DISTINCT UserId FROM t1 WHERE UserId=22; +drop table t1; + +# +# Test of distinct +# + +CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned); +INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1); +CREATE TABLE t2 (a int(10) unsigned not null, key (A)); +INSERT INTO t2 VALUES (1),(2); +CREATE TABLE t3 (a int(10) unsigned, key(A), b text); +INSERT INTO t3 VALUES (1,'1'),(2,'2'); +SELECT DISTINCT t3.b FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; +INSERT INTO t2 values (1),(2),(3); +INSERT INTO t3 VALUES (1,'1'),(2,'2'),(1,'1'),(2,'2'); +explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; +SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; + +# Create a lot of data into t3; +create temporary table t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; + +explain select distinct t1.a from t1,t3 where t1.a=t3.a; +#flush status; +select distinct t1.a from t1,t3 where t1.a=t3.a; +#show status like 'Handler%'; +#flush status; +select distinct 1 from t1,t3 where t1.a=t3.a; +#show status like 'Handler%'; + +explain SELECT distinct t1.a from t1; +explain SELECT distinct t1.a from t1 order by a desc; +explain SELECT t1.a from t1 group by a order by a desc; +explain SELECT distinct t1.a from t1 order by a desc limit 1; +explain SELECT distinct a from t3 order by a desc limit 2; +explain SELECT distinct a,b from t3 order by a+1; +explain SELECT distinct a,b from t3 order by a limit 10; +explain SELECT a,b from t3 group by a,b order by a+1; + +drop table t1,t2,t3,t4; + +CREATE TABLE t1 (name varchar(255)); +INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae'); +SELECT DISTINCT * FROM t1 LIMIT 2; +SELECT DISTINCT name FROM t1 LIMIT 2; +SELECT DISTINCT 1 FROM t1 LIMIT 2; +drop table t1; + +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(75) DEFAULT '' NOT NULL, + LINK_ID int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME), + KEY LINK_ID (LINK_ID) +); + +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0),(2,'Jack',0),(3,'Bill',0); + +CREATE TABLE t2 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(150) DEFAULT '' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME) +); + +SELECT DISTINCT + t2.id AS key_link_id, + t2.name AS link +FROM t1 +LEFT JOIN t2 ON t1.link_id=t2.id +GROUP BY t1.id +ORDER BY link; +drop table t1,t2; + +# +# Problem with table dependencies +# + +create table t1 ( + id int not null, + name tinytext not null, + unique (id) +); +create table t2 ( + id int not null, + idx int not null, + unique (id, idx) +); +create table t3 ( + id int not null, + idx int not null, + unique (id, idx) +); +insert into t1 values (1,'yes'), (2,'no'); +insert into t2 values (1,1); +insert into t3 values (1,1); +EXPLAIN +SELECT DISTINCT + t1.id +from + t1 + straight_join + t2 + straight_join + t3 + straight_join + t1 as j_lj_t2 left join t2 as t2_lj + on j_lj_t2.id=t2_lj.id + straight_join + t1 as j_lj_t3 left join t3 as t3_lj + on j_lj_t3.id=t3_lj.id +WHERE + ((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2)) + AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); +SELECT DISTINCT + t1.id +from + t1 + straight_join + t2 + straight_join + t3 + straight_join + t1 as j_lj_t2 left join t2 as t2_lj + on j_lj_t2.id=t2_lj.id + straight_join + t1 as j_lj_t3 left join t3 as t3_lj + on j_lj_t3.id=t3_lj.id +WHERE + ((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2)) + AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); +drop table t1,t2,t3; + +# +# Test using DISTINCT on a function that contains a group function +# This also test the case when one doesn't use all fields in GROUP BY. +# + +create table t1 (a int not null, b int not null, t time); +insert into t1 values (1,1,"00:06:15"),(1,2,"00:06:15"),(1,2,"00:30:15"),(1,3,"00:06:15"),(1,3,"00:30:15"); +select a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; +select distinct a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; +create table t2 (a int not null primary key, b int); +insert into t2 values (1,1),(2,2),(3,3); +select t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b; +select distinct t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b; +drop table t1,t2; + +# +# Test problem with DISTINCT and HAVING +# +create table t1 (a int not null,b char(5), c text); +insert into t1 (a) values (1),(2),(3),(4),(1),(2),(3),(4); +select distinct a from t1 group by b,a having a > 2 order by a desc; +select distinct a,c from t1 group by b,c,a having a > 2 order by a desc; +drop table t1; + +# +# Test problem with DISTINCT and ORDER BY DESC +# + +create table t1 (a char(1), key(a)) engine=myisam; +insert into t1 values('1'),('1'); +select * from t1 where a >= '1'; +select distinct a from t1 order by a desc; +select distinct a from t1 where a >= '1' order by a desc; +drop table t1; + +# +# Test when using a not previously used column in ORDER BY +# + +CREATE TABLE t1 (email varchar(50), infoID BIGINT, dateentered DATETIME); +CREATE TABLE t2 (infoID BIGINT, shipcode varchar(10)); + +INSERT INTO t1 (email, infoID, dateentered) VALUES + ('test1@testdomain.com', 1, '2002-07-30 22:56:38'), + ('test1@testdomain.com', 1, '2002-07-27 22:58:16'), + ('test2@testdomain.com', 1, '2002-06-19 15:22:19'), + ('test2@testdomain.com', 2, '2002-06-18 14:23:47'), + ('test3@testdomain.com', 1, '2002-05-19 22:17:32'); + +INSERT INTO t2(infoID, shipcode) VALUES + (1, 'Z001'), + (2, 'R002'); + +SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID; +SELECT DISTINCTROW email FROM t1 ORDER BY dateentered DESC; +SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID ORDER BY dateentered DESC; +drop table t1,t2; + +# +# test with table.* in DISTINCT +# + +CREATE TABLE t1 (privatemessageid int(10) unsigned NOT NULL auto_increment, folderid smallint(6) NOT NULL default '0', userid int(10) unsigned NOT NULL default '0', touserid int(10) unsigned NOT NULL default '0', fromuserid int(10) unsigned NOT NULL default '0', title varchar(250) NOT NULL default '', message mediumtext NOT NULL, dateline int(10) unsigned NOT NULL default '0', showsignature smallint(6) NOT NULL default '0', iconid smallint(5) unsigned NOT NULL default '0', messageread smallint(6) NOT NULL default '0', readtime int(10) unsigned NOT NULL default '0', receipt smallint(6) unsigned NOT NULL default '0', deleteprompt smallint(6) unsigned NOT NULL default '0', multiplerecipients smallint(6) unsigned NOT NULL default '0', PRIMARY KEY (privatemessageid), KEY userid (userid)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (128,0,33,33,8,':D','',996121863,1,0,2,996122850,2,0,0); +CREATE TABLE t2 (userid int(10) unsigned NOT NULL auto_increment, usergroupid smallint(5) unsigned NOT NULL default '0', username varchar(50) NOT NULL default '', password varchar(50) NOT NULL default '', email varchar(50) NOT NULL default '', styleid smallint(5) unsigned NOT NULL default '0', parentemail varchar(50) NOT NULL default '', coppauser smallint(6) NOT NULL default '0', homepage varchar(100) NOT NULL default '', icq varchar(20) NOT NULL default '', aim varchar(20) NOT NULL default '', yahoo varchar(20) NOT NULL default '', signature mediumtext NOT NULL, adminemail smallint(6) NOT NULL default '0', showemail smallint(6) NOT NULL default '0', invisible smallint(6) NOT NULL default '0', usertitle varchar(250) NOT NULL default '', customtitle smallint(6) NOT NULL default '0', joindate int(10) unsigned NOT NULL default '0', cookieuser smallint(6) NOT NULL default '0', daysprune smallint(6) NOT NULL default '0', lastvisit int(10) unsigned NOT NULL default '0', lastactivity int(10) unsigned NOT NULL default '0', lastpost int(10) unsigned NOT NULL default '0', posts smallint(5) unsigned NOT NULL default '0', timezoneoffset varchar(4) NOT NULL default '', emailnotification smallint(6) NOT NULL default '0', buddylist mediumtext NOT NULL, ignorelist mediumtext NOT NULL, pmfolders mediumtext NOT NULL, receivepm smallint(6) NOT NULL default '0', emailonpm smallint(6) NOT NULL default '0', pmpopup smallint(6) NOT NULL default '0', avatarid smallint(6) NOT NULL default '0', avatarrevision int(6) unsigned NOT NULL default '0', options smallint(6) NOT NULL default '15', birthday date NOT NULL default '0000-00-00', maxposts smallint(6) NOT NULL default '-1', startofweek smallint(6) NOT NULL default '1', ipaddress varchar(20) NOT NULL default '', referrerid int(10) unsigned NOT NULL default '0', nosessionhash smallint(6) NOT NULL default '0', autorefresh smallint(6) NOT NULL default '-1', messagepopup tinyint(2) NOT NULL default '0', inforum smallint(5) unsigned NOT NULL default '0', ratenum smallint(5) unsigned NOT NULL default '0', ratetotal smallint(5) unsigned NOT NULL default '0', allowrate smallint(5) unsigned NOT NULL default '1', PRIMARY KEY (userid), KEY usergroupid (usergroupid), KEY username (username), KEY inforum (inforum)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (33,6,'Kevin','0','kevin@stileproject.com',1,'',0,'http://www.stileproject.com','','','','',1,1,0,'Administrator',0,996120694,1,-1,1030996168,1031027028,1030599436,36,'-6',0,'','','',1,0,1,0,0,15,'0000-00-00',-1,1,'64.0.0.0',0,1,-1,0,0,4,19,1); +SELECT DISTINCT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t2.userid = t1.touserid); +DROP TABLE t1,t2; + +# +# test with const_item in ORDER BY +# + +CREATE TABLE t1 (a int primary key, b int, c int); +INSERT t1 VALUES (1,2,3); +CREATE TABLE t2 (a int primary key, b int, c int); +INSERT t2 VALUES (3,4,5); +SELECT DISTINCT t1.a, t2.b FROM t1, t2 WHERE t1.a=1 ORDER BY t2.c; +DROP TABLE t1,t2; + +# +# Test of LEFT() with distinct +# + +CREATE table t1 ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL default '', PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=3 ; +INSERT INTO t1 VALUES (1, 'aaaaa'); +INSERT INTO t1 VALUES (3, 'aaaaa'); +INSERT INTO t1 VALUES (2, 'eeeeeee'); +select distinct left(name,1) as name from t1; +drop table t1; + +# +# Test case from sel000100 +# + +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(75) DEFAULT '' NOT NULL, + LINK_ID int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME), + KEY LINK_ID (LINK_ID) +); + +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (2,'Jack',0); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (3,'Bill',0); + +CREATE TABLE t2 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(150) DEFAULT '' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME) +); + +SELECT DISTINCT + t2.id AS key_link_id, + t2.name AS link +FROM t1 +LEFT JOIN t2 ON t1.link_id=t2.id +GROUP BY t1.id +ORDER BY link; +drop table t1,t2; + +# +# test case for #674 +# + +CREATE TABLE t1 ( + html varchar(5) default NULL, + rin int(11) default '0', + rout int(11) default '0' +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES ('1',1,0); +SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; +drop table t1; + +# +# Test cases for #12625: DISTINCT for a list with constants +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5); +SELECT DISTINCT a, 1 FROM t1; +SELECT DISTINCT 1, a FROM t1; + +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES (1,1),(2,2),(2,3),(2,4),(3,5); +SELECT DISTINCT a, b, 2 FROM t2; +SELECT DISTINCT 2, a, b FROM t2; +SELECT DISTINCT a, 2, b FROM t2; + +DROP TABLE t1,t2; + +# Bug 9784 DISTINCT IFNULL truncates data +# +create table t1 (id int, dsc varchar(50)); +insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); +select distinct id, IFNULL(dsc, '-') from t1; +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test index 2cd7866caf5..7cd943d46da 100644 --- a/mysql-test/t/drop.test +++ b/mysql-test/t/drop.test @@ -6,13 +6,13 @@ drop database if exists mysqltest; drop database if exists client_test_db; --enable_warnings ---error 1051; +--error 1051 drop table t1; create table t1(n int); insert into t1 values(1); create temporary table t1( n int); insert into t1 values(2); ---error 1050; +--error 1050 create table t1(n int); drop table t1; select * from t1; @@ -56,13 +56,13 @@ drop database mysqltest; # test drop/create database and FLUSH TABLES WITH READ LOCK flush tables with read lock; ---error 1209,1223; +--error 1209,1223 create database mysqltest; unlock tables; create database mysqltest; show databases; flush tables with read lock; ---error 1208,1223; +--error 1208,1223 drop database mysqltest; unlock tables; drop database mysqltest; @@ -73,7 +73,7 @@ drop database mysqltest; # test create table and FLUSH TABLES WITH READ LOCK drop table t1; flush tables with read lock; ---error 1223; +--error 1223 create table t1(n int); unlock tables; create table t1(n int); diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index 255b9dc22d7..9880cd78653 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -17,7 +17,7 @@ CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:@/too/many/items/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:@/too/many/items/federated/t1'; # test not enough items (malformed) in the comment string url --error 1432 @@ -26,7 +26,7 @@ CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1'; + CONNECTION='mysql://root@127.0.0.1'; # test non-existant table --replace_result $SLAVE_MYPORT SLAVE_PORT @@ -36,7 +36,7 @@ eval CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t3'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t3'; # test bad user/password --replace_result $SLAVE_MYPORT SLAVE_PORT @@ -46,7 +46,7 @@ eval CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://user:pass@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://user:pass@127.0.0.1:$SLAVE_MYPORT/federated/t1'; DROP TABLE IF EXISTS federated.t1; # # correct connection, same named tables @@ -56,7 +56,7 @@ eval CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); INSERT INTO federated.t1 (id, name) VALUES (2, 'fee'); @@ -73,7 +73,10 @@ eval CREATE TABLE federated.t2 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval SHOW CREATE TABLE federated.t2; INSERT INTO federated.t2 (id, name) VALUES (1, 'foo'); INSERT INTO federated.t2 (id, name) VALUES (2, 'fee'); @@ -100,7 +103,7 @@ eval CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1%'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1%'; INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); INSERT INTO federated.t1 (id, name) VALUES (2, 'fee'); @@ -115,7 +118,7 @@ eval CREATE TABLE federated.`t1%` ( `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1%'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1%'; INSERT INTO federated.`t1%` (id, name) VALUES (1, 'foo'); INSERT INTO federated.`t1%` (id, name) VALUES (2, 'fee'); @@ -146,7 +149,7 @@ eval CREATE TABLE federated.t1 ( `created` datetime default '2004-04-04 04:04:04', PRIMARY KEY (`id`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111); INSERT INTO federated.t1 (name, other) VALUES ('Second Name', 22222); @@ -213,7 +216,7 @@ eval CREATE TABLE federated.t1 ( key other(`other`), key created(`created`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (name, other, created) VALUES ('First Name', 11111, '2004-01-01 01:01:01'); @@ -284,7 +287,7 @@ eval CREATE TABLE federated.t1 ( PRIMARY KEY (`id`) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111); INSERT INTO federated.t1 (name, other) VALUES ('Second Name', NULL); @@ -333,7 +336,7 @@ eval CREATE TABLE federated.t1 ( KEY nameoth (name, other)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (name, other) VALUES ('First Name', '1111'); INSERT INTO federated.t1 (name, other) VALUES ('Second Name', '2222'); @@ -348,7 +351,7 @@ DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( `id` int NOT NULL auto_increment, `name` char(32) NOT NULL DEFAULT '', - `bincol` binary(4) NOT NULL, + `bincol` binary(1) NOT NULL, `floatval` decimal(5,2) NOT NULL DEFAULT 0.0, `other` int NOT NULL DEFAULT 0, PRIMARY KEY (id), @@ -363,7 +366,7 @@ DROP TABLE IF EXISTS federated.t1; eval CREATE TABLE federated.t1 ( `id` int NOT NULL auto_increment, `name` char(32) NOT NULL DEFAULT '', - `bincol` binary(4) NOT NULL, + `bincol` binary(1) NOT NULL, `floatval` decimal(5,2) NOT NULL DEFAULT 0.0, `other` int NOT NULL DEFAULT 0, PRIMARY KEY (id), @@ -372,7 +375,7 @@ eval CREATE TABLE federated.t1 ( KEY floatval(floatval)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (name, bincol, floatval, other) VALUES ('first', 0x65, 11.11, 1111); @@ -421,7 +424,7 @@ eval CREATE TABLE federated.t1 ( key col3(col3), key col4(col4)) ENGINE="FEDERATED" - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (col1, col2, col3, col4) VALUES (1, 'one One', 11, 1111); @@ -515,7 +518,7 @@ eval CREATE TABLE federated.t1 ( key 2key (`col3`,`col4`), key col4(col4)) ENGINE="FEDERATED" - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (col1, col2, col3, col4) VALUES ('aaaa', 'aaaaaaaaaaaaaaaaaaa', 'ababababab', 'acacacacacacacac'); @@ -567,7 +570,7 @@ eval CREATE TABLE federated.t1 ( primary key (`col1`, `col2`, `col3`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 VALUES ('a00', '110', 'cc0'); INSERT INTO federated.t1 VALUES ('aaa', '111', 'ccc'); @@ -606,7 +609,7 @@ eval CREATE TABLE federated.t1 ( `other` int) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; # these both should be the same INSERT INTO federated.t1 values (NULL, NULL, NULL, NULL); @@ -640,7 +643,7 @@ eval CREATE TABLE federated.t1 ( PRIMARY KEY (blurb_id)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 VALUES (1, " MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values."); INSERT INTO federated.t1 VALUES (2, "All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE."); @@ -667,7 +670,7 @@ eval CREATE TABLE federated.t1 ( KEY (b)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 VALUES (3,3,3),(1,1,1),(2,2,2),(4,4,4); @@ -931,7 +934,7 @@ int, i999 int, i1000 int, b varchar(256)) row_format=dynamic ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1000,7 +1003,7 @@ eval CREATE TABLE federated.t1 ( index(code), index(fileguts(10))) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03'); INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04'); INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04'); @@ -1019,7 +1022,7 @@ DROP TABLE IF EXISTS federated.t1; eval CREATE TABLE federated.t1 ( `a` BLOB) ENGINE="FEDERATED" -COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 VALUES (0x00); INSERT INTO federated.t1 VALUES (0x0001); @@ -1031,7 +1034,7 @@ SELECT HEX(a) FROM federated.t1; # --replace_result $SLAVE_MYPORT SLAVE_PORT # eval CREATE TABLE federated.t1 # (a char(20)) charset=cp1251 -# ENGINE="FEDERATED" COMMENT="mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1"; +# ENGINE="FEDERATED" CONNECTION="mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1"; # # # connection slave; # DROP TABLE IF EXISTS federated.t1; @@ -1093,7 +1096,7 @@ eval CREATE TABLE federated.t1 ( PRIMARY KEY (`id`), KEY (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 (name, country_id, other) VALUES ('Kumar', 1, 11111); INSERT INTO federated.t1 (name, country_id, other) VALUES ('Lenz', 2, 22222); @@ -1137,11 +1140,53 @@ ORDER BY federated.t1.country_id; DROP TABLE federated.countries; -# optimize and repair tests +#BEGIN optimize and repair tests OPTIMIZE TABLE federated.t1; REPAIR TABLE federated.t1; REPAIR TABLE federated.t1 QUICK; REPAIR TABLE federated.t1 EXTENDED; REPAIR TABLE federated.t1 USE_FRM; +#END optimize and repair tests + + +# BEGIN ALTER TEST +connection slave; +--disable_warnings +DROP TABLE IF EXISTS federated.normal_table; +--enable_warnings + +CREATE TABLE federated.normal_table ( + `id` int(4) NOT NULL, + `name` varchar(10) default NULL + ) DEFAULT CHARSET=latin1; + +connection master; +--disable_warnings +DROP TABLE IF EXISTS federated.alter_me; +--enable_warnings + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.alter_me ( + `id` int(4) NOT NULL, + `name` varchar(10) default NULL, + PRIMARY KEY (`id`) + ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/normal_table'; + +INSERT INTO federated.alter_me (id, name) VALUES (1, 'Monty'); +INSERT INTO federated.alter_me (id, name) VALUES (2, 'David'); + +SELECT * FROM federated.alter_me; + +--error 1031 +ALTER TABLE federated.alter_me MODIFY COLUMN id int(16) NOT NULL; + +SELECT * FROM federated.alter_me; + +DROP TABLE federated.alter_me; +connection slave; +DROP TABLE federated.normal_table; +# END ALTER TEST + source include/federated_cleanup.inc; diff --git a/mysql-test/t/federated_archive.test b/mysql-test/t/federated_archive.test new file mode 100644 index 00000000000..6d80664fef7 --- /dev/null +++ b/mysql-test/t/federated_archive.test @@ -0,0 +1,58 @@ +source include/have_archive.inc; +source include/federated.inc; + + +connection slave; +--disable_warnings +DROP TABLE IF EXISTS federated.archive_table; +--enable_warnings + +CREATE TABLE federated.archive_table ( + `id` int(4) NOT NULL, + `name` varchar(54) default NULL + ) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; + + +connection master; +--disable_warnings +DROP TABLE IF EXISTS federated.t1; +--enable_warnings + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `id` int(4) NOT NULL, + `name` varchar(54) default NULL, + PRIMARY KEY (`id`) + ) + ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/archive_table'; + +INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); +INSERT INTO federated.t1 (id, name) VALUES (2, 'bar'); + +SELECT * FROM federated.t1; + +--error 1296 +DELETE FROM federated.t1 WHERE id = 1; + +SELECT * FROM federated.t1; + + +--error 1296 +UPDATE federated.t1 SET name='baz' WHERE id = 1; + +SELECT * FROM federated.t1; + + +# --error 1296 +# TRUNCATE federated.t1; +# +# SELECT * from federated.t1; + +DROP TABLE federated.t1; +connection slave; +DROP TABLE federated.archive_table; + + +source include/federated_cleanup.inc; + diff --git a/mysql-test/t/federated_bug_13118.test b/mysql-test/t/federated_bug_13118.test new file mode 100644 index 00000000000..deec79becd2 --- /dev/null +++ b/mysql-test/t/federated_bug_13118.test @@ -0,0 +1,42 @@ +source include/federated.inc; + + +connection slave; +--disable_warnings +DROP TABLE IF EXISTS federated.bug_13118_table; +--enable_warnings + +CREATE TABLE federated.bug_13118_table ( + `foo` integer, + `bar` integer + ); + + +connection master; +--disable_warnings +DROP TABLE IF EXISTS federated.t1; +--enable_warnings + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `foo` integer, + `bar` integer + ) ENGINE="FEDERATED" + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/bug_13118_table'; + +SELECT * from federated.t1; + +INSERT INTO federated.t1 VALUES (1,1); +SELECT * FROM federated.t1; + +INSERT INTO federated.t1 VALUES (1,1); +SELECT * FROM federated.t1; + + +DROP TABLE federated.t1; +connection slave; +DROP TABLE federated.bug_13118_table; + + +source include/federated_cleanup.inc; + diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test index 02384357711..de2576300dc 100644 --- a/mysql-test/t/flush_read_lock_kill.test +++ b/mysql-test/t/flush_read_lock_kill.test @@ -34,7 +34,7 @@ send flush tables with read lock; connection con2; select ((@id := kill_id) - kill_id) from t1; ---sleep 2; # leave time for FLUSH to block +--sleep 2 # leave time for FLUSH to block kill connection @id; connection con1; diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index 5e0283feb28..cc3cdb9564d 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -49,4 +49,10 @@ select old_password(' i d k f a '); explain extended select password('idkfa '), old_password('idkfa'); +# +# Bug #13619: Crash on FreeBSD with salt like '_.' +# +--replace_column 1 # +select encrypt('1234','_.'); + # End of 4.1 tests diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index fc7ce8e38a5..a519d51e0b5 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -282,6 +282,16 @@ drop table t1; drop table t2; # +# Bug #12829 +# Cannot convert the charset of a GROUP_CONCAT result +# +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +SELECT GROUP_CONCAT(a) FROM t1; +DROP TABLE t1; + +# # bug #7769: group_concat returning null is checked in having # CREATE TABLE t1 (id int); @@ -355,4 +365,28 @@ DROP TABLE t1,t2; # select * from (select group_concat('c') from DUAL) t; +# +# Bug #12859 group_concat in subquery cause incorrect not null +# +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +select group_concat('x') UNION ALL select 1; +drop table t1; + +# +# Bug #12863 : missing separators after first empty cancatanated elements +# + +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES + (2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); + +SELECT GROUP_CONCAT(a) FROM t1; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; + +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index fb9470c16dd..9237205eeb5 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -2,6 +2,8 @@ # simple test of all group functions # +--source include/have_innodb.inc + --disable_warnings drop table if exists t1,t2; --enable_warnings @@ -539,6 +541,75 @@ INSERT INTO t1 VALUES SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; DROP TABLE t1; +# +# Bug #12882 min/max inconsistent on empty table +# + +create table t1m (a int) engine=myisam; +create table t1i (a int) engine=innodb; +create table t2m (a int) engine=myisam; +create table t2i (a int) engine=innodb; +insert into t2m values (5); +insert into t2i values (5); + +# test with MyISAM +select min(a) from t1m; +select min(7) from t1m; +select min(7) from DUAL; +explain select min(7) from t2m join t1m; +select min(7) from t2m join t1m; + +select max(a) from t1m; +select max(7) from t1m; +select max(7) from DUAL; +explain select max(7) from t2m join t1m; +select max(7) from t2m join t1m; + +select 1, min(a) from t1m where a=99; +select 1, min(a) from t1m where 1=99; +select 1, min(1) from t1m where a=99; +select 1, min(1) from t1m where 1=99; + +select 1, max(a) from t1m where a=99; +select 1, max(a) from t1m where 1=99; +select 1, max(1) from t1m where a=99; +select 1, max(1) from t1m where 1=99; + +# test with InnoDB +select min(a) from t1i; +select min(7) from t1i; +select min(7) from DUAL; +explain select min(7) from t2i join t1i; +select min(7) from t2i join t1i; + +select max(a) from t1i; +select max(7) from t1i; +select max(7) from DUAL; +explain select max(7) from t2i join t1i; +select max(7) from t2i join t1i; + +select 1, min(a) from t1i where a=99; +select 1, min(a) from t1i where 1=99; +select 1, min(1) from t1i where a=99; +select 1, min(1) from t1i where 1=99; + +select 1, max(a) from t1i where a=99; +select 1, max(a) from t1i where 1=99; +select 1, max(1) from t1i where a=99; +select 1, max(1) from t1i where 1=99; + +# mixed MyISAM/InnoDB test +explain select count(*), min(7), max(7) from t1m, t1i; +select count(*), min(7), max(7) from t1m, t1i; + +explain select count(*), min(7), max(7) from t1m, t2i; +select count(*), min(7), max(7) from t1m, t2i; + +explain select count(*), min(7), max(7) from t2m, t1i; +select count(*), min(7), max(7) from t2m, t1i; + +drop table t1m, t1i, t2m, t2i; + # End of 4.1 tests # diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 7bf737402ef..0472968f918 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -97,11 +97,18 @@ select 1 in ('1.1',2.0); # Test case for bug #6365 -create table t1 (a char(20) character set binary); +create table t1 (a char(2) character set binary); insert into t1 values ('aa'), ('bb'); select * from t1 where a in (NULL, 'aa'); drop table t1; +# BUG#13419 +create table t1 (id int, key(id)); +insert into t1 values (1),(2),(3); +select count(*) from t1 where id not in (1); +select count(*) from t1 where id not in (1,2); +drop table t1; + # End of 4.1 tests # diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index 684d7032038..4e1183afeff 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -96,4 +96,21 @@ DROP TABLE t1; # select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; +# +# Check 8bit escape character +# +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; + +# Check 8bit escape character with charset conversion: +# For "a LIKE b ESCAPE c" expressions, +# escape character is converted into the operation character set, +# which is result of aggregation of character sets of "a" and "b". +# "c" itself doesn't take part in aggregation, because its collation +# doesn't matter, escape character is always compared binary. +# In the example below, escape character is converted from koi8r into cp1251: +# +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; + +# # End of 4.1 tests diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index bf692325a6a..633e36f51ab 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -107,4 +107,13 @@ drop table t1; # select abs(-2) * -2; +# +# Bug #6172 RAND(a) should only accept constant values as arguments +# +create table t1 (i int); +insert into t1 values (1); +--error 1210 +select rand(i) from t1; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 4a6c98c8d7f..ac2bf820257 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -15,6 +15,7 @@ select bit_length('\n\t\r\b\0\_\%\\'); select char_length('\n\t\r\b\0\_\%\\'); select length(_latin1'\n\t\n\b\0\\_\\%\\'); select concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'); +select hex(char(256)); select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ; select instr('hello','HE'), instr('hello',binary 'HE'), instr(binary 'hello','HE'); select position(binary 'll' in 'hello'),position('a' in binary 'hello'); @@ -467,6 +468,7 @@ SELECT lpad(12345, 5, "#"); # SELECT conv(71, 10, 36), conv('1Z', 36, 10); +SELECT conv(71, 10, 37), conv('1Z', 37, 10), conv(0,1,10),conv(0,0,10), conv(0,-1,10); # # Bug in SUBSTRING when mixed with CONCAT and ORDER BY (Bug #3089) @@ -665,3 +667,13 @@ select rpad(i, 7, ' ') as t from t1; drop table t1; # End of 4.1 tests + +# +# Bug #13361: SELECT FORMAT(<decimal field with null>, 2) crashes +# +create table t1 (d decimal default null); +insert into t1 values (null); +select format(d, 2) from t1; +drop table t1; + +# End of 5.0 tests diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index ee9cd1924c6..2fa82ce5dce 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -351,4 +351,47 @@ set password = password("changed"); disconnect n5; connection default; + +# Bug #12423 "Deadlock when doing FLUSH PRIVILEGES and GRANT in +# multi-threaded environment". We should be able to execute FLUSH +# PRIVILEGES and SET PASSWORD simultaneously with other account +# management commands (such as GRANT and REVOKE) without causing +# deadlocks. To achieve this we should ensure that all account +# management commands take table and internal locks in the same order. +connect (con2root,localhost,root,,); +connect (con3root,localhost,root,,); +# Check that we can execute FLUSH PRIVILEGES and GRANT simultaneously +# This will check that locks are taken in proper order during both +# user/db-level and table/column-level privileges reloading. +connection default; +lock table mysql.user write; +connection con2root; +send flush privileges; +connection con3root; +send grant all on *.* to 'mysqltest_1'@'localhost'; +connection default; +unlock tables; +connection con2root; +reap; +connection con3root; +reap; +# Check for simultaneous SET PASSWORD and REVOKE. +connection default; +lock table mysql.user write; +connection con2root; +send set password for 'mysqltest_1'@'localhost' = password(''); +connection con3root; +send revoke all on *.* from 'mysqltest_1'@'localhost'; +connection default; +unlock tables; +connection con2root; +reap; +connection con3root; +reap; +connection default; +# Clean-up +drop user 'mysqltest_1'@'localhost'; +disconnect con2root; +disconnect con3root; + # End of 4.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 8300b502518..bf557029a55 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -580,7 +580,6 @@ SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment DROP TABLE t1, t2; - # # Bug #12266 GROUP BY expression on DATE column produces result with # reduced length @@ -602,6 +601,16 @@ SELECT n+1 AS n FROM t1 GROUP BY n; --enable_ps_protocol DROP TABLE t1; +# +# BUG#12695: Item_func_isnull::update_used_tables +# did not update const_item_cache +# +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +select sql_buffer_result max(f1)+1 from t1; +drop table t1; + # End of 4.1 tests # diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index da3fdec80d2..3d751f4a571 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -655,26 +655,21 @@ select distinct a1 from t1 where a2 = 'b'; # Bug #12672: primary key implcitly included in every innodb index # -create table bug12672 ( +--disable_warnings +create table t4 ( pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' ) engine=innodb; +--enable_warnings +insert into t4 (a1, a2, b, c, d, dummy) select * from t1; -insert into bug12672 (a1, a2, b, c, d, dummy) select * from t1; - -create index idx12672_0 on bug12672 (a1); -create index idx12672_1 on bug12672 (a1,a2,b,c); -create index idx12672_2 on bug12672 (a1,a2,b); +create index idx12672_0 on t4 (a1); +create index idx12672_1 on t4 (a1,a2,b,c); +create index idx12672_2 on t4 (a1,a2,b); analyze table t1; ---replace_column 9 # -explain select distinct a1 from bug12672 where pk_col not in (1,2,3,4); -select distinct a1 from bug12672 where pk_col not in (1,2,3,4); - -drop table bug12672; +select distinct a1 from t4 where pk_col not in (1,2,3,4); -drop table t1; -drop table t2; -drop table t3; +drop table t1,t2,t3,t4; # # Bug #6142: a problem with the empty innodb table diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index eb970e7a710..1bb9b1d3504 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -300,7 +300,7 @@ handler t5 open as h5; handler h5 read first limit 9; # close first alter table t1 engine=MyISAM; ---error 1109; +--error 1109 handler h1 read first limit 9; handler h2 read first limit 9; handler h3 read first limit 9; @@ -308,22 +308,22 @@ handler h4 read first limit 9; handler h5 read first limit 9; # close last alter table t5 engine=MyISAM; ---error 1109; +--error 1109 handler h1 read first limit 9; handler h2 read first limit 9; handler h3 read first limit 9; handler h4 read first limit 9; ---error 1109; +--error 1109 handler h5 read first limit 9; # close middle alter table t3 engine=MyISAM; ---error 1109; +--error 1109 handler h1 read first limit 9; handler h2 read first limit 9; ---error 1109; +--error 1109 handler h3 read first limit 9; handler h4 read first limit 9; ---error 1109; +--error 1109 handler h5 read first limit 9; handler h2 close; handler h4 close; @@ -335,11 +335,11 @@ handler h1_1 read first limit 9; handler h1_2 read first limit 9; handler h1_3 read first limit 9; alter table t1 engine=MyISAM; ---error 1109; +--error 1109 handler h1_1 read first limit 9; ---error 1109; +--error 1109 handler h1_2 read first limit 9; ---error 1109; +--error 1109 handler h1_3 read first limit 9; drop table t1; drop table t2; diff --git a/mysql-test/t/im_daemon_life_cycle-im.opt b/mysql-test/t/im_daemon_life_cycle-im.opt new file mode 100644 index 00000000000..6bfd9a24107 --- /dev/null +++ b/mysql-test/t/im_daemon_life_cycle-im.opt @@ -0,0 +1,2 @@ +--run-as-service +--log=$MYSQL_TEST_DIR/var/log/im.log diff --git a/mysql-test/t/im_daemon_life_cycle.imtest b/mysql-test/t/im_daemon_life_cycle.imtest new file mode 100644 index 00000000000..87388d7c1e6 --- /dev/null +++ b/mysql-test/t/im_daemon_life_cycle.imtest @@ -0,0 +1,15 @@ +########################################################################### +# +# This file contains test for (1.2) test suite. +# +# Consult WL#2789 for more information. +# +########################################################################### + +--source include/im_check_os.inc + +########################################################################### + +SHOW INSTANCES; + +--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted diff --git a/mysql-test/t/im_life_cycle.imtest b/mysql-test/t/im_life_cycle.imtest new file mode 100644 index 00000000000..c2b1c9a56ec --- /dev/null +++ b/mysql-test/t/im_life_cycle.imtest @@ -0,0 +1,142 @@ +########################################################################### +# +# This file contains test for (1.1) test suite. +# +# Consult WL#2789 for more information. +# +########################################################################### + +--source include/im_check_os.inc + +########################################################################### +# +# 1.1.1. Check that Instance Manager is able: +# - to read definitions of two mysqld-instances; +# - to start the first instance; +# - to understand 'nonguarded' option and keep the second instance down; +# +########################################################################### + +SHOW INSTANCES; +--replace_column 3 VERSION +SHOW INSTANCE STATUS mysqld1; +--replace_column 3 VERSION +SHOW INSTANCE STATUS mysqld2; + +########################################################################### +# +# 1.1.2. Check 'START INSTANCE' command: +# - start the second instance; +# - check that it is reported as online; +# - execute some SQL-statement on mysqld2 to ensure that it is really up and +# running; +# +########################################################################### + +START INSTANCE mysqld2; +# FIXME +--sleep 3 + +SHOW INSTANCES; +--replace_column 3 VERSION +SHOW INSTANCE STATUS mysqld1; +--replace_column 3 VERSION +SHOW INSTANCE STATUS mysqld2; + +--connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK) +--connection mysql_con + +--replace_result $IM_MYSQLD1_PORT IM_MYSQLD1_PORT +SHOW VARIABLES LIKE 'port'; + +--connection default +--disconnect mysql_con + +########################################################################### +# +# 1.1.3. Check 'STOP INSTANCE' command: +# - stop the second instance; +# - check that it is reported as offline; +# - TODO: try to execute some SQL-statement to ensure that it is really down; +# +########################################################################### + +STOP INSTANCE mysqld2; +# FIXME +--sleep 3 + +SHOW INSTANCES; +--replace_column 3 VERSION +SHOW INSTANCE STATUS mysqld1; +--replace_column 3 VERSION +SHOW INSTANCE STATUS mysqld2; + +########################################################################### +# +# 1.1.4. Check that Instance Manager reports correct errors for 'START +# INSTANCE' command: +# - if the client tries to start unregistered instance; +# - if the client tries to start already started instance; +# - if the client submits invalid arguments; +# +########################################################################### + +--error 3000 +START INSTANCE mysqld3; + +--error 3002 +START INSTANCE mysqld1; + +# FIXME TODO +# BUG#12813: START/STOP INSTANCE commands accept a list as argument +# START INSTANCE mysqld1, mysqld2; + +########################################################################### +# +# 1.1.5. Check that Instance Manager reports correct errors for 'STOP INSTANCE' +# command: +# - if the client tries to start unregistered instance; +# - if the client tries to start already stopped instance; +# - if the client submits invalid arguments; +# +########################################################################### + +--error 3000 +STOP INSTANCE mysqld3; + +# TODO: IM should be fixed. +# BUG#12673: Instance Manager allows to stop the instance many times +# --error 3002 +# STOP INSTANCE mysqld2; + +# FIXME TODO +# BUG#12813: START/STOP INSTANCE commands accept a list as argument +# STOP INSTANCE mysqld1, mysqld2; + +########################################################################### +# +# 1.1.6. Check that Instance Manager is able to restart guarded instances. +# +########################################################################### + +SHOW INSTANCES; + +--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted + +########################################################################### +# +# 1.1.7. Check that Instance Manager does not restart non-guarded instance. +# +########################################################################### + +SHOW INSTANCES; + +START INSTANCE mysqld2; +# FIXME +--sleep 3 + +SHOW INSTANCES; + +--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD2_PATH_PID killed + +SHOW INSTANCES; diff --git a/mysql-test/t/im_options_set.imtest b/mysql-test/t/im_options_set.imtest new file mode 100644 index 00000000000..785c6d05fef --- /dev/null +++ b/mysql-test/t/im_options_set.imtest @@ -0,0 +1,142 @@ +########################################################################### +# +# This file contains test for (3) test suite. +# +# Consult WL#2789 for more information. +# +########################################################################### + +# +# Check the options-management commands: +# - SET; +# - FLUSH INSTANCES; +# +# Let's test the commands on the option 'server_id'. It's expected that +# originally the instances have the following server ids: +# - mysqld1: 1 +# - mysqld2: 2 +# +# 1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12. +# 1.1. check that the configuration file has been updated (i.e. contains +# server_id=SERVER_ID for the instance); +# 1.2. (for mysqld1) check that the running instance has not been affected: +# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id'' +# returns zero; +# 1.3. check that internal cache of Instance Manager has not been affected +# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value). +# +# 2. FLUSH INSTANCES; +# 2.1. check that the configuration file has not been updated; +# 2.2. (for mysqld1) check that the running instance has not been affected: +# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id'' +# returns zero value; +# 2.3. check that internal cache of Instance Manager has been updated (i.e. +# SHOW INSTANCE OPTIONS <instance> contains 'server_id=SERVER_ID' line). +# +# 3. Restore options. +# + +########################################################################### + +--source include/im_check_os.inc + +########################################################################### +# +# 0. Check starting conditions. +# +########################################################################### + +# - check the configuration file; + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf ; + +# - check the running instances. + +--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK) + +--connection mysql1_con + +SHOW VARIABLES LIKE 'server_id'; + +--connection default + +# - check the internal cache. +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld1; +# SHOW INSTANCE OPTIONS mysqld2; + +########################################################################### +# +# 1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12. +# +########################################################################### + +# * mysqld1 + +SET mysqld1.server_id = 11; + +# - check that the configuration file has been updated (i.e. contains +# server_id=SERVER_ID for the instance); + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf ; + +# - (for mysqld1) check that the running instance has not been affected: +# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id'' +# returns zero; + +--connection mysql1_con + +SHOW VARIABLES LIKE 'server_id'; + +--connection default + +# - check that internal cache of Instance Manager has not been affected +# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value). +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld1; + +# * mysqld2 + +SET mysqld2.server_id = 12; + +# - check that the configuration file has been updated (i.e. contains +# server_id=SERVER_ID for the instance); + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf ; + +# - check that internal cache of Instance Manager has not been affected +# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value). +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld2; + +########################################################################### +# +# 2. FLUSH INSTANCES; +# +########################################################################### + +FLUSH INSTANCES; + +# - check that the configuration file has not been updated; + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf ; + +# - (for mysqld1) check that the running instance has not been affected: +# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id'' +# returns zero value; + +--connection mysql1_con + +SHOW VARIABLES LIKE 'server_id'; + +--connection default + +# - check that internal cache of Instance Manager has been updated (i.e. +# SHOW INSTANCE OPTIONS <instance> contains 'server_id=' line). +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld1; +# SHOW INSTANCE OPTIONS mysqld2; diff --git a/mysql-test/t/im_options_unset.imtest b/mysql-test/t/im_options_unset.imtest new file mode 100644 index 00000000000..74ec42ac3f9 --- /dev/null +++ b/mysql-test/t/im_options_unset.imtest @@ -0,0 +1,150 @@ +########################################################################### +# +# This file contains test for (3) test suite. +# +# Consult WL#2789 for more information. +# +########################################################################### + +# +# Check the options-management commands: +# - UNSET; +# - FLUSH INSTANCES; +# +# Let's test the commands on the option 'server_id'. It's expected that +# originally the instances have the following server ids: +# - mysqld1: 1 +# - mysqld2: 2 +# +# The test case: +# +# 1. UNSET <instance_id>.server_id; +# +# Do the step for both instances. +# +# 1.1. check that the configuration file has been updated (i.e. does not +# contain 'server_id=' line for the instance); +# 1.2. (for mysqld1) check that the running instance has not been affected: +# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id'' +# returns non-zero value; +# 1.3. check that internal cache of Instance Manager is not affected (i.e. +# SHOW INSTANCE OPTIONS <instance> contains non-zero value for server_id); +# +# 2. FLUSH INSTANCES; +# +# Do the step for both instances. +# +# 2.1. check that the configuration file has not been updated (i.e. does not +# contain 'server_id=' for the instance); +# 2.2. (for mysqld1) check that the running instance has not been affected: +# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id'' +# returns non-zero value; +# 2.3. check that internal cache of Instance Manager has been updated (i.e. +# SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line). +# + +########################################################################### + +--source include/im_check_os.inc + +########################################################################### +# +# 0. Check starting conditions. +# +########################################################################### + +# - check the configuration file; + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf ; + +# - check the running instances. + +--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK) + +--connection mysql1_con + +SHOW VARIABLES LIKE 'server_id'; + +--connection default + +# - check the internal cache. +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld1; +# SHOW INSTANCE OPTIONS mysqld2; + +########################################################################### +# +# 1. UNSET <instance_id>.server_id; +# +########################################################################### + +# * mysqld1 + +UNSET mysqld1.server_id; + +# - check that the configuration file has been updated (i.e. does not +# contain 'server_id=' line for the instance); + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf ; + +# - check that the running instance has not been affected: connect to the +# instance and check that 'SHOW VARIABLES LIKE 'server_id'' returns non-zero +# value; + +--connection mysql1_con + +SHOW VARIABLES LIKE 'server_id'; + +--connection default + +# - check that internal cache of Instance Manager is not affected (i.e. SHOW +# INSTANCE OPTIONS <instance> contains non-zero value for server_id); +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld1; + +# * mysqld2 + +UNSET mysqld2.server_id; + +# - check that the configuration file has been updated (i.e. does not +# contain 'server_id=' line for the instance); + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf || true; + +# - check that internal cache of Instance Manager is not affected (i.e. SHOW +# INSTANCE OPTIONS <instance> contains non-zero value for server_id); +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld2; + +########################################################################### +# +# 2. FLUSH INSTANCES; +# +########################################################################### + +FLUSH INSTANCES; + +# - check that the configuration file has not been updated (i.e. does not +# contain 'server_id=' for the instance); + +--exec grep server_id $MYSQL_TEST_DIR/var/im.cnf || true; + +# - (for mysqld1) check that the running instance has not been affected: +# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id'' +# returns non-zero value; + +--connection mysql1_con + +SHOW VARIABLES LIKE 'server_id'; + +--connection default + +# - check that internal cache of Instance Manager has been updated (i.e. +# SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line). +# TODO: we should check only server_id option here. + +# SHOW INSTANCE OPTIONS mysqld1; +# SHOW INSTANCE OPTIONS mysqld2; diff --git a/mysql-test/t/im_utils.imtest b/mysql-test/t/im_utils.imtest new file mode 100644 index 00000000000..dc6fb93c4ff --- /dev/null +++ b/mysql-test/t/im_utils.imtest @@ -0,0 +1,115 @@ +########################################################################### +# +# This file contains test for (2) test suite. +# +# Consult WL#2789 for more information. +# +########################################################################### + +--source include/im_check_os.inc + +########################################################################### + +# +# Check starting conditions. This test case assumes that: +# - two mysqld-instances are registered; +# - the first instance is online; +# - the second instance is offline; +# + +SHOW INSTANCES; + +# +# Check 'SHOW INSTANCE OPTIONS' command: +# - check that options of both offline and online instances are accessible; +# - since configuration of an mysqld-instance contains directories, we should +# completely ignore the second column (values) in order to make the test +# case produce the same results on different installations; +# TODO: ignore values of only directory-specific options. +# + +--replace_column 2 VALUE +SHOW INSTANCE OPTIONS mysqld1; + +--replace_column 2 VALUE +SHOW INSTANCE OPTIONS mysqld2; + +# +# Before checking log files, we should start the second instance (mysqld2) to +# give it a chance to create log files. +# + +START INSTANCE mysqld2; + +# FIXME +-- sleep 3 + +STOP INSTANCE mysqld2; + +# +# Check 'SHOW LOG FILES' command: +# - check that log files of both offline and online instances are accessible; +# - since placement of the log files is installation-specific, we should +# ignore it in comparisson; +# - also, we should ignore log file size, since it may depend on the version +# being tested; +# + +--replace_column 2 PATH 3 FILE_SIZE +SHOW mysqld1 LOG FILES; + +--replace_column 2 PATH 3 FILE_SIZE +SHOW mysqld2 LOG FILES; + +# +# Check 'SHOW LOG' command: +# - check that all three kinds of logs are available for both offline and +# online instances; +# - we should ignore the value, because it is very specific and depends on +# many factors; we only check that Instance Manager is able to provide log +# files. +# + +# mysqld1 (online) w/o the optional argument. + +--replace_column 1 LOG_DATA +SHOW mysqld1 LOG ERROR 10; + +--replace_column 1 LOG_DATA +SHOW mysqld1 LOG SLOW 10; + +--replace_column 1 LOG_DATA +SHOW mysqld1 LOG GENERAL 10; + +# mysqld1 (online) with the optional argument. + +--replace_column 1 LOG_DATA +SHOW mysqld1 LOG ERROR 10, 2; + +--replace_column 1 LOG_DATA +SHOW mysqld1 LOG SLOW 10, 2; + +--replace_column 1 LOG_DATA +SHOW mysqld1 LOG GENERAL 10, 2; + +# mysqld2 (offline) w/o the optional argument. + +--replace_column 1 LOG_DATA +SHOW mysqld2 LOG ERROR 10; + +--replace_column 1 LOG_DATA +SHOW mysqld2 LOG SLOW 10; + +--replace_column 1 LOG_DATA +SHOW mysqld2 LOG GENERAL 10; + +# mysqld2 (offline) with the optional argument. + +--replace_column 1 LOG_DATA +SHOW mysqld2 LOG ERROR 10, 2; + +--replace_column 1 LOG_DATA +SHOW mysqld2 LOG SLOW 10, 2; + +--replace_column 1 LOG_DATA +SHOW mysqld2 LOG GENERAL 10, 2; diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test index 3ed7d44981b..a48626a9ec3 100644 --- a/mysql-test/t/index_merge_innodb.test +++ b/mysql-test/t/index_merge_innodb.test @@ -204,3 +204,47 @@ and (zeit1.geloescht = 0); select * from v1 where oid = 21; drop view v1; drop table t1; +## +CREATE TABLE t1( + t_cpac varchar(2) NOT NULL, + t_vers varchar(4) NOT NULL, + t_rele varchar(2) NOT NULL, + t_cust varchar(4) NOT NULL, + filler1 char(250) default NULL, + filler2 char(250) default NULL, + PRIMARY KEY (t_cpac,t_vers,t_rele,t_cust), + UNIQUE KEY IX_4 (t_cust,t_cpac,t_vers,t_rele), + KEY IX_5 (t_vers,t_rele,t_cust) +) ENGINE=InnoDB; + +insert into t1 values +('tm','2.5 ','a ',' ','',''), ('tm','2.5U','a ','stnd','',''), +('da','3.3 ','b ',' ','',''), ('da','3.3U','b ','stnd','',''), +('tl','7.6 ','a ',' ','',''), ('tt','7.6 ','a ',' ','',''), +('bc','B61 ','a ',' ','',''), ('bp','B61 ','a ',' ','',''), +('ca','B61 ','a ',' ','',''), ('ci','B61 ','a ',' ','',''), +('cp','B61 ','a ',' ','',''), ('dm','B61 ','a ',' ','',''), +('ec','B61 ','a ',' ','',''), ('ed','B61 ','a ',' ','',''), +('fm','B61 ','a ',' ','',''), ('nt','B61 ','a ',' ','',''), +('qm','B61 ','a ',' ','',''), ('tc','B61 ','a ',' ','',''), +('td','B61 ','a ',' ','',''), ('tf','B61 ','a ',' ','',''), +('tg','B61 ','a ',' ','',''), ('ti','B61 ','a ',' ','',''), +('tp','B61 ','a ',' ','',''), ('ts','B61 ','a ',' ','',''), +('wh','B61 ','a ',' ','',''), ('bc','B61U','a ','stnd','',''), +('bp','B61U','a ','stnd','',''), ('ca','B61U','a ','stnd','',''), +('ci','B61U','a ','stnd','',''), ('cp','B61U','a ','stnd','',''), +('dm','B61U','a ','stnd','',''), ('ec','B61U','a ','stnd','',''), +('fm','B61U','a ','stnd','',''), ('nt','B61U','a ','stnd','',''), +('qm','B61U','a ','stnd','',''), ('tc','B61U','a ','stnd','',''), +('td','B61U','a ','stnd','',''), ('tf','B61U','a ','stnd','',''), +('tg','B61U','a ','stnd','',''), ('ti','B61U','a ','stnd','',''), +('tp','B61U','a ','stnd','',''), ('ts','B61U','a ','stnd','',''), +('wh','B61U','a ','stnd','',''); +show create table t1; + +select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6'; +select t_vers,t_rele,t_cust,filler1 from t1 where t_vers = '7.6' + and t_rele='a' and t_cust = ' '; + +drop table t1; + diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 23f88b75576..9fb57fc187b 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -5,7 +5,8 @@ # show databases --disable_warnings -DROP TABLE IF EXISTS t0,t1,t2,t3,t5; +DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5; +DROP VIEW IF EXISTS v1; --enable_warnings @@ -253,7 +254,7 @@ flush privileges; # QQ a LOCK TABLES is in effect when selecting from # QQ information_schema.tables. ---disable_parsing until bug is fixes +--disable_parsing # until bug is fixed delimiter //; create procedure px5 () begin @@ -338,7 +339,7 @@ from information_schema.tables where table_schema='information_schema' limit 2; show tables from information_schema like "T%"; ---error 1007 +--error 1044 create database information_schema; use information_schema; show full tables like "T%"; @@ -364,8 +365,8 @@ use test; create function sub1(i int) returns int return i+1; create table t1(f1 int); -create view t2 (c) as select f1 from t1; -create view t3 (c) as select sub1(1); +create view v2 (c) as select f1 from t1; +create view v3 (c) as select sub1(1); create table t4(f1 int, KEY f1_key (f1)); drop table t1; drop function sub1; @@ -378,8 +379,8 @@ where table_schema='test'; select index_name from information_schema.statistics where table_schema='test'; select constraint_name from information_schema.table_constraints where table_schema='test'; -drop view t2; -drop view t3; +drop view v2; +drop view v3; drop table t4; # @@ -665,4 +666,64 @@ SHOW TABLE STATUS FROM test WHERE name IN ( SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); -DROP TABLE t1,t2 +DROP TABLE t1,t2; + +# +# Bug #12905 show fields from view behaving erratically with current database +# +create table t1(f1 int); +create view v1 (c) as select f1 from t1; +connect (con5,localhost,root,,*NO-ONE*); +select database(); +show fields from test.v1; +connection default; +drop view v1; +drop table t1; + +# +# Bug #9846 Inappropriate error displayed while dropping table from 'INFORMATION_SCHEMA' +# +--error 1044 +alter database information_schema; +--error 1044 +drop database information_schema; +--error 1044 +drop table information_schema.tables; +--error 1044 +alter table information_schema.tables; +# +# Bug #9683 INFORMATION_SCH: Creation of temporary table allowed in Information_schema DB +# +use information_schema; +--error 1044 +create temporary table schemata(f1 char(10)); +# +# Bug #10708 SP's can use INFORMATION_SCHEMA as ROUTINE_SCHEMA +# +delimiter |; +--error 1044 +CREATE PROCEDURE p1 () +BEGIN + SELECT 'foo' FROM DUAL; +END | +delimiter ;| +select ROUTINE_NAME from routines; +# +# Bug #10734 Grant of privileges other than 'select' and 'create view' should fail on schema +# +--error 1044 +grant all on information_schema.* to 'user1'@'localhost'; +--error 1044 +grant select on information_schema.* to 'user1'@'localhost'; + +# +# Bug#14089 FROM list subquery always fails when information_schema is current database +# +use test; +create table t1(id int); +insert into t1(id) values (1); +select 1 from (select 1 from test.t1) a; +use information_schema; +select 1 from (select 1 from test.t1) a; +use test; +drop table t1; diff --git a/mysql-test/t/information_schema_inno.test b/mysql-test/t/information_schema_inno.test index dd7015bfd9a..9cd64a54ad9 100644 --- a/mysql-test/t/information_schema_inno.test +++ b/mysql-test/t/information_schema_inno.test @@ -1,6 +1,6 @@ -- source include/have_innodb.inc --disable_warnings -DROP TABLE IF EXISTS t1,t2; +DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings # diff --git a/mysql-test/t/innodb-deadlock.test b/mysql-test/t/innodb-deadlock.test index 9d15a23da3c..41741942963 100644 --- a/mysql-test/t/innodb-deadlock.test +++ b/mysql-test/t/innodb-deadlock.test @@ -25,7 +25,7 @@ set autocommit=0; # The following query should hang because con1 is locking the page --send update t1 set x=2 where id = 0; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; @@ -63,7 +63,7 @@ set autocommit=0; # The following query should hang because con1 is locking the page --send update t1 set x=2 where id = 0; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; @@ -97,7 +97,7 @@ update t2 set a=2 where b = 0; select * from t2; --send update t1 set x=2 where id = 0; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index dd7f4319892..55a712fef9b 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -39,7 +39,7 @@ set autocommit=0; # The following statement should hang because con1 is locking the page --send lock table t1 write; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 18c27cee3ad..cf0e08e2e66 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -978,9 +978,9 @@ create table `t2` (`id` int( 11 ) not null default '0',unique key `id` ( `id` ) insert into `t2`values ( 1 ) ; create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb; insert into `t3`values ( 1 ) ; ---error 1217 +--error 1451 delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ---error 1217 +--error 1451 update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; --error 1054 update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; @@ -996,7 +996,7 @@ create table t1( foreign key(pid) references t1(id) on delete cascade) engine=innodb; insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6), (8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14); --- error 1217 +-- error 1451 delete from t1 where id=0; delete from t1 where id=15; delete from t1 where id=0; @@ -1212,7 +1212,7 @@ drop table t1; # CREATE TABLE t1 ( a char(10) ) ENGINE=InnoDB; ---error 1214; +--error 1214 SELECT a FROM t1 WHERE MATCH (a) AGAINST ('test' IN BOOLEAN MODE); DROP TABLE t1; @@ -1249,6 +1249,26 @@ insert into t1 values (42); select * from t1; drop table t1; +# +# Bug #13025 Server crash during filesort +# + +create table t1 (a int not null, b int not null, c blob not null, d int not null, e int, primary key (a,b,c(255),d)) engine=innodb; +insert into t1 values (2,2,"b",2,2),(1,1,"a",1,1),(3,3,"ab",3,3); +select * from t1 order by a,b,c,d; +explain select * from t1 order by a,b,c,d; +drop table t1; + +# +# BUG#11039,#13218 Wrong key length in min() +# + +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +select min(b) from t1 where a='8'; +drop table t1; + # End of 4.1 tests # @@ -1264,9 +1284,6 @@ select count(*) from t1 where x<0; select count(*) from t1 where x < -16; select count(*) from t1 where x = -16; explain select count(*) from t1 where x > -16; - -# The following result should be (2). To be fixed when we add 'unsigned flag' to -# Field::store(longlong) select count(*) from t1 where x > -16; select * from t1 where x > -16; select count(*) from t1 where x = 18446744073709551601; @@ -1451,3 +1468,286 @@ TRUNCATE t1; INSERT INTO t1 (id) VALUES (NULL); SELECT * FROM t1; DROP TABLE t2, t1; + +-- Test that foreign keys in temporary tables are not accepted (bug #12084) +CREATE TABLE t1 +( + id INT PRIMARY KEY +) ENGINE=InnoDB; + +--error 1005,1005 +CREATE TEMPORARY TABLE t2 +( + id INT NOT NULL PRIMARY KEY, + b INT, + FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +DROP TABLE t1; + +# +# Test that index column max sizes are checked (bug #13315) +# + +# prefix index +create table t1 (col1 varchar(2000), index (col1(767))) + character set = latin1 engine = innodb; + +# normal indexes +create table t2 (col1 char(255), index (col1)) + character set = latin1 engine = innodb; +create table t3 (col1 binary(255), index (col1)) + character set = latin1 engine = innodb; +create table t4 (col1 varchar(767), index (col1)) + character set = latin1 engine = innodb; +create table t5 (col1 varchar(767) primary key) + character set = latin1 engine = innodb; +create table t6 (col1 varbinary(767) primary key) + character set = latin1 engine = innodb; +create table t7 (col1 text, index(col1(767))) + character set = latin1 engine = innodb; +create table t8 (col1 blob, index(col1(767))) + character set = latin1 engine = innodb; + +# multi-column indexes are allowed to be longer +create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2)) + character set = latin1 engine = innodb; + +drop table t1, t2, t3, t4, t5, t6, t7, t8, t9; + +--error 1005 +create table t1 (col1 varchar(768), index (col1)) + character set = latin1 engine = innodb; +--error 1005 +create table t2 (col1 varchar(768) primary key) + character set = latin1 engine = innodb; +--error 1005 +create table t3 (col1 varbinary(768) primary key) + character set = latin1 engine = innodb; +--error 1005 +create table t4 (col1 text, index(col1(768))) + character set = latin1 engine = innodb; +--error 1005 +create table t5 (col1 blob, index(col1(768))) + character set = latin1 engine = innodb; + +# +# Test improved foreign key error messages (bug #3443) +# + +CREATE TABLE t1 +( + id INT PRIMARY KEY +) ENGINE=InnoDB; + +CREATE TABLE t2 +( + v INT, + CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) +) ENGINE=InnoDB; + +--error 1452 +INSERT INTO t2 VALUES(2); + +INSERT INTO t1 VALUES(1); +INSERT INTO t2 VALUES(1); + +--error 1451 +DELETE FROM t1 WHERE id = 1; + +--error 1217 +DROP TABLE t1; + +SET FOREIGN_KEY_CHECKS=0; +DROP TABLE t1; +SET FOREIGN_KEY_CHECKS=1; + +--error 1452 +INSERT INTO t2 VALUES(3); + +DROP TABLE t2; +# +# Test that checksum table uses a consistent read Bug #12669 +# +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=0; +checksum table t1; +connection b; +insert into t1 values(3); +connection a; +# +# Here checksum should not see insert +# +checksum table t1; +connection a; +commit; +checksum table t1; +commit; +drop table t1; +# +# autocommit = 1 +# +connection a; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2); +set autocommit=1; +checksum table t1; +connection b; +set autocommit=1; +insert into t1 values(3); +connection a; +# +# Here checksum sees insert +# +checksum table t1; +drop table t1; + +# +# BUG#11238 - in prelocking mode SELECT .. FOR UPDATE is changed to +# non-blocking SELECT +# +create table t1 (col1 integer primary key, col2 integer) engine=innodb; +insert t1 values (1,100); +delimiter |; +create function f1 () returns integer begin +declare var1 int; +select col2 into var1 from t1 where col1=1 for update; +return var1; +end| +delimiter ;| +start transaction; +select f1(); +connection b; +send update t1 set col2=0 where col1=1; +connection default; +select * from t1; +connection a; +rollback; +connection b; +reap; +rollback; +connection default; +drop table t1; +drop function f1; +disconnect a; +disconnect b; + +# +# BUG 14056 Column prefix index on UTF-8 primary key column causes: Can't find record.. +# + +create table t1 ( + a int, b char(10), c char(10), filler char(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( + a int, b char(10), c char(10), filler char(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xe880bde880bd,_utf8 0xe880bde880bd,'six'); +insert into t1 values (4,_utf8 0xe880bdD0B1e880bd,_utf8 0xe880bdD0B1e880bd,'seven'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); +insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; + +create table t1 ( + a int, b varchar(10), c varchar(10), filler varchar(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( + a int, b varchar(10), c varchar(10), filler varchar(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xe880bde880bd,_utf8 0xe880bde880bd,'six'); +insert into t1 values (4,_utf8 0xe880bdD0B1e880bd,_utf8 0xe880bdD0B1e880bd,'seven'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); +insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; + +create table t1 ( + a int, b text(10), c text(10), filler text(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( + a int, b text(10), c text(10), filler text(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xe880bde880bd,_utf8 0xe880bde880bd,'six'); +insert into t1 values (4,_utf8 0xe880bdD0B1e880bd,_utf8 0xe880bdD0B1e880bd,'seven'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); +insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; + +create table t1 ( + a int, b blob(10), c blob(10), filler blob(10), primary key(a, b(2)), unique key (a, c(2)) +) character set utf8 engine = innodb; +create table t2 ( + a int, b blob(10), c blob(10), filler blob(10), primary key(a, b(2)), unique key (a, c(2)) +) character set ucs2 engine = innodb; +insert into t1 values (1,'abcdefg','abcdefg','one'); +insert into t1 values (2,'ijkilmn','ijkilmn','two'); +insert into t1 values (3,'qrstuvw','qrstuvw','three'); +insert into t1 values (4,_utf8 0xe880bd,_utf8 0xe880bd,'four'); +insert into t1 values (4,_utf8 0x5b,_utf8 0x5b,'five'); +insert into t1 values (4,_utf8 0xD0B1,_utf8 0xD0B1,'eight'); +insert into t2 values (1,'abcdefg','abcdefg','one'); +insert into t2 values (2,'ijkilmn','ijkilmn','two'); +insert into t2 values (3,'qrstuvw','qrstuvw','three'); +insert into t2 values (4,_ucs2 0x00e400,_ucs2 0x00e400,'four'); +insert into t2 values (4,_ucs2 0x00640065,_ucs2 0x00640065,'five'); +insert into t2 values (4,_ucs2 0x00e400e50068,_ucs2 0x00e400e50068,'six'); +insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); +insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); +insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); +insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +drop table t1; +drop table t2; +commit; diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index 482c7f9f8b9..0592ec3152f 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -801,3 +801,34 @@ SELECT * FROM DROP VIEW v1,v2; DROP TABLE t1,t2,t3,t4; + +# +# Bug #13545: problem with NATURAL/USING joins. +# + +CREATE TABLE t1(a int); +CREATE TABLE t2(b int); +CREATE TABLE t3(c int, d int); +CREATE TABLE t4(d int); +CREATE TABLE t5(e int, f int); +CREATE TABLE t6(f int); +CREATE VIEW v1 AS + SELECT e FROM t5 JOIN t6 ON t5.e=t6.f; +CREATE VIEW v2 AS + SELECT e FROM t5 NATURAL JOIN t6; + +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +--error 1054 +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +--error 1054 +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +SELECT v1.e FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +--error 1054 +SELECT v1.x FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +SELECT v2.e FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +--error 1054 +SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); + +DROP VIEW v1, v2; +DROP TABLE t1, t2, t3, t4, t5, t6; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index aabc32c009a..367b98f2485 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -135,7 +135,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL); -INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); CREATE TABLE t2 ( idAssignatura int(11) DEFAULT '0' NOT NULL, @@ -590,7 +590,6 @@ INSERT INTO t2 VALUES("0", "EN", "0-EN"); INSERT INTO t2 VALUES("0", "SV", "0-SV"); INSERT INTO t2 VALUES("10", "EN", "10-EN"); INSERT INTO t2 VALUES("10", "SV", "10-SV"); - SELECT t1.id, t1.text_id, t2.text_data FROM t1 LEFT JOIN t2 ON t1.text_id = t2.text_id @@ -713,3 +712,49 @@ INSERT INTO t1 VALUES (30), (40), (50); INSERT INTO t2 VALUES (300), (400), (500); SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40; DROP TABLE t1, t2; +# +# Test for bugs +# #12101: erroneously applied outer join elimination in case of WHERE NOT BETWEEN +# #12102: erroneously missing outer join elimination in case of WHERE IN/IF +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); + +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); + +DROP TABLE t1,t2; + diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 3503d5fde1d..7f3a9932d31 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -25,6 +25,7 @@ select ((@id := kill_id) - kill_id) from t1; kill @id; connection con1; +--sleep 1 # this statement should fail --error 2006,2013 @@ -49,7 +50,7 @@ select get_lock("a", 10); connection con2; let $ID= `select connection_id()`; send select get_lock("a", 10); ---real_sleep 2; +real_sleep 2; connection con1; disable_query_log; eval kill query $ID; diff --git a/mysql-test/t/kill_n_check.sh b/mysql-test/t/kill_n_check.sh new file mode 100755 index 00000000000..e722b3a180d --- /dev/null +++ b/mysql-test/t/kill_n_check.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +if [ $# -ne 2 ]; then + echo "Usage: kill_n_check.sh <pid file path> killed|restarted" + exit 0 +fi + +pid_path="$1" +expected_result="$2" + +if [ -z "$pid_path" -o ! -r "$pid_path" ]; then + echo "Error: invalid PID path ($pid_path) or PID file does not exist." + exit 0 +fi + +if [ "$expected_result" != "killed" -a \ + "$expected_result" != "restarted" ]; then + echo "Error: expected result must be either 'killed' or 'restarted'." + exit 0 +fi + +# echo "PID path: '$pid_path'" + +original_pid=`cat "$pid_path"` + +# echo "Original PID: $original_pid" + +echo "Killing the process..." + +kill -9 $original_pid + +echo "Sleeping..." + +sleep 3 + +new_pid="" + +[ -r "$pid_path" ] && new_pid=`cat "$pid_path"` + +# echo "New PID: $new_pid" + +if [ "$expected_result" = "restarted" ]; then + + if [ -z "$new_pid" ]; then + echo "Error: the process was killed." + exit 0 + fi + + if [ "$original_pid" -eq "$new_pid" ]; then + echo "Error: the process was not restarted." + exit 0 + fi + + echo "Success: the process was restarted." + exit 0 + +else # $expected_result = killed + + if [ "$new_pid" -a "$new_pid" -ne "$original_pid" ]; then + echo "Error: the process was restarted." + exit 0 + fi + + echo "Success: the process was killed." + exit 0 +fi diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index fe6828916a3..cd3a8f0fd92 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -31,6 +31,34 @@ load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated select * from t1; drop table t1; + +# +# Bug #12053 LOAD DATA INFILE ignores NO_AUTO_VALUE_ON_ZERO setting +# +SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +create table t1(id integer not null auto_increment primary key); +insert into t1 values(0); +disable_query_log; +eval SELECT * INTO OUTFILE '$MYSQL_TEST_DIR/var/tmp/t1' from t1; +delete from t1; +eval load data infile '$MYSQL_TEST_DIR/var/tmp/t1' into table t1; +enable_query_log; +select * from t1; +--exec rm $MYSQL_TEST_DIR/var/tmp/t1 + +disable_query_log; +eval SELECT * INTO OUTFILE '$MYSQL_TEST_DIR/var/tmp/t1' +FIELDS TERMINATED BY '' OPTIONALLY ENCLOSED BY '' LINES TERMINATED BY '\r\n' +FROM t1; +delete from t1; +eval load data infile '$MYSQL_TEST_DIR/var/tmp/t1' into table t1 +FIELDS TERMINATED BY '' OPTIONALLY ENCLOSED BY '' LINES TERMINATED BY '\r\n'; +enable_query_log; +select * from t1; +--exec rm $MYSQL_TEST_DIR/var/tmp/t1 +SET @@SQL_MODE=@OLD_SQL_MODE; +drop table t1; + # End of 4.1 tests # diff --git a/mysql-test/t/lowercase_view.test b/mysql-test/t/lowercase_view.test index b39223f71d5..e9cc26bec18 100644 --- a/mysql-test/t/lowercase_view.test +++ b/mysql-test/t/lowercase_view.test @@ -23,29 +23,29 @@ create table t2aA (col1 int); create view v1Aa as select * from t1aA; create view v2aA as select * from v1aA; create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update v2aA set col1 = (select max(col1) from v1Aa); --- error 1093 +-- error 1443 update v2Aa set col1 = (select max(col1) from t1Aa); -- error 1093 update v2aA set col1 = (select max(col1) from v2Aa); --- error 1093 +-- error 1443 update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v1Aa) where t1aA.col1 = t2aA.col1; -- error 1093 update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from v1aA) where v2Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v1Aa) where t1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t2Aa,v1aA set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from t1aA) where v2aA.col1 = t2aA.col1; -- error 1093 update t1Aa,t2Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; --- error 1093 +-- error 1443 update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from t1Aa) where v1aA.col1 = t2aA.col1; -- error 1093 update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from t1aA) where v2Aa.col1 = t2aA.col1; @@ -55,71 +55,71 @@ update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from t1Aa) where v1Aa.col1 = t2aA.col1; -- error 1093 update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v2aA) where t1aA.col1 = t2aA.col1; --- error 1093 +-- error 1443 update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v2Aa) where v1aA.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t2Aa,v2aA set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v2aA) where t1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from v2Aa) where v1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 update v3aA set v3Aa.col1 = (select max(col1) from v1aA); --- error 1093 +-- error 1443 update v3aA set v3Aa.col1 = (select max(col1) from t1aA); --- error 1093 +-- error 1443 update v3aA set v3Aa.col1 = (select max(col1) from v2aA); -- error 1093 update v3aA set v3Aa.col1 = (select max(col1) from v3aA); --- error 1093 +-- error 1443 delete from v2Aa where col1 = (select max(col1) from v1Aa); --- error 1093 +-- error 1443 delete from v2aA where col1 = (select max(col1) from t1Aa); -- error 1093 delete from v2Aa where col1 = (select max(col1) from v2aA); --- error 1093 +-- error 1443 delete v2Aa from v2aA,t2Aa where (select max(col1) from v1aA) > 0 and v2Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 delete t1aA from t1Aa,t2Aa where (select max(col1) from v1Aa) > 0 and t1aA.col1 = t2aA.col1; -- error 1093 delete v1aA from v1Aa,t2Aa where (select max(col1) from v1aA) > 0 and v1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 delete v2aA from v2Aa,t2Aa where (select max(col1) from t1Aa) > 0 and v2aA.col1 = t2aA.col1; -- error 1093 delete t1aA from t1Aa,t2Aa where (select max(col1) from t1aA) > 0 and t1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 delete v1aA from v1Aa,t2Aa where (select max(col1) from t1aA) > 0 and v1aA.col1 = t2aA.col1; -- error 1093 delete v2Aa from v2aA,t2Aa where (select max(col1) from v2Aa) > 0 and v2aA.col1 = t2aA.col1; --- error 1093 +-- error 1443 delete t1Aa from t1aA,t2Aa where (select max(col1) from v2Aa) > 0 and t1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 delete v1Aa from v1aA,t2Aa where (select max(col1) from v2aA) > 0 and v1Aa.col1 = t2aA.col1; --- error 1093 +-- error 1443 insert into v2Aa values ((select max(col1) from v1aA)); --- error 1093 +-- error 1443 insert into t1aA values ((select max(col1) from v1Aa)); --- error 1093 +-- error 1443 insert into v2aA values ((select max(col1) from v1aA)); --- error 1093 +-- error 1443 insert into v2Aa values ((select max(col1) from t1Aa)); -- error 1093 insert into t1aA values ((select max(col1) from t1Aa)); --- error 1093 +-- error 1443 insert into v2aA values ((select max(col1) from t1aA)); -- error 1093 insert into v2Aa values ((select max(col1) from v2aA)); --- error 1093 +-- error 1443 insert into t1Aa values ((select max(col1) from v2Aa)); -- error 1093 insert into v2aA values ((select max(col1) from v2Aa)); --- error 1093 +-- error 1443 insert into v3Aa (col1) values ((select max(col1) from v1Aa)); --- error 1093 +-- error 1443 insert into v3aA (col1) values ((select max(col1) from t1aA)); --- error 1093 +-- error 1443 insert into v3Aa (col1) values ((select max(col1) from v2aA)); drop view v3aA,v2Aa,v1aA; drop table t1Aa,t2Aa; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 7d708243a10..ff05867b7c1 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -288,6 +288,38 @@ create table t3 engine=merge union=(t1, t2) select * from t2; create table t3 engine=merge union=(t1, t2) select (select max(a) from t2); drop table t1, t2; +# +# Bug#9112 - Merge table with composite index producing invalid results with some queries +# This test case will fail only without the bugfix and some +# non-deterministic circumstances. It depends on properly initialized +# "un-initialized" memory. At the time it happens with a standard +# non-debug build. But there is no guarantee that this will be always so. +# +create table t1 ( + a double(14,4), + b varchar(10), + index (a,b) +) engine=merge union=(t2,t3); + +create table t2 ( + a double(14,4), + b varchar(10), + index (a,b) +) engine=myisam; + +create table t3 ( + a double(14,4), + b varchar(10), + index (a,b) +) engine=myisam; + +insert into t2 values ( null, ''); +insert into t2 values ( 9999999999.999, ''); +insert into t3 select * from t2; +select min(a), max(a) from t1; +flush tables; +select min(a), max(a) from t1; +drop table t1, t2, t3; # BUG#6699 : no sorting on 'ref' retrieval create table t1 (a int,b int,c int, index (a,b,c)); create table t2 (a int,b int,c int, index (a,b,c)); diff --git a/mysql-test/t/multi_statement.test b/mysql-test/t/multi_statement.test index eb8d867f3f0..785aa749f5e 100644 --- a/mysql-test/t/multi_statement.test +++ b/mysql-test/t/multi_statement.test @@ -1,6 +1,10 @@ # PS doesn't support multi-statements --disable_ps_protocol +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + select 1; delimiter ||||; select 2; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index eeac2971788..73afcab5e27 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -578,6 +578,59 @@ checksum table t1; # The above should give the same number as the following. checksum table t2; drop table t1, t2; + +# +# BUG#12232: New myisam_stats_method variable. +# + +show variables like 'myisam_stats_method'; + +create table t1 (a int, key(a)); +insert into t1 values (0),(1),(2),(3),(4); +insert into t1 select NULL from t1; + +# default: NULLs considered inequal +analyze table t1; +show index from t1; +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +show index from t1; + +# Set nulls to be equal: +set myisam_stats_method=nulls_equal; +show variables like 'myisam_stats_method'; +insert into t1 values (11); +delete from t1 where a=11; + +analyze table t1; +show index from t1; + +insert into t1 values (11); +delete from t1 where a=11; + +check table t1; +show index from t1; + +# Set nulls back to be equal +set myisam_stats_method=DEFAULT; +show variables like 'myisam_stats_method'; +insert into t1 values (11); +delete from t1 where a=11; + +analyze table t1; +show index from t1; + +insert into t1 values (11); +delete from t1 where a=11; + +check table t1; +show index from t1; + +drop table t1; + +# End of 4.1 tests + # # Test varchar # @@ -700,4 +753,3 @@ create table t3 (c1 int) engine=myisam pack_keys=default; create table t4 (c1 int) engine=myisam pack_keys=2; drop table t1, t2, t3; -# End of 4.1 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index c1d9813ea39..0783c043ef6 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -14,21 +14,21 @@ create table t1(a int); insert into t1 values(1); # Test delimiters ---exec $MYSQL test < "./t/mysql_delimiter.sql" +--exec $MYSQL test 2>&1 < "./t/mysql_delimiter.sql" --disable_query_log # Test delimiter : supplied on the command line select "Test delimiter : from command line" as " "; ---exec $MYSQL test --delimiter=':' -e 'select * from t1:' +--exec $MYSQL test --delimiter=":" -e "select * from t1:" # Test delimiter :; supplied on the command line select "Test delimiter :; from command line" as " "; ---exec $MYSQL test --delimiter=':;' -e 'select * from t1:;' +--exec $MYSQL test --delimiter=":;" -e "select * from t1:;" # Test 'go' command (vertical output) \G select "Test 'go' command(vertical output) \G" as " "; ---exec $MYSQL test -e 'select * from t1\G' +--exec $MYSQL test -e "select * from t1\G" # Test 'go' command \g select "Test 'go' command \g" as " "; ---exec $MYSQL test -e 'select * from t1\g' +--exec $MYSQL test -e "select * from t1\g" --enable_query_log drop table t1; @@ -37,7 +37,7 @@ drop table t1; # create table t1(a int); lock tables t1 write; ---exec $MYSQL -e 'use test; select database();' +--exec $MYSQL -e "use test; select database();" unlock tables; drop table t1; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index e5bd8c554cb..61d7d9994ba 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -102,10 +102,10 @@ select "--- --position --" as ""; select "--- reading stdin --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec cat $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 | $MYSQL_BINLOG --short-form - +--exec $MYSQL_BINLOG --short-form - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec cat $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 | $MYSQL_BINLOG --short-form --position=79 - +--exec $MYSQL_BINLOG --short-form --position=79 - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 # clean up drop table t1, t2; diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test new file mode 100644 index 00000000000..bc88be001ab --- /dev/null +++ b/mysql-test/t/mysqlcheck.test @@ -0,0 +1,11 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc + +# +# Bug #13783 mysqlcheck tries to optimize and analyze information_schema +# +--replace_result 'Table is already up to date' OK +--exec $MYSQL_CHECK --all-databases --analyze --optimize +--replace_result 'Table is already up to date' OK +--exec $MYSQL_CHECK --analyze --optimize --databases test information_schema mysql +--exec $MYSQL_CHECK --analyze --optimize information_schema schemata diff --git a/mysql-test/t/mysqldump-max.test b/mysql-test/t/mysqldump-max.test new file mode 100644 index 00000000000..fbea84808b4 --- /dev/null +++ b/mysql-test/t/mysqldump-max.test @@ -0,0 +1,73 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc +--source include/have_innodb.inc +--source include/have_archive.inc + +--disable-warnings +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +drop table if exists t4; +drop table if exists t5; +drop table if exists t6; +--enable-warnings + +create table t1 (id int(8), name varchar(32)); +create table t2 (id int(8), name varchar(32)) ENGINE="MyISAM"; +create table t3 (id int(8), name varchar(32)) ENGINE="MEMORY"; +create table t4 (id int(8), name varchar(32)) ENGINE="HEAP"; +create table t5 (id int(8), name varchar(32)) ENGINE="ARCHIVE"; +create table t6 (id int(8), name varchar(32)) ENGINE="InnoDB"; + +insert into t1 values (1, 'first value'); +insert into t1 values (2, 'first value'); +insert into t1 values (3, 'first value'); +insert into t1 values (4, 'first value'); +insert into t1 values (5, 'first value'); + +insert into t2 values (1, 'first value'); +insert into t2 values (2, 'first value'); +insert into t2 values (3, 'first value'); +insert into t2 values (4, 'first value'); +insert into t2 values (5, 'first value'); + +insert into t3 values (1, 'first value'); +insert into t3 values (2, 'first value'); +insert into t3 values (3, 'first value'); +insert into t3 values (4, 'first value'); +insert into t3 values (5, 'first value'); + +insert into t4 values (1, 'first value'); +insert into t4 values (2, 'first value'); +insert into t4 values (3, 'first value'); +insert into t4 values (4, 'first value'); +insert into t4 values (5, 'first value'); + +insert into t5 values (1, 'first value'); +insert into t5 values (2, 'first value'); +insert into t5 values (3, 'first value'); +insert into t5 values (4, 'first value'); +insert into t5 values (5, 'first value'); + +insert into t6 values (1, 'first value'); +insert into t6 values (2, 'first value'); +insert into t6 values (3, 'first value'); +insert into t6 values (4, 'first value'); +insert into t6 values (5, 'first value'); + +select * from t1; +select * from t2; +select * from t3; +select * from t4; +select * from t5; +select * from t6; + +--exec $MYSQL_DUMP --skip-comments --delayed-insert --insert-ignore --databases test +--exec $MYSQL_DUMP --skip-comments --delayed-insert --databases test + +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; +drop table t6; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 27bea937dcf..377a8c8179e 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -4,6 +4,8 @@ --disable_warnings DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; +drop database if exists db1; +drop database if exists db2; drop view if exists v1, v2, v3; --enable_warnings @@ -140,7 +142,7 @@ drop table t1; --exec $MYSQL_DUMP --skip-comments --databases test create database mysqldump_test_db character set latin2 collate latin2_bin; ---exec $MYSQL_DUMP --skip-comments --databases mysqldump_test_db; +--exec $MYSQL_DUMP --skip-comments --databases mysqldump_test_db drop database mysqldump_test_db; # @@ -545,6 +547,64 @@ CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (1),(2),(3); --exec $MYSQL_DUMP --add-drop-database --skip-comments --databases test DROP TABLE t1; + + +# +# Bug #10213 mysqldump crashes when dumping VIEWs(on MacOS X) +# + +create database db1; +use db1; + +CREATE TABLE t2 ( + a varchar(30) default NULL, + KEY a (a(5)) +); + +INSERT INTO t2 VALUES ('alfred'); +INSERT INTO t2 VALUES ('angie'); +INSERT INTO t2 VALUES ('bingo'); +INSERT INTO t2 VALUES ('waffle'); +INSERT INTO t2 VALUES ('lemon'); +create view v2 as select * from t2 where a like 'a%' with check option; +--exec $MYSQL_DUMP --skip-comments db1 +drop table t2; +drop view v2; +drop database db1; + +# +# Bug 10713 mysqldump includes database in create view and referenced tables +# + +# create table and views in db2 +create database db2; +use db2; +create table t1 (a int); +create table t2 (a int, b varchar(10), primary key(a)); +insert into t2 values (1, "on"), (2, "off"), (10, "pol"), (12, "meg"); +insert into t1 values (289), (298), (234), (456), (789); +create view v1 as select * from t2; +create view v2 as select * from t1; + +# dump tables and view from db2 +--exec $MYSQL_DUMP db2 > var/tmp/bug10713.sql + +# drop the db, tables and views +drop table t1, t2; +drop view v1, v2; +drop database db2; + +# create db1 and reload dump +create database db1; +use db1; +--exec $MYSQL db1 < var/tmp/bug10713.sql + +# check that all tables and views could be created +show tables; +select * from t2 order by a; + +drop table t1, t2; +drop database db1; # # Bug #9558 mysqldump --no-data db t1 t2 format still dumps data # @@ -698,17 +758,7 @@ select * from v3 where b in (1, 2, 3, 4, 5, 6, 7); create view v2 as select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; ---exec $MYSQL_DUMP test > var/tmp/bug10927.sql -drop view v1, v2, v3; -drop table t1; ---exec $MYSQL test < var/tmp/bug10927.sql - -# Without dropping the original tables in between ---exec $MYSQL_DUMP test > var/tmp/bug10927.sql ---exec $MYSQL test < var/tmp/bug10927.sql -show full tables; -show create view v1; -select * from v1; +--exec $MYSQL_DUMP --skip-comments test drop view v1, v2, v3; drop table t1; @@ -761,3 +811,154 @@ show tables; --replace_column 6 # show triggers; DROP TABLE t1, t2; + +# +# Bugs #9136, #12917: problems with --defaults-extra-file option +# + +--exec echo "[mysqltest1]" > $MYSQL_TEST_DIR/var/tmp/tmp.cnf +--exec echo "port=1234" >> $MYSQL_TEST_DIR/var/tmp/tmp.cnf +--exec $MYSQL_MY_PRINT_DEFAULTS -c $MYSQL_TEST_DIR/var/tmp/tmp.cnf mysqltest1 +--exec $MYSQL_MY_PRINT_DEFAULTS -e $MYSQL_TEST_DIR/var/tmp/tmp.cnf mysqltest1 mysqltest1 +--exec rm $MYSQL_TEST_DIR/var/tmp/tmp.cnf + +# +# Test of fix to BUG 12597 +# + +DROP TABLE IF EXISTS `test1`; +CREATE TABLE `test1` ( + `a1` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +DROP TABLE IF EXISTS `test2`; +CREATE TABLE `test2` ( + `a2` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +DELIMITER //; +CREATE TRIGGER `testref` BEFORE INSERT ON `test1` FOR EACH ROW BEGIN +INSERT INTO test2 SET a2 = NEW.a1; END // +DELIMITER ;// + +INSERT INTO `test1` VALUES (1); +SELECT * FROM `test2`; + +# dump +--exec $MYSQL_DUMP --skip-comments --databases test > var/tmp/mysqldump.sql + +#DROP TRIGGER testref; +#DROP TABLE test1; +#DROP TABLE test2; +# restore +--exec $MYSQL test < var/tmp/mysqldump.sql +SHOW TRIGGERS; +SELECT * FROM `test1`; +SELECT * FROM `test2`; + +DROP TRIGGER testref; +DROP TABLE test1; +DROP TABLE test2; + +# +# BUG#9056 - mysqldump does not dump routines +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS bug9056_func1; +DROP FUNCTION IF EXISTS bug9056_func2; +DROP PROCEDURE IF EXISTS bug9056_proc1; +DROP PROCEDURE IF EXISTS bug9056_proc2; +--enable_warnings + +CREATE TABLE t1 (id int); +INSERT INTO t1 VALUES(1), (2), (3), (4), (5); + +DELIMITER //; +CREATE FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11) RETURN a+b // +CREATE PROCEDURE `bug9056_proc1`(IN a INT, IN b INT, OUT c INT) +BEGIN SELECT a+b INTO c; end // + +create function bug9056_func2(f1 char binary) returns char binary +begin + set f1= concat( 'hello', f1 ); + return f1; +end // + +CREATE PROCEDURE bug9056_proc2(OUT a INT) +BEGIN + select sum(id) from t1 into a; +END // + +DELIMITER ;// + +set sql_mode='ansi'; +create procedure `a'b` () select 1; # to fix syntax highlighting :') +set sql_mode=''; + +# Dump the DB and ROUTINES +--exec $MYSQL_DUMP --skip-comments --routines --databases test + +# ok, now blow it all away +DROP FUNCTION bug9056_func1; +DROP FUNCTION bug9056_func2; +DROP PROCEDURE bug9056_proc1; +DROP PROCEDURE bug9056_proc2; +drop table t1; + +# +# BUG# 13052 - mysqldump timestamp reloads broken +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (`d` timestamp, unique (`d`)); +set time_zone='+00:00'; +insert into t1 values ('2003-10-25 22:00:00'),('2003-10-25 23:00:00'); +# results should show two different time values +select * from t1; +set time_zone='Europe/Moscow'; +# results should show two same time values, despite unique +select * from t1; +set global time_zone='Europe/Moscow'; +--exec $MYSQL_DUMP --skip-comments --databases test +--exec $MYSQL_DUMP --skip-tz-utc --skip-comments --databases test +drop table t1; +set global time_zone=default; +set time_zone=default; + +# +# Test of fix to BUG 13146 - ansi quotes break loading of triggers +# +--disable_warnings +DROP TABLE IF EXISTS `t1 test`; +CREATE TABLE `t1 test` ( + `a1` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +DROP TABLE IF EXISTS `t2 test`; +CREATE TABLE `t2 test` ( + `a2` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +--enable_warnings + +DELIMITER //; +CREATE TRIGGER `test trig` BEFORE INSERT ON `t1 test` FOR EACH ROW BEGIN +INSERT INTO `t2 test` SET a2 = NEW.a1; END // +DELIMITER ;// + +INSERT INTO `t1 test` VALUES (1); +INSERT INTO `t1 test` VALUES (2); +INSERT INTO `t1 test` VALUES (3); +SELECT * FROM `t2 test`; +# dump with compatible=ansi. Everything except triggers should be double +# quoted +--exec $MYSQL_DUMP --skip-comments --compatible=ansi --triggers test + +--disable_warnings +DROP TRIGGER `test trig`; +DROP TABLE `t1 test`; +DROP TABLE `t2 test`; +--enable_warnings diff --git a/mysql-test/t/mysqlshow.test b/mysql-test/t/mysqlshow.test index 33ae8aef9a0..1e2e97a4e07 100644 --- a/mysql-test/t/mysqlshow.test +++ b/mysql-test/t/mysqlshow.test @@ -1,6 +1,10 @@ # Can't run test of external client with embedded server -- source include/not_embedded.inc +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + # ## Bug #5036 mysqlshow is missing a column # diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 08e51aadc24..11fbb023963 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -3,6 +3,24 @@ # # Test of mysqltest itself # +# There are three rules that determines what belong to each command +# 1. A normal command is delimited by the <delimiter> which by default is +# set to ';' +# +# ex: | select * +# | from t1; +# | +# Command: "select * from t1" +# +# 2. Special case is a line that starts with "--", this is a comment +# ended when the new line character is reached. But the first word +# in the comment may contain a valid command, which then will be +# executed. This can be useful when sending commands that +# contains <delimiter> +# +# 3. Special case is also a line that starts with '#' which is treated +# as a comment and will be ended by new line character +# # ============================================================================ # ---------------------------------------------------------------------------- @@ -37,7 +55,9 @@ select otto from (select 1 as otto) as t1; # expectation <> response #--error 0 -#select friedrich from (select 1 as otto) as t1; +#select friedrich from (select 1 as otto) as t1 +--error 1 +--exec echo "select friedrich from (select 1 as otto) as t1;" | $MYSQL_TEST 2>&1 # expectation = response --error 1054 @@ -55,8 +75,9 @@ select friedrich from (select 1 as otto) as t1; # Positive case(statement) # ---------------------------------------------------------------------------- +# This syntax not allowed anymore, use --error S00000, see below # expectation = response -!S00000 select otto from (select 1 as otto) as t1; +#!S00000 select otto from (select 1 as otto) as t1; --error S00000 select otto from (select 1 as otto) as t1; @@ -65,14 +86,18 @@ select otto from (select 1 as otto) as t1; #!S42S22 select otto from (select 1 as otto) as t1; #--error S42S22 #select otto from (select 1 as otto) as t1; +--error 1 +--exec echo "error S42S22; select otto from (select 1 as otto) as t1;" | $MYSQL_TEST 2>&1 + # ---------------------------------------------------------------------------- # Negative case(statement) # ---------------------------------------------------------------------------- +# This syntax not allowed anymore, use --error S42S22, see below # expectation = response -!S42S22 select friedrich from (select 1 as otto) as t1; +#!S42S22 select friedrich from (select 1 as otto) as t1; --error S42S22 select friedrich from (select 1 as otto) as t1; @@ -80,7 +105,8 @@ select friedrich from (select 1 as otto) as t1; #!S00000 select friedrich from (select 1 as otto) as t1; #--error S00000 #select friedrich from (select 1 as otto) as t1; - +--error 1 +--exec echo "error S00000; select friedrich from (select 1 as otto) as t1;" | $MYSQL_TEST 2>&1 # ---------------------------------------------------------------------------- # test cases for $mysql_errno @@ -262,6 +288,8 @@ eval select $mysql_errno as "after_!errno_masked_error" ; # select 3 from t1 ; # --error 1000 # select 3 from t1 ; +--error 1 +--exec echo "disable_abort_on_error; error 1000; select 3 from t1; error 1000; select 3 from t1;" | $MYSQL_TEST 2>&1 # ---------------------------------------------------------------------------- # Switch the abort on error on and check the effect on $mysql_errno @@ -288,6 +316,528 @@ select 3 from t1 ; #select 3 from t1 ; # End of 4.1 tests +--error 1 +--exec echo "disable_abort_on_error; enable_abort_on_error; error 1064; select 3 from t1; select 3 from t1;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test comments +# ---------------------------------------------------------------------------- + +# This is a comment +# This is a ; comment +# This is a -- comment +-- This is also a comment +-- # This is also a comment +-- This is also a ; comment + +# ---------------------------------------------------------------------------- +# Test comments with embedded command +# ---------------------------------------------------------------------------- + +--echo hello +-- echo hello +-- echo ;;;;;;;; + +--echo # MySQL: -- The + +# ---------------------------------------------------------------------------- +# Test detect end of line "junk" +# Most likely causes by a missing delimiter +# ---------------------------------------------------------------------------- + +# Too many parameters to function +--error 1 +--exec echo "sleep 5 6;" | $MYSQL_TEST 2>&1 + +# Too many parameters to function +--error 1 +--exec echo "--sleep 5 6" | $MYSQL_TEST 2>&1 + +# +# Missing delimiter +# The comment will be "sucked into" the sleep command since +# delimiter is missing until after "show status" +--system echo "sleep 4" > var/log/mysqltest.sql +--system echo "# A comment" >> var/log/mysqltest.sql +--system echo "show status;" >> var/log/mysqltest.sql +--error 1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +# +# Extra delimiter +# +--error 1 +--exec echo "--sleep 4;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--disable_query_log;" | $MYSQL_TEST 2>&1 + + +# Allow trailing # comment +--sleep 1 # Wait for insert delayed to be executed. +--sleep 1 # Wait for insert delayed to be executed. + + +# ---------------------------------------------------------------------------- +# Test echo command +# ---------------------------------------------------------------------------- + +echo MySQL; +echo "MySQL"; +echo MySQL: The world''s most popular open source database; +echo "MySQL: The world's most popular open source database"; + +echo MySQL: The world''s + most popular open + source database; + +echo # MySQL: The world''s +# most popular open +# source database; + +echo - MySQL: The world''s +- most popular open +- source database; + +echo - MySQL: The world''s +-- most popular open +-- source database; + +echo # MySQL: The +--world''s +# most popular +-- open +- source database; + +echo "MySQL: The world's most popular; open source database"; +echo "MySQL: The world's most popular ; open source database"; +echo "MySQL: The world's most popular ;open source database"; +echo echo message echo message; + + +echo ; + +# Illegal use of echo + +--error 1 +--exec echo "echo $;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test exec command +# ---------------------------------------------------------------------------- + +# Illegal use of exec +--error 1 +--exec echo "--exec false" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--exec " | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test let command +# ---------------------------------------------------------------------------- + +let $message=MySQL; +echo $message; + +let $message="MySQL"; +echo $message; + +let $message= MySQL: The + world''s most + popular open + source database; +echo $message; + +let $message= # MySQL: The +# world''s most +# popular open +# source database; +echo $message; + +let $message= -- MySQL: The +-- world''s most +-- popular open +-- source database; +echo $message; + +let $message= # MySQL: The +- world''s most +-- popular open +# source database; +echo $message; + +echo '$message'; +echo "$message"; + +let $1=hej; +echo $1; + +let $1 =hej ; +echo $1; + +let $1 = hej; +echo $1; + +let $1=1; +let $2=$1; +echo $2; +let $5=$6; +echo $5; +echo $6; + +let $where=a long variable content; +echo $where; + +let $where2= $where; +echo $where2; + +let $where3=a long $where variable content; +echo $where3; + +let $novar1= $novar2; +echo $novar1; + + + +# Test illegal uses of let + +--error 1 +--exec echo "let ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $=hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let hi=hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $1 hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $m hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $ hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let =hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let hi;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test source command +# ---------------------------------------------------------------------------- + +# Test illegal uses of source + +--error 1 +--exec echo "source ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "source non_existingFile;" | $MYSQL_TEST 2>&1 + +# Too many source +--exec echo "source var/tmp/recursive.sql;" > var/tmp/recursive.sql +--error 1 +--exec echo "source var/tmp/recursive.sql;" | $MYSQL_TEST 2>&1 + +# Source a file with error +--exec echo "garbage ;" > var/tmp/error.sql +--error 1 +--exec echo "source var/tmp/error.sql;" | $MYSQL_TEST 2>&1 + + +# Test execution of source in a while loop +--exec echo "echo here is the sourced script;" > var/tmp/sourced.sql +--disable_query_log +let $outer= 2; # Number of outer loops +while ($outer) +{ + eval SELECT '$outer = outer loop variable after while' AS ""; + + --source var/tmp/sourced.sql + + eval SELECT '$outer = outer loop variable before dec' AS ""; + dec $outer; + eval SELECT '$outer = outer loop variable after dec' AS ""; +} + +let $outer= 2; # Number of outer loops +while ($outer) +{ + eval SELECT '$outer = outer loop variable after while' AS ""; + + echo here is the sourced script; + + eval SELECT '$outer = outer loop variable before dec' AS ""; + dec $outer; + eval SELECT '$outer = outer loop variable after dec' AS ""; +} + + +# Test execution of source in a while loop +--exec echo "--source var/tmp/sourced.sql" > var/tmp/sourced1.sql +--disable_abort_on_error +# Sourcing of a file within while loop, sourced file will +# source other file +let $num= 9; +while ($num) +{ + SELECT 'In loop' AS ""; + --source var/tmp/sourced1.sql + dec $num; +} +--enable_abort_on_error +--enable_query_log + +# ---------------------------------------------------------------------------- +# Test sleep command +# ---------------------------------------------------------------------------- + +sleep 0.5; +sleep 1; +real_sleep 1; + +# Missing parameter +--error 1 +--exec echo "sleep ;" | $MYSQL_TEST 2>&1 + +# Illegal parameter +--error 1 +--exec echo "sleep abc;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test inc +# ---------------------------------------------------------------------------- +inc $i; +echo $i; +inc $i; +echo $i; +let $i=100; +inc $i; +echo $i; + +let $i=hej; +echo $i; +inc $i; +echo $i; + +--error 1 +--exec echo "inc;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "inc i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "let \$i=100; inc \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1 + +inc $i; inc $i; inc $i; --echo $i +echo $i; + + +# ---------------------------------------------------------------------------- +# Test dec +# ---------------------------------------------------------------------------- + +dec $d; +echo $d; +dec $d; +echo $d; +let $d=100; +dec $d; +echo $d; + +let $d=hej; +echo $d; +dec $d; +echo $d; + +--error 1 +--exec echo "dec;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "dec i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "let \$i=100; dec \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test system +# ---------------------------------------------------------------------------- +system ls > /dev/null; +system echo "hej" > /dev/null; +--system ls > /dev/null +--system echo "hej" > /dev/null; + +--error 1 +--exec echo "system;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "system $NONEXISTSINFVAREABLI;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "system false;" | $MYSQL_TEST 2>&1 + +--disable_abort_on_error +system NonExistsinfComamdn; +--enable_abort_on_error + + +# ---------------------------------------------------------------------------- +# Test delimiter +# ---------------------------------------------------------------------------- + +delimiter stop; +echo teststop +delimiter ;stop +echo test2; +--delimiter stop +echo test3stop +--delimiter ; +echo test4; + +# ---------------------------------------------------------------------------- +# Test while, { and } +# ---------------------------------------------------------------------------- + +let $i=1; +while ($i) +{ + echo $i; + dec $i; +} +# One liner +#let $i=1;while ($i){echo $i;dec $i;} + + + +# Exceed max nesting level +--error 1 +--exec echo "source include/mysqltest_while.inc;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "while \$i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "while (\$i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "let \$i=1; while (\$i) dec \$i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "};" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "end;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "{;" | $MYSQL_TEST 2>&1 + +--system echo "while (0)" > var/log/mysqltest.sql +--system echo "echo hej;" >> var/log/mysqltest.sql +--error 1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +--system echo "while (0)" > var/log/mysqltest.sql +--system echo "{echo hej;" >> var/log/mysqltest.sql +--error 1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +--system echo "while (0){" > var/log/mysqltest.sql +--system echo "echo hej;" >> var/log/mysqltest.sql +--error 1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +# ---------------------------------------------------------------------------- +# Test error messages returned from comments starting with a command +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "--if the other server is down" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "-- end when ..." | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test replace +# ---------------------------------------------------------------------------- +--replace_result a b +select "a" as col1, "c" as col2; + +--replace_result a b c d +select "a" as col1, "c" as col2; + +--error 1 +--exec echo "--replace_result a" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_result a;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_result a;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_result a ;" | $MYSQL_TEST 2>&1 +--exec echo "replace_result a b;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_result a b c" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_result a b c ;" | $MYSQL_TEST 2>&1 + + +--replace_column 1 b +select "a" as col1, "c" as col2; + +--replace_column 1 b 2 d +select "a" as col1, "c" as col2; + +--error 1 +--exec echo "--replace_column a" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--replace_column 1" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--replace_column a b" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_column a 1" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_column 1 b c " | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test sync_with_master +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "save_master_pos; sync_with_master 10!;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "save_master_pos; sync_with_master 10 !;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "save_master_pos; sync_with_master a;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test mysqltest arguments +# ---------------------------------------------------------------------------- + +# -x <file_name>, use the file specified after -x as the test file +--exec $MYSQL_TEST < $MYSQL_TEST_DIR/include/mysqltest-x.inc +--exec $MYSQL_TEST -x $MYSQL_TEST_DIR/include/mysqltest-x.inc +--exec $MYSQL_TEST --test_file=$MYSQL_TEST_DIR/include/mysqltest-x.inc +--error 1 +--exec $MYSQL_TEST -x non_existing_file.inc 2>&1 + + +# ---------------------------------------------------------------------------- +# TODO Test queries, especially their errormessages... so it's easy to debug +# new scripts and diagnose errors +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Test bug#12386 +# ---------------------------------------------------------------------------- +let $num= 2; +while ($num) +{ + --error 1064 + failing_statement; + + dec $num; +} + +SELECT 1 as a; + # # Bug #10251: Identifiers containing quotes not handled correctly diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 0f7b0bb7edc..357f658a296 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -203,5 +203,124 @@ drop table t4; show tables; connection server1; +create table t1 ( +ai bigint auto_increment, +c001 int(11) not null, +c002 int(11) not null, +c003 int(11) not null, +c004 int(11) not null, +c005 int(11) not null, +c006 int(11) not null, +c007 int(11) not null, +c008 int(11) not null, +c009 int(11) not null, +c010 int(11) not null, +c011 int(11) not null, +c012 int(11) not null, +c013 int(11) not null, +c014 int(11) not null, +c015 int(11) not null, +c016 int(11) not null, +c017 int(11) not null, +c018 int(11) not null, +c019 int(11) not null, +c020 int(11) not null, +c021 int(11) not null, +c022 int(11) not null, +c023 int(11) not null, +c024 int(11) not null, +c025 int(11) not null, +c026 int(11) not null, +c027 int(11) not null, +c028 int(11) not null, +c029 int(11) not null, +c030 int(11) not null, +c031 int(11) not null, +c032 int(11) not null, +c033 int(11) not null, +c034 int(11) not null, +c035 int(11) not null, +c036 int(11) not null, +c037 int(11) not null, +c038 int(11) not null, +c039 int(11) not null, +c040 int(11) not null, +c041 int(11) not null, +c042 int(11) not null, +c043 int(11) not null, +c044 int(11) not null, +c045 int(11) not null, +c046 int(11) not null, +c047 int(11) not null, +c048 int(11) not null, +c049 int(11) not null, +c050 int(11) not null, +c051 int(11) not null, +c052 int(11) not null, +c053 int(11) not null, +c054 int(11) not null, +c055 int(11) not null, +c056 int(11) not null, +c057 int(11) not null, +c058 int(11) not null, +c059 int(11) not null, +c060 int(11) not null, +c061 int(11) not null, +c062 int(11) not null, +c063 int(11) not null, +c064 int(11) not null, +c065 int(11) not null, +c066 int(11) not null, +c067 int(11) not null, +c068 int(11) not null, +c069 int(11) not null, +c070 int(11) not null, +c071 int(11) not null, +c072 int(11) not null, +c073 int(11) not null, +c074 int(11) not null, +c075 int(11) not null, +c076 int(11) not null, +c077 int(11) not null, +c078 int(11) not null, +c079 int(11) not null, +c080 int(11) not null, +c081 int(11) not null, +c082 int(11) not null, +c083 int(11) not null, +c084 int(11) not null, +c085 int(11) not null, +c086 int(11) not null, +c087 int(11) not null, +c088 int(11) not null, +c089 int(11) not null, +c090 int(11) not null, +c091 int(11) not null, +c092 int(11) not null, +c093 int(11) not null, +c094 int(11) not null, +c095 int(11) not null, +c096 int(11) not null, +c097 int(11) not null, +c098 int(11) not null, +c099 int(11) not null, +c100 int(11) not null, +c101 int(11) not null, +c102 int(11) not null, +c103 int(11) not null, +c104 int(11) not null, +c105 int(11) not null, +c106 int(11) not null, +c107 int(11) not null, +c108 int(11) not null, +c109 int(11) not null, +primary key (ai), +unique key tx1 (c002, c003, c004, c005)) engine=ndb; + +create index tx2 +on t1 (c010, c011, c012, c013); + +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/ndb_autodiscover2.test b/mysql-test/t/ndb_autodiscover2.test index f12d3d31fdd..ebe14696cd2 100644 --- a/mysql-test/t/ndb_autodiscover2.test +++ b/mysql-test/t/ndb_autodiscover2.test @@ -6,7 +6,7 @@ # The previous step has simply removed the frm file # from disk, but left the table in NDB # ---sleep 3; +--sleep 3 select * from t9 order by a; # handler_discover should be 1 diff --git a/mysql-test/t/ndb_bitfield.test b/mysql-test/t/ndb_bitfield.test index efacd8f7c06..0256ecf89ed 100644 --- a/mysql-test/t/ndb_bitfield.test +++ b/mysql-test/t/ndb_bitfield.test @@ -47,6 +47,58 @@ select a+0 from t1 order by a; select b+0 from t1 order by b; drop table t1; +create table t1 ( + dummyKey INTEGER NOT NULL, + a001 TINYINT, + a010 TINYINT, + a012 TINYINT, + a015 TINYINT, + a016 TINYINT, + a017 TINYINT, + a019 TINYINT, + a029 TINYINT, + a030 TINYINT, + a031 TINYINT, + a032 TINYINT, + a042 TINYINT, + a043 TINYINT, + a044 TINYINT, + a3001 TINYINT, + a3002 TINYINT, + a3003 TINYINT, + a3004 TINYINT, + a3005 TINYINT, + a3021 TINYINT, + a3022 TINYINT, + a BIT(6), + b BIT(6), + c BIT(6), + d TINYINT, + e TINYINT, + f TINYINT, + g TINYINT, + h TINYINT, + i TINYINT, + j TINYINT, + k TINYINT, + l TINYINT, + m TINYINT, + n TINYINT, + o TINYINT, + a034 TINYINT, +PRIMARY KEY USING HASH (dummyKey) ) engine=ndb; +INSERT INTO `t1` VALUES +(1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000001',b'111111',b'111110',4,5,5,5,5,5,5,5,5,5,3,2,1), +(2,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000010',b'000000',b'111101',4,5,5,5,5,5,5,5,5,5,3,2,1), +(3,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000100',b'001111',b'111011',4,5,5,5,5,5,5,5,5,5,3,2,1), +(4,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'001000',b'110000',b'110111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(5,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'010000',b'100001',b'101111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(6,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'100000',b'010010',b'011111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(7,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000000',b'001100',b'111111',4,5,5,5,5,5,5,5,5,5,3,2,1), +(8,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'111111',b'000000',b'000000',4,5,5,5,5,5,5,5,5,5,3,2,1); +--exec $MYSQL_DUMP --hex-blob --compact --order-by-primary --skip-extended-insert --no-create-info test t1 +drop table t1; + --error 1005 create table t1 ( pk1 bit(9) not null primary key, diff --git a/mysql-test/t/ndb_condition_pushdown.test b/mysql-test/t/ndb_condition_pushdown.test index d090d12e81b..9f512430085 100644 --- a/mysql-test/t/ndb_condition_pushdown.test +++ b/mysql-test/t/ndb_condition_pushdown.test @@ -12,7 +12,7 @@ CREATE TABLE t1 ( auto int(5) unsigned NOT NULL auto_increment, string char(10), vstring varchar(10), - bin binary(7), + bin binary(2), vbin varbinary(7), tiny tinyint(4) DEFAULT '0' NOT NULL , short smallint(6) DEFAULT '1' NOT NULL , diff --git a/mysql-test/t/ndb_config.test b/mysql-test/t/ndb_config.test index ab3063af672..e40e89d76bd 100644 --- a/mysql-test/t/ndb_config.test +++ b/mysql-test/t/ndb_config.test @@ -6,5 +6,13 @@ --exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=nodeid,host,DataMemory,IndexMemory --type=ndbd 2> /dev/null --exec $NDB_TOOLS_DIR/ndb_config --no-defaults -r \\n -f " " --query=nodeid,host,DataMemory,IndexMemory --type=ndbd 2> /dev/null --exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=nodeid --type=ndbd --host=localhost 2> /dev/null +--exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=type,nodeid,host --config-file=$NDB_BACKUP_DIR/config.ini 2> /dev/null # End of 4.1 tests + +--exec $NDB_TOOLS_DIR/ndb_config --defaults-group-suffix=.jonas --defaults-file=$MYSQL_TEST_DIR/std_data/ndb_config_mycnf1.cnf --query=type,nodeid,host,IndexMemory,DataMemory --mycnf 2> /dev/null + +--exec $NDB_TOOLS_DIR/ndb_config --defaults-group-suffix=.cluster0 --defaults-file=$MYSQL_TEST_DIR/std_data/ndb_config_mycnf2.cnf --query=type,nodeid,host --mycnf 2> /dev/null +--exec $NDB_TOOLS_DIR/ndb_config --defaults-group-suffix=.cluster1 --defaults-file=$MYSQL_TEST_DIR/std_data/ndb_config_mycnf2.cnf --query=type,nodeid,host --mycnf 2> /dev/null +--exec $NDB_TOOLS_DIR/ndb_config --defaults-group-suffix=.cluster2 --defaults-file=$MYSQL_TEST_DIR/std_data/ndb_config_mycnf2.cnf --query=type,nodeid,host --mycnf 2> /dev/null +--exec $NDB_TOOLS_DIR/ndb_config --defaults-group-suffix=.cluster2 --defaults-file=$MYSQL_TEST_DIR/std_data/ndb_config_mycnf2.cnf --ndb-shm --connections --query=type,nodeid1,nodeid2,group,nodeidserver --mycnf 2> /dev/null diff --git a/mysql-test/t/ndb_index_ordered.test b/mysql-test/t/ndb_index_ordered.test index 9b70919ab2a..e6827bdbe12 100644 --- a/mysql-test/t/ndb_index_ordered.test +++ b/mysql-test/t/ndb_index_ordered.test @@ -349,4 +349,10 @@ select a from t1 where b = 2; show tables; drop table t1; +# mysqld 5.0.13 crash, no bug# +create table t1 (a int, c varchar(10), + primary key using hash (a), index(c)) engine=ndb; +insert into t1 (a, c) values (1,'aaa'),(3,'bbb'); +select count(*) from t1 where c<'bbb'; + # End of 4.1 tests diff --git a/mysql-test/t/ndb_types.test b/mysql-test/t/ndb_types.test index 3446a409b2a..10b8eb87e2c 100644 --- a/mysql-test/t/ndb_types.test +++ b/mysql-test/t/ndb_types.test @@ -12,7 +12,7 @@ CREATE TABLE t1 ( auto int(5) unsigned NOT NULL auto_increment, string char(10) default "hello", vstring varchar(10) default "hello", - bin binary(7), + bin binary(2), vbin varbinary(7), tiny tinyint(4) DEFAULT '0' NOT NULL , short smallint(6) DEFAULT '1' NOT NULL , diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 2e09bc5b3a3..e34ac6a865c 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -251,6 +251,41 @@ SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 DROP TABLE t1,t2; # +# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY +# + +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); + +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; + +DROP TABLE t1; + +# Bug #12885(1): derived table specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes +# + +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; + +DROP TABLE t1; + +# +# Bug #12887 Distinct is not always applied after rollup +# +create table t1 ( a varchar(9), b int ); +insert into t1 values('a',1),(null,2); +select a, max(b) from t1 group by a with rollup; +select distinct a, max(b) from t1 group by a with rollup; +drop table t1; + +# End of 4.1 tests + +# # Tests for bug #11639: ROLLUP over view executed through filesort # @@ -266,15 +301,21 @@ EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; DROP VIEW v1; DROP TABLE t1; -# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY + +# +# Bug #12885(2): view specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes # -CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); -INSERT INTO t1 VALUES (1, 1); -INSERT INTO t1 VALUES (1, 2); +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); -SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; +CREATE VIEW v1 AS + SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; -DROP TABLE t1; +DESC v1; +SELECT * FROM v1; +DROP VIEW v1; +DROP TABLE t1; # End of 4.1 tests diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test index 96c92615430..e04c77ddf45 100644 --- a/mysql-test/t/openssl_1.test +++ b/mysql-test/t/openssl_1.test @@ -20,22 +20,22 @@ connect (con4,localhost,ssl_user4,,); connection con1; select * from t1; ---error 1142; +--error 1142 delete from t1; connection con2; select * from t1; ---error 1142; +--error 1142 delete from t1; connection con3; select * from t1; ---error 1142; +--error 1142 delete from t1; connection con4; select * from t1; ---error 1142; +--error 1142 delete from t1; connection default; diff --git a/mysql-test/t/outfile.test b/mysql-test/t/outfile.test index a74bebe1460..37e96d9d38d 100644 --- a/mysql-test/t/outfile.test +++ b/mysql-test/t/outfile.test @@ -65,3 +65,21 @@ EXPLAIN DROP TABLE t1; # End of 4.1 tests + +# +# Bug#13202 SELECT * INTO OUTFILE ... FROM information_schema.schemata now fails +# +disable_query_log; +eval SELECT * INTO OUTFILE "$MYSQL_TEST_DIR/var/tmp/outfile-test.4" +FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' +FROM information_schema.schemata LIMIT 0, 5; +# enable_query_log; +--exec rm $MYSQL_TEST_DIR/var/tmp/outfile-test.4 + +use information_schema; +# disable_query_log; +eval SELECT * INTO OUTFILE "$MYSQL_TEST_DIR/var/tmp/outfile-test.4" +FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' +FROM schemata LIMIT 0, 5; +enable_query_log; +--exec rm $MYSQL_TEST_DIR/var/tmp/outfile-test.4 diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index b4c04e4432a..94ee2b1ca39 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -371,12 +371,10 @@ insert into t1 (a) values (1), (2), (3), (4); set @precision=10000000000; --replace_column 1 - 3 - select rand(), - cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer) from t1; + cast(rand(10)*@precision as unsigned integer) from t1; prepare stmt from "select rand(), cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer), cast(rand(?)*@precision as unsigned integer) from t1"; set @var=1; --replace_column 1 - 3 - @@ -811,6 +809,21 @@ select ??; select ? from t1; --enable_ps_protocol drop table t1; + +# +# Bug#12651 +# (Crash on a PS including a subquery which is a select from a simple view) +# +CREATE TABLE b12651_T1(a int) ENGINE=MYISAM; +CREATE TABLE b12651_T2(b int) ENGINE=MYISAM; +CREATE VIEW b12651_V1 as SELECT b FROM b12651_T2; + +PREPARE b12651 FROM 'SELECT 1 FROM b12651_T1 WHERE a IN (SELECT b FROM b12651_V1)'; +EXECUTE b12651; + +DROP VIEW b12651_V1; +DROP TABLE b12651_T1, b12651_T2; + # # Bug#9359 "Prepared statements take snapshot of system vars at PREPARE # time" diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index db759fcbac3..646151a5aae 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -776,6 +776,7 @@ delimiter ;// # # query in QC from normal execution and SP (BUG#6897) +# improved to also test BUG#3583 and BUG#12990 # flush query cache; reset query cache; @@ -785,6 +786,22 @@ create table t1 (s1 int)// create procedure f1 () begin select sql_cache * from t1; select sql_cache * from t1; +select sql_cache * from t1; +end;// +create procedure f2 () begin +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +end;// +create procedure f3 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +end;// +create procedure f4 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1 where s1=1; end;// delimiter ;// call f1(); @@ -811,7 +828,32 @@ select sql_cache * from t1; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; show status like "Qcache_hits"; +flush query cache; +reset query cache; +flush status; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +call f1(); +call f2(); +call f3(); +call f4(); +call f4(); +call f3(); +call f2(); +select sql_cache * from t1 where s1=1; +insert into t1 values (2); +call f1(); +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +call f1(); +call f3(); +call f3(); +call f1(); + drop procedure f1; +drop procedure f2; +drop procedure f3; +drop procedure f4; drop table t1; set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 12dda022cb9..f6493bac244 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1, t2; +drop table if exists t1, t2, t3; --enable_warnings CREATE TABLE t1 ( @@ -406,8 +406,8 @@ select count(*) from t1 where x = 18446744073709551601; create table t2 (x bigint not null); -insert into t2(x) values (0xfffffffffffffff0); -insert into t2(x) values (0xfffffffffffffff1); +insert into t2(x) values (cast(0xfffffffffffffff0+0 as signed)); +insert into t2(x) values (cast(0xfffffffffffffff1+0 as signed)); select * from t2; select count(*) from t2 where x>0; select count(*) from t2 where x=0; @@ -578,3 +578,56 @@ DELETE FROM t1 WHERE NOT(a <=> 2); SELECT * FROM t1; DROP TABLE t1; + +# +# BUG#13317: range optimization doesn't work for IN over VIEW. +# +create table t1 (a int, b int, primary key(a,b)); +create view v1 as select a, b from t1; + +INSERT INTO `t1` VALUES +(0,0),(1,0),(2,0),(3,0),(4,0),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(11,2),(12,2) +,(13,2),(14,2),(15,3),(16,3),(17,3),(18,3),(19,3); + +--replace_column 9 # +explain select * from t1 where a in (3,4) and b in (1,2,3); +--replace_column 9 # +explain select * from v1 where a in (3,4) and b in (1,2,3); +--replace_column 9 # +explain select * from t1 where a between 3 and 4 and b between 1 and 2; +--replace_column 9 # +explain select * from v1 where a between 3 and 4 and b between 1 and 2; + +drop view v1; +drop table t1; + +# BUG#13455: +create table t3 (a int); +insert into t3 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t1 (a varchar(10), filler char(200), key(a)) charset=binary; +insert into t1 values ('a',''); +insert into t1 values ('a ',''); +insert into t1 values ('a ', ''); +insert into t1 select concat('a', 1000 + A.a + 10 * (B.a + 10 * C.a)), '' + from t3 A, t3 B, t3 C; + +create table t2 (a varchar(10), filler char(200), key(a)); +insert into t2 select * from t1; + +--replace_column 9 # +explain select * from t1 where a between 'a' and 'a '; +--replace_column 9 # +explain select * from t1 where a = 'a' or a='a '; + +--replace_column 9 # +explain select * from t2 where a between 'a' and 'a '; +--replace_column 9 # +explain select * from t2 where a = 'a' or a='a '; + +update t1 set a='b' where a<>'a'; +--replace_column 9 # +explain select * from t1 where a not between 'b' and 'b'; +select a, hex(filler) from t1 where a not between 'b' and 'b'; + +drop table t1,t2,t3; diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index 13dba142d54..3d03823d474 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -92,7 +92,7 @@ kill @id; # We don't drop t3 as this is a temporary table drop table t2; connection master; ---error 1053; +--error 1053 reap; connection slave; # The SQL slave thread should now have stopped because the query was killed on diff --git a/mysql-test/t/rpl_EE_error.test b/mysql-test/t/rpl_EE_error.test index 683ccf1bc40..72df0c20ef8 100644 --- a/mysql-test/t/rpl_EE_error.test +++ b/mysql-test/t/rpl_EE_error.test @@ -22,7 +22,7 @@ set sql_log_bin=0; insert into t1 values(2); set sql_log_bin=1; save_master_pos; ---error 1062; +--error 1062 insert into t1 values(1),(2); drop table t1; save_master_pos; diff --git a/mysql-test/t/rpl_change_master.test b/mysql-test/t/rpl_change_master.test index 45a6d2c0c28..6c055a81ceb 100644 --- a/mysql-test/t/rpl_change_master.test +++ b/mysql-test/t/rpl_change_master.test @@ -16,7 +16,7 @@ insert into t1 values(1); insert into t1 values(2); save_master_pos; connection slave; ---real_sleep 3; # wait for I/O thread to have read updates +--real_sleep 3 # wait for I/O thread to have read updates stop slave; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 8 # 9 # 23 # 33 # diff --git a/mysql-test/t/rpl_ddl.test b/mysql-test/t/rpl_ddl.test index 9521ba3d4c1..d2a41a305b6 100644 --- a/mysql-test/t/rpl_ddl.test +++ b/mysql-test/t/rpl_ddl.test @@ -340,6 +340,164 @@ connection master; SELECT '-------- switch to master -------' as ""; --enable_query_log +# End of 4.1 tests + +############################################################### +# Cases with stored procedures +############################################################### +let $my_stmt= CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1"; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +--vertical_results +--replace_column 5 # 6 # +SHOW PROCEDURE STATUS LIKE 'p1'; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +--replace_column 5 # 6 # +SHOW PROCEDURE STATUS LIKE 'p1'; +connection master; +--horizontal_results + +let $my_stmt= ALTER PROCEDURE p1 COMMENT "I have been altered"; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +--vertical_results +--replace_column 5 # 6 # +SHOW PROCEDURE STATUS LIKE 'p1'; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +--replace_column 5 # 6 # +SHOW PROCEDURE STATUS LIKE 'p1'; +connection master; +--horizontal_results + +let $my_stmt= DROP PROCEDURE p1; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +--vertical_results +SHOW PROCEDURE STATUS LIKE 'p1'; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SHOW PROCEDURE STATUS LIKE 'p1'; +connection master; +--horizontal_results + +############################################################### +# Cases with VIEWs +############################################################### +let $my_stmt= CREATE OR REPLACE VIEW v1 as select * from t1; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +SHOW CREATE VIEW v1; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SHOW CREATE VIEW v1; +connection master; + +let $my_stmt= ALTER VIEW v1 AS select f1 from t1; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +SHOW CREATE VIEW v1; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SHOW CREATE VIEW v1; +connection master; + +let $my_stmt= DROP VIEW IF EXISTS v1; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +--error 1146 +SHOW CREATE VIEW v1; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +--error 1146 +SHOW CREATE VIEW v1; +connection master; + +############################################################### +# Cases with TRIGGERs +############################################################### +let $my_stmt= CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +SHOW TRIGGERS; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SHOW TRIGGERS; +connection master; + +let $my_stmt= DROP TRIGGER trg1; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +SHOW TRIGGERS; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SHOW TRIGGERS; +connection master; + +############################################################### +# Cases with USERs +############################################################### +let $my_stmt= CREATE USER user1@localhost; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +SELECT user FROM mysql.user WHERE user = 'user1'; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SELECT user FROM mysql.user WHERE user = 'user1'; +connection master; + +let $my_stmt= RENAME USER user1@localhost TO rename1@localhost; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +SELECT user FROM mysql.user WHERE user = 'rename1'; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SELECT user FROM mysql.user WHERE user = 'rename1'; +connection master; + +let $my_stmt= DROP USER rename1@localhost; +let $my_master_commit= true; +let $my_slave_commit= true; +--source include/rpl_stmt_seq.inc +SELECT user FROM mysql.user WHERE user = 'rename1'; +--disable_query_log +SELECT '-------- switch to slave -------' as ""; +--enable_query_log +connection slave; +SELECT user FROM mysql.user WHERE user = 'rename1'; +connection master; + ############################################################### # Cleanup ############################################################### @@ -349,4 +507,4 @@ DROP DATABASE IF EXISTS mysqltest2; DROP DATABASE IF EXISTS mysqltest3; --enable_warnings -# End of 4.1 tests + diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test index d31ef3a5bef..d2a8fc0c844 100644 --- a/mysql-test/t/rpl_deadlock.test +++ b/mysql-test/t/rpl_deadlock.test @@ -58,7 +58,7 @@ while ($1) enable_query_log; select * from t1 for update; start slave; ---sleep 3; # hope that slave is blocked now +--sleep 3 # hope that slave is blocked now insert into t2 values(22); # provoke deadlock, slave should be victim commit; sync_with_master; @@ -76,7 +76,7 @@ change master to master_log_pos=532; # the BEGIN log event begin; select * from t2 for update; # hold lock start slave; ---sleep 10; # slave should have blocked, and be retrying +--sleep 10 # slave should have blocked, and be retrying commit; sync_with_master; select * from t1; # check that slave succeeded finally @@ -97,7 +97,7 @@ change master to master_log_pos=532; begin; select * from t2 for update; start slave; ---sleep 10; +--sleep 10 commit; sync_with_master; select * from t1; diff --git a/mysql-test/t/rpl_drop.test b/mysql-test/t/rpl_drop.test index 2544599208e..ebb33c92a20 100644 --- a/mysql-test/t/rpl_drop.test +++ b/mysql-test/t/rpl_drop.test @@ -5,7 +5,7 @@ source include/master-slave.inc; drop table if exists t1, t2; --enable_warnings create table t1 (a int); ---error 1051; +--error 1051 drop table t1, t2; save_master_pos; connection slave; diff --git a/mysql-test/t/rpl_drop_temp.test b/mysql-test/t/rpl_drop_temp.test index 18fc17ed064..55a4e741d7c 100644 --- a/mysql-test/t/rpl_drop_temp.test +++ b/mysql-test/t/rpl_drop_temp.test @@ -9,7 +9,7 @@ sync_slave_with_master; connection master; disconnect master; connection slave; ---real_sleep 3; # time for DROP to be written +--real_sleep 3 # time for DROP to be written show status like 'Slave_open_temp_tables'; connection default; drop database mysqltest; diff --git a/mysql-test/t/rpl_dual_pos_advance-master.opt b/mysql-test/t/rpl_dual_pos_advance-master.opt new file mode 100644 index 00000000000..35fcc5f30c6 --- /dev/null +++ b/mysql-test/t/rpl_dual_pos_advance-master.opt @@ -0,0 +1 @@ +--loose-to-force-a-restart diff --git a/mysql-test/t/rpl_dual_pos_advance.test b/mysql-test/t/rpl_dual_pos_advance.test new file mode 100644 index 00000000000..518fa9df885 --- /dev/null +++ b/mysql-test/t/rpl_dual_pos_advance.test @@ -0,0 +1,108 @@ +# This test checks that in a dual-head setup +# A->B->A, where A has --log-slave-updates (why would it? +# assume that there is a C as slave of A), +# then the Exec_master_log_pos of SHOW SLAVE STATUS does +# not stay too low on B(BUG#13023 due to events ignored because +# of their server id). +# It also will test BUG#13861. + +source include/master-slave.inc; + + +# set up "dual head" + +connection slave; +reset master; + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval change master to master_host="127.0.0.1",master_port=$SLAVE_MYPORT,master_user="root"; + +start slave; + +# now we test it + +connection slave; + +create table t1 (n int); + +save_master_pos; +connection master; +sync_with_master; + +# Now test BUG#13861. This will be enabled when Guilhem fixes this +# bug. + +# stop slave + +# create table t2 (n int); # create one ignored event + +# save_master_pos; +# connection slave; +# sync_with_master; + +# connection slave; + +# show tables; + +# save_master_pos; + +# create table t3 (n int); + +# connection master; + +# bug is that START SLAVE UNTIL may stop too late, we test that by +# asking it to stop before creation of t3. + +# start slave until master_log_file="slave-bin.000001",master_log_pos=195; + +# wait until it's started (the position below is the start of "CREATE +# TABLE t2") (otherwise wait_for_slave_to_stop may return at once) + +# select master_pos_wait("slave-bin.000001",137); + +# wait_for_slave_to_stop; + +# then BUG#13861 causes t3 to show up below (because stopped too +# late). + +# show tables; + +# start slave; + +# BUG#13023 is that Exec_master_log_pos may stay too low "forever": + +connection master; + +create table t4 (n int); # create 3 ignored events +create table t5 (n int); +create table t6 (n int); + +save_master_pos; +connection slave; +sync_with_master; + +connection slave; + +save_master_pos; + +connection master; + +# then BUG#13023 caused hang below ("master" looks behind, while it's +# not in terms of updates done). + +sync_with_master; + +show tables; + +# cleanup + +stop slave; +reset slave; +drop table t1,t4,t5,t6; # add t2 and t3 later + +save_master_pos; +connection slave; +sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test index 7d948e96c39..cb4137c49e0 100644 --- a/mysql-test/t/rpl_error_ignored_table.test +++ b/mysql-test/t/rpl_error_ignored_table.test @@ -6,7 +6,7 @@ source include/master-slave.inc; connection master; create table t1 (a int primary key); # generate an error that goes to the binlog ---error 1062; +--error 1062 insert into t1 values (1),(1); save_master_pos; connection slave; @@ -45,7 +45,7 @@ select (@id := id) - id from t3; kill @id; drop table t2,t3; connection master; ---error 0,1053; +--error 0,1053 reap; connection master1; --replace_column 2 # 5 # @@ -57,3 +57,4 @@ connection slave; sync_with_master; # End of 4.1 tests +# Adding comment for force manual merge 5.0 -> wl1012. delete me if needed diff --git a/mysql-test/t/rpl_flush_log_loop.test b/mysql-test/t/rpl_flush_log_loop.test index ff599af89a3..6e45047bd30 100644 --- a/mysql-test/t/rpl_flush_log_loop.test +++ b/mysql-test/t/rpl_flush_log_loop.test @@ -1,15 +1,15 @@ # Testing if "flush logs" command bouncing resulting in logs created in a loop # in case of bi-directional replication -source include/master-slave.inc +source include/master-slave.inc; connection slave; +stop slave; --replace_result $MASTER_MYPORT MASTER_PORT eval change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=$MASTER_MYPORT; start slave; connection master; -stop slave; --replace_result $SLAVE_MYPORT SLAVE_PORT eval change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=$SLAVE_MYPORT; diff --git a/mysql-test/t/rpl_flush_tables.test b/mysql-test/t/rpl_flush_tables.test index 48fda818890..92aef9c85d0 100644 --- a/mysql-test/t/rpl_flush_tables.test +++ b/mysql-test/t/rpl_flush_tables.test @@ -39,4 +39,15 @@ select * from t3; # Note that all this confusion may cause warnings 'table xx is open on rename' # in the .err files; these are not fatal and are not reported by mysql-test-run. +stop slave; +connection master; +drop table t1; +connection slave; +flush tables with read lock; +start slave; +sleep 1; +--error 1192 +stop slave; + # End of 4.1 tests +# Adding comment for force manual merge 5.0 -> wl1012. Delete me if needed. diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 704de1a423b..49d3a03640c 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -4,7 +4,7 @@ # We also check how the foreign_key_check variable is replicated source include/master-slave.inc; -source include/have_innodb.inc +source include/have_innodb.inc; connection master; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 1b5980eb92e..00121092bbf 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -124,7 +124,7 @@ connection master; reset master; create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), unique(day)) engine=MyISAM; # no transactions ---error 1062; +--error 1062 load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; @@ -140,7 +140,7 @@ select * from t2; alter table t2 drop key day; connection master; delete from t2; ---error 1062; +--error 1062 load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; diff --git a/mysql-test/t/rpl_loaddata_rule_m.test b/mysql-test/t/rpl_loaddata_rule_m.test index 68024c340a8..c956f2c7720 100644 --- a/mysql-test/t/rpl_loaddata_rule_m.test +++ b/mysql-test/t/rpl_loaddata_rule_m.test @@ -27,3 +27,4 @@ show binlog events from 98; drop database mysqltest; # End of 4.1 tests +# Adding comment for force manual merge 5.0 -> wl1012: Delete me diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test index 899f812535a..1f71d2981c5 100644 --- a/mysql-test/t/rpl_log.test +++ b/mysql-test/t/rpl_log.test @@ -110,3 +110,4 @@ show slave status; show binlog events in 'slave-bin.000005' from 4; # End of 4.1 tests +# Adding comment for force manual merge 5.0 -> wl1012: Delete me diff --git a/mysql-test/t/rpl_max_relay_size.test b/mysql-test/t/rpl_max_relay_size.test index 8b54cf5ab7f..9b6b06e0b14 100644 --- a/mysql-test/t/rpl_max_relay_size.test +++ b/mysql-test/t/rpl_max_relay_size.test @@ -93,3 +93,4 @@ flush logs; show master status; # End of 4.1 tests +# diff --git a/mysql-test/t/rpl_multi_delete.test b/mysql-test/t/rpl_multi_delete.test index 2fd7b820b1a..4a8c0ab6912 100644 --- a/mysql-test/t/rpl_multi_delete.test +++ b/mysql-test/t/rpl_multi_delete.test @@ -16,10 +16,26 @@ sync_with_master; select * from t1; select * from t2; +# End of 4.1 tests + +# Check if deleting 0 rows is binlogged (BUG#13348) + connection master; -drop table t1,t2; -save_master_pos; -connection slave; -sync_with_master; +delete from t1; +delete from t2; -# End of 4.1 tests +sync_slave_with_master; +# force a difference to see if master's multi-DELETE will correct it +insert into t1 values(1); +insert into t2 values(1); + +connection master; +DELETE t1.*, t2.* from t1, t2; + +sync_slave_with_master; +select * from t1; +select * from t2; + +connection master; +drop table t1,t2; +sync_slave_with_master; diff --git a/mysql-test/t/rpl_multi_delete2-slave.opt b/mysql-test/t/rpl_multi_delete2-slave.opt index b828d03fafb..0febb2891b1 100644 --- a/mysql-test/t/rpl_multi_delete2-slave.opt +++ b/mysql-test/t/rpl_multi_delete2-slave.opt @@ -1 +1 @@ ---replicate-wild-ignore-table=test.% +"--replicate-rewrite-db=mysqltest_from->mysqltest_to" --replicate-do-table=mysqltest_to.a diff --git a/mysql-test/t/rpl_multi_delete2.test b/mysql-test/t/rpl_multi_delete2.test index 62d95a3a90f..c50311de363 100644 --- a/mysql-test/t/rpl_multi_delete2.test +++ b/mysql-test/t/rpl_multi_delete2.test @@ -1,4 +1,41 @@ +#multi delete replication bugs + + source include/master-slave.inc; + +#BUG#11139 - improper wild-table and table rules +#checking for multi deletes with an alias + +connection master; +set sql_log_bin=0; +create database mysqltest_from; +set sql_log_bin=1; + +connection slave; +create database mysqltest_to; + + +connection master; +use mysqltest_from; +--disable_warnings +drop table if exists a; +--enable_warnings +CREATE TABLE a (i INT); +INSERT INTO a VALUES(1); +DELETE alias FROM a alias WHERE alias.i=1; +SELECT * FROM a; +insert into a values(2),(3); +delete a alias FROM a alias where alias.i=2; +select * from a; +save_master_pos; +connection slave; + +use mysqltest_to; +sync_with_master; +select * from a; + +# BUG#3461 +connection master; create table t1 (a int); create table t2 (a int); @@ -19,7 +56,13 @@ select * from t1; error 1146; select * from t2; +# cleanup connection master; -drop table t1,t2; +set sql_log_bin=0; +drop database mysqltest_from; +set sql_log_bin=1; +connection slave; +drop database mysqltest_to; # End of 4.1 tests + diff --git a/mysql-test/t/rpl_multi_query.test b/mysql-test/t/rpl_multi_query.test index fa94928e13a..b4cd88f756e 100644 --- a/mysql-test/t/rpl_multi_query.test +++ b/mysql-test/t/rpl_multi_query.test @@ -29,3 +29,4 @@ drop database mysqltest; sync_slave_with_master; # End of 4.1 tests +# diff --git a/mysql-test/t/rpl_multi_update.test b/mysql-test/t/rpl_multi_update.test index dd75edb3055..f6a960434ad 100644 --- a/mysql-test/t/rpl_multi_update.test +++ b/mysql-test/t/rpl_multi_update.test @@ -24,3 +24,26 @@ connection slave; sync_with_master; # End of 4.1 tests + +# Check if updating 0 rows is binlogged (BUG#13348) + +connection master; +delete from t1; +delete from t2; +insert into t1 values(1,1); +insert into t2 values(1,1); + +sync_slave_with_master; +# force a difference to see if master's multi-UPDATE will correct it +update t1 set a=2; + +connection master; +UPDATE t1, t2 SET t1.a = t2.a; + +sync_slave_with_master; +select * from t1; +select * from t2; + +connection master; +drop table t1, t2; +sync_slave_with_master; diff --git a/mysql-test/t/rpl_multi_update2.test b/mysql-test/t/rpl_multi_update2.test index f92c5504f43..a78b1901f51 100644 --- a/mysql-test/t/rpl_multi_update2.test +++ b/mysql-test/t/rpl_multi_update2.test @@ -4,6 +4,10 @@ source include/master-slave.inc; +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + CREATE TABLE t1 ( a int unsigned not null auto_increment primary key, b int unsigned @@ -32,4 +36,27 @@ sync_with_master; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; +connection master; +drop table t1,t2; +sync_slave_with_master; + +# +# BUG#13236 multi-update with subquery & --replicate-ignore-table +# +reset master; + +connection master; +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (0); +UPDATE t1, (SELECT 3 as b) AS x SET t1.a = x.b; +select * from t1; +sync_slave_with_master; + +connection slave; +select * from t1; + +connection master; +drop table t1; +sync_slave_with_master; + # End of 4.1 tests diff --git a/mysql-test/t/rpl_multi_update3.test b/mysql-test/t/rpl_multi_update3.test index 64e46882c16..36ac7a59cb3 100644 --- a/mysql-test/t/rpl_multi_update3.test +++ b/mysql-test/t/rpl_multi_update3.test @@ -158,4 +158,63 @@ SELECT * FROM t1; connection master; DROP TABLE t1, t2, t3; +############################################################################## +# +# BUG#12618 +# +# TEST: Replication of a statement containing a join in a multi-update. + +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; + +CREATE TABLE t1 ( + idp int(11) NOT NULL default '0', + idpro int(11) default NULL, + price decimal(19,4) default NULL, + PRIMARY KEY (idp) +); + +CREATE TABLE t2 ( + idpro int(11) NOT NULL default '0', + price decimal(19,4) default NULL, + nbprice int(11) default NULL, + PRIMARY KEY (idpro) +); + +INSERT INTO t1 VALUES + (1,1,'3.0000'), + (2,2,'1.0000'), + (3,1,'1.0000'), + (4,1,'4.0000'), + (5,3,'2.0000'), + (6,2,'4.0000'); + +INSERT INTO t2 VALUES + (1,'0.0000',0), + (2,'0.0000',0), + (3,'0.0000',0); + +# This update sets t2 to the minimal prices for each product +update + t2 + join + ( select idpro, min(price) as min_price, count(*) as nbr_price + from t1 + where idpro>0 and price>0 + group by idpro + ) as table_price +on t2.idpro = table_price.idpro +set t2.price = table_price.min_price, + t2.nbprice = table_price.nbr_price; + +select "-- MASTER AFTER JOIN --" as ""; +select * from t1; +select * from t2; + +sync_slave_with_master; + +select "-- SLAVE AFTER JOIN --" as ""; +select * from t1; +select * from t2; + # End of 4.1 tests diff --git a/mysql-test/t/rpl_replicate_do.test b/mysql-test/t/rpl_replicate_do.test index ff5af71ea5b..b8559af2394 100644 --- a/mysql-test/t/rpl_replicate_do.test +++ b/mysql-test/t/rpl_replicate_do.test @@ -36,4 +36,22 @@ sync_with_master; --replace_column 1 # 8 # 9 # 23 # 33 # show slave status; +# +# BUG#12542 +# TEST: "SET ONE_SHOT should always be executed on slave" +# +# We could use any timezone different than server default in this test +# +connection master; +create table t1 (ts timestamp); +set one_shot time_zone='met'; +insert into t1 values('2005-08-12 00:00:00'); +set one_shot time_zone='met'; +select * from t1; +sync_slave_with_master; + +connection slave; +set one_shot time_zone='met'; +select * from t1; + # End of 4.1 tests diff --git a/mysql-test/t/rpl_reset_slave.test b/mysql-test/t/rpl_reset_slave.test index aeac1b50110..00b1cf68294 100644 --- a/mysql-test/t/rpl_reset_slave.test +++ b/mysql-test/t/rpl_reset_slave.test @@ -48,3 +48,4 @@ sync_with_master; show status like 'slave_open_temp_tables'; # End of 4.1 tests +# diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test index 26cb5ac8631..b125408d89e 100644 --- a/mysql-test/t/rpl_rotate_logs.test +++ b/mysql-test/t/rpl_rotate_logs.test @@ -103,7 +103,7 @@ show master logs; purge binary logs to 'master-bin.000002'; show binary logs; # sleeping 10 seconds or more would make the slave believe connection is down ---real_sleep 1; +--real_sleep 1 purge master logs before now(); show binary logs; insert into t2 values (65); diff --git a/mysql-test/t/rpl_slave_status.test b/mysql-test/t/rpl_slave_status.test index 7e16097edd0..67d3816f443 100644 --- a/mysql-test/t/rpl_slave_status.test +++ b/mysql-test/t/rpl_slave_status.test @@ -1,5 +1,5 @@ # Test case for BUG #10780 -source include/master-slave.inc +--source include/master-slave.inc connection master; grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl'; connection slave; @@ -23,7 +23,9 @@ connection slave; stop slave; start slave; --replace_result $MASTER_MYPORT MASTER_MYPORT ---replace_column 7 # 8 # 9 # 22 # 23 # +# Column 1 is replaced, since the output can be either +# "Connecting to master" or "Waiting for master update" +--replace_column 1 # 7 # 8 # 9 # 22 # 23 # --vertical_results show slave status; diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index 98a06159a57..e62a6c73c0a 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -27,7 +27,7 @@ drop function if exists fn1; --enable_warnings delimiter |; ---error 1418; # not deterministic +--error 1418 # not deterministic create procedure foo() begin declare b int; @@ -85,7 +85,7 @@ call foo2(); --replace_column 2 # 5 # show binlog events from 518; ---error 1418; +--error 1418 alter procedure foo2 contains sql; # SP with definer's right @@ -106,7 +106,7 @@ grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,); connection con1; ---error 1419; # only full-global-privs user can create a routine +--error 1419 # only full-global-privs user can create a routine create procedure foo4() deterministic insert into t1 values (10); @@ -127,7 +127,7 @@ delimiter ;| # I add ,0 so that it does not print the error in the test output, # because this error is hostname-dependent ---error 1142,0; +--error 1142,0 call foo4(); # invoker has no INSERT grant on table => failure show warnings; @@ -136,7 +136,7 @@ call foo3(); # success (definer == root) show warnings; --replace_result localhost.localdomain localhost 127.0.0.1 localhost ---error 1142,0; +--error 1142,0 call foo4(); # definer's rights => failure show warnings; @@ -226,7 +226,7 @@ select * from mysql.proc where db='mysqltest1'; # And now triggers connection con1; ---error 1227; +--error 1227 create trigger trg before insert on t1 for each row set new.a= 10; connection master; @@ -258,6 +258,23 @@ sync_slave_with_master; select * from t1; +# +# Test for bug #13969 "Routines which are replicated from master can't be +# executed on slave". +# +connection master; +create procedure foo() + not deterministic + reads sql data + select * from t1; +sync_slave_with_master; +# This should not fail +call foo(); +connection master; +drop procedure foo; +sync_slave_with_master; + + # Clean up connection master; drop function fn1; diff --git a/mysql-test/t/rpl_sp_effects.test b/mysql-test/t/rpl_sp_effects.test index f8e83eabe90..9da5723b993 100644 --- a/mysql-test/t/rpl_sp_effects.test +++ b/mysql-test/t/rpl_sp_effects.test @@ -152,4 +152,52 @@ drop procedure p1; drop function f1; drop table t1,t2; +# BUG#12637: User variables + SPs replication +create table t1 (a int); +delimiter //; +create procedure p1() +begin + insert into t1 values(@x); + set @x=@x+1; + insert into t1 values(@x); + if (f2()) then + insert into t1 values(1243); + end if; +end// + +create function f2() returns int +begin + insert into t1 values(@z); + set @z=@z+1; + insert into t1 values(@z); + return 0; +end// + +create function f1() returns int +begin + insert into t1 values(@y); + call p1(); + return 0; +end// + +delimiter ;// + +set @x=10; +set @y=20; +set @z=100; +select f1(); + +set @x=30; +call p1(); + +select 'master', a from t1; +sync_slave_with_master; +connection slave; +select 'slave', a from t1; + +connection master; +drop table t1; +drop function f1; +drop function f2; +drop procedure p1; sync_slave_with_master; diff --git a/mysql-test/t/rpl_view.test b/mysql-test/t/rpl_view.test index c50e9fc6dc9..0a0c6a6dddb 100644 --- a/mysql-test/t/rpl_view.test +++ b/mysql-test/t/rpl_view.test @@ -3,6 +3,7 @@ source include/master-slave.inc; drop table if exists t1,v1; drop view if exists t1,v1; sync_slave_with_master; +reset master; --enable_warnings # @@ -42,3 +43,5 @@ select * from v1 order by a; connection master; drop table t1; sync_slave_with_master; +--replace_column 2 # 5 # +show binlog events limit 1,100; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index fad01ac9acf..af51a705122 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -7,7 +7,7 @@ # --disable_warnings -drop table if exists t1,t2,t3,t4; +drop table if exists t1,t2,t3,t4,t11; # The following may be left from older tests drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; drop view if exists v1; @@ -2070,6 +2070,7 @@ AND FK_firma_id = 2; drop table t1; # +# # Test for Bug#8009, SELECT failed on bigint unsigned when using HEX # @@ -2181,6 +2182,68 @@ select found_rows(); DROP TABLE t1; +# +# Bug 7672 Unknown column error in order clause +# +CREATE TABLE t1 (a INT, b INT); +(SELECT a, b AS c FROM t1) ORDER BY c+1; +(SELECT a, b AS c FROM t1) ORDER BY b+1; +SELECT a, b AS c FROM t1 ORDER BY c+1; +SELECT a, b AS c FROM t1 ORDER BY b+1; +drop table t1; + +# +# Bug #13356 assertion failed in resolve_const_item() +# +create table t1(f1 int, f2 int); +create table t2(f3 int); +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,1)); +select f1 from t1,t2 where f1=f2 and (f1,NULL) = ((1,1)); +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,NULL)); +insert into t1 values(1,1),(2,null); +insert into t2 values(2); +select * from t1,t2 where f1=f3 and (f1,f2) = (2,null); +select * from t1,t2 where f1=f3 and (f1,f2) <=> (2,null); +drop table t1,t2; + +# +# Bug #13535 +# +create table t1 (f1 int not null auto_increment primary key, f2 varchar(10)); +create table t11 like t1; +insert into t1 values(1,""),(2,""); +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X +show table status like 't1%'; +select 123 as a from t1 where f1 is null; +drop table t1,t11; + +# Bug 7672 Unknown column error in order clause +# +CREATE TABLE t1 (a INT, b INT); +(SELECT a, b AS c FROM t1) ORDER BY c+1; +(SELECT a, b AS c FROM t1) ORDER BY b+1; +SELECT a, b AS c FROM t1 ORDER BY c+1; +SELECT a, b AS c FROM t1 ORDER BY b+1; +drop table t1; + +# +# Bug #3874 (function in GROUP and LEFT JOIN) +# + +CREATE TABLE t1 ( a INT NOT NULL, b INT NOT NULL, UNIQUE idx (a,b) ); +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4); +CREATE TABLE t2 ( a INT NOT NULL, b INT NOT NULL, e INT ); +INSERT INTO t2 VALUES ( 1,10,1), (1,10,2), (1,11,1), (1,11,2), (1,2,1), (1,2,2),(1,2,3); +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t1.a, t1.b, c; +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t2.a, t2.b, c; +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2,t1 +WHERE t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +DROP TABLE IF EXISTS t1, t2; + # End of 4.1 tests # @@ -2455,6 +2518,45 @@ SELECT ABS(IFNULL(NULL, NULL)); SELECT IFNULL(NULL, NULL); # +# BUG #12595 (ESCAPE must be exactly one) +# +SET @OLD_SQL_MODE12595=@@SQL_MODE, @@SQL_MODE=''; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; + +CREATE TABLE BUG_12595(a varchar(100)); +INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +# this should work when sql_mode is not NO_BACKSLASH_ESCAPES +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE ''; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE '\\'; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; + +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE '\\'; +#this gives an error when NO_BACKSLASH_ESCAPES is set +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\n%' ESCAPE '\n'; + +SET @@SQL_MODE=@OLD_SQL_MODE12595; +DROP TABLE BUG_12595; + +# # Bug #6495 Illogical requirement for column qualification in NATURAL join # @@ -2465,3 +2567,124 @@ insert into t2 values ('b'),('c'),('d'); select a from t1 natural join t2; select * from t1 natural join t2 where a = 'b'; drop table t1, t2; + +# +# Bug #12977 Compare table names with qualifying field tables only +# for base tables, search all nested join operands of natural joins. +# + +CREATE TABLE t1 (`id` TINYINT); +CREATE TABLE t2 (`id` TINYINT); +CREATE TABLE t3 (`id` TINYINT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +-- error 1052 +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id); + +drop table t1, t2, t3; + +# +# Bug #13067 JOIN xxx USING is case sensitive +# + +create table t1 (a int(10),b int(10)); +create table t2 (a int(10),b int(10)); +insert into t1 values (1,10),(2,20),(3,30); +insert into t2 values (1,10); +# both queries should produce the same result +select * from t1 inner join t2 using (A); +select * from t1 inner join t2 using (a); +drop table t1, t2; + +# +# Bug #12943 Incorrect nesting of [INNER| CROSS] JOIN due to unspecified +# associativity in the parser. +# + +create table t1 (a int, c int); +create table t2 (b int); +create table t3 (b int, a int); +create table t4 (c int); +insert into t1 values (1,1); +insert into t2 values (1); +insert into t3 values (1,1); +insert into t4 values (1); + +select * from t1 join t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +# Notice that ',' has lower priority than 'join', thus we have that: +# t1, t2 join t3 <==> t1, (t2 join t3). +-- error 1054 +select * from t1, t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +select * from t1 join t2 join t3 join t4 on (t1.a = t4.c and t2.b = t4.c); +select * from t1 join t2 join t4 using (c); +drop table t1, t2, t3, t4; + +# +# Bug #12291 Table wasn't reinited for index scan after sequential scan +# +create table t1(x int, y int); +create table t2(x int, y int); +create table t3(x int, primary key(x)); +insert into t1 values (1, 1), (2, 1), (3, 1), (4, 3), (5, 6), (6, 6); +insert into t2 values (1, 1), (2, 1), (3, 3), (4, 6), (5, 6); +insert into t3 values (1), (2), (3), (4), (5); +select t1.x, t3.x from t1, t2, t3 where t1.x = t2.x and t3.x >= t1.y and t3.x <= t2.y; +drop table t1,t2,t3; + +# +# Bug #13127 LEFT JOIN against a VIEW returns NULL instead of correct value +# + +create table t1 (id char(16) not null default '', primary key (id)); +insert into t1 values ('100'),('101'),('102'); +create table t2 (id char(16) default null); +insert into t2 values (1); +create view v1 as select t1.id from t1; +create view v2 as select t2.id from t2; +create view v3 as select (t1.id+2) as id from t1 natural left join t2; + +# all queries must return the same result +select t1.id from t1 left join v2 using (id); +select t1.id from v2 right join t1 using (id); +select t1.id from t1 left join v3 using (id); +select * from t1 left join v2 using (id); +select * from v2 right join t1 using (id); +select * from t1 left join v3 using (id); + +select v1.id from v1 left join v2 using (id); +select v1.id from v2 right join v1 using (id); +select v1.id from v1 left join v3 using (id); +select * from v1 left join v2 using (id); +select * from v2 right join v1 using (id); +select * from v1 left join v3 using (id); + +drop table t1, t2; +drop view v1, v2, v3; + +# +# Bug #13597 Column in ON condition not resolved if references a table in +# nested right join. +# + +create table t1 (id int(11) not null default '0'); +insert into t1 values (123),(191),(192); +create table t2 (id char(16) character set utf8 not null); +insert into t2 values ('58013'),('58014'),('58015'),('58016'); +create table t3 (a_id int(11) not null, b_id char(16) character set utf8); +insert into t3 values (123,null),(123,null),(123,null),(123,null),(123,null),(123,'58013'); + +-- both queries are equivalent +select count(*) +from t1 inner join (t3 left join t2 on t2.id = t3.b_id) on t1.id = t3.a_id; + +select count(*) +from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; + +drop table t1,t2,t3; diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index b9fc991dc80..89d281a2c58 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -386,6 +386,19 @@ create table t1 ( SHOW CREATE TABLE t1; DROP TABLE t1; +# Test for BUG#93: 4.1 protocl crash on corupted frm and SHOW TABLE STATUS + +flush tables; + +# Create a junk frm file on disk +system echo "this is a junk file for test" >> var/master-data/test/t1.frm ; +--replace_column 6 # 7 # 8 # 9 # +SHOW TABLE STATUS like 't1'; +--error 1033 +show create table t1; +drop table t1; + + # End of 4.1 tests # # BUG 12183 - SHOW OPEN TABLES behavior doesn't match grammar diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test index 99223fa4756..7a729f98661 100644 --- a/mysql-test/t/skip_grants.test +++ b/mysql-test/t/skip_grants.test @@ -9,9 +9,8 @@ use test; # test that we can create VIEW if privileges check switched off # create table t1 (field1 INT); +-- error ER_NO_VIEW_USER CREATE VIEW v1 AS SELECT field1 FROM t1; - -drop view v1; drop table t1; # @@ -20,3 +19,11 @@ drop table t1; # create procedure f1() select 1; drop procedure f1; + +# +# BUG#13504: creation view with DEFINER clause if --skip-grant-tables +# +create table t1 (a int); +create definer='user'@'host' sql security definer view v1 as select * from t1; +drop view v1; +drop table t1; diff --git a/mysql-test/t/skip_name_resolve.test b/mysql-test/t/skip_name_resolve.test index 02339ca14c5..b67869692d2 100644 --- a/mysql-test/t/skip_name_resolve.test +++ b/mysql-test/t/skip_name_resolve.test @@ -8,3 +8,13 @@ REVOKE ALL ON test.* FROM mysqltest_1@'127.0.0.1/255.255.255.255'; DROP USER mysqltest_1@'127.0.0.1/255.255.255.255'; # End of 4.1 tests + +# Bug #13407 "Remote connecting crashes server". +# Server crashed when one used USER() function in connection for which +# was impossible to obtain peer hostname. +connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, ); +--replace_column 1 # +select user(); +--replace_column 1 # 6 # 3 # +show processlist; +connection default; diff --git a/mysql-test/t/sp-big.test b/mysql-test/t/sp-big.test index 769d77dbef9..389a6f04504 100644 --- a/mysql-test/t/sp-big.test +++ b/mysql-test/t/sp-big.test @@ -31,3 +31,52 @@ call test.longprocedure(@value); select @value; drop procedure test.longprocedure; drop table t1; +# +# Bug #9819 "Cursors: Mysql Server Crash while fetching from table with 5 +# million records.": +# To really test the bug, increase the number of loop iterations ($1). +# For 4 millions set $1 to 22. +create table t1 (f1 char(100) , f2 mediumint , f3 int , f4 real, f5 numeric); +insert into t1 (f1, f2, f3, f4, f5) values +("This is a test case for for Bug#9819", 1, 2, 3.0, 4.598); +create table t2 like t1; +let $1=8; +--disable_query_log +--disable_result_log +while ($1) +{ + eval insert into t1 select * from t1; + dec $1; +} +--enable_result_log +--enable_query_log +select count(*) from t1; +select count(*) from t2; +delimiter |; +create procedure p1() +begin + declare done integer default 0; + declare vf1 char(100) ; + declare vf2 mediumint; + declare vf3 int ; + declare vf4 real ; + declare vf5 numeric ; + declare cur1 cursor for select f1,f2,f3,f4,f5 from t1; + declare continue handler for sqlstate '02000' set done = 1; + open cur1; + while done <> 1 do + fetch cur1 into vf1, vf2, vf3, vf4, vf5; + if not done then + insert into t2 values (vf1, vf2, vf3, vf4, vf5); + end if; + end while; + close cur1; +end| +delimiter ;| +call p1(); +select count(*) from t1; +select count(*) from t2; +select f1 from t1 limit 1; +select f1 from t2 limit 1; +drop procedure p1; +drop table t1, t2; diff --git a/mysql-test/t/sp-dynamic.test b/mysql-test/t/sp-dynamic.test new file mode 100644 index 00000000000..e9816ee3ef0 --- /dev/null +++ b/mysql-test/t/sp-dynamic.test @@ -0,0 +1,335 @@ +delimiter |; +###################################################################### +# Test Dynamic SQL in stored procedures. ############################# +###################################################################### +# +# A. Basics +# +create procedure p1() +begin + prepare stmt from "select 1"; + execute stmt; + execute stmt; + execute stmt; + deallocate prepare stmt; +end| +call p1()| +call p1()| +call p1()| +drop procedure p1| +# +# B. Recursion. Recusion is disabled in SP, and recursive use of PS is not +# possible as well. +# +create procedure p1() +begin + execute stmt; +end| +prepare stmt from "call p1()"| +--error ER_PS_NO_RECURSION +execute stmt| +--error ER_PS_NO_RECURSION +execute stmt| +--error ER_PS_NO_RECURSION +execute stmt| +--error ER_SP_NO_RECURSION +call p1()| +--error ER_SP_NO_RECURSION +call p1()| +--error ER_SP_NO_RECURSION +call p1()| +drop procedure p1| +# +# C. Create/drop a stored procedure in Dynamic SQL. +# One cannot create stored procedure from a stored procedure because of +# the way MySQL SP cache works: it's important that this limitation is not +# possible to circumvent by means of Dynamic SQL. +# +create procedure p1() +begin + prepare stmt from "create procedure p2() begin select 1; end"; + execute stmt; + deallocate prepare stmt; +end| +--error ER_UNSUPPORTED_PS +call p1()| +--error ER_UNSUPPORTED_PS +call p1()| +drop procedure p1| +create procedure p1() +begin + prepare stmt from "drop procedure p2"; + execute stmt; + deallocate prepare stmt; +end| +--error ER_UNSUPPORTED_PS +call p1()| +--error ER_UNSUPPORTED_PS +call p1()| +drop procedure p1| +# +# D. Create/Drop a table (a DDL that issues a commit) in Dynamic SQL. +# (should work ok). +# +create procedure p1() +begin + prepare stmt_drop from "drop table if exists t1"; + execute stmt_drop; + prepare stmt from "create table t1 (a int)"; + execute stmt; + insert into t1 (a) values (1); + select * from t1; + deallocate prepare stmt; + deallocate prepare stmt_drop; +end| +call p1()| +call p1()| +drop procedure p1| +# +# A more real example (a case similar to submitted by 24/7). +# +create procedure p1() +begin + set @tab_name=concat("tab_", replace(curdate(), '-', '_')); + set @drop_sql=concat("drop table if exists ", @tab_name); + set @create_sql=concat("create table ", @tab_name, " (a int)"); + set @insert_sql=concat("insert into ", @tab_name, " values (1), (2), (3)"); + set @select_sql=concat("select * from ", @tab_name); + select @tab_name; + select @drop_sql; + select @create_sql; + select @insert_sql; + select @select_sql; + prepare stmt_drop from @drop_sql; + execute stmt_drop; + prepare stmt from @create_sql; + execute stmt; + prepare stmt from @insert_sql; + execute stmt; + prepare stmt from @select_sql; + execute stmt; + execute stmt_drop; + deallocate prepare stmt; + deallocate prepare stmt_drop; +end| +--disable_result_log +call p1()| +call p1()| +--enable_result_log +drop procedure p1| +# +# E. Calling a stored procedure with Dynamic SQL +# from a stored function (currently disabled). +# +create procedure p1() +begin + prepare stmt_drop from "drop table if exists t1"; + execute stmt_drop; + prepare stmt from "create table t1 (a int)"; + execute stmt; + deallocate prepare stmt; + deallocate prepare stmt_drop; +end| +--disable_warnings +drop function if exists f1| +--enable_warnings +create function f1(a int) returns int +begin + call p1(); + return 1; +end| + +# Every stored procedure that contains Dynamic SQL is marked as +# such. Stored procedures that contain Dynamic SQL are not +# allowed in a stored function or trigger, and here we get the +# corresponding error message. + +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +select f1(0)| +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +select f1(f1(0))| +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +select f1(f1(f1(0)))| +drop function f1| +drop procedure p1| +# +# F. Rollback and cleanup lists management in Dynamic SQL. +# +create procedure p1() +begin + drop table if exists t1; + create table t1 (id integer not null primary key, + name varchar(20) not null); + insert into t1 (id, name) values (1, 'aaa'), (2, 'bbb'), (3, 'ccc'); + prepare stmt from "select name from t1"; + execute stmt; + select name from t1; + execute stmt; + prepare stmt from + "select name from t1 where name=(select name from t1 where id=2)"; + execute stmt; + select name from t1 where name=(select name from t1 where id=2); + execute stmt; +end| +call p1()| +call p1()| +drop procedure p1| +# +# H. Executing a statement prepared externally in SP. +# +prepare stmt from "select * from t1"| +create procedure p1() +begin + execute stmt; + deallocate prepare stmt; +end| +call p1()| +--error ER_UNKNOWN_STMT_HANDLER +call p1()| +drop procedure p1| +# +# I. Use of an SP variable in Dynamic SQL is not possible and +# this limitation is necessary for correct binary logging: prepared +# statements do not substitute SP variables with their values for binlog, so +# SP variables must be not accessible in Dynamic SQL. +# +create procedure p1() +begin + declare a char(10); + set a="sp-variable"; + set @a="mysql-variable"; + prepare stmt from "select 'dynamic sql:', @a, a"; + execute stmt; +end| +--error ER_BAD_FIELD_ERROR +call p1()| +--error ER_BAD_FIELD_ERROR +call p1()| +drop procedure p1| +# +# J. Use of placeholders in Dynamic SQL. +# +create procedure p1() +begin + prepare stmt from 'select ? as a'; + execute stmt using @a; +end| +set @a=1| +call p1()| +call p1()| +drop procedure p1| +# +# K. Use of continue handlers with Dynamic SQL. +# +drop table if exists t1| +create table t1 (id integer primary key auto_increment, + stmt_text char(35), status varchar(20))| +insert into t1 (stmt_text) values + ("select 1"), ("flush tables"), ("handler t1 open as ha"), + ("analyze table t1"), ("check table t1"), ("checksum table t1"), + ("check table t1"), ("optimize table t1"), ("repair table t1"), + ("describe extended select * from t1"), + ("help help"), ("show databases"), ("show tables"), + ("show table status"), ("show open tables"), ("show storage engines"), + ("insert into t1 (id) values (1)"), ("update t1 set status=''"), + ("delete from t1"), ("truncate t1"), ("call p1()"), ("foo bar")| +create procedure p1() +begin + declare v_stmt_text varchar(255); + declare v_id integer; + declare done int default 0; + declare c cursor for select id, stmt_text from t1; + declare continue handler for 1295 -- ER_UNSUPPORTED_PS + set @status='not supported'; + declare continue handler for 1064 -- ER_SYNTAX_ERROR + set @status='syntax error'; + declare continue handler for sqlstate '02000' set done = 1; + + prepare update_stmt from "update t1 set status=? where id=?"; + open c; + repeat + if not done then + fetch c into v_id, v_stmt_text; + set @id=v_id, @stmt_text=v_stmt_text; + set @status="supported"; + prepare stmt from @stmt_text; + execute update_stmt using @status, @id; + end if; + until done end repeat; + deallocate prepare update_stmt; +end| +call p1()| +select * from t1| +drop procedure p1| +drop table t1| +# +# Bug#7115 "Prepared Statements: packet error if execution within stored +# procedure". +# +prepare stmt from 'select 1'| +create procedure p1() execute stmt| +call p1()| +call p1()| +drop procedure p1| +# +# Bug#10975 "Prepared statements: crash if function deallocates" +# Check that a prepared statement that is currently in use +# can't be deallocated. +# +# a) Prepared statements and stored procedure cache: +# +# TODO: add when the corresponding bug (Bug #12093 "SP not found on second +# PS execution if another thread drops other SP in between") is fixed. +# +# b) attempt to deallocate a prepared statement that is being executed +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +create function f1() returns int +begin + deallocate prepare stmt; + return 1; +end| + +# b)-2 a crash (#1) spotted by Sergey Petrunia during code review +create procedure p1() +begin + prepare stmt from 'select 1 A'; + execute stmt; +end| +prepare stmt from 'call p1()'| +--error ER_PS_NO_RECURSION +execute stmt| +--error ER_PS_NO_RECURSION +execute stmt| +drop procedure p1| + +# +# Bug#10605 "Stored procedure with multiple SQL prepared statements +# disconnects client" +# +--disable_warnings +drop table if exists t1, t2| +--enable_warnings +create procedure p1 (a int) language sql deterministic +begin + declare rsql varchar(100); + drop table if exists t1, t2; + set @rsql= "create table t1 (a int)"; + select @rsql; + prepare pst from @rsql; + execute pst; + set @rsql= null; + set @rsql= "create table t2 (a int)"; + select @rsql; + prepare pst from @rsql; + execute pst; + drop table if exists t1, t2; +end| +set @a:=0| +call p1(@a)| +select @a| +call p1(@a)| +select @a| +drop procedure if exists p1| + +# End of the test +delimiter ;| diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 5921d59b284..c41be99cb30 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -875,7 +875,7 @@ create procedure bug8408_p() select * from t1| call bug8408_p()| ---error ER_SP_BADSELECT +--error ER_SP_NO_RETSET select bug8408_f()| drop procedure bug8408_p| @@ -956,39 +956,10 @@ end| drop procedure bug10969| -# -# BUG#NNNN: New bug synopsis -# -#--disable_warnings -#drop procedure if exists bugNNNN| -#--enable_warnings -#create procedure bugNNNN... - - drop table t1| delimiter ;| -# -# Bug#10975, #10605, #7115: Dynamic SQL by means of -# PREPARE/EXECUTE/DEALLOCATE is not supported yet. -# Check that an error message is returned. -# -prepare stmt from "select 1"; ---error ER_SP_BADSTATEMENT -create procedure p() deallocate prepare stmt; ---error ER_SP_BADSTATEMENT -create function f() returns int begin deallocate prepare stmt; ---error ER_SP_BADSTATEMENT -create procedure p() prepare stmt from "select 1"; ---error ER_SP_BADSTATEMENT -create function f() returns int begin prepare stmt from "select 1"; ---error ER_SP_BADSTATEMENT -create procedure p() execute stmt; ---error ER_SP_BADSTATEMENT -create function f() returns int begin execute stmt; -deallocate prepare stmt; - # BUG#9814: Closing a cursor that is not open create table t1(f1 int); create table t2(f1 int); @@ -1020,6 +991,7 @@ P1: BEGIN SELECT 'end of proc'; END P1| delimiter ;| +--error 1326 call SP001(); drop procedure SP001; drop table t1, t2; @@ -1114,3 +1086,207 @@ drop function bug11834_1; execute stmt; deallocate prepare stmt; drop function bug11834_2; + +# +# Bug#12953 "Stored procedures: crash if OPTIMIZE TABLE in function" +# +delimiter |; +--disable_warnings +DROP FUNCTION IF EXISTS bug12953| +--enable_warnings +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12953() RETURNS INT +BEGIN + OPTIMIZE TABLE t1; + RETURN 1; +END| +delimiter ;| + +# +# Bug##12995 "Inside function "Table 't4' was not locked with LOCK TABLES" +# +delimiter |; +--disable_warnings +DROP FUNCTION IF EXISTS bug12995| +--enable_warnings +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 OPEN; + RETURN 1; +END| +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 READ FIRST; + RETURN 1; +END| +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 CLOSE; + RETURN 1; +END| +--error 1305 +SELECT bug12995()| +delimiter ;| + + +# +# BUG#12712: SET AUTOCOMMIT should fail within SP/functions/triggers +# +--disable_warnings +drop procedure if exists bug12712; +drop function if exists bug12712; +--enable_warnings +# Can... +create procedure bug12712() + set session autocommit = 0; + +select @@autocommit; +set @au = @@autocommit; +call bug12712(); +select @@autocommit; +set session autocommit = @au; + +delimiter |; +create function bug12712() + returns int +begin + call bug12712(); + return 0; +end| + +# Can't... +--error ER_SP_CANT_SET_AUTOCOMMIT +set @x = bug12712()| +drop procedure bug12712| +drop function bug12712| +--error ER_SP_CANT_SET_AUTOCOMMIT +create function bug12712() + returns int +begin + set session autocommit = 0; + return 0; +end| +--error ER_SP_CANT_SET_AUTOCOMMIT +create function bug12712() + returns int +begin + set @@autocommit = 0; + return 0; +end| +--error ER_SP_CANT_SET_AUTOCOMMIT +create function bug12712() + returns int +begin + set local autocommit = 0; + return 0; +end| +delimiter ;| +--error ER_SP_CANT_SET_AUTOCOMMIT +create trigger bug12712 + before insert on t1 for each row set session autocommit = 0; + +# +# BUG#9367: Stored procedures: client hang after "show warnings" +# +--disable_parsing +--disable_warnings +drop procedure if exists bug9367; +--enable_warnings +create table t1 (s1 int); +select s1 from t1; +delimiter |; +create procedure bug9367() +begin + declare v int; + declare c cursor for select s1 from t1; + open c; + show warnings; + fetch c into v; + select v; +end| +delimiter ;| +call bug9367(); +drop procedure bug9367; +drop table t1; +--enable_parsing + +# +# BUG#13510: Setting password local variable changes current password +# +delimiter |; +--disable_warnings +drop procedure if exists bug13510_1| +drop procedure if exists bug13510_2| +drop procedure if exists bug13510_3| +drop procedure if exists bug13510_4| +--enable_warnings + +--error ER_SP_BAD_VAR_SHADOW +create procedure bug13510_1() +begin + declare password varchar(10); + + set password = 'foo1'; + select password; +end| + +--error ER_SP_BAD_VAR_SHADOW +create procedure bug13510_2() +begin + declare names varchar(10); + + set names = 'foo2'; + select names; +end| + +create procedure bug13510_3() +begin + declare password varchar(10); + + set `password` = 'foo3'; + select password; +end| + +create procedure bug13510_4() +begin + declare names varchar(10); + + set `names` = 'foo4'; + select names; +end| + +call bug13510_3()| +call bug13510_4()| + +drop procedure bug13510_3| +drop procedure bug13510_4| +delimiter ;| + +# +# Bug#13514 "server crash when create a stored procedure before choose a +# database" and +# Bug#13587 "Server crash when SP is created without database +# selected" +# +create database mysqltest1; +use mysqltest1; +drop database mysqltest1; +--error ER_NO_DB_ERROR +create function f1() returns int return 1; +delimiter |; +--error ER_NO_DB_ERROR +create procedure p1(out param1 int) +begin + select count(*) into param1 from t3; +end| +delimiter ;| +use test; +# BUG#NNNN: New bug synopsis +# +#--disable_warnings +#drop procedure if exists bugNNNN| +#--enable_warnings +#create procedure bugNNNN... diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index 6f1332f80d5..afbc383a17a 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -412,4 +412,28 @@ drop database mysqltest_1; revoke usage on *.* from mysqltest_1@localhost; drop user mysqltest_1@localhost; +# +# BUG#12812 create view calling a function works without execute right +# on function +delimiter |; +--disable_warnings +drop function if exists bug12812| +--enable_warnings +create function bug12812() returns char(2) +begin + return 'ok'; +end; +create user user_bug12812@localhost IDENTIFIED BY 'ABC'| +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +connect (test_user_12812,localhost,user_bug12812,ABC,test)| +--error 1370 +SELECT test.bug12812()| +--error 1370 +CREATE VIEW v1 AS SELECT test.bug12812()| +# Cleanup +connection default| +disconnect test_user_12812| +DROP USER user_bug12812@localhost| +drop function bug12812| +delimiter ;| # End of 5.0 bugs. diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index f1662a57c1b..18607c7f13c 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1213,7 +1213,7 @@ end| select f5(1)| # This should generate an error about insuficient number of tables locked # Now this crash server ---disable_parsing until bug#11394 fix +--disable_parsing # until bug#11394 fix --error 1100 select f5(2)| # But now it simply miserably fails because we are trying to use the same @@ -2431,7 +2431,7 @@ create function bug3788() returns date return cast("2005-03-04" as date)| select bug3788()| drop function bug3788| -create function bug3788() returns binary(5) return 5| +create function bug3788() returns binary(1) return 5| select bug3788()| drop function bug3788| @@ -2469,7 +2469,7 @@ drop table t3| # BUG#4318 # ---disable_parsing Don't know if HANDLER commands can work with SPs, or at all.. +--disable_parsing # Don't know if HANDLER commands can work with SPs, or at all.. create table t3 (s1 int)| insert into t3 values (3), (4)| @@ -2836,7 +2836,7 @@ drop table t3| # BUG#6022: Stored procedure shutdown problem with self-calling function. # ---disable_parsing until we implement support for recursive stored functions. +--disable_parsing # until we implement support for recursive stored functions. --disable_warnings drop function if exists bug6022| --enable_warnings @@ -3762,7 +3762,7 @@ drop procedure if exists bug7088_1| drop procedure if exists bug7088_2| --enable_warnings ---disable_parsing temporarily disabled until Bar fixes BUG#11986 +--disable_parsing # temporarily disabled until Bar fixes BUG#11986 create procedure bug6063() lâbel: begin end| call bug6063()| @@ -3877,29 +3877,23 @@ drop function bug10055| # consumption by passing large input parameter. # -# -# Note: the test is currenly disabled because of the -# Bug #12637: SP crashes the server if it has update query with user var -# & binlog is enabled. -# - --disable_warnings -#drop procedure if exists bug12297| +drop procedure if exists bug12297| --enable_warnings -#create procedure bug12297(lim int) -#begin -# set @x = 0; -# repeat -# insert into t1(id,data) -# values('aa', @x); -# set @x = @x + 1; -# until @x >= lim -# end repeat; -#end| +create procedure bug12297(lim int) +begin + set @x = 0; + repeat + insert into t1(id,data) + values('aa', @x); + set @x = @x + 1; + until @x >= lim + end repeat; +end| -#call bug12297(10)| -#drop procedure bug12297| +call bug12297(10)| +drop procedure bug12297| # # Bug #11247 "Stored procedures: Function calls in long loops leak memory" @@ -4043,6 +4037,402 @@ begin end| drop function bug9048| +# Bug #12849 Stored Procedure: Crash on procedure call with CHAR type +# 'INOUT' parameter +# + +--disable_warnings +drop procedure if exists bug12849_1| +--enable_warnings +create procedure bug12849_1(inout x char) select x into x| +set @var='a'| +call bug12849_1(@var)| +select @var| +drop procedure bug12849_1| + +--disable_warnings +drop procedure if exists bug12849_2| +--enable_warnings +create procedure bug12849_2(inout foo varchar(15)) +begin +select concat(foo, foo) INTO foo; +end| +set @var='abcd'| +call bug12849_2(@var)| +select @var| +drop procedure bug12849_2| + +# +# BUG#13133: Local variables in stored procedures are not initialized correctly. +# +--disable_warnings +drop procedure if exists bug131333| +drop function if exists bug131333| +--enable_warnings +create procedure bug131333() +begin + begin + declare a int; + + select a; + set a = 1; + select a; + end; + begin + declare b int; + + select b; + end; +end| + +create function bug131333() + returns int +begin + begin + declare a int; + + set a = 1; + end; + begin + declare b int; + + return b; + end; +end| + +call bug131333()| +select bug131333()| + +drop procedure bug131333| +drop function bug131333| + +# +# BUG#12379: PROCEDURE with HANDLER calling FUNCTION with error get +# strange result +# +--disable_warnings +drop function if exists bug12379| +drop procedure if exists bug12379_1| +drop procedure if exists bug12379_2| +drop procedure if exists bug12379_3| +drop table if exists t3| +--enable_warnings + +create table t3 (c1 char(1) primary key not null)| + +create function bug12379() + returns integer +begin + insert into t3 values('X'); + insert into t3 values('X'); + return 0; +end| + +create procedure bug12379_1() +begin + declare exit handler for sqlexception select 42; + + select bug12379(); +END| +create procedure bug12379_2() +begin + declare exit handler for sqlexception begin end; + + select bug12379(); +end| +create procedure bug12379_3() +begin + select bug12379(); +end| + +--error 1062 +select bug12379()| +select 1| +call bug12379_1()| +select 2| +call bug12379_2()| +select 3| +--error 1062 +call bug12379_3()| +select 4| + +drop function bug12379| +drop procedure bug12379_1| +drop procedure bug12379_2| +drop procedure bug12379_3| +drop table t3| + +# +# Bug #13124 Stored Procedure using SELECT INTO crashes server +# + +--disable_warnings +drop procedure if exists bug13124| +--enable_warnings +create procedure bug13124() +begin + declare y integer; + set @x=y; +end| +call bug13124()| +drop procedure bug13124| + +# +# Bug #12979 Stored procedures: crash if inout decimal parameter +# + +# check NULL inout parameters processing + +--disable_warnings +drop procedure if exists bug12979_1| +--enable_warnings +create procedure bug12979_1(inout d decimal(5)) set d = d / 2| +set @bug12979_user_var = NULL| +call bug12979_1(@bug12979_user_var)| +drop procedure bug12979_1| + +# check NULL local variables processing + +--disable_warnings +drop procedure if exists bug12979_2| +--enable_warnings +create procedure bug12979_2() +begin +declare internal_var decimal(5); +set internal_var= internal_var / 2; +select internal_var; +end| +call bug12979_2()| +drop procedure bug12979_2| + + +# +# BUG#6127: Stored procedure handlers within handlers don't work +# +--disable_warnings +drop table if exists t3| +drop procedure if exists bug6127| +--enable_warnings +create table t3 (s1 int unique)| + +set @sm=@@sql_mode| +set sql_mode='traditional'| + +create procedure bug6127() +begin + declare continue handler for sqlstate '23000' + begin + declare continue handler for sqlstate '22003' + insert into t3 values (0); + + insert into t3 values (1000000000000000); + end; + + insert into t3 values (1); + insert into t3 values (1); +end| + +call bug6127()| +select * from t3| +--error ER_DUP_ENTRY +call bug6127()| +select * from t3| +set sql_mode=@sm| +drop table t3| +drop procedure bug6127| + + +# +# BUG#12589: Assert when creating temp. table from decimal stored procedure +# variable +# +--disable_warnings +drop procedure if exists bug12589_1| +drop procedure if exists bug12589_2| +drop procedure if exists bug12589_3| +--enable_warnings +create procedure bug12589_1() +begin + declare spv1 decimal(3,3); + set spv1= 123.456; + + set spv1 = 'test'; + create temporary table tm1 as select spv1; + show create table tm1; + drop temporary table tm1; +end| + +create procedure bug12589_2() +begin + declare spv1 decimal(6,3); + set spv1= 123.456; + + create temporary table tm1 as select spv1; + show create table tm1; + drop temporary table tm1; +end| + +create procedure bug12589_3() +begin + declare spv1 decimal(6,3); + set spv1= -123.456; + + create temporary table tm1 as select spv1; + show create table tm1; + drop temporary table tm1; +end| + +# Note: The type of the field will match the value, not the declared +# type of the variable. (This is a type checking issue which +# might be changed later.) + +# Warning expected from "set spv1 = 'test'", the value is set to decimal "0". +call bug12589_1()| +# No warnings here +call bug12589_2()| +call bug12589_3()| + +# +# BUG#7049: Stored procedure CALL errors are ignored +# +--disable_warnings +drop table if exists t3| +drop procedure if exists bug7049_1| +drop procedure if exists bug7049_2| +drop procedure if exists bug7049_3| +drop procedure if exists bug7049_4| +drop procedure if exists bug7049_5| +drop procedure if exists bug7049_6| +drop function if exists bug7049_1| +drop function if exists bug7049_2| +--enable_warnings + +create table t3 ( x int unique )| + +create procedure bug7049_1() +begin + insert into t3 values (42); + insert into t3 values (42); +end| + +create procedure bug7049_2() +begin + declare exit handler for sqlexception + select 'Caught it' as 'Result'; + + call bug7049_1(); + select 'Missed it' as 'Result'; +end| + +create procedure bug7049_3() + call bug7049_1()| + +create procedure bug7049_4() +begin + declare exit handler for sqlexception + select 'Caught it' as 'Result'; + + call bug7049_3(); + select 'Missed it' as 'Result'; +end| + +create procedure bug7049_5() +begin + declare x decimal(2,1); + + set x = 'zap'; +end| + +create procedure bug7049_6() +begin + declare exit handler for sqlwarning + select 'Caught it' as 'Result'; + + call bug7049_5(); + select 'Missed it' as 'Result'; +end| + +create function bug7049_1() + returns int +begin + insert into t3 values (42); + insert into t3 values (42); + return 42; +end| + +create function bug7049_2() + returns int +begin + declare x int default 0; + declare continue handler for sqlexception + set x = 1; + + set x = bug7049_1(); + return x; +end| + +call bug7049_2()| +select * from t3| +delete from t3| +call bug7049_4()| +select * from t3| +call bug7049_6()| +select bug7049_2()| + +drop table t3| +drop procedure bug7049_1| +drop procedure bug7049_2| +drop procedure bug7049_3| +drop procedure bug7049_4| +drop procedure bug7049_5| +drop procedure bug7049_6| +drop function bug7049_1| +drop function bug7049_2| + + +# +# BUG#13941: replace() string fuction behaves badly inside stored procedure +# (BUG#13914: IFNULL is returning garbage in stored procedure) +# +--disable_warnings +drop function if exists bug13941| +drop procedure if exists bug13941| +--enable_warnings + +create function bug13941(p_input_str text) + returns text +begin + declare p_output_str text; + + set p_output_str = p_input_str; + + set p_output_str = replace(p_output_str, 'xyzzy', 'plugh'); + set p_output_str = replace(p_output_str, 'test', 'prova'); + set p_output_str = replace(p_output_str, 'this', 'questo'); + set p_output_str = replace(p_output_str, ' a ', 'una '); + set p_output_str = replace(p_output_str, 'is', ''); + + return p_output_str; +end| + +create procedure bug13941(out sout varchar(128)) +begin + set sout = 'Local'; + set sout = ifnull(sout, 'DEF'); +end| + +# Note: The bug showed different behaviour in different types of builds, +# giving garbage results in some, and seemingly working in others. +# Running with valgrind (or purify) is the safe way to check that it's +# really working correctly. +select bug13941('this is a test')| +call bug13941(@a)| +select @a| + +drop function bug13941| +drop procedure bug13941| + + # # BUG#NNNN: New bug synopsis # diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index 10db520cd12..b11afe9e59d 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -86,6 +86,18 @@ drop table t1 ; --error 1231 set @@SQL_MODE=NULL; +# +# Bug #797: in sql_mode=ANSI, show create table ignores auto_increment +# +set session sql_mode=ansi; +create table t1 +(f1 integer auto_increment primary key, + f2 timestamp default current_timestamp on update current_timestamp); +show create table t1; +set session sql_mode=no_field_options; +show create table t1; +drop table t1; + # End of 4.1 tests # diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index ca57ca646f2..d3b36cbc2a8 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -315,7 +315,7 @@ INSERT INTO t1 (col2) VALUES(CAST('0000-00-00' AS DATETIME)); ## Test INSERT with CAST AS DATETIME into TIMESTAMP # All test cases expected to fail should return # SQLSTATE 22007 <invalid datetime value> -!$1292 +--error 1292 INSERT INTO t1 (col3) VALUES(CAST('0000-10-31 15:30' AS DATETIME)); -- should return OK -- We accept this to be a failure @@ -406,7 +406,7 @@ INSERT INTO t1 (col2) VALUES(CONVERT('0000-00-00',DATETIME)); ## Test INSERT with CONVERT to DATETIME into DATETIME # All test cases expected to fail should return # SQLSTATE 22007 <invalid datetime value> -!$1292 +--error 1292 INSERT INTO t1 (col3) VALUES(CONVERT('0000-10-31 15:30',DATETIME)); -- should return OK -- We accept this to be a failure @@ -659,9 +659,11 @@ INSERT INTO t1 VALUES(-9223372036854775808,0),(0,0),(9223372036854775807,1844674 INSERT INTO t1 VALUES('-9223372036854775808','0'),('9223372036854775807','18446744073709551615'); INSERT INTO t1 VALUES(-9223372036854774000.0,0.0),(9223372036854775700.0,1844674407370954000.0); --- error 1264 +--error 1264 INSERT INTO t1 (col1) VALUES(-9223372036854775809); +--error 1264 INSERT INTO t1 (col1) VALUES(9223372036854775808); +--error 1264 INSERT INTO t1 (col2) VALUES(-1); --error 1264 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 5020902009d..cc621fb5835 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1962,4 +1962,9 @@ insert into t1 values ('1'); select * from (select max(fld) from t1) as foo; drop table t1; +# +# BUG #10308: purge log with subselect +# + +purge master logs before (select adddate(current_timestamp(), interval -4 day)); diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index 839e94206d0..b21eda176b6 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -25,6 +25,8 @@ DOCID VARCHAR(32)BINARY NOT NULL ) ENGINE=InnoDB ; +INSERT INTO t1 (DOCID) VALUES ("1"), ("2"); + CREATE TABLE t2 ( DOCID VARCHAR(32)BINARY NOT NULL diff --git a/mysql-test/t/subselect_innodb.test b/mysql-test/t/subselect_innodb.test index 3b1d2f393c2..a07cc93ad68 100644 --- a/mysql-test/t/subselect_innodb.test +++ b/mysql-test/t/subselect_innodb.test @@ -161,3 +161,25 @@ deallocate prepare my_stmt; drop table t1,t2; # End of 4.1 tests + +CREATE TABLE t1 ( + school_name varchar(45) NOT NULL, + country varchar(45) NOT NULL, + funds_requested float NOT NULL, + schooltype varchar(45) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +insert into t1 values ("the school", "USA", 1200, "Human"); + +select count(country) as countrycount, sum(funds_requested) as smcnt, + country, (select sum(funds_requested) from t1) as total_funds +from t1 +group by country; + +select count(country) as countrycount, sum(funds_requested) as smcnt, + country, (select sum(funds_requested) from t1) as total_funds +from t1 +group by country; + +drop table t1; + diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test index 9a7678ed712..6b3991c9c78 100644 --- a/mysql-test/t/temp_table.test +++ b/mysql-test/t/temp_table.test @@ -4,6 +4,7 @@ --disable_warnings drop table if exists t1,t2; +drop view if exists v1; --enable_warnings CREATE TABLE t1 (c int not null, d char (10) not null); @@ -91,18 +92,18 @@ show status like "created_tmp%tables"; drop table t1; # Fix for BUG#8921: Check that temporary table is ingored by view commands. -create temporary table t1 as select 'This is temp. table' A; -create view t1 as select 'This is view' A; -select * from t1; -show create table t1; -show create view t1; -drop view t1; -select * from t1; -create view t1 as select 'This is view again' A; -select * from t1; -drop table t1; -select * from t1; -drop view t1; +create temporary table v1 as select 'This is temp. table' A; +create view v1 as select 'This is view' A; +select * from v1; +show create table v1; +show create view v1; +drop view v1; +select * from v1; +create view v1 as select 'This is view again' A; +select * from v1; +drop table v1; +select * from v1; +drop view v1; # Bug #8497: tmpdir with extra slashes would cause failures # diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 9920f203c94..cd79eb82ace 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -10,6 +10,11 @@ drop function if exists f1; drop procedure if exists p1; --enable_warnings +# Create additional connections used through test +connect (addconroot1, localhost, root,,); +connect (addconroot2, localhost, root,,); +connection default; + create table t1 (i int); # let us test some very simple trigger @@ -680,12 +685,10 @@ end| delimiter ;| update t1 set data = 1; -connect (addconroot, localhost, root,,); -connection addconroot; +connection addconroot1; update t1 set data = 2; connection default; -disconnect addconroot; drop table t1; # @@ -723,7 +726,7 @@ begin end| delimiter ;| ---error 1312 +--error ER_SP_NO_RETSET insert into t1 (c1) values (4),(5),(6); select * from t1; @@ -765,3 +768,110 @@ insert into t1 values (3); select * from t1; drop trigger t1_bi; drop tables t1, t2; + +# Tests for bug #12704 "Server crashes during trigger execution". +# If we run DML statements and CREATE TRIGGER statements concurrently +# it may happen that trigger will be created while DML statement is +# waiting for table lock. In this case we have to reopen tables and +# recalculate prelocking set. +# Unfortunately these tests rely on the order in which tables are locked +# by statement so they are non determenistic and are disabled. +--disable_parsing +create table t1 (id int); +create table t2 (id int); +create table t3 (id int); +create function f1() returns int return (select max(id)+2 from t2); +create view v1 as select f1() as f; + +# Let us check that we notice trigger at all +connection addconroot1; +lock tables t2 write; +connection default; +send insert into t1 values ((select max(id) from t2)), (2); +--sleep 1 +connection addconroot2; +create trigger t1_trg before insert on t1 for each row set NEW.id:= 1; +connection addconroot1; +unlock tables; +connection default; +reap; +select * from t1; + +# Check that we properly calculate new prelocking set +insert into t2 values (3); +connection addconroot1; +lock tables t2 write; +connection default; +send insert into t1 values ((select max(id) from t2)), (4); +--sleep 1 +connection addconroot2; +drop trigger t1_trg; +create trigger t1_trg before insert on t1 for each row + insert into t3 values (new.id); +connection addconroot1; +unlock tables; +connection default; +reap; +select * from t1; +select * from t3; + +# We should be able to do this even if fancy views are involved +connection addconroot1; +lock tables t2 write; +connection default; +send insert into t1 values ((select max(f) from v1)), (6); +--sleep 1 +connection addconroot2; +drop trigger t1_trg; +create trigger t1_trg before insert on t1 for each row + insert into t3 values (new.id + 100); +connection addconroot1; +unlock tables; +connection default; +reap; +select * from t1; +select * from t3; + +# This also should work for multi-update +# Let us drop trigger to demonstrate that prelocking set is really +# rebuilt +drop trigger t1_trg; +connection addconroot1; +lock tables t2 write; +connection default; +send update t1, t2 set t1.id=10 where t1.id=t2.id; +--sleep 1 +connection addconroot2; +create trigger t1_trg before update on t1 for each row + insert into t3 values (new.id); +connection addconroot1; +unlock tables; +connection default; +reap; +select * from t1; +select * from t3; + +# And even for multi-update converted from ordinary update thanks to view +drop view v1; +drop trigger t1_trg; +create view v1 as select t1.id as id1 from t1, t2 where t1.id= t2.id; +insert into t2 values (10); +connection addconroot1; +lock tables t2 write; +connection default; +send update v1 set id1= 11; +--sleep 1 +connection addconroot2; +create trigger t1_trg before update on t1 for each row + insert into t3 values (new.id + 100); +connection addconroot1; +unlock tables; +connection default; +reap; +select * from t1; +select * from t3; + +drop function f1; +drop view v1; +drop table t1, t2, t3; +--enable_parsing diff --git a/mysql-test/t/type_binary.test b/mysql-test/t/type_binary.test new file mode 100644 index 00000000000..b5928cb14c4 --- /dev/null +++ b/mysql-test/t/type_binary.test @@ -0,0 +1,67 @@ +# check 0x00 padding +create table t1 (s1 binary(3)); +insert into t1 values (0x61), (0x6120), (0x612020); +select hex(s1) from t1; +drop table t1; + +# check that 0x00 is not stripped in val_str +create table t1 (s1 binary(2), s2 varbinary(2)); +insert into t1 values (0x4100,0x4100); +select length(concat('*',s1,'*',s2,'*')) from t1; +delete from t1; +insert into t1 values (0x4120,0x4120); +select length(concat('*',s1,'*',s2,'*')) from t1; +drop table t1; + +# check that trailing 0x00 and 0x20 do matter on comparison +create table t1 (s1 varbinary(20), s2 varbinary(20)); +show create table t1; +insert into t1 values (0x41,0x4100),(0x41,0x4120),(0x4100,0x4120); +select hex(s1), hex(s2) from t1; +select count(*) from t1 where s1 < s2; +drop table t1; + +# check that trailing 0x00 do matter on filesort +create table t1 (s1 varbinary(2), s2 varchar(1)); +insert into t1 values (0x41,'a'), (0x4100,'b'), (0x41,'c'), (0x4100,'d'); +select hex(s1),s2 from t1 order by s1,s2; +drop table t1; + +# check that 0x01 is padded to 0x0100 and thus we get a duplicate value +create table t1 (s1 binary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +--error 1062 +insert into t1 values (0x0100); +select hex(s1) from t1 order by s1; +# check index search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +alter table t1 drop primary key; +# check non-indexed search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +drop table t1; + +# check that 0x01 is not padded, and all three values are unique +create table t1 (s1 varbinary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +insert into t1 values (0x0100); +select hex(s1) from t1 order by s1; +# check index search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +alter table t1 drop primary key; +# check non-indexed search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +drop table t1; diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index 6906cfc2808..0c45dea21bb 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -224,3 +224,5 @@ select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2; select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1; select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2; select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1; +select 1 from t1 join t2 on b1 = b2 group by b1 order by 1; +select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1; diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index 1ec5c600296..503d7ffc0b9 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -67,9 +67,9 @@ select * from t1; drop table t1; # -# test of blob, text, char and char binary +# test of blob, text, char and varbinary # -create table t1 (t text,c char(10),b blob, d binary(10)); +create table t1 (t text,c char(10),b blob, d varbinary(10)); insert into t1 values (NULL,NULL,NULL,NULL); insert into t1 values ("","","",""); insert into t1 values ("hello","hello","hello","hello"); @@ -404,3 +404,22 @@ alter table t1 add primary key (a,b,c(255),d); alter table t1 add key (a,b,d,e); show create table t1; drop table t1; + +# +# Test that blob's and varbinary are sorted according to length +# + +CREATE table t1 (a blob); +insert into t1 values ('b'),('a\0'),('a'),('a '),('aa'),(NULL); +select hex(a) from t1 order by a; +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +alter table t1 modify a varbinary(5); +select hex(a) from t1 order by a; +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +alter table t1 modify a char(5); +select hex(a) from t1 order by a; +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +alter table t1 modify a binary(5); +select hex(a) from t1 order by a; +select hex(concat(a,'\0')) as b from t1 order by concat(a,'\0'); +drop table t1; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 44032fde46f..1f6310cb819 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -268,6 +268,16 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000 select * from t1; drop table t1; +# +# Bug #7589: a problem with update from column +# + +create table t1(a decimal(10,5), b decimal(10,1)); +insert into t1 values(123.12345, 123.12345); +update t1 set b=a; +select * from t1; +drop table t1; + # End of 4.1 tests # diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index c0f1854d5b2..6a0814ef113 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -146,4 +146,26 @@ select * from t1 where reckey=109; select * from t1 where reckey=1.09E2; drop table t1; +# +# Bug #13372 (decimal union) +# +create table t1 (d double(10,1)); +create table t2 (d double(10,9)); +insert into t1 values ("100000000.0"); +insert into t2 values ("1.23456780"); +create table t3 select * from t2 union select * from t1; +select * from t3; +show create table t3; +drop table t1, t2, t3; + + # End of 4.1 tests + +# +# bug #12694 (float(m,d) specifications) +# + +--error 1427 +create table t1 (s1 float(0,2)); +--error 1427 +create table t1 (s1 float(1,2)); diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 81e06c70c7d..3f04aa931d2 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -494,7 +494,7 @@ select 0.8 = 0.7 + 0.1; # #drop procedure p1; # -delimiter // +delimiter //; # create procedure p1 () begin declare v1, v2, v3, v4 decimal(16,12); declare v5 int; @@ -1015,3 +1015,32 @@ create table t1 ( f1 decimal (0,0) zerofill not null default 0); show create table t1; drop table t1; + +# +# Bug 12938 (arithmetic loop's zero) +# +--disable-warnings +drop procedure if exists wg2; +--enable-warnings +delimiter //; +create procedure wg2() +begin + declare v int default 1; + declare tdec decimal(5) default 0; + while v <= 9 do set tdec =tdec * 10; + select v, tdec; + set v = v + 1; + end while; +end// + +call wg2()// + +delimiter ;// +drop procedure wg2; + +# +# Bug #12979 Stored procedures: crash if inout decimal parameter +# (not a SP bug in fact) +# + +select cast(@non_existing_user_var/2 as DECIMAL); diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index d4b0c1746af..daa83ef0fa4 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -443,14 +443,6 @@ create table t1 SELECT b from t2 UNION select tx from t2; select * from t1; show create table t1; drop table t1,t2; -create table t1 (d decimal(10,1)); -create table t2 (d decimal(10,9)); -insert into t1 values ("100000000.0"); -insert into t2 values ("1.23456780"); -create table t3 select * from t2 union select * from t1; -select * from t3; -show create table t3; -drop table t1,t2,t3; create table t1 select 1 union select -1; select * from t1; show create table t1; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index dd6c36d8414..13ced76079f 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -215,4 +215,45 @@ UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); select * from t1; drop table t1,t2; +# +# Bug #13180 sometimes server accepts sum func in update/delete where condition +# +create table t1(f1 int); +select DATABASE(); +--error 1111 +update t1 set f1=1 where count(*)=1; +select DATABASE(); +--error 1111 +delete from t1 where count(*)=1; +drop table t1; + +# BUG#12915: Optimize "DELETE|UPDATE ... ORDER BY ... LIMIT n" to use an index +create table t1 ( a int, index (a) ); +insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0); + +flush status; +select a from t1 order by a limit 1; +show status like 'handler_read%'; + +flush status; +update t1 set a=unix_timestamp() order by a limit 1; +show status like 'handler_read%'; + +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; + +flush status; +delete from t1 order by a desc limit 1; +show status like 'handler_read%'; + +alter table t1 disable keys; + +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; + +select count(*) from t1; + +drop table t1; # End of 4.1 tests diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 7ce2cf22db0..f23cc0152c1 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -390,6 +390,29 @@ SET GLOBAL table_cache=-1; SHOW VARIABLES LIKE 'table_cache'; SET GLOBAL table_cache=DEFAULT; +# +# Bugs12363: character_set_results is nullable, +# but value_ptr returns string "NULL" +# +set character_set_results=NULL; +select ifnull(@@character_set_results,"really null"); +set names latin1; + + +# +# Bug #9613: @@have_innodb +# + +--replace_column 1 # +select @@have_innodb; + +# +# Bug #13334: query_prealloc_size default less than minimum +# +set @test = @@query_prealloc_size; +set @@query_prealloc_size = @test; +select @@query_prealloc_size = @test; + # End of 4.1 tests # @@ -422,8 +445,12 @@ set @@max_heap_table_size= 4294967296; select @@max_heap_table_size > 0; # -# Bug #9613: @@have_innodb +# Bug #11775 Variable character_set_system does not exist (sometimes) # +select @@character_set_system; +--error 1238 +set global character_set_system = latin1; +--error 1238 +set @@global.version_compile_os='234'; ---replace_column 1 # -select @@have_innodb; +# End of 5.0 tests diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index d786b61c8a8..dd773c4c650 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -147,7 +147,7 @@ insert into t1 values (1), (2), (3); create view v1 (a) as select a+1 from t1; create view v2 (a) as select a-1 from t1; ---disable_parsing WL #2486 should enable these tests +--disable_parsing # WL #2486 should enable these tests select * from t1 natural left join v1; select * from v2 natural left join t1; select * from v2 natural left join v1; @@ -786,6 +786,22 @@ select * from v1; drop view v1; # +# renaming views +# +create table t1 (a int); +create view v1 as select a from t1; +create view v3 as select a from t1; +create database mysqltest; +-- error 1450 +rename table v1 to mysqltest.v1; +rename table v1 to v2; +--error 1050 +rename table v3 to v1, v2 to t1; +drop table t1; +drop view v2,v3; +drop database mysqltest; + +# # bug handling from VIEWs # create view v1 as select 'a',1; @@ -827,29 +843,29 @@ create table t2 (col1 int); create view v1 as select * from t1; create view v2 as select * from v1; create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1; --- error 1093 +-- error 1443 update v2 set col1 = (select max(col1) from v1); --- error 1093 +-- error 1443 update v2 set col1 = (select max(col1) from t1); -- error 1093 update v2 set col1 = (select max(col1) from v2); --- error 1093 +-- error 1443 update v2,t2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1; --- error 1093 +-- error 1443 update t1,t2 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1; -- error 1093 update v1,t2 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1; --- error 1093 +-- error 1443 update t2,v2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1; --- error 1093 +-- error 1443 update t2,t1 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1; --- error 1093 +-- error 1443 update t2,v1 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1; --- error 1093 +-- error 1443 update v2,t2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1; -- error 1093 update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; --- error 1093 +-- error 1443 update v1,t2 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1; -- error 1093 update t2,v2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1; @@ -859,74 +875,74 @@ update t2,t1 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; update t2,v1 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1; -- error 1093 update v2,t2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1; --- error 1093 +-- error 1443 update t1,t2 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1; --- error 1093 +-- error 1443 update v1,t2 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1; --- error 1093 +-- error 1443 update t2,v2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1; --- error 1093 +-- error 1443 update t2,t1 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1; --- error 1093 +-- error 1443 update t2,v1 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1; --- error 1093 +-- error 1443 update v3 set v3.col1 = (select max(col1) from v1); --- error 1093 +-- error 1443 update v3 set v3.col1 = (select max(col1) from t1); --- error 1093 +-- error 1443 update v3 set v3.col1 = (select max(col1) from v2); -- error 1093 update v3 set v3.col1 = (select max(col1) from v3); --- error 1093 +-- error 1443 delete from v2 where col1 = (select max(col1) from v1); --- error 1093 +-- error 1443 delete from v2 where col1 = (select max(col1) from t1); -- error 1093 delete from v2 where col1 = (select max(col1) from v2); --- error 1093 +-- error 1443 delete v2 from v2,t2 where (select max(col1) from v1) > 0 and v2.col1 = t2.col1; --- error 1093 +-- error 1443 delete t1 from t1,t2 where (select max(col1) from v1) > 0 and t1.col1 = t2.col1; -- error 1093 delete v1 from v1,t2 where (select max(col1) from v1) > 0 and v1.col1 = t2.col1; --- error 1093 +-- error 1443 delete v2 from v2,t2 where (select max(col1) from t1) > 0 and v2.col1 = t2.col1; -- error 1093 delete t1 from t1,t2 where (select max(col1) from t1) > 0 and t1.col1 = t2.col1; --- error 1093 +-- error 1443 delete v1 from v1,t2 where (select max(col1) from t1) > 0 and v1.col1 = t2.col1; -- error 1093 delete v2 from v2,t2 where (select max(col1) from v2) > 0 and v2.col1 = t2.col1; --- error 1093 +-- error 1443 delete t1 from t1,t2 where (select max(col1) from v2) > 0 and t1.col1 = t2.col1; --- error 1093 +-- error 1443 delete v1 from v1,t2 where (select max(col1) from v2) > 0 and v1.col1 = t2.col1; --- error 1093 +-- error 1443 insert into v2 values ((select max(col1) from v1)); --- error 1093 +-- error 1443 insert into t1 values ((select max(col1) from v1)); --- error 1093 +-- error 1443 insert into v2 values ((select max(col1) from v1)); --- error 1093 +-- error 1443 insert into v2 values ((select max(col1) from t1)); -- error 1093 insert into t1 values ((select max(col1) from t1)); --- error 1093 +-- error 1443 insert into v2 values ((select max(col1) from t1)); -- error 1093 insert into v2 values ((select max(col1) from v2)); --- error 1093 +-- error 1443 insert into t1 values ((select max(col1) from v2)); -- error 1093 insert into v2 values ((select max(col1) from v2)); --- error 1093 +-- error 1443 insert into v3 (col1) values ((select max(col1) from v1)); --- error 1093 +-- error 1443 insert into v3 (col1) values ((select max(col1) from t1)); --- error 1093 +-- error 1443 insert into v3 (col1) values ((select max(col1) from v2)); #check with TZ tables in list --- error 1093 +-- error 1443 insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2)); insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2)); -- error 1048 @@ -1083,11 +1099,11 @@ create view v1 as select * from t1; create view v2 as select * from v1; -- error 1146 alter view v1 as select * from v2; --- error 1066 +-- error 1146 alter view v1 as select * from v1; -- error 1146 create or replace view v1 as select * from v2; --- error 1066 +-- error 1146 create or replace view v1 as select * from v1; drop view v2,v1; drop table t1; @@ -1242,7 +1258,7 @@ create view v3 as select * from t1 where 20 < (select (s1) from v2); -- error 1288 insert into v3 values (30); create view v4 as select * from v2 where 20 < (select (s1) from t1); --- error 1093 +-- error 1288 insert into v4 values (30); drop view v4, v3, v2, v1; drop table t1; @@ -1761,6 +1777,20 @@ SELECT * FROM v1; drop view v1; # +# hide underlying tables names in case of imposibility to update (BUG#10773) +# +create table t1 (f59 int, f60 int, f61 int); +insert into t1 values (19,41,32); +create view v1 as select f59, f60 from t1 where f59 in + (select f59 from t1); +-- error 1288 +update v1 set f60=2345; +-- error 1443 +update t1 set f60=(select max(f60) from v1); +drop view v1; +drop table t1; + +# # Using var_samp with view (BUG#10651) # create table t1 (s1 int); @@ -2004,3 +2034,159 @@ create view v1 as select strcmp(f1,'a') from t1; select * from v1; drop view v1; drop table t1; + +# +# Bug #12922 if(sum(),...) with group from view returns wrong results +# +create table t1 (f1 int, f2 int,f3 int); +insert into t1 values (1,10,20),(2,0,0); +create view v1 as select * from t1; +select if(sum(f1)>1,f2,f3) from v1 group by f1; +drop view v1; +drop table t1; +# BUG#12941 +# +--disable_warnings +create table t1 ( + r_object_id char(16) NOT NULL, + group_name varchar(32) NOT NULL +) engine = InnoDB; + +create table t2 ( + r_object_id char(16) NOT NULL, + i_position int(11) NOT NULL, + users_names varchar(32) default NULL +) Engine = InnoDB; +--enable_warnings + +create view v1 as select r_object_id, group_name from t1; +create view v2 as select r_object_id, i_position, users_names from t2; + +create unique index r_object_id on t1(r_object_id); +create index group_name on t1(group_name); +create unique index r_object_id_i_position on t2(r_object_id,i_position); +create index users_names on t2(users_names); + +insert into t1 values('120001a080000542','tstgroup1'); +insert into t2 values('120001a080000542',-1, 'guser01'); +insert into t2 values('120001a080000542',-2, 'guser02'); + +select v1.r_object_id, v2.users_names from v1, v2 +where (v1.group_name='tstgroup1') and v2.r_object_id=v1.r_object_id +order by users_names; + +drop view v1, v2; +drop table t1, t2; + +# +# DEFINER information check +# +-- error ER_NO_VIEW_USER +create definer=some_user@__% sql security invoker view v1 as select 1; +create definer=some_user@localhost sql security invoker view v1 as select 1; +show create view v1; +drop view v1; + +# +# Bug #6808 - Views: CREATE VIEW v ... FROM t AS v fails +# + +create table t1 (s1 int); +create view abc as select * from t1 as abc; +drop table t1; +drop view abc; + +# +# Bug #12993 View column rename broken in subselect +# +create table t1(f1 char(1)); +create view v1 as select * from t1; +select * from (select f1 as f2 from v1) v where v.f2='a'; +drop view v1; +drop table t1; + +# +# Bug #11416 Server crash if using a view that uses function convert_tz +# +create view v1 as SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET'); +select * from v1; +drop view v1; + +# +# Bugs #12963, #13000: wrong creation of VIEW with DAYNAME, DAYOFWEEK, and WEEKDAY +# + +CREATE TABLE t1 (date DATE NOT NULL); +INSERT INTO t1 VALUES ('2005-09-06'); + +CREATE VIEW v1 AS SELECT DAYNAME(date) FROM t1; +SHOW CREATE VIEW v1; + +CREATE VIEW v2 AS SELECT DAYOFWEEK(date) FROM t1; +SHOW CREATE VIEW v2; + +CREATE VIEW v3 AS SELECT WEEKDAY(date) FROM t1; +SHOW CREATE VIEW v3; + +SELECT DAYNAME('2005-09-06'); +SELECT DAYNAME(date) FROM t1; +SELECT * FROM v1; + +SELECT DAYOFWEEK('2005-09-06'); +SELECT DAYOFWEEK(date) FROM t1; +SELECT * FROM v2; + +SELECT WEEKDAY('2005-09-06'); +SELECT WEEKDAY(date) FROM t1; +SELECT * FROM v3; + +DROP TABLE t1; +DROP VIEW v1, v2, v3; + +# +# Bug #13411: crash when using non-qualified view column in HAVING clause +# + +CREATE TABLE t1 ( a int, b int ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +CREATE VIEW v1 AS SELECT a,b FROM t1; +SELECT t1.a FROM t1 GROUP BY t1.a HAVING a > 1; +SELECT v1.a FROM v1 GROUP BY v1.a HAVING a > 1; + +DROP VIEW v1; +DROP TABLE t1; + +# +# Bug #13410: failed name resolution for qualified view column in HAVING +# + +CREATE TABLE t1 ( a int, b int ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +CREATE VIEW v1 AS SELECT a,b FROM t1; +SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > 1; +SELECT v1.a FROM v1 GROUP BY v1.a HAVING v1.a > 1; +SELECT t_1.a FROM t1 AS t_1 GROUP BY t_1.a HAVING t_1.a IN (1,2,3); +SELECT v_1.a FROM v1 AS v_1 GROUP BY v_1.a HAVING v_1.a IN (1,2,3); + +DROP VIEW v1; +DROP TABLE t1; + +# +# Bug #13327 view wasn't using index for const condition +# + +CREATE TABLE t1 (a INT, b INT, INDEX(a,b)); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 (a INT); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +INSERT INTO t2 VALUES (1,1),(2,2),(3,3); +INSERT INTO t3 VALUES (1),(2),(3); +CREATE VIEW v1 AS SELECT t1.* FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b; +CREATE VIEW v2 AS SELECT t3.* FROM t1,t3 WHERE t1.a=t3.a; +EXPLAIN SELECT t1.* FROM t1 JOIN t2 WHERE t1.a=t2.a AND t1.b=t2.b AND t1.a=1; +EXPLAIN SELECT * FROM v1 WHERE a=1; +EXPLAIN SELECT * FROM v2 WHERE a=1; +DROP VIEW v1,v2; +DROP TABLE t1,t2,t3; + + diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index 6283a1abf11..ea93345e894 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -24,6 +24,8 @@ grant create view,select on test.* to mysqltest_1@localhost; connect (user1,localhost,mysqltest_1,,test); connection user1; +-- error ER_VIEW_OTHER_USER +create definer=root@localhost view v1 as select * from mysqltest.t1; create view v1 as select * from mysqltest.t1; # try to modify view without DROP privilege on it -- error 1142 @@ -38,6 +40,9 @@ create view mysqltest.v2 as select * from mysqltest.t1; create view v2 as select * from mysqltest.t2; connection root; +# check view definer information +show create view v1; + grant create view,drop,select on test.* to mysqltest_1@localhost; connection user1; diff --git a/mysql-test/t/view_query_cache.test b/mysql-test/t/view_query_cache.test index bca111a5ed1..81994407641 100644 --- a/mysql-test/t/view_query_cache.test +++ b/mysql-test/t/view_query_cache.test @@ -84,4 +84,16 @@ select * from v3; drop view v3; drop table t1, t2; +# +# Bug #13424 locking view with query cache enabled crashes server +# +create table t1(f1 int); +insert into t1 values(1),(2),(3); +create view v1 as select * from t1; +set query_cache_wlock_invalidate=1; +lock tables v1 read /*!32311 local */; +unlock tables; +set query_cache_wlock_invalidate=default; +drop view v1; +drop table t1; set GLOBAL query_cache_size=default; diff --git a/mysql-test/t/wait_timeout-master.opt b/mysql-test/t/wait_timeout-master.opt new file mode 100644 index 00000000000..0ad622e9677 --- /dev/null +++ b/mysql-test/t/wait_timeout-master.opt @@ -0,0 +1 @@ +--wait-timeout=2 diff --git a/mysql-test/t/wait_timeout.test b/mysql-test/t/wait_timeout.test new file mode 100644 index 00000000000..26f91569868 --- /dev/null +++ b/mysql-test/t/wait_timeout.test @@ -0,0 +1,11 @@ +# +# Bug #8731: wait_timeout does not work on Mac OS X +# +--disable_reconnect +select 1; +# wait_timeout is 2, so we should get disconnected now +--sleep 5 +--error 2006 +select 2; +--enable_reconnect +select 3; diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test index 1347fd05415..92405bac137 100644 --- a/mysql-test/t/xa.test +++ b/mysql-test/t/xa.test @@ -26,13 +26,24 @@ select * from t1; xa start 'testa','testb'; insert t1 values (30); + +--error 1399 +commit; + xa end 'testa','testb'; +--error 1399 +begin; +--error 1399 +create table t2 (a int); + connect (con1,localhost,,,); connection con1; --error 1440 xa start 'testa','testb'; +--error 1440 +xa start 'testa','testb', 123; # gtrid [ , bqual [ , formatID ] ] xa start 0x7465737462, 0x2030405060, 0xb; @@ -40,6 +51,9 @@ insert t1 values (40); xa end 'testb',' 0@P`',11; xa prepare 'testb',0x2030405060,11; +--error 1399 +start transaction; + xa recover; # uncomment the line below when binlog will be able to prepare diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 26f3477140b..7737810653d 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -52,6 +52,16 @@ } { + pthread pthread_key_create + Memcheck:Leak + fun:malloc + fun:* + fun:* + fun:pthread_key_create + fun:my_thread_global_init +} + +{ pthread strstr uninit Memcheck:Cond fun:strstr @@ -127,8 +137,18 @@ { libz deflate Memcheck:Cond - obj:/usr/lib/libz.so.* - obj:/usr/lib/libz.so.* + obj:*/libz.so.* + obj:*/libz.so.* fun:deflate fun:compress2 } + +{ + libz deflate2 + Memcheck:Cond + obj:*/libz.so.* + obj:*/libz.so.* + fun:deflate + obj:*/libz.so.* + fun:gzflush +} diff --git a/mysys/charset-def.c b/mysys/charset-def.c index 0464ba893fb..5b30d1ee135 100644 --- a/mysys/charset-def.c +++ b/mysys/charset-def.c @@ -42,6 +42,7 @@ extern CHARSET_INFO my_charset_ucs2_slovak_uca_ci; extern CHARSET_INFO my_charset_ucs2_spanish2_uca_ci; extern CHARSET_INFO my_charset_ucs2_roman_uca_ci; extern CHARSET_INFO my_charset_ucs2_persian_uca_ci; +extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci; #endif #ifdef HAVE_CHARSET_utf8 @@ -62,6 +63,7 @@ extern CHARSET_INFO my_charset_utf8_slovak_uca_ci; extern CHARSET_INFO my_charset_utf8_spanish2_uca_ci; extern CHARSET_INFO my_charset_utf8_roman_uca_ci; extern CHARSET_INFO my_charset_utf8_persian_uca_ci; +extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci; #ifdef HAVE_UTF8_GENERAL_CS extern CHARSET_INFO my_charset_utf8_general_cs; #endif @@ -148,6 +150,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_ucs2_spanish2_uca_ci); add_compiled_collation(&my_charset_ucs2_roman_uca_ci); add_compiled_collation(&my_charset_ucs2_persian_uca_ci); + add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci); #endif #endif @@ -180,6 +183,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8_spanish2_uca_ci); add_compiled_collation(&my_charset_utf8_roman_uca_ci); add_compiled_collation(&my_charset_utf8_persian_uca_ci); + add_compiled_collation(&my_charset_utf8_esperanto_uca_ci); #endif #endif diff --git a/mysys/charset.c b/mysys/charset.c index e61d08cbc33..64b15fab0c2 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -38,6 +38,22 @@ my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2) } +static uint +get_collation_number_internal(const char *name) +{ + CHARSET_INFO **cs; + for (cs= all_charsets; + cs < all_charsets+array_elements(all_charsets)-1 ; + cs++) + { + if ( cs[0] && cs[0]->name && + !my_strcasecmp(&my_charset_latin1, cs[0]->name, name)) + return cs[0]->number; + } + return 0; +} + + static my_bool init_state_maps(CHARSET_INFO *cs) { uint i; @@ -189,7 +205,8 @@ static my_bool simple_cs_is_full(CHARSET_INFO *cs) static int add_collation(CHARSET_INFO *cs) { - if (cs->name && (cs->number || (cs->number=get_collation_number(cs->name)))) + if (cs->name && (cs->number || + (cs->number=get_collation_number_internal(cs->name)))) { if (!all_charsets[cs->number]) { @@ -419,18 +436,8 @@ void free_charsets(void) uint get_collation_number(const char *name) { - CHARSET_INFO **cs; init_available_charsets(MYF(0)); - - for (cs= all_charsets; - cs < all_charsets+array_elements(all_charsets)-1 ; - cs++) - { - if ( cs[0] && cs[0]->name && - !my_strcasecmp(&my_charset_latin1, cs[0]->name, name)) - return cs[0]->number; - } - return 0; /* this mimics find_type() */ + return get_collation_number_internal(name); } diff --git a/mysys/default.c b/mysys/default.c index bde7cbf2563..edd02402a2a 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -42,6 +42,7 @@ #include <winbase.h> #endif +const char *defaults_file=0; const char *defaults_group_suffix=0; char *defaults_extra_file=0; @@ -136,7 +137,13 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv, if (! defaults_group_suffix) defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV)); + + if (forced_extra_defaults) + defaults_extra_file= (char *) forced_extra_defaults; + if (forced_default_file) + defaults_file= forced_default_file; + /* We can only handle 'defaults-group-suffix' if we are called from load_defaults() as otherwise we can't know the type of 'func_ctx' diff --git a/mysys/mf_format.c b/mysys/mf_format.c index 0fec9d27b1d..50f354df1cd 100644 --- a/mysys/mf_format.c +++ b/mysys/mf_format.c @@ -17,13 +17,12 @@ #include "mysys_priv.h" #include <m_string.h> - /* - Formats a filename with possible replace of directory of extension - Function can handle the case where 'to' == 'name' - For a description of the flag values, consult my_sys.h - The arguments should be in unix format. - */ - +/* + Formats a filename with possible replace of directory of extension + Function can handle the case where 'to' == 'name' + For a description of the flag values, consult my_sys.h + The arguments should be in unix format. +*/ my_string fn_format(my_string to, const char *name, const char *dir, const char *extension, uint flag) @@ -54,8 +53,7 @@ my_string fn_format(my_string to, const char *name, const char *dir, pack_dirname(dev,dev); /* Put in ./.. and ~/.. */ if (flag & MY_UNPACK_FILENAME) (void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */ - if (flag & MY_UNIX_PATH) - to_unix_path(dev); /* Fix to MySQL representation */ + if ((pos= (char*) strchr(name,FN_EXTCHAR)) != NullS) { if ((flag & MY_REPLACE_EXT) == 0) /* If we should keep old ext */ diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index b000af19aa0..63f5dc964da 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -165,7 +165,7 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize, (ulong) info, (int) type, (ulong) seek_offset)); info->file= file; - info->type= 0; /* Don't set it until mutex are created */ + info->type= TYPE_NOT_SET; /* Don't set it until mutex are created */ info->pos_in_file= seek_offset; info->pre_close = info->pre_read = info->post_read = 0; info->arg = 0; @@ -1246,7 +1246,7 @@ int end_io_cache(IO_CACHE *info) if (info->type == SEQ_READ_APPEND) { /* Destroy allocated mutex */ - info->type=0; + info->type= TYPE_NOT_SET; #ifdef THREAD pthread_mutex_destroy(&info->append_buffer_lock); #endif diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index cb2e0c98e8a..3b5e277b56d 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -161,10 +161,12 @@ KEY_CACHE *dflt_key_cache= &dflt_key_cache_var; #define FLUSH_CACHE 2000 /* sort this many blocks at once */ static int flush_all_key_blocks(KEY_CACHE *keycache); +#ifdef THREAD static void link_into_queue(KEYCACHE_WQUEUE *wqueue, struct st_my_thread_var *thread); static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue, struct st_my_thread_var *thread); +#endif static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block); static void test_key_cache(KEY_CACHE *keycache, const char *where, my_bool lock); @@ -215,6 +217,7 @@ static void keycache_debug_print _VARARGS((const char *fmt,...)); #endif /* defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG) */ #if defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF) +#ifdef THREAD static long keycache_thread_id; #define KEYCACHE_THREAD_TRACE(l) \ KEYCACHE_DBUG_PRINT(l,("|thread %ld",keycache_thread_id)) @@ -226,6 +229,11 @@ static long keycache_thread_id; #define KEYCACHE_THREAD_TRACE_END(l) \ KEYCACHE_DBUG_PRINT(l,("]thread %ld",keycache_thread_id)) +#else /* THREAD */ +#define KEYCACHE_THREAD_TRACE(l) KEYCACHE_DBUG_PRINT(l,("")) +#define KEYCACHE_THREAD_TRACE_BEGIN(l) KEYCACHE_DBUG_PRINT(l,("")) +#define KEYCACHE_THREAD_TRACE_END(l) KEYCACHE_DBUG_PRINT(l,("")) +#endif /* THREAD */ #else #define KEYCACHE_THREAD_TRACE_BEGIN(l) #define KEYCACHE_THREAD_TRACE_END(l) @@ -492,6 +500,7 @@ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, keycache_pthread_mutex_lock(&keycache->cache_lock); +#ifdef THREAD wqueue= &keycache->resize_queue; thread= my_thread_var; link_into_queue(wqueue, thread); @@ -500,6 +509,7 @@ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, { keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock); } +#endif keycache->resize_in_flush= 1; if (flush_all_key_blocks(keycache)) @@ -512,12 +522,16 @@ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, } keycache->resize_in_flush= 0; keycache->can_be_used= 0; +#ifdef THREAD while (keycache->cnt_for_resize_op) { KEYCACHE_DBUG_PRINT("resize_key_cache: wait", ("suspend thread %ld", thread->id)); keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock); } +#else + KEYCACHE_DBUG_ASSERT(keycache->cnt_for_resize_op == 0); +#endif end_key_cache(keycache, 0); /* Don't free mutex */ /* The following will work even if use_mem is 0 */ @@ -525,6 +539,7 @@ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, division_limit, age_threshold); finish: +#ifdef THREAD unlink_from_queue(wqueue, thread); /* Signal for the next resize request to proceeed if any */ if (wqueue->last_thread) @@ -533,6 +548,7 @@ finish: ("thread %ld", wqueue->last_thread->next->id)); keycache_pthread_cond_signal(&wqueue->last_thread->next->suspend); } +#endif keycache_pthread_mutex_unlock(&keycache->cache_lock); return blocks; } @@ -553,6 +569,7 @@ static inline void inc_counter_for_resize_op(KEY_CACHE *keycache) */ static inline void dec_counter_for_resize_op(KEY_CACHE *keycache) { +#ifdef THREAD struct st_my_thread_var *last_thread; if (!--keycache->cnt_for_resize_op && (last_thread= keycache->resize_queue.last_thread)) @@ -561,6 +578,9 @@ static inline void dec_counter_for_resize_op(KEY_CACHE *keycache) ("thread %ld", last_thread->next->id)); keycache_pthread_cond_signal(&last_thread->next->suspend); } +#else + keycache->cnt_for_resize_op--; +#endif } /* @@ -632,12 +652,13 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) keycache->blocks_changed= 0; } - DBUG_PRINT("status", - ("used: %d changed: %d w_requests: %ld \ -writes: %ld r_requests: %ld reads: %ld", - keycache->blocks_used, keycache->global_blocks_changed, - keycache->global_cache_w_requests, keycache->global_cache_write, - keycache->global_cache_r_requests, keycache->global_cache_read)); + DBUG_PRINT("status", ("used: %d changed: %d w_requests: %lu " + "writes: %lu r_requests: %lu reads: %lu", + keycache->blocks_used, keycache->global_blocks_changed, + (ulong) keycache->global_cache_w_requests, + (ulong) keycache->global_cache_write, + (ulong) keycache->global_cache_r_requests, + (ulong) keycache->global_cache_read)); if (cleanup) { @@ -649,6 +670,7 @@ writes: %ld r_requests: %ld reads: %ld", } /* end_key_cache */ +#ifdef THREAD /* Link a thread into double-linked queue of waiting threads. @@ -785,6 +807,7 @@ static void release_queue(KEYCACHE_WQUEUE *wqueue) while (thread != last); wqueue->last_thread= NULL; } +#endif /* @@ -892,6 +915,7 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot, BLOCK_LINK **pins; KEYCACHE_DBUG_ASSERT(! (block->hash_link && block->hash_link->requests)); +#ifdef THREAD if (!hot && keycache->waiting_for_block.last_thread) { /* Signal that in the LRU warm sub-chain an available block has appeared */ @@ -928,6 +952,10 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot, #endif return; } +#else /* THREAD */ + KEYCACHE_DBUG_ASSERT(! (!hot && keycache->waiting_for_block.last_thread)); + /* Condition not transformed using DeMorgan, to keep the text identical */ +#endif /* THREAD */ pins= hot ? &keycache->used_ins : &keycache->used_last; ins= *pins; if (ins) @@ -1100,6 +1128,7 @@ static inline void remove_reader(BLOCK_LINK *block) static inline void wait_for_readers(KEY_CACHE *keycache, BLOCK_LINK *block) { +#ifdef THREAD struct st_my_thread_var *thread= my_thread_var; while (block->hash_link->requests) { @@ -1110,6 +1139,9 @@ static inline void wait_for_readers(KEY_CACHE *keycache, BLOCK_LINK *block) keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock); block->condvar= NULL; } +#else + KEYCACHE_DBUG_ASSERT(block->hash_link->requests == 0); +#endif } @@ -1139,6 +1171,7 @@ static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link) if ((*hash_link->prev= hash_link->next)) hash_link->next->prev= hash_link->prev; hash_link->block= NULL; +#ifdef THREAD if (keycache->waiting_for_hash_link.last_thread) { /* Signal that a free hash link has appeared */ @@ -1174,6 +1207,9 @@ static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link) hash_link); return; } +#else /* THREAD */ + KEYCACHE_DBUG_ASSERT(! (keycache->waiting_for_hash_link.last_thread)); +#endif /* THREAD */ hash_link->next= keycache->free_hash_list; keycache->free_hash_list= hash_link; } @@ -1239,6 +1275,7 @@ restart: } else { +#ifdef THREAD /* Wait for a free hash link */ struct st_my_thread_var *thread= my_thread_var; KEYCACHE_DBUG_PRINT("get_hash_link", ("waiting")); @@ -1251,6 +1288,9 @@ restart: keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock); thread->opt_info= NULL; +#else + KEYCACHE_DBUG_ASSERT(0); +#endif goto restart; } hash_link->file= file; @@ -1362,6 +1402,7 @@ restart: /* Wait intil the page is flushed on disk */ hash_link->requests--; { +#ifdef THREAD struct st_my_thread_var *thread= my_thread_var; add_to_queue(&block->wqueue[COND_FOR_SAVED], thread); do @@ -1372,6 +1413,16 @@ restart: &keycache->cache_lock); } while(thread->next); +#else + KEYCACHE_DBUG_ASSERT(0); + /* + Given the use of "resize_in_flush", it seems impossible + that this whole branch is ever entered in single-threaded case + because "(wrmode && keycache->resize_in_flush)" cannot be true. + TODO: Check this, and then put the whole branch into the + "#ifdef THREAD" guard. + */ +#endif } /* Invalidate page in the block if it has not been done yet */ if (block->status) @@ -1400,6 +1451,7 @@ restart: KEYCACHE_DBUG_PRINT("find_key_block", ("request waiting for old page to be saved")); { +#ifdef THREAD struct st_my_thread_var *thread= my_thread_var; /* Put the request into the queue of those waiting for the old page */ add_to_queue(&block->wqueue[COND_FOR_SAVED], thread); @@ -1412,6 +1464,10 @@ restart: &keycache->cache_lock); } while(thread->next); +#else + KEYCACHE_DBUG_ASSERT(0); + /* No parallel requests in single-threaded case */ +#endif } KEYCACHE_DBUG_PRINT("find_key_block", ("request for old page resubmitted")); @@ -1470,6 +1526,7 @@ restart: all of them must get the same block */ +#ifdef THREAD if (! keycache->used_last) { struct st_my_thread_var *thread= my_thread_var; @@ -1485,6 +1542,9 @@ restart: while (thread->next); thread->opt_info= NULL; } +#else + KEYCACHE_DBUG_ASSERT(keycache->used_last); +#endif block= hash_link->block; if (! block) { @@ -1673,6 +1733,7 @@ static void read_block(KEY_CACHE *keycache, KEYCACHE_DBUG_PRINT("read_block", ("secondary request waiting for new page to be read")); { +#ifdef THREAD struct st_my_thread_var *thread= my_thread_var; /* Put the request into a queue and wait until it can be processed */ add_to_queue(&block->wqueue[COND_FOR_REQUESTED], thread); @@ -1684,6 +1745,10 @@ static void read_block(KEY_CACHE *keycache, &keycache->cache_lock); } while (thread->next); +#else + KEYCACHE_DBUG_ASSERT(0); + /* No parallel requests in single-threaded case */ +#endif } KEYCACHE_DBUG_PRINT("read_block", ("secondary request: new page in cache")); @@ -1821,7 +1886,7 @@ byte *key_cache_read(KEY_CACHE *keycache, #ifndef THREAD /* This is only true if we where able to read everything in one block */ if (return_buffer) - return (block->buffer); + DBUG_RETURN(block->buffer); #endif buff+= read_length; filepos+= read_length+offset; @@ -2397,6 +2462,7 @@ restart: #endif block= first_in_switch; { +#ifdef THREAD struct st_my_thread_var *thread= my_thread_var; add_to_queue(&block->wqueue[COND_FOR_SAVED], thread); do @@ -2407,6 +2473,10 @@ restart: &keycache->cache_lock); } while (thread->next); +#else + KEYCACHE_DBUG_ASSERT(0); + /* No parallel requests in single-threaded case */ +#endif } #if defined(KEYCACHE_DEBUG) cnt++; @@ -2573,7 +2643,6 @@ static void test_key_cache(KEY_CACHE *keycache __attribute__((unused)), static void keycache_dump(KEY_CACHE *keycache) { FILE *keycache_dump_file=fopen(KEYCACHE_DUMP_FILE, "w"); - struct st_my_thread_var *thread_var= my_thread_var; struct st_my_thread_var *last; struct st_my_thread_var *thread; BLOCK_LINK *block; @@ -2681,9 +2750,12 @@ static int keycache_pthread_cond_wait(pthread_cond_t *cond, gettimeofday(&now, &tz); /* Prepare timeout value */ timeout.tv_sec= now.tv_sec + KEYCACHE_TIMEOUT; - timeout.tv_nsec= now.tv_usec * 1000; /* timeval uses microseconds. */ - /* timespec uses nanoseconds. */ - /* 1 nanosecond = 1000 micro seconds. */ + /* + timeval uses microseconds. + timespec uses nanoseconds. + 1 nanosecond = 1000 micro seconds + */ + timeout.tv_nsec= now.tv_usec * 1000; KEYCACHE_THREAD_TRACE_END("started waiting"); #if defined(KEYCACHE_DEBUG) cnt++; @@ -2693,17 +2765,15 @@ static int keycache_pthread_cond_wait(pthread_cond_t *cond, #endif rc= pthread_cond_timedwait(cond, mutex, &timeout); KEYCACHE_THREAD_TRACE_BEGIN("finished waiting"); -#if defined(KEYCACHE_DEBUG) - if (rc == ETIMEDOUT) + if (rc == ETIMEDOUT || rc == ETIME) { +#if defined(KEYCACHE_DEBUG) fprintf(keycache_debug_log,"aborted by keycache timeout\n"); fclose(keycache_debug_log); abort(); - } #endif - - if (rc == ETIMEDOUT) keycache_dump(); + } #if defined(KEYCACHE_DEBUG) KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT); diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 5a78eb17c96..d5346d530c3 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -221,11 +221,58 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) #endif } -#ifdef SAFEMALLOC -#define TRASH(X) bfill(((char*)(X) + ((X)->size-(X)->left)), (X)->left, 0xa5) -#else -#define TRASH /* no-op */ -#endif + +/* + Allocate many pointers at the same time. + + DESCRIPTION + ptr1, ptr2, etc all point into big allocated memory area. + + SYNOPSIS + multi_alloc_root() + root Memory root + ptr1, length1 Multiple arguments terminated by a NULL pointer + ptr2, length2 ... + ... + NULL + + RETURN VALUE + A pointer to the beginning of the allocated memory block + in case of success or NULL if out of memory. +*/ + +gptr multi_alloc_root(MEM_ROOT *root, ...) +{ + va_list args; + char **ptr, *start, *res; + uint tot_length, length; + DBUG_ENTER("multi_alloc_root"); + + va_start(args, root); + tot_length= 0; + while ((ptr= va_arg(args, char **))) + { + length= va_arg(args, uint); + tot_length+= ALIGN_SIZE(length); + } + va_end(args); + + if (!(start= (char*) alloc_root(root, tot_length))) + DBUG_RETURN(0); /* purecov: inspected */ + + va_start(args, root); + res= start; + while ((ptr= va_arg(args, char **))) + { + *ptr= res; + length= va_arg(args, uint); + res+= ALIGN_SIZE(length); + } + va_end(args); + DBUG_RETURN((gptr) start); +} + +#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left) /* Mark all data in blocks free for reusage */ @@ -239,7 +286,7 @@ static inline void mark_blocks_free(MEM_ROOT* root) for (next= root->free; next; next= *(last= &next->next)) { next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM)); - TRASH(next); + TRASH_MEM(next); } /* Combine the free and the used list */ @@ -249,7 +296,7 @@ static inline void mark_blocks_free(MEM_ROOT* root) for (; next; next= next->next) { next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM)); - TRASH(next); + TRASH_MEM(next); } /* Now everything is set; Indicate that nothing is used anymore */ @@ -310,7 +357,7 @@ void free_root(MEM_ROOT *root, myf MyFlags) { root->free=root->pre_alloc; root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM)); - TRASH(root->pre_alloc); + TRASH_MEM(root->pre_alloc); root->free->next=0; } root->block_num= 4; diff --git a/mysys/my_conio.c b/mysys/my_conio.c new file mode 100644 index 00000000000..e381f9f23ef --- /dev/null +++ b/mysys/my_conio.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include "mysys_priv.h" + +#ifdef __WIN__ + +static HANDLE my_coninpfh= 0; /* console input */ + +/* + functions my_pthread_auto_mutex_lock & my_pthread_auto_mutex_free + are experimental at this moment, they are intended to bring + ability of protecting code sections without necessity to explicitly + initialize synchronization object in one of threads + + if found useful they are to be exported in mysys +*/ + +/* + int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, + int id, int time) + + NOTES + creates a mutex with given name and tries to lock it time msec. + mutex name is appended with id to allow system wide or process wide + locks. Handle to created mutex returned in ph argument. + + RETURN + 0 thread owns mutex + <>0 error + +*/ +static +int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time) +{ + int res; + char tname[FN_REFLEN]; + + sprintf(tname, "%s-%08X", name, id); + + *ph= CreateMutex(NULL, FALSE, tname); + if (*ph == NULL) + return GetLastError(); + + res= WaitForSingleObject(*ph, time); + + if (res == WAIT_TIMEOUT) + return ERROR_SEM_TIMEOUT; + + if (res == WAIT_FAILED) + return GetLastError(); + + return 0; +} + +/* + int my_pthread_auto_mutex_free(HANDLE* ph) + + + NOTES + releases a mutex. + + RETURN + 0 thread released mutex + <>0 error + +*/ +static +int my_pthread_auto_mutex_free(HANDLE* ph) +{ + if (*ph) + { + ReleaseMutex(*ph); + CloseHandle(*ph); + *ph= NULL; + } + + return 0; +} + + +#define pthread_auto_mutex_decl(name) \ + HANDLE __h##name= NULL; + +#define pthread_auto_mutex_lock(name, proc, time) \ + my_pthread_auto_mutex_lock(&__h##name, #name, (proc), (time)) + +#define pthread_auto_mutex_free(name) \ + my_pthread_auto_mutex_free(&__h##name) + + +/* + char* my_cgets(char *string, unsigned long clen, unsigned long* plen) + + NOTES + Replaces _cgets from libc to support input of more than 255 chars. + Reads from the console via ReadConsole into buffer which + should be at least clen characters. + Actual length of string returned in plen. + + WARNING + my_cgets() does NOT check the pushback character buffer (i.e., _chbuf). + Thus, my_cgets() will not return any character that is pushed back by + the _ungetch() call. + + RETURN + string pointer ok + NULL Error + +*/ +char* my_cgets(char *buffer, unsigned long clen, unsigned long* plen) +{ + ULONG state; + char *result; + CONSOLE_SCREEN_BUFFER_INFO csbi; + + pthread_auto_mutex_decl(my_conio_cs); + + /* lock the console for the current process*/ + if (pthread_auto_mutex_lock(my_conio_cs, GetCurrentProcessId(), INFINITE)) + { + /* can not lock console */ + pthread_auto_mutex_free(my_conio_cs); + return NULL; + } + + /* init console input */ + if (my_coninpfh == 0) + { + /* same handle will be used until process termination */ + my_coninpfh= CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + } + + if (my_coninpfh == INVALID_HANDLE_VALUE) + { + /* unlock the console */ + pthread_auto_mutex_free(my_conio_cs); + return(NULL); + } + + GetConsoleMode((HANDLE)my_coninpfh, &state); + SetConsoleMode((HANDLE)my_coninpfh, ENABLE_LINE_INPUT | + ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT); + + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + + /* + there is no known way to determine allowed buffer size for input + though it is known it should not be more than 64K + so we cut 64K and try first size of screen buffer + if it is still to large we cut half of it and try again + later we may want to cycle from min(clen, 65535) to allowed size + with small decrement to determine exact allowed buffer + */ + clen= min(clen, 65535); + do + { + clen= min(clen, (unsigned long)csbi.dwSize.X*csbi.dwSize.Y); + if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, clen - 1, plen, NULL)) + { + result= NULL; + clen>>= 1; + } + else + { + result= buffer; + break; + } + } + while (GetLastError() == ERROR_NOT_ENOUGH_MEMORY); + + + if (result != NULL) + { + if (buffer[*plen - 2] == '\r') + { + *plen= *plen - 2; + } + else + { + if (buffer[*plen - 1] == '\r') + { + char tmp[3]; + int tmplen= sizeof(tmp); + + *plen= *plen - 1; + /* read /n left in the buffer */ + ReadConsole((HANDLE)my_coninpfh, (LPVOID)tmp, tmplen, &tmplen, NULL); + } + } + buffer[*plen]= '\0'; + } + + SetConsoleMode((HANDLE)my_coninpfh, state); + /* unlock the console */ + pthread_auto_mutex_free(my_conio_cs); + + return result; +} + +#endif /* __WIN__ */ diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 68bf65b2abe..31ef21632b9 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -342,11 +342,24 @@ int handle_options(int *argc, char ***argv, --enable-'option-name'. *optend was set to '0' if one used --disable-option */ - my_bool tmp= (my_bool) (!optend || *optend == '1'); - *((my_bool*) value)= tmp; (*argc)--; + if (!optend || *optend == '1' || + !my_strcasecmp(&my_charset_latin1, optend, "true")) + *((my_bool*) value)= (my_bool) 1; + else if (*optend == '0' || + !my_strcasecmp(&my_charset_latin1, optend, "false")) + *((my_bool*) value)= (my_bool) 0; + else + { + my_getopt_error_reporter(WARNING_LEVEL, + "%s: ignoring option '--%s' due to \ +invalid value '%s'\n", + my_progname, optp->name, optend); + continue; + } get_one_option(optp->id, optp, - tmp ? (char*) "1" : disabled_my_option); + *((my_bool*) value) ? + (char*) "1" : disabled_my_option); continue; } argument= optend; @@ -587,16 +600,27 @@ static int setval(const struct my_option *opts, gptr *value, char *argument, return 0; } -/* - function: findopt - Arguments: opt_pattern, length of opt_pattern, opt_struct, first found - name (ffname) +/* + Find option - Go through all options in the my_option struct. Return number - of options found that match the pattern and in the argument - list the option found, if any. In case of ambiguous option, store - the name in ffname argument + SYNOPSIS + findopt() + optpat Prefix of option to find (with - or _) + length Length of optpat + opt_res Options + ffname Place for pointer to first found name + + IMPLEMENTATION + Go through all options in the my_option struct. Return number + of options found that match the pattern and in the argument + list the option found, if any. In case of ambiguous option, store + the name in ffname argument + + RETURN + 0 No matching options + # Number of matching options + ffname points to first matching option */ static int findopt(char *optpat, uint length, @@ -611,12 +635,21 @@ static int findopt(char *optpat, uint length, if (!getopt_compare_strings(opt->name, optpat, length)) /* match found */ { (*opt_res)= opt; - if (!count) - *ffname= (char *) opt->name; /* We only need to know one prev */ if (!opt->name[length]) /* Exact match */ return 1; - if (!count || strcmp(*ffname, opt->name)) /* Don't count synonyms */ + if (!count) + { + count= 1; + *ffname= (char *) opt->name; /* We only need to know one prev */ + } + else if (strcmp(*ffname, opt->name)) + { + /* + The above test is to not count same option twice + (see mysql.cc, option "help") + */ count++; + } } } return count; diff --git a/mysys/my_init.c b/mysys/my_init.c index abb1ad27f7b..f28f47e090e 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -127,11 +127,23 @@ my_bool my_init(void) void my_end(int infoflag) { - FILE *info_file; - if (!(info_file=DBUG_FILE)) - info_file=stderr; - DBUG_PRINT("info",("Shutting down")); - if (infoflag & MY_CHECK_ERROR || info_file != stderr) + /* + this code is suboptimal to workaround a bug in + Sun CC: Sun C++ 5.6 2004/06/02 for x86, and should not be + optimized until this compiler is not in use anymore + */ + FILE *info_file= DBUG_FILE; + my_bool print_info= (info_file != stderr); + DBUG_ENTER("my_end"); + if (!info_file) + { + info_file= stderr; + print_info= 0; + } + + DBUG_PRINT("info",("Shutting down: print_info: %d", print_info)); + if ((infoflag & MY_CHECK_ERROR) || print_info) + { /* Test if some file is left open */ if (my_file_opened | my_stream_opened) { @@ -141,7 +153,8 @@ void my_end(int infoflag) } } my_once_free(); - if (infoflag & MY_GIVE_INFO || info_file != stderr) + + if ((infoflag & MY_GIVE_INFO) || print_info) { #ifdef HAVE_GETRUSAGE struct rusage rus; diff --git a/mysys/my_lib.c b/mysys/my_lib.c index c3b0b57e549..1908c70f407 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -427,6 +427,18 @@ MY_DIR *my_dir(const char *path, myf MyFlags) do { #ifdef __BORLANDC__ + attrib= find.ff_attrib; +#else + attrib= find.attrib; + /* + Do not show hidden and system files which Windows sometimes create. + Note. Because Borland's findfirst() is called with the third + argument = 0 hidden/system files are excluded from the search. + */ + if (attrib & (_A_HIDDEN | _A_SYSTEM)) + continue; +#endif +#ifdef __BORLANDC__ if (!(finfo.name= strdup_root(names_storage, find.ff_name))) goto error; #else @@ -442,11 +454,10 @@ MY_DIR *my_dir(const char *path, myf MyFlags) bzero(finfo.mystat, sizeof(MY_STAT)); #ifdef __BORLANDC__ finfo.mystat->st_size=find.ff_fsize; - mode=MY_S_IREAD; attrib=find.ff_attrib; #else finfo.mystat->st_size=find.size; - mode=MY_S_IREAD; attrib=find.attrib; #endif + mode=MY_S_IREAD; if (!(attrib & _A_RDONLY)) mode|=MY_S_IWRITE; if (attrib & _A_SUBDIR) diff --git a/mysys/my_os2cond.c b/mysys/my_os2cond.c index 83a03d62046..bf3e85c26a9 100644 --- a/mysys/my_os2cond.c +++ b/mysys/my_os2cond.c @@ -22,7 +22,7 @@ ** The following is a simple implementation of posix conditions *****************************************************************************/ -#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */ +#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */ #include "mysys_priv.h" #if defined(THREAD) && defined(OS2) #include <m_string.h> @@ -31,134 +31,109 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) { - APIRET rc = 0; - HEV event; - cond->waiting=0; - /* Warp3 FP29 or Warp4 FP4 or better required */ - rc = DosCreateEventSem( NULL, &cond->semaphore, 0x0800, 0); - if (rc) - return ENOMEM; - + cond->waiting= 0; + /* Warp3 FP29 or Warp4 FP4 or better required */ + if (DosCreateEventSem(NULL, &cond->semaphore, 0x0800, 0)) + return ENOMEM; return 0; } int pthread_cond_destroy(pthread_cond_t *cond) { - APIRET rc; - - do { - rc = DosCloseEventSem(cond->semaphore); - if (rc == 301) DosPostEventSem(cond->semaphore); - } while (rc == 301); - if (rc) - return EINVAL; - - return 0; + for (;;) + { + APIRET rc; + if ((rc= DosCloseEventSem(cond->semaphore)) != 301) + return rc ? EINVAL : 0; + DosPostEventSem(cond->semaphore); + } } int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { - APIRET rc; - int rval; - - rval = 0; - cond->waiting++; - - if (mutex) pthread_mutex_unlock(mutex); - - rc = DosWaitEventSem(cond->semaphore,SEM_INDEFINITE_WAIT); - if (rc != 0) - rval = EINVAL; - - if (mutex) pthread_mutex_lock(mutex); - - cond->waiting--; - - return rval; + int rval= 0; + cond->waiting++; + if (mutex) + pthread_mutex_unlock(mutex); + if (DosWaitEventSem(cond->semaphore, SEM_INDEFINITE_WAIT)) + rval= EINVAL; + if (mutex) + pthread_mutex_lock(mutex); + cond->waiting--; + return rval; } int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - struct timespec *abstime) + struct timespec *abstime) { struct timeb curtime; int result; long timeout; - APIRET rc; - int rval; - - _ftime(&curtime); - timeout= ((long) (abstime->ts_sec - curtime.time)*1000L + - (long)((abstime->ts_nsec/1000) - curtime.millitm)/1000L); - if (timeout < 0) /* Some safety */ - timeout = 0L; + int rval= 0; - rval = 0; - cond->waiting++; + _ftime(&curtime); + timeout= ((long) (abstime->ts_sec - curtime.time) * 1000L + + (long) ((abstime->ts_nsec / 1000) - curtime.millitm) / 1000L); + if (timeout < 0) /* Some safety */ + timeout= 0L; - if (mutex) pthread_mutex_unlock(mutex); + cond->waiting++; - rc = DosWaitEventSem(cond->semaphore, timeout); - if (rc != 0) - rval= ETIMEDOUT; + if (mutex) + pthread_mutex_unlock(mutex); + if (DosWaitEventSem(cond->semaphore, timeout) != 0) + rval= ETIMEDOUT; + if (mutex) + pthread_mutex_lock(mutex); - if (mutex) pthread_mutex_lock(mutex); + cond->waiting--; - cond->waiting--; - - return rval; + return rval; } int pthread_cond_signal(pthread_cond_t *cond) { - APIRET rc; - - /* Bring the next thread off the condition queue: */ - rc = DosPostEventSem(cond->semaphore); - return 0; + /* Bring the next thread off the condition queue: */ + DosPostEventSem(cond->semaphore); + return 0; } int pthread_cond_broadcast(pthread_cond_t *cond) { - int i; - APIRET rc; - - /* - * Enter a loop to bring all threads off the - * condition queue: - */ - i = cond->waiting; - while (i--) rc = DosPostEventSem(cond->semaphore); - - return 0 ; + int i; + /* Enter a loop to bring all threads off the condition queue */ + for (i= cond->waiting; i--;) + DosPostEventSem(cond->semaphore); + return 0; } int pthread_attr_init(pthread_attr_t *connect_att) { - connect_att->dwStackSize = 0; - connect_att->dwCreatingFlag = 0; - connect_att->priority = 0; + connect_att->dwStackSize= 0; + connect_att->dwCreatingFlag= 0; + connect_att->priority= 0; return 0; } -int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack) +int pthread_attr_setstacksize(pthread_attr_t *connect_att, DWORD stack) { - connect_att->dwStackSize=stack; + connect_att->dwStackSize= stack; return 0; } -int pthread_attr_setprio(pthread_attr_t *connect_att,int priority) +int pthread_attr_setprio(pthread_attr_t *connect_att, int priority) { - connect_att->priority=priority; + connect_att->priority= priority; return 0; } int pthread_attr_destroy(pthread_attr_t *connect_att) { - bzero((gptr) connect_att,sizeof(*connect_att)); + bzero((gptr) connect_att, sizeof(*connect_att)); return 0; } @@ -166,22 +141,22 @@ int pthread_attr_destroy(pthread_attr_t *connect_att) ** Fix localtime_r() to be a bit safer ****************************************************************************/ -struct tm *localtime_r(const time_t *timep,struct tm *tmp) +struct tm *localtime_r(const time_t *timep, struct tm *tmp) { - if (*timep == (time_t) -1) /* This will crash win32 */ + if (*timep == (time_t) - 1) /* This will crash win32 */ { - bzero(tmp,sizeof(*tmp)); + bzero(tmp, sizeof(*tmp)); } else { - struct tm *res=localtime(timep); - if (!res) /* Wrong date */ + struct tm *res= localtime(timep); + if (!res) /* Wrong date */ { - bzero(tmp,sizeof(*tmp)); /* Keep things safe */ + bzero(tmp, sizeof(*tmp)); /* Keep things safe */ return 0; } *tmp= *res; } return tmp; } -#endif /* __WIN__ */ +#endif /* __WIN__ */ diff --git a/mysys/my_os2thread.c b/mysys/my_os2thread.c index 0696f480a91..785ff07954d 100644 --- a/mysys/my_os2thread.c +++ b/mysys/my_os2thread.c @@ -51,7 +51,7 @@ void win_pthread_init(void) ** in the new thread. */ -static pthread_handler_decl(pthread_start,param) +pthread_handler_t pthread_start(void *param) { DBUG_ENTER("pthread_start"); pthread_handler func=((struct pthread_map *) param)->func; diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c index 37517fb8327..315e966bf43 100644 --- a/mysys/my_pthread.c +++ b/mysys/my_pthread.c @@ -404,23 +404,6 @@ int sigwait(sigset_t *setp, int *sigp) #endif /* DONT_USE_SIGSUSPEND */ #endif /* HAVE_SIGWAIT */ -/***************************************************************************** -** Implement pthread_signal for systems that can't use signal() with threads -** Currently this is only used with BSDI 3.0 -*****************************************************************************/ - -#ifdef USE_PTHREAD_SIGNAL - -int pthread_signal(int sig, void (*func)()) -{ - struct sigaction sact; - sact.sa_flags= 0; - sact.sa_handler= func; - sigemptyset(&sact.sa_mask); - sigaction(sig, &sact, (struct sigaction*) 0); - return 0; -} -#endif /**************************************************************************** The following functions fixes that all pthread functions should work diff --git a/mysys/my_realloc.c b/mysys/my_realloc.c index c8edb172890..a385bf1e530 100644 --- a/mysys/my_realloc.c +++ b/mysys/my_realloc.c @@ -52,7 +52,7 @@ gptr my_realloc(gptr oldpoint, uint size, myf my_flags) if ((point = (char*)realloc(oldpoint,size)) == NULL) { if (my_flags & MY_FREE_ON_ERROR) - my_free(oldpoint,MyFLAGS); + my_free(oldpoint, my_flags); if (my_flags & MY_HOLD_ON_ERROR) DBUG_RETURN(oldpoint); my_errno=errno; diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c index eebc07df180..8aaf3b1e31c 100644 --- a/mysys/my_winthread.c +++ b/mysys/my_winthread.c @@ -51,7 +51,7 @@ void win_pthread_init(void) ** in the new thread. */ -static pthread_handler_decl(pthread_start,param) +pthread_handler_t pthread_start(void *param) { pthread_handler func=((struct pthread_map *) param)->func; void *func_param=((struct pthread_map *) param)->param; diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 05d14073953..e5b77de5e38 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -80,17 +80,7 @@ void init_thr_alarm(uint max_alarms) pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST); pthread_cond_init(&COND_alarm,NULL); #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD) -#if defined(HAVE_mit_thread) - sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */ -#else - { - struct sigaction sact; - sact.sa_flags = 0; - bzero((char*) &sact, sizeof(sact)); - sact.sa_handler = thread_alarm; - sigaction(THR_CLIENT_ALARM, &sact, (struct sigaction*) 0); - } -#endif + my_sigset(THR_CLIENT_ALARM,thread_alarm); #endif sigemptyset(&s); sigaddset(&s, THR_SERVER_ALARM); @@ -110,12 +100,12 @@ void init_thr_alarm(uint max_alarms) #elif defined(USE_ONE_SIGNAL_HAND) pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */ #if THR_SERVER_ALARM == THR_CLIENT_ALARM - sigset(THR_CLIENT_ALARM,process_alarm); /* Linuxthreads */ + my_sigset(THR_CLIENT_ALARM,process_alarm); /* Linuxthreads */ pthread_sigmask(SIG_UNBLOCK, &s, NULL); #endif #else + my_sigset(THR_SERVER_ALARM, process_alarm); pthread_sigmask(SIG_UNBLOCK, &s, NULL); - sigset(THR_SERVER_ALARM,process_alarm); #endif DBUG_VOID_RETURN; } @@ -290,7 +280,7 @@ sig_handler process_alarm(int sig __attribute__((unused))) printf("thread_alarm\n"); fflush(stdout); #endif #ifdef DONT_REMEMBER_SIGNAL - sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */ + my_sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */ #endif return; } @@ -310,7 +300,7 @@ sig_handler process_alarm(int sig __attribute__((unused))) process_alarm_part2(sig); #ifndef USE_ALARM_THREAD #if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND) - sigset(THR_SERVER_ALARM,process_alarm); + my_sigset(THR_SERVER_ALARM,process_alarm); #endif pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); @@ -512,7 +502,7 @@ static sig_handler thread_alarm(int sig) printf("thread_alarm\n"); fflush(stdout); #endif #ifdef DONT_REMEMBER_SIGNAL - sigset(sig,thread_alarm); /* int. thread system calls */ + my_sigset(sig,thread_alarm); /* int. thread system calls */ #endif } #endif @@ -916,7 +906,7 @@ static sig_handler print_signal_warning(int sig) printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name()); fflush(stdout); #ifdef DONT_REMEMBER_SIGNAL - sigset(sig,print_signal_warning); /* int. thread system calls */ + my_sigset(sig,print_signal_warning); /* int. thread system calls */ #endif #ifndef OS2 if (sig == SIGALRM) diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 41266d61b0a..f5a8b618949 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -408,9 +408,10 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, set_timespec(wait_timeout, table_lock_wait_timeout); while (!thread_var->abort || in_wait_list) { - int rc= can_deadlock ? pthread_cond_timedwait(cond, &data->lock->mutex, - &wait_timeout) : - pthread_cond_wait(cond, &data->lock->mutex); + int rc= (can_deadlock ? + pthread_cond_timedwait(cond, &data->lock->mutex, + &wait_timeout) : + pthread_cond_wait(cond, &data->lock->mutex)); /* We must break the wait if one of the following occurs: - the connection has been aborted (!thread_var->abort), but @@ -426,7 +427,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, */ if (data->cond == 0) break; - if (rc == ETIMEDOUT) + if (rc == ETIMEDOUT || rc == ETIME) { result= THR_LOCK_WAIT_TIMEOUT; break; diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index 2facb4e18cf..3326068d164 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -239,7 +239,7 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, pthread_mutex_unlock(&mp->global); error=pthread_cond_timedwait(cond,&mp->mutex,abstime); #ifdef EXTRA_DEBUG - if (error && (error != EINTR && error != ETIMEDOUT)) + if (error && (error != EINTR && error != ETIMEDOUT && error != ETIME)) { fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait at %s, line %d\n", error, errno, file, line); } diff --git a/ndb/include/Makefile.am b/ndb/include/Makefile.am index 10f297492e9..240101c2004 100644 --- a/ndb/include/Makefile.am +++ b/ndb/include/Makefile.am @@ -33,7 +33,8 @@ mgmapi/mgmapi.h \ mgmapi/mgmapi_debug.h \ mgmapi/mgmapi_config_parameters.h \ mgmapi/mgmapi_config_parameters_debug.h \ -mgmapi/ndb_logevent.h +mgmapi/ndb_logevent.h \ +mgmapi/ndbd_exit_codes.h noinst_HEADERS = \ ndb_global.h \ diff --git a/ndb/include/kernel/GlobalSignalNumbers.h b/ndb/include/kernel/GlobalSignalNumbers.h index ff3690d60a5..98b6ce7d949 100644 --- a/ndb/include/kernel/GlobalSignalNumbers.h +++ b/ndb/include/kernel/GlobalSignalNumbers.h @@ -553,7 +553,6 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_STATISTICS_CONF 454 #define GSN_START_ORD 455 -/* 456 unused */ /* 457 unused */ #define GSN_EVENT_SUBSCRIBE_REQ 458 @@ -835,14 +834,6 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; /* Start Global Replication */ #define GSN_GREP_REQ 656 -/** - * Management server - */ -#define GSN_MGM_LOCK_CONFIG_REQ 657 -#define GSN_MGM_LOCK_CONFIG_REP 658 -#define GSN_MGM_UNLOCK_CONFIG_REQ 659 -#define GSN_MGM_UNLOCK_CONFIG_REP 660 - #define GSN_UTIL_CREATE_LOCK_REQ 132 #define GSN_UTIL_CREATE_LOCK_REF 133 #define GSN_UTIL_CREATE_LOCK_CONF 188 @@ -900,6 +891,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_RESUME_REQ 682 #define GSN_STOP_REQ 443 #define GSN_STOP_REF 444 +#define GSN_STOP_CONF 456 #define GSN_API_VERSION_REQ 697 #define GSN_API_VERSION_CONF 698 diff --git a/ndb/include/kernel/signaldata/ApiVersion.hpp b/ndb/include/kernel/signaldata/ApiVersion.hpp index 28281e7d186..a3774c9fba6 100644 --- a/ndb/include/kernel/signaldata/ApiVersion.hpp +++ b/ndb/include/kernel/signaldata/ApiVersion.hpp @@ -49,12 +49,11 @@ class ApiVersionConf { */ friend class MgmtSrv; public: - STATIC_CONST( SignalLength = 3 ); + STATIC_CONST( SignalLength = 4 ); Uint32 senderRef; Uint32 nodeId; //api node id Uint32 version; // Version of API node - - + Uint32 inet_addr; }; #endif diff --git a/ndb/include/kernel/signaldata/BackupImpl.hpp b/ndb/include/kernel/signaldata/BackupImpl.hpp index 2032e2347b5..298440ad377 100644 --- a/ndb/include/kernel/signaldata/BackupImpl.hpp +++ b/ndb/include/kernel/signaldata/BackupImpl.hpp @@ -33,7 +33,7 @@ class DefineBackupReq { friend bool printDEFINE_BACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 8 + NdbNodeBitmask::Size); + STATIC_CONST( SignalLength = 9 + NdbNodeBitmask::Size); private: /** @@ -60,6 +60,13 @@ private: * Length of backup data */ Uint32 backupDataLen; + + /** + * Backup flags + */ + /* & 0x3 - waitCompleted + */ + Uint32 flags; }; class DefineBackupRef { diff --git a/ndb/include/kernel/signaldata/BackupSignalData.hpp b/ndb/include/kernel/signaldata/BackupSignalData.hpp index b38dd8d14b2..e1b8c6203a1 100644 --- a/ndb/include/kernel/signaldata/BackupSignalData.hpp +++ b/ndb/include/kernel/signaldata/BackupSignalData.hpp @@ -36,11 +36,14 @@ class BackupReq { friend bool printBACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 2 ); + STATIC_CONST( SignalLength = 3 ); private: Uint32 senderData; Uint32 backupDataLen; + /* & 0x3 - waitCompleted + */ + Uint32 flags; }; class BackupData { diff --git a/ndb/include/kernel/signaldata/DumpStateOrd.hpp b/ndb/include/kernel/signaldata/DumpStateOrd.hpp index 7368a0ec40d..bde690e056d 100644 --- a/ndb/include/kernel/signaldata/DumpStateOrd.hpp +++ b/ndb/include/kernel/signaldata/DumpStateOrd.hpp @@ -98,6 +98,8 @@ public: StartTcTimer = 2509, StopTcTimer = 2510, StartPeriodicTcTimer = 2511, + TcStartDumpIndexOpCount = 2512, + TcDumpIndexOpCount = 2513, CmvmiDumpConnections = 2600, CmvmiDumpLongSignalMemory = 2601, CmvmiSetRestartOnErrorInsert = 2602, diff --git a/ndb/include/kernel/signaldata/EventReport.hpp b/ndb/include/kernel/signaldata/EventReport.hpp index 9822a0539cf..e1cdbcfd753 100644 --- a/ndb/include/kernel/signaldata/EventReport.hpp +++ b/ndb/include/kernel/signaldata/EventReport.hpp @@ -68,6 +68,8 @@ public: 4) Add SentHeartbeat in EventLogger::getText() */ + void setNodeId(Uint32 nodeId); + Uint32 getNodeId() const; void setEventType(Ndb_logevent_type type); Ndb_logevent_type getEventType() const; UintR eventType; // DATA 0 @@ -75,14 +77,26 @@ public: inline void +EventReport::setNodeId(Uint32 nodeId){ + eventType = (nodeId << 16) | (eventType & 0xFFFF); +} + +inline +Uint32 +EventReport::getNodeId() const { + return eventType >> 16; +} + +inline +void EventReport::setEventType(Ndb_logevent_type type){ - eventType = (UintR) type; + eventType = (eventType & 0xFFFF0000) | (((UintR) type) & 0xFFFF); } inline Ndb_logevent_type EventReport::getEventType() const { - return (Ndb_logevent_type)eventType; + return (Ndb_logevent_type)(eventType & 0xFFFF); } #endif diff --git a/ndb/include/kernel/signaldata/FsRef.hpp b/ndb/include/kernel/signaldata/FsRef.hpp index 2f7038de4ec..a0e1dc55dae 100644 --- a/ndb/include/kernel/signaldata/FsRef.hpp +++ b/ndb/include/kernel/signaldata/FsRef.hpp @@ -17,6 +17,7 @@ #ifndef FS_REF_H #define FS_REF_H +#include <ndbd_exit_codes.h> #include "SignalData.hpp" /** @@ -37,17 +38,15 @@ struct FsRef { */ enum NdbfsErrorCodeType { fsErrNone=0, - fsErrHardwareFailed=1, - fsErrUserError=2, - fsErrEnvironmentError=3, - fsErrTemporaryNotAccessible=4, - fsErrNoSpaceLeftOnDevice=5, - fsErrPermissionDenied=6, - fsErrInvalidParameters=7, - fsErrUnknown=8, - fsErrNoMoreResources=9, - fsErrFileDoesNotExist=10, - fsErrReadUnderflow = 11, + fsErrEnvironmentError=NDBD_EXIT_AFS_ENVIRONMENT, + fsErrTemporaryNotAccessible=NDBD_EXIT_AFS_TEMP_NO_ACCESS, + fsErrNoSpaceLeftOnDevice=NDBD_EXIT_AFS_DISK_FULL, + fsErrPermissionDenied=NDBD_EXIT_AFS_PERMISSION_DENIED, + fsErrInvalidParameters=NDBD_EXIT_AFS_INVALID_PARAM, + fsErrUnknown=NDBD_EXIT_AFS_UNKNOWN, + fsErrNoMoreResources=NDBD_EXIT_AFS_NO_MORE_RESOURCES, + fsErrFileDoesNotExist=NDBD_EXIT_AFS_NO_SUCH_FILE, + fsErrReadUnderflow = NDBD_EXIT_AFS_READ_UNDERFLOW, fsErrMax }; /** diff --git a/ndb/include/kernel/signaldata/NFCompleteRep.hpp b/ndb/include/kernel/signaldata/NFCompleteRep.hpp index c8bde705a86..764da85b163 100644 --- a/ndb/include/kernel/signaldata/NFCompleteRep.hpp +++ b/ndb/include/kernel/signaldata/NFCompleteRep.hpp @@ -30,28 +30,12 @@ * from the failed NDB node * */ -class NFCompleteRep { - /** - * Sender(s) - */ - friend class Dbdict; - friend class Dblqh; - friend class Dbtc; - friend class Qmgr; - - /** - * Sender/Reciver - */ - friend class Dbdih; - friend class ClusterMgr; +struct NFCompleteRep { friend bool printNF_COMPLETE_REP(FILE *, const Uint32 *, Uint32, Uint16); -public: STATIC_CONST( SignalLength = 5 ); -private: - /** * Which block has completed... * diff --git a/ndb/include/kernel/signaldata/NodeFailRep.hpp b/ndb/include/kernel/signaldata/NodeFailRep.hpp index 060acd6a3e2..fe57ba1a712 100644 --- a/ndb/include/kernel/signaldata/NodeFailRep.hpp +++ b/ndb/include/kernel/signaldata/NodeFailRep.hpp @@ -24,34 +24,8 @@ * This signals is sent by Qmgr to NdbCntr * and then from NdbCntr sent to: dih, dict, lqh, tc & API */ -class NodeFailRep { - /** - * Sender(s) - */ - friend class Qmgr; - - /** - * Sender(s) / Reciver(s) - */ - friend class Ndbcntr; - friend class Dbdict; - - /** - * Reciver(s) - */ - friend class Dbdih; - friend class Dblqh; - friend class Dbtc; - friend class ClusterMgr; - friend class Trix; - friend class Backup; - friend class Suma; - friend class Grep; - friend class SafeCounterManager; - -public: +struct NodeFailRep { STATIC_CONST( SignalLength = 3 + NodeBitmask::Size ); -private: Uint32 failNo; diff --git a/ndb/include/kernel/signaldata/SignalData.hpp b/ndb/include/kernel/signaldata/SignalData.hpp index f825b0feb7b..0591a85d6e6 100644 --- a/ndb/include/kernel/signaldata/SignalData.hpp +++ b/ndb/include/kernel/signaldata/SignalData.hpp @@ -222,5 +222,6 @@ GSN_PRINT_SIGNATURE(printSCAN_FRAGREQ); GSN_PRINT_SIGNATURE(printCONTINUEB_NDBFS); GSN_PRINT_SIGNATURE(printCONTINUEB_DBDIH); +GSN_PRINT_SIGNATURE(printSTART_FRAG_REQ); #endif diff --git a/ndb/include/kernel/signaldata/StartFragReq.hpp b/ndb/include/kernel/signaldata/StartFragReq.hpp index ec05c1ee366..ab17a147195 100644 --- a/ndb/include/kernel/signaldata/StartFragReq.hpp +++ b/ndb/include/kernel/signaldata/StartFragReq.hpp @@ -32,6 +32,8 @@ class StartFragReq { public: STATIC_CONST( SignalLength = 19 ); + friend bool printSTART_FRAG_REQ(FILE *, const Uint32 *, Uint32, Uint16); + private: Uint32 userPtr; Uint32 userRef; diff --git a/ndb/include/kernel/signaldata/StopReq.hpp b/ndb/include/kernel/signaldata/StopReq.hpp index ea453ae115d..8e6a0b90a91 100644 --- a/ndb/include/kernel/signaldata/StopReq.hpp +++ b/ndb/include/kernel/signaldata/StopReq.hpp @@ -67,6 +67,13 @@ public: static bool getStopAbort(const Uint32 & requestInfo); }; +struct StopConf +{ + STATIC_CONST( SignalLength = 2 ); + Uint32 senderData; + Uint32 nodeState; +}; + class StopRef { /** @@ -86,7 +93,8 @@ public: OK = 0, NodeShutdownInProgress = 1, SystemShutdownInProgress = 2, - NodeShutdownWouldCauseSystemCrash = 3 + NodeShutdownWouldCauseSystemCrash = 3, + TransactionAbortFailed = 4 }; public: diff --git a/ndb/include/kernel/signaldata/SystemError.hpp b/ndb/include/kernel/signaldata/SystemError.hpp index 7b4d47c5c2e..c2c51e88bf2 100644 --- a/ndb/include/kernel/signaldata/SystemError.hpp +++ b/ndb/include/kernel/signaldata/SystemError.hpp @@ -41,10 +41,7 @@ public: STATIC_CONST( SignalLength = 4 ); enum ErrorCode { - ScanfragStateError = 1, - ScanfragTimeout = 2, GCPStopDetected = 3, - StartInProgressError = 4, CopyFragRefError = 5, TestStopOnError = 6 }; diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index 924d65c2847..36dee7193c7 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -1022,6 +1022,8 @@ extern "C" { int param, const char ** value); int ndb_mgm_purge_stale_sessions(NdbMgmHandle handle, char **); int ndb_mgm_check_connection(NdbMgmHandle handle); + + int ndb_mgm_report_event(NdbMgmHandle handle, Uint32 *data, Uint32 length); #endif #ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED diff --git a/ndb/include/mgmapi/mgmapi_config_parameters.h b/ndb/include/mgmapi/mgmapi_config_parameters.h index 8f95e159b38..41516b1c3e4 100644 --- a/ndb/include/mgmapi/mgmapi_config_parameters.h +++ b/ndb/include/mgmapi/mgmapi_config_parameters.h @@ -116,6 +116,7 @@ #define CFG_CONNECTION_HOSTNAME_1 407 #define CFG_CONNECTION_HOSTNAME_2 408 #define CFG_CONNECTION_GROUP 409 +#define CFG_CONNECTION_NODE_ID_SERVER 410 #define CFG_TCP_SERVER 452 #define CFG_TCP_SEND_BUFFER_SIZE 454 diff --git a/ndb/include/mgmapi/ndb_logevent.h b/ndb/include/mgmapi/ndb_logevent.h index d5744b0fffe..6025ff2725c 100644 --- a/ndb/include/mgmapi/ndb_logevent.h +++ b/ndb/include/mgmapi/ndb_logevent.h @@ -76,6 +76,10 @@ extern "C" { /** NDB_MGM_EVENT_CATEGORY_STARTUP */ NDB_LE_NDBStopStarted = 17, /** NDB_MGM_EVENT_CATEGORY_STARTUP */ + NDB_LE_NDBStopCompleted = 53, + /** NDB_MGM_EVENT_CATEGORY_STARTUP */ + NDB_LE_NDBStopForced = 59, + /** NDB_MGM_EVENT_CATEGORY_STARTUP */ NDB_LE_NDBStopAborted = 18, /** NDB_MGM_EVENT_CATEGORY_STARTUP */ NDB_LE_StartREDOLog = 19, @@ -148,9 +152,12 @@ extern "C" { /** NDB_MGM_EVENT_CATEGORY_INFO */ NDB_LE_InfoEvent = 49, - /* GREP */ - NDB_LE_GrepSubscriptionInfo = 52, - NDB_LE_GrepSubscriptionAlert = 53, + /* 50 used */ + /* 51 used */ + + /* SINGLE USER */ + NDB_LE_SingleUser = 52, + /* 53 used */ /** NDB_MGM_EVENT_CATEGORY_BACKUP */ NDB_LE_BackupStarted = 54, @@ -160,6 +167,13 @@ extern "C" { NDB_LE_BackupCompleted = 56, /** NDB_MGM_EVENT_CATEGORY_BACKUP */ NDB_LE_BackupAborted = 57 + + /* 58 used in 5.1 */ + /* 59 used */ + /* 60 unused */ + /* 61 unused */ + /* 62 unused */ + }; /** @@ -389,6 +403,19 @@ extern "C" { } NDBStopStarted; /** Log event specific data for for corresponding NDB_LE_ log event */ struct { + unsigned action; + unsigned signum; + } NDBStopCompleted; + /** Log event specific data for for corresponding NDB_LE_ log event */ + struct { + unsigned action; + unsigned signum; + unsigned error; + unsigned sphase; + unsigned extra; + } NDBStopForced; + /** Log event specific data for for corresponding NDB_LE_ log event */ + struct { } NDBStopAborted; /** Log event specific data for for corresponding NDB_LE_ log event */ struct { @@ -593,6 +620,11 @@ extern "C" { unsigned backup_id; unsigned error; } BackupAborted; + /** Log event data @ref NDB_LE_SingleUser */ + struct { + unsigned type; + unsigned node_id; + } SingleUser; #ifndef DOXYGEN_FIX }; #else diff --git a/ndb/include/mgmapi/ndbd_exit_codes.h b/ndb/include/mgmapi/ndbd_exit_codes.h new file mode 100644 index 00000000000..2a0802add02 --- /dev/null +++ b/ndb/include/mgmapi/ndbd_exit_codes.h @@ -0,0 +1,158 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef NDBD_EXIT_CODES_H +#define NDBD_EXIT_CODES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + +/** + * Exit error codes for NDBD + * + * These errorcodes should be used whenever a condition + * is detected where it's necesssary to shutdown NDB. + * + * Example: When another node fails while a NDB node are performing + * a system restart the node should be shutdown. This + * is kind of an error but the cause of the error is known + * and a proper errormessage describing the problem should + * be printed in error.log. It's therefore important to use + * the proper errorcode. + * + */ + +typedef enum +{ + ndbd_exit_st_success = 0, + ndbd_exit_st_unknown = 1, + ndbd_exit_st_permanent = 2, + ndbd_exit_st_temporary = 3, + ndbd_exit_st_filesystem_error = 4 +} ndbd_exit_status_enum; + +typedef enum +{ + ndbd_exit_cl_none = 0, + ndbd_exit_cl_unknown = 1, + ndbd_exit_cl_internal_error = 2, + ndbd_exit_cl_configuration_error = 3, + ndbd_exit_cl_arbitration_error = 4, + ndbd_exit_cl_restart_error = 5, + ndbd_exit_cl_resource_configuration_error = 6, + ndbd_exit_cl_filesystem_full_error = 7, + ndbd_exit_cl_filesystem_inconsistency_error = 8, + ndbd_exit_cl_filesystem_limit = 9 +} ndbd_exit_classification_enum; + +typedef ndbd_exit_status_enum ndbd_exit_status; +typedef ndbd_exit_classification_enum ndbd_exit_classification; + +/* Errorcodes before block division was used */ +#define NDBD_EXIT_PRGERR 2301 +#define NDBD_EXIT_NODE_NOT_IN_CONFIG 2302 +#define NDBD_EXIT_SYSTEM_ERROR 2303 +#define NDBD_EXIT_INDEX_NOTINRANGE 2304 +#define NDBD_EXIT_ARBIT_SHUTDOWN 2305 +#define NDBD_EXIT_POINTER_NOTINRANGE 2306 +#define NDBD_EXIT_SR_OTHERNODEFAILED 2308 +#define NDBD_EXIT_NODE_NOT_DEAD 2309 +#define NDBD_EXIT_SR_REDOLOG 2310 +/* +#define NDBD_EXIT_SR_RESTARTCONFLICT 2311 +*/ +#define NDBD_EXIT_NO_MORE_UNDOLOG 2312 +#define NDBD_EXIT_SR_UNDOLOG 2313 +#define NDBD_EXIT_MEMALLOC 2327 +#define NDBD_EXIT_BLOCK_JBUFCONGESTION 2334 +#define NDBD_EXIT_TIME_QUEUE_SHORT 2335 +#define NDBD_EXIT_TIME_QUEUE_LONG 2336 +#define NDBD_EXIT_TIME_QUEUE_DELAY 2337 +#define NDBD_EXIT_TIME_QUEUE_INDEX 2338 +#define NDBD_EXIT_BLOCK_BNR_ZERO 2339 +#define NDBD_EXIT_WRONG_PRIO_LEVEL 2340 +#define NDBD_EXIT_NDBREQUIRE 2341 +#define NDBD_EXIT_ERROR_INSERT 2342 +#define NDBD_EXIT_NDBASSERT 2343 +#define NDBD_EXIT_INVALID_CONFIG 2350 +#define NDBD_EXIT_OUT_OF_LONG_SIGNAL_MEMORY 2351 + +#define NDBD_EXIT_OS_SIGNAL_RECEIVED 6000 + +/* VM 6050-> */ +#define NDBD_EXIT_WATCHDOG_TERMINATE 6050 +#define NDBD_EXIT_SIGNAL_LOST 6051 +#define NDBD_EXIT_SIGNAL_LOST_SEND_BUFFER_FULL 6052 +#define NDBD_EXIT_ILLEGAL_SIGNAL 6053 +#define NDBD_EXIT_CONNECTION_SETUP_FAILED 6054 + +/* NDBCNTR 6100-> */ +#define NDBD_EXIT_RESTART_TIMEOUT 6100 +#define NDBD_EXIT_RESTART_DURING_SHUTDOWN 6101 + +/* TC 6200-> */ +/* DIH 6300-> */ +#define NDBD_EXIT_MAX_CRASHED_REPLICAS 6300 +#define NDBD_EXIT_MASTER_FAILURE_DURING_NR 6301 +#define NDBD_EXIT_LOST_NODE_GROUP 6302 +#define NDBD_EXIT_NO_RESTORABLE_REPLICA 6303 + +/* ACC 6600-> */ +#define NDBD_EXIT_SR_OUT_OF_INDEXMEMORY 6600 +/* TUP 6800-> */ +#define NDBD_EXIT_SR_OUT_OF_DATAMEMORY 6800 +/* LQH 7200-> */ + + +/* Errorcodes for NDB filesystem */ +#define NDBD_EXIT_AFS_NOPATH 2801 +/* +#define NDBD_EXIT_AFS_CHANNALFULL 2802 +#define NDBD_EXIT_AFS_NOMORETHREADS 2803 +*/ +#define NDBD_EXIT_AFS_PARAMETER 2804 +#define NDBD_EXIT_AFS_INVALIDPATH 2805 +#define NDBD_EXIT_AFS_MAXOPEN 2806 +#define NDBD_EXIT_AFS_ALREADY_OPEN 2807 + +#define NDBD_EXIT_AFS_ENVIRONMENT 2808 +#define NDBD_EXIT_AFS_TEMP_NO_ACCESS 2809 +#define NDBD_EXIT_AFS_DISK_FULL 2810 +#define NDBD_EXIT_AFS_PERMISSION_DENIED 2811 +#define NDBD_EXIT_AFS_INVALID_PARAM 2812 +#define NDBD_EXIT_AFS_UNKNOWN 2813 +#define NDBD_EXIT_AFS_NO_MORE_RESOURCES 2814 +#define NDBD_EXIT_AFS_NO_SUCH_FILE 2815 +#define NDBD_EXIT_AFS_READ_UNDERFLOW 2816 + +const char * +ndbd_exit_message(int faultId, ndbd_exit_classification *cl); +const char * +ndbd_exit_classification_message(ndbd_exit_classification classification, + ndbd_exit_status *status); +const char * +ndbd_exit_status_message(ndbd_exit_status status); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* NDBD_EXIT_CODES_H */ diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index db2212075e8..7e2e9037a34 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -984,10 +984,10 @@ class BaseString; class NdbEventOperation; class NdbBlob; class NdbReceiver; +template <class T> struct Ndb_free_list_t; typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); - #if defined NDB_OSE /** * Default time to wait for response after request has been sent to @@ -1457,8 +1457,20 @@ public: */ NdbTransaction* hupp( NdbTransaction* ); Uint32 getReference() const { return theMyRef;} + + struct Free_list_usage + { + const char * m_name; + Uint32 m_created; + Uint32 m_free; + Uint32 m_sizeof; + }; + + Free_list_usage * get_free_list_usage(Free_list_usage*); #endif + + /***************************************************************************** * These are service routines used by the other classes in the NDBAPI. ****************************************************************************/ @@ -1630,22 +1642,8 @@ private: class NdbDictionaryImpl* theDictionary; class NdbGlobalEventBufferHandle* theGlobalEventBufferHandle; - NdbTransaction* theConIdleList; // First connection in idle list. - - NdbOperation* theOpIdleList; // First operation in the idle list. - - NdbIndexScanOperation* theScanOpIdleList; // First scan operation in the idle list. - NdbIndexOperation* theIndexOpIdleList; // First index operation in the idle list. NdbTransaction* theTransactionList; NdbTransaction** theConnectionArray; - NdbRecAttr* theRecAttrIdleList; - NdbApiSignal* theSignalIdleList; // First signal in idlelist. - NdbLabel* theLabelList; // First label descriptor in list - NdbBranch* theBranchList; // First branch descriptor in list - NdbSubroutine* theSubroutineList; // First subroutine descriptor in - NdbCall* theCallList; // First call descriptor in list - NdbReceiver* theScanList; - NdbBlob* theNdbBlobIdleList; Uint32 theMyRef; // My block reference Uint32 theNode; // The node number of our node diff --git a/ndb/include/ndbapi/NdbBlob.hpp b/ndb/include/ndbapi/NdbBlob.hpp index 271287b765c..cb0caafe34f 100644 --- a/ndb/include/ndbapi/NdbBlob.hpp +++ b/ndb/include/ndbapi/NdbBlob.hpp @@ -277,7 +277,7 @@ private: // for keeping in lists NdbBlob* theNext; // initialization - NdbBlob(); + NdbBlob(Ndb*); void init(); void release(); // classify operations @@ -329,6 +329,10 @@ private: int getOperationType() const; friend class NdbOut& operator<<(NdbOut&, const NdbBlob&); #endif + + void next(NdbBlob* obj) { theNext= obj;} + NdbBlob* next() { return theNext;} + friend struct Ndb_free_list_t<NdbBlob>; }; #endif diff --git a/ndb/include/ndbapi/NdbIndexOperation.hpp b/ndb/include/ndbapi/NdbIndexOperation.hpp index 3de6835238e..a8a15978568 100644 --- a/ndb/include/ndbapi/NdbIndexOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexOperation.hpp @@ -181,6 +181,7 @@ private: // Private attributes const NdbIndexImpl* m_theIndex; + friend struct Ndb_free_list_t<NdbIndexOperation>; }; #endif diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index 0a31f228921..e9f92d84d1c 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -165,9 +165,10 @@ private: int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*); Uint32 m_sort_columns; - Uint32 m_this_bound_start; Uint32 * m_first_bound_word; + + friend struct Ndb_free_list_t<NdbIndexScanOperation>; }; #endif diff --git a/ndb/include/ndbapi/NdbOperation.hpp b/ndb/include/ndbapi/NdbOperation.hpp index fca610772cc..1035c642c97 100644 --- a/ndb/include/ndbapi/NdbOperation.hpp +++ b/ndb/include/ndbapi/NdbOperation.hpp @@ -22,6 +22,7 @@ #include "NdbError.hpp" #include "NdbReceiver.hpp" #include "NdbDictionary.hpp" +#include "Ndb.hpp" class Ndb; class NdbApiSignal; @@ -756,8 +757,6 @@ protected: /****************************************************************************** * These are the methods used to create and delete the NdbOperation objects. *****************************************************************************/ - NdbOperation(Ndb* aNdb); - virtual ~NdbOperation(); bool needReply(); /****************************************************************************** @@ -769,6 +768,8 @@ protected: int init(const class NdbTableImpl*, NdbTransaction* aCon); void initInterpreter(); + NdbOperation(Ndb* aNdb); + virtual ~NdbOperation(); void next(NdbOperation*); // Set next pointer NdbOperation* next(); // Get next pointer public: @@ -965,6 +966,8 @@ protected: * IgnoreError on connection level. */ Int8 m_abortOption; + + friend struct Ndb_free_list_t<NdbOperation>; }; #ifdef NDB_NO_DROPPED_SIGNAL diff --git a/ndb/include/ndbapi/NdbRecAttr.hpp b/ndb/include/ndbapi/NdbRecAttr.hpp index 50de4f3277e..3607a64f3b3 100644 --- a/ndb/include/ndbapi/NdbRecAttr.hpp +++ b/ndb/include/ndbapi/NdbRecAttr.hpp @@ -17,7 +17,8 @@ #ifndef NdbRecAttr_H #define NdbRecAttr_H -#include <NdbDictionary.hpp> +#include "NdbDictionary.hpp" +#include "Ndb.hpp" class NdbOperation; @@ -248,7 +249,6 @@ public: const NdbRecAttr* next() const; #endif private: - NdbRecAttr(); Uint32 attrId() const; /* Get attribute id */ bool setNULL(); /* Set NULL indicator */ @@ -258,6 +258,7 @@ private: void release(); /* Release memory if allocated */ void init(); /* Initialise object when allocated */ + NdbRecAttr(Ndb*); void next(NdbRecAttr* aRecAttr); NdbRecAttr* next(); @@ -280,6 +281,8 @@ private: Uint32 theAttrSize; Uint32 theArraySize; const NdbDictionary::Column* m_column; + + friend struct Ndb_free_list_t<NdbRecAttr>; }; #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL diff --git a/ndb/include/ndbapi/NdbTransaction.hpp b/ndb/include/ndbapi/NdbTransaction.hpp index 2e102b104d8..a6ba6a11c4d 100644 --- a/ndb/include/ndbapi/NdbTransaction.hpp +++ b/ndb/include/ndbapi/NdbTransaction.hpp @@ -18,8 +18,9 @@ #define NdbTransaction_H #include <ndb_types.h> -#include <NdbError.hpp> -#include <NdbDictionary.hpp> +#include "NdbError.hpp" +#include "NdbDictionary.hpp" +#include "Ndb.hpp" class NdbTransaction; class NdbOperation; @@ -581,9 +582,7 @@ private: /************************************************************************** * These are the create and delete methods of this class. * **************************************************************************/ - NdbTransaction(Ndb* aNdb); - ~NdbTransaction(); void init(); // Initialize connection object for new transaction @@ -807,6 +806,7 @@ private: void define_scan_op(NdbIndexScanOperation*); friend class HugoOperations; + friend struct Ndb_free_list_t<NdbTransaction>; }; #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL diff --git a/ndb/include/transporter/TransporterCallback.hpp b/ndb/include/transporter/TransporterCallback.hpp index f2432edd394..ef9be8c5a69 100644 --- a/ndb/include/transporter/TransporterCallback.hpp +++ b/ndb/include/transporter/TransporterCallback.hpp @@ -81,7 +81,9 @@ reportConnect(void * callbackObj, NodeId nodeId); void reportDisconnect(void * callbackObj, NodeId nodeId, Uint32 errNo); - + +#define TE_DO_DISCONNECT 0x8000 + enum TransporterError { TE_NO_ERROR = 0, /** @@ -111,7 +113,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisconnect) */ - TE_INVALID_MESSAGE_LENGTH = 0x8003, + TE_INVALID_MESSAGE_LENGTH = 0x3 | TE_DO_DISCONNECT, /** * TE_INVALID_CHECKSUM @@ -120,7 +122,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - TE_INVALID_CHECKSUM = 0x8004, + TE_INVALID_CHECKSUM = 0x4 | TE_DO_DISCONNECT, /** * TE_COULD_NOT_CREATE_SOCKET @@ -129,7 +131,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - TE_COULD_NOT_CREATE_SOCKET = 0x8005, + TE_COULD_NOT_CREATE_SOCKET = 0x5, /** * TE_COULD_NOT_BIND_SOCKET @@ -138,7 +140,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - TE_COULD_NOT_BIND_SOCKET = 0x8006, + TE_COULD_NOT_BIND_SOCKET = 0x6, /** * TE_LISTEN_FAILED @@ -147,7 +149,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - TE_LISTEN_FAILED = 0x8007, + TE_LISTEN_FAILED = 0x7, /** * TE_ACCEPT_RETURN_ERROR @@ -158,7 +160,7 @@ enum TransporterError { * Recommended behavior: Ignore * (or possible do setPerformState(PerformDisconnect) */ - TE_ACCEPT_RETURN_ERROR = 0x8008 + TE_ACCEPT_RETURN_ERROR = 0x8 /** * TE_SHM_DISCONNECT @@ -167,7 +169,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SHM_DISCONNECT = 0x800b + ,TE_SHM_DISCONNECT = 0xb | TE_DO_DISCONNECT /** * TE_SHM_IPC_STAT @@ -178,7 +180,12 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SHM_IPC_STAT = 0x800c + ,TE_SHM_IPC_STAT = 0xc | TE_DO_DISCONNECT + + /** + * Permanent error + */ + ,TE_SHM_IPC_PERMANENT = 0x21 /** * TE_SHM_UNABLE_TO_CREATE_SEGMENT @@ -188,7 +195,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SHM_UNABLE_TO_CREATE_SEGMENT = 0x800d + ,TE_SHM_UNABLE_TO_CREATE_SEGMENT = 0xd /** * TE_SHM_UNABLE_TO_ATTACH_SEGMENT @@ -198,7 +205,7 @@ enum TransporterError { * * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SHM_UNABLE_TO_ATTACH_SEGMENT = 0x800e + ,TE_SHM_UNABLE_TO_ATTACH_SEGMENT = 0xe /** * TE_SHM_UNABLE_TO_REMOVE_SEGMENT @@ -208,12 +215,12 @@ enum TransporterError { * Recommended behavior: Ignore (not much to do) * Print warning to logfile */ - ,TE_SHM_UNABLE_TO_REMOVE_SEGMENT = 0x800f + ,TE_SHM_UNABLE_TO_REMOVE_SEGMENT = 0xf - ,TE_TOO_SMALL_SIGID = 0x0010 - ,TE_TOO_LARGE_SIGID = 0x0011 - ,TE_WAIT_STACK_FULL = 0x8012 - ,TE_RECEIVE_BUFFER_FULL = 0x8013 + ,TE_TOO_SMALL_SIGID = 0x10 + ,TE_TOO_LARGE_SIGID = 0x11 + ,TE_WAIT_STACK_FULL = 0x12 | TE_DO_DISCONNECT + ,TE_RECEIVE_BUFFER_FULL = 0x13 | TE_DO_DISCONNECT /** * TE_SIGNAL_LOST_SEND_BUFFER_FULL @@ -222,7 +229,7 @@ enum TransporterError { * a signal is dropped!! very bad very bad * */ - ,TE_SIGNAL_LOST_SEND_BUFFER_FULL = 0x8014 + ,TE_SIGNAL_LOST_SEND_BUFFER_FULL = 0x14 | TE_DO_DISCONNECT /** * TE_SIGNAL_LOST @@ -231,14 +238,14 @@ enum TransporterError { * a signal is dropped!! very bad very bad * */ - ,TE_SIGNAL_LOST = 0x8015 + ,TE_SIGNAL_LOST = 0x15 /** * TE_SEND_BUFFER_FULL * * The send buffer was full, but sleeping for a while solved it */ - ,TE_SEND_BUFFER_FULL = 0x0016 + ,TE_SEND_BUFFER_FULL = 0x16 /** * TE_SCI_UNABLE_TO_CLOSE_CHANNEL @@ -246,7 +253,7 @@ enum TransporterError { * Unable to close the sci channel and the resources allocated by * the sisci api. */ - ,TE_SCI_UNABLE_TO_CLOSE_CHANNEL = 0x8016 + ,TE_SCI_UNABLE_TO_CLOSE_CHANNEL = 0x22 /** * TE_SCI_LINK_ERROR @@ -255,7 +262,7 @@ enum TransporterError { * No point in continuing. Must check the connections. * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_LINK_ERROR = 0x8017 + ,TE_SCI_LINK_ERROR = 0x0017 /** * TE_SCI_UNABLE_TO_START_SEQUENCE @@ -264,14 +271,14 @@ enum TransporterError { * are exumed or no sequence has been created. * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_UNABLE_TO_START_SEQUENCE = 0x8018 + ,TE_SCI_UNABLE_TO_START_SEQUENCE = 0x18 | TE_DO_DISCONNECT /** * TE_SCI_UNABLE_TO_REMOVE_SEQUENCE * * Could not remove a sequence */ - ,TE_SCI_UNABLE_TO_REMOVE_SEQUENCE = 0x8019 + ,TE_SCI_UNABLE_TO_REMOVE_SEQUENCE = 0x19 | TE_DO_DISCONNECT /** * TE_SCI_UNABLE_TO_CREATE_SEQUENCE @@ -280,7 +287,7 @@ enum TransporterError { * exempted. Must reboot. * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_UNABLE_TO_CREATE_SEQUENCE = 0x801a + ,TE_SCI_UNABLE_TO_CREATE_SEQUENCE = 0x1a | TE_DO_DISCONNECT /** * TE_SCI_UNRECOVERABLE_DATA_TFX_ERROR @@ -288,7 +295,7 @@ enum TransporterError { * Tried to send data on redundant link but failed. * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_UNRECOVERABLE_DATA_TFX_ERROR = 0x801b + ,TE_SCI_UNRECOVERABLE_DATA_TFX_ERROR = 0x1b | TE_DO_DISCONNECT /** * TE_SCI_CANNOT_INIT_LOCALSEGMENT @@ -297,7 +304,7 @@ enum TransporterError { * gone wrong (no system resources). Must reboot. * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_CANNOT_INIT_LOCALSEGMENT = 0x801c + ,TE_SCI_CANNOT_INIT_LOCALSEGMENT = 0x1c | TE_DO_DISCONNECT /** * TE_SCI_CANNOT_MAP_REMOTESEGMENT @@ -306,7 +313,7 @@ enum TransporterError { * Must reboot system. * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_CANNOT_MAP_REMOTESEGMENT = 0x801d + ,TE_SCI_CANNOT_MAP_REMOTESEGMENT = 0x1d | TE_DO_DISCONNECT /** * TE_SCI_UNABLE_TO_UNMAP_SEGMENT @@ -314,7 +321,7 @@ enum TransporterError { * Cannot free the resources used by this segment (step 1). * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_UNABLE_TO_UNMAP_SEGMENT = 0x801e + ,TE_SCI_UNABLE_TO_UNMAP_SEGMENT = 0x1e | TE_DO_DISCONNECT /** * TE_SCI_UNABLE_TO_REMOVE_SEGMENT @@ -324,7 +331,7 @@ enum TransporterError { * to map more segment * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_UNABLE_TO_REMOVE_SEGMENT = 0x801f + ,TE_SCI_UNABLE_TO_REMOVE_SEGMENT = 0x1f | TE_DO_DISCONNECT /** * TE_SCI_UNABLE_TO_DISCONNECT_SEGMENT @@ -332,15 +339,18 @@ enum TransporterError { * Cannot disconnect from a remote segment. * Recommended behavior: setPerformState(PerformDisonnect) */ - ,TE_SCI_UNABLE_TO_DISCONNECT_SEGMENT = 0x8020 + ,TE_SCI_UNABLE_TO_DISCONNECT_SEGMENT = 0x20 | TE_DO_DISCONNECT + /* Used 0x21 */ + /* Used 0x22 */ }; /** * Report error */ void -reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode); +reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode, + const char *info = 0); void transporter_recv_from(void* callbackObj, NodeId node); diff --git a/ndb/include/util/Parser.hpp b/ndb/include/util/Parser.hpp index c117498e1ba..3baf7601a6c 100644 --- a/ndb/include/util/Parser.hpp +++ b/ndb/include/util/Parser.hpp @@ -285,7 +285,7 @@ template<class T> inline void Parser<T>::setBreakOnInvalidArg(bool v){ - impl->m_breakOnInvalidArg; + impl->m_breakOnInvalidArg = v; } #endif diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index f60ac4e6a63..787c32f06fd 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -30,6 +30,7 @@ my_bool opt_ndb_optimized_node_selection int opt_ndb_nodeid; bool opt_endinfo= 0; my_bool opt_ndb_shm; +my_bool opt_core; const char *opt_ndb_connectstring= 0; const char *opt_connect_str= 0; const char *opt_ndb_mgmd= 0; @@ -41,6 +42,11 @@ const char *opt_debug= 0; #endif #define OPT_NDB_CONNECTSTRING 'c' +#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) +#define OPT_WANT_CORE_DEFAULT 1 +#else +#define OPT_WANT_CORE_DEFAULT 0 +#endif #define NDB_STD_OPTS_COMMON \ { "usage", '?', "Display this help and exit.", \ @@ -75,7 +81,10 @@ const char *opt_debug= 0; GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},\ { "connect-string", OPT_NDB_CONNECTSTRING, "same as --ndb-connectstring",\ (gptr*) &opt_ndb_connectstring, (gptr*) &opt_ndb_connectstring, \ - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "core-file", OPT_WANT_CORE, "Write core on errors.",\ + (gptr*) &opt_core, (gptr*) &opt_core, 0,\ + GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0} #ifndef DBUG_OFF #define NDB_STD_OPTS(prog_name) \ @@ -99,6 +108,7 @@ enum ndb_std_options { OPT_NDB_SHM= 256, OPT_NDB_SHM_SIGNUM, OPT_NDB_OPTIMIZED_NODE_SELECTION, + OPT_WANT_CORE, OPT_NDB_MGMD, OPT_NDB_NODEID, NDB_STD_OPTIONS_LAST /* should always be last in this enum */ diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp index 5a534b36b59..f785cda5215 100644 --- a/ndb/src/common/debugger/EventLogger.cpp +++ b/ndb/src/common/debugger/EventLogger.cpp @@ -25,6 +25,8 @@ #include <NodeState.hpp> #include <version.h> +#include <ndbd_exit_codes.h> + // // PUBLIC // @@ -33,7 +35,6 @@ EventLoggerBase::~EventLoggerBase() } - #define QQQQ char *m_text, size_t m_text_len, const Uint32* theData void getTextConnected(QQQQ) { @@ -85,6 +86,57 @@ void getTextNDBStopStarted(QQQQ) { "%s shutdown initiated", (theData[1] == 1 ? "Cluster" : "Node")); } +void getRestartAction(Uint32 action, BaseString &str) +{ + if (action == 0) + return; + str.appfmt(", restarting"); + if (action & 2) + str.appfmt(", no start"); + if (action & 4) + str.appfmt(", initial"); +} +void getTextNDBStopCompleted(QQQQ) { + BaseString action_str(""); + BaseString signum_str(""); + getRestartAction(theData[1], action_str); + if (theData[2]) + signum_str.appfmt(" Initiated by signal %d.", theData[2]); + BaseString::snprintf(m_text, m_text_len, + "Node shutdown completed%s.%s", + action_str.c_str(), + signum_str.c_str()); +} +void getTextNDBStopForced(QQQQ) { + BaseString action_str(""); + BaseString reason_str(""); + BaseString sphase_str(""); + int signum = theData[2]; + int error = theData[3]; + int sphase = theData[4]; + int extra = theData[5]; + getRestartAction(theData[1],action_str); + if (signal) + reason_str.appfmt(" Initiated by signal %d.", signum); + if (error) + { + ndbd_exit_classification cl; + ndbd_exit_status st; + const char *msg = ndbd_exit_message(error, &cl); + const char *cl_msg = ndbd_exit_classification_message(cl, &st); + const char *st_msg = ndbd_exit_status_message(st); + reason_str.appfmt(" Caused by error %d: \'%s(%s). %s\'.", + error, msg, cl_msg, st_msg); + if (extra != 0) + reason_str.appfmt(" (extra info %d)", extra); + } + if (sphase < 255) + sphase_str.appfmt(" Occured during startphase %u.", sphase); + BaseString::snprintf(m_text, m_text_len, + "Forced node shutdown completed%s.%s%s", + action_str.c_str(), sphase_str.c_str(), + reason_str.c_str()); +} void getTextNDBStopAborted(QQQQ) { BaseString::snprintf(m_text, m_text_len, "Node shutdown aborted"); @@ -434,10 +486,12 @@ void getTextNR_CopyFragsCompleted(QQQQ) { void getTextLCPFragmentCompleted(QQQQ) { BaseString::snprintf(m_text, m_text_len, "Table ID = %u, fragment ID = %u has completed LCP " - "on Node %u", + "on Node %u maxGciStarted: %d maxGciCompleted: %d", theData[2], theData[3], - theData[1]); + theData[1], + theData[4], + theData[5]); } void getTextTransReportCounters(QQQQ) { // ------------------------------------------------------------------- @@ -632,6 +686,27 @@ void getTextBackupAborted(QQQQ) { theData[3]); } +void getTextSingleUser(QQQQ) { + switch (theData[1]) + { + case 0: + BaseString::snprintf(m_text, m_text_len, "Entering single user mode"); + break; + case 1: + BaseString::snprintf(m_text, m_text_len, + "Entered single user mode " + "Node %d has exclusive access", theData[2]); + break; + case 2: + BaseString::snprintf(m_text, m_text_len,"Exiting single user mode"); + break; + default: + BaseString::snprintf(m_text, m_text_len, + "Unknown single user report %d", theData[1]); + break; + } +} + #if 0 BaseString::snprintf(m_text, m_text_len, @@ -674,6 +749,8 @@ const EventLoggerBase::EventRepLogLevelMatrix EventLoggerBase::matrix[] = { ROW(CM_REGREF, LogLevel::llStartUp, 8, Logger::LL_INFO ), ROW(FIND_NEIGHBOURS, LogLevel::llStartUp, 8, Logger::LL_INFO ), ROW(NDBStopStarted, LogLevel::llStartUp, 1, Logger::LL_INFO ), + ROW(NDBStopCompleted, LogLevel::llStartUp, 1, Logger::LL_INFO ), + ROW(NDBStopForced, LogLevel::llStartUp, 1, Logger::LL_ALERT ), ROW(NDBStopAborted, LogLevel::llStartUp, 1, Logger::LL_INFO ), ROW(StartREDOLog, LogLevel::llStartUp, 10, Logger::LL_INFO ), ROW(StartLog, LogLevel::llStartUp, 10, Logger::LL_INFO ), @@ -715,6 +792,9 @@ const EventLoggerBase::EventRepLogLevelMatrix EventLoggerBase::matrix[] = { ROW(CreateLogBytes, LogLevel::llInfo, 11, Logger::LL_INFO ), ROW(InfoEvent, LogLevel::llInfo, 2, Logger::LL_INFO ), + //Single User + ROW(SingleUser, LogLevel::llInfo, 7, Logger::LL_INFO ), + // Backup ROW(BackupStarted, LogLevel::llBackup, 7, Logger::LL_INFO ), ROW(BackupCompleted, LogLevel::llBackup, 7, Logger::LL_INFO ), diff --git a/ndb/src/common/debugger/signaldata/FsRef.cpp b/ndb/src/common/debugger/signaldata/FsRef.cpp index ccf3d6da9c8..ff659208d20 100644 --- a/ndb/src/common/debugger/signaldata/FsRef.cpp +++ b/ndb/src/common/debugger/signaldata/FsRef.cpp @@ -30,42 +30,13 @@ printFSREF(FILE * output, const Uint32 * theData, sig->userPointer); fprintf(output, " ErrorCode: %d, ", sig->errorCode); + ndbd_exit_classification cl; switch (sig->getErrorCode(sig->errorCode)){ case FsRef::fsErrNone: fprintf(output, "No error"); break; - case FsRef::fsErrHardwareFailed: - fprintf(output, "Hardware failure!"); - break; - case FsRef::fsErrUserError: - fprintf(output, "User error!"); - break; - case FsRef::fsErrEnvironmentError: - fprintf(output, "Environment error!"); - break; - case FsRef::fsErrTemporaryNotAccessible: - fprintf(output, "Temporary not accesible!"); - break; - case FsRef::fsErrNoSpaceLeftOnDevice: - fprintf(output, "No space left on device!"); - break; - case FsRef::fsErrPermissionDenied: - fprintf(output, "Permission denied!"); - break; - case FsRef::fsErrInvalidParameters: - fprintf(output, "Invalid parameters!"); - break; - case FsRef::fsErrNoMoreResources: - fprintf(output, "No more resources!"); - break; - case FsRef::fsErrFileDoesNotExist: - fprintf(output, "File does not exist!"); - break; - - case FsRef::fsErrUnknown: default: - fprintf(output, "Unknown!"); - ret = false; + fprintf(output, ndbd_exit_message(sig->getErrorCode(sig->errorCode), &cl)); break; } fprintf(output, "\n"); diff --git a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp index ab23c04bffa..34cae9f618f 100644 --- a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp +++ b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp @@ -198,6 +198,7 @@ SignalDataPrintFunctions[] = { ,{ GSN_ACC_LOCKREQ, printACC_LOCKREQ } ,{ GSN_LQH_TRANSCONF, printLQH_TRANSCONF } ,{ GSN_SCAN_FRAGREQ, printSCAN_FRAGREQ } + ,{ GSN_START_FRAGREQ, printSTART_FRAG_REQ } ,{ 0, 0 } }; diff --git a/ndb/src/common/debugger/signaldata/StartRec.cpp b/ndb/src/common/debugger/signaldata/StartRec.cpp index 482e3cb0728..54830e533c5 100644 --- a/ndb/src/common/debugger/signaldata/StartRec.cpp +++ b/ndb/src/common/debugger/signaldata/StartRec.cpp @@ -17,6 +17,7 @@ #include <RefConvert.hpp> #include <signaldata/StartRec.hpp> +#include <signaldata/StartFragReq.hpp> bool printSTART_REC_REQ(FILE * output, @@ -50,3 +51,27 @@ printSTART_REC_CONF(FILE * output, return true; } + +bool +printSTART_FRAG_REQ(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo) +{ + StartFragReq* sig = (StartFragReq*)theData; + + fprintf(output, " table: %d frag: %d lcpId: %d lcpNo: %d #nodes: %d \n", + sig->tableId, sig->fragId, sig->lcpId, sig->lcpNo, + sig->noOfLogNodes); + + for(Uint32 i = 0; i<sig->noOfLogNodes; i++) + { + fprintf(output, " (node: %d startGci: %d lastGci: %d)", + sig->lqhLogNode[i], + sig->startGci[i], + sig->lastGci[i]); + } + + fprintf(output, "\n"); + return true; +} diff --git a/ndb/src/common/mgmcommon/IPCConfig.cpp b/ndb/src/common/mgmcommon/IPCConfig.cpp index f935f8ffab4..bc442ffc3ef 100644 --- a/ndb/src/common/mgmcommon/IPCConfig.cpp +++ b/ndb/src/common/mgmcommon/IPCConfig.cpp @@ -231,8 +231,11 @@ IPCConfig::configureTransporters(Uint32 nodeId, Uint32 server_port= 0; if(iter.get(CFG_CONNECTION_SERVER_PORT, &server_port)) break; + Uint32 nodeIdServer= 0; + if(iter.get(CFG_CONNECTION_NODE_ID_SERVER, &nodeIdServer)) break; + /* - We check the node type. MGM node becomes server. + We check the node type. */ Uint32 node1type, node2type; ndb_mgm_configuration_iterator node1iter(config, CFG_SECTION_NODE); @@ -242,20 +245,12 @@ IPCConfig::configureTransporters(Uint32 nodeId, node1iter.get(CFG_TYPE_OF_SECTION,&node1type); node2iter.get(CFG_TYPE_OF_SECTION,&node2type); - conf.serverNodeId= (nodeId1 < nodeId2)? nodeId1:nodeId2; - - conf.isMgmConnection= false; - if(node2type==NODE_TYPE_MGM) - { - conf.isMgmConnection= true; - conf.serverNodeId= nodeId2; - } - else if(node1type==NODE_TYPE_MGM) - { + if(node1type==NODE_TYPE_MGM || node2type==NODE_TYPE_MGM) conf.isMgmConnection= true; - conf.serverNodeId= nodeId1; - } - else if (nodeId == conf.serverNodeId) { + else + conf.isMgmConnection= false; + + if (nodeId == nodeIdServer && !conf.isMgmConnection) { tr.add_transporter_interface(remoteNodeId, localHostName, server_port); } @@ -279,6 +274,7 @@ IPCConfig::configureTransporters(Uint32 nodeId, conf.s_port = server_port; conf.localHostName = localHostName; conf.remoteHostName = remoteHostName; + conf.serverNodeId = nodeIdServer; switch(type){ case CONNECTION_TYPE_SHM: diff --git a/ndb/src/common/portlib/NdbTCP.cpp b/ndb/src/common/portlib/NdbTCP.cpp index 768292ac7c0..41471548b7e 100644 --- a/ndb/src/common/portlib/NdbTCP.cpp +++ b/ndb/src/common/portlib/NdbTCP.cpp @@ -86,6 +86,7 @@ Ndb_getInAddr(struct in_addr * dst, const char *address) { int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock) { +#ifdef HAVE_POLL struct pollfd pfd[1]; int r; @@ -97,4 +98,35 @@ int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock) return 1; return 0; +#else /* HAVE_POLL */ + fd_set readfds, writefds, errorfds; + struct timeval tv= {0,0}; + int s_err; + int s_err_size= sizeof(s_err); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&errorfds); + + FD_SET(sock, &readfds); + FD_SET(sock, &writefds); + FD_SET(sock, &errorfds); + + if(select(1, &readfds, &writefds, &errorfds, &tv)<0) + return 1; + + if(FD_ISSET(sock,&errorfds)) + return 1; + + s_err=0; + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) + return(1); + + if (s_err) + { /* getsockopt could succeed */ + return(1); /* but return an error... */ + } + + return 0; +#endif /* HAVE_POLL */ } diff --git a/ndb/src/common/portlib/NdbThread.c b/ndb/src/common/portlib/NdbThread.c index 55ebc4c8111..48d00956ec2 100644 --- a/ndb/src/common/portlib/NdbThread.c +++ b/ndb/src/common/portlib/NdbThread.c @@ -53,6 +53,16 @@ ndb_thread_wrapper(void* _ss){ } #endif { + /** + * Block all signals to thread by default + * let them go to main process instead + */ + sigset_t mask; + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, 0); + } + + { void *ret; struct NdbThread * ss = (struct NdbThread *)_ss; ret= (* ss->func)(ss->object); diff --git a/ndb/src/common/portlib/win32/NdbTCP.c b/ndb/src/common/portlib/win32/NdbTCP.c index a14cd4409eb..5d6c0ae5c7d 100644 --- a/ndb/src/common/portlib/win32/NdbTCP.c +++ b/ndb/src/common/portlib/win32/NdbTCP.c @@ -52,7 +52,7 @@ int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock) FD_SET(sock, &writefds); FD_SET(sock, &errorfds); - if(select(1, &readfds, &writefds, &errorfds, &t)==SOCKET_ERROR) + if(select(1, &readfds, &writefds, &errorfds, &tv)==SOCKET_ERROR) return 1; if(FD_ISSET(sock,&errorfds)) diff --git a/ndb/src/common/transporter/SHM_Transporter.cpp b/ndb/src/common/transporter/SHM_Transporter.cpp index a225988d37f..93d718b8713 100644 --- a/ndb/src/common/transporter/SHM_Transporter.cpp +++ b/ndb/src/common/transporter/SHM_Transporter.cpp @@ -47,6 +47,9 @@ SHM_Transporter::SHM_Transporter(TransporterRegistry &t_reg, shmKey(_shmKey), shmSize(_shmSize) { +#ifndef NDB_WIN32 + shmId= 0; +#endif _shmSegCreated = false; _attached = false; @@ -202,7 +205,8 @@ SHM_Transporter::connect_server_impl(NDB_SOCKET_TYPE sockfd) // Create if(!_shmSegCreated){ if (!ndb_shm_create()) { - report_error(TE_SHM_UNABLE_TO_CREATE_SEGMENT); + make_error_info(buf, sizeof(buf)); + report_error(TE_SHM_UNABLE_TO_CREATE_SEGMENT, buf); NDB_CLOSE_SOCKET(sockfd); DBUG_RETURN(false); } @@ -212,7 +216,8 @@ SHM_Transporter::connect_server_impl(NDB_SOCKET_TYPE sockfd) // Attach if(!_attached){ if (!ndb_shm_attach()) { - report_error(TE_SHM_UNABLE_TO_ATTACH_SEGMENT); + make_error_info(buf, sizeof(buf)); + report_error(TE_SHM_UNABLE_TO_ATTACH_SEGMENT, buf); NDB_CLOSE_SOCKET(sockfd); DBUG_RETURN(false); } @@ -224,7 +229,8 @@ SHM_Transporter::connect_server_impl(NDB_SOCKET_TYPE sockfd) m_transporter_registry.m_shm_own_pid); // Wait for ok from client - if (s_input.gets(buf, 256) == 0) + DBUG_PRINT("info", ("Wait for ok from client")); + if (s_input.gets(buf, sizeof(buf)) == 0) { NDB_CLOSE_SOCKET(sockfd); DBUG_RETURN(false); @@ -262,10 +268,8 @@ SHM_Transporter::connect_client_impl(NDB_SOCKET_TYPE sockfd) SocketOutputStream s_output(sockfd); char buf[256]; -#if 1 -#endif - // Wait for server to create and attach + DBUG_PRINT("info", ("Wait for server to create and attach")); if (s_input.gets(buf, 256) == 0) { NDB_CLOSE_SOCKET(sockfd); DBUG_PRINT("error", ("Server id %d did not attach", @@ -293,7 +297,8 @@ SHM_Transporter::connect_client_impl(NDB_SOCKET_TYPE sockfd) // Attach if(!_attached){ if (!ndb_shm_attach()) { - report_error(TE_SHM_UNABLE_TO_ATTACH_SEGMENT); + make_error_info(buf, sizeof(buf)); + report_error(TE_SHM_UNABLE_TO_ATTACH_SEGMENT, buf); NDB_CLOSE_SOCKET(sockfd); DBUG_PRINT("error", ("Failed attach of shm seg to node %d", remoteNodeId)); @@ -310,6 +315,7 @@ SHM_Transporter::connect_client_impl(NDB_SOCKET_TYPE sockfd) if (r) { // Wait for ok from server + DBUG_PRINT("info", ("Wait for ok from server")); if (s_input.gets(buf, 256) == 0) { NDB_CLOSE_SOCKET(sockfd); DBUG_PRINT("error", ("No ok from server node %d", @@ -330,8 +336,6 @@ bool SHM_Transporter::connect_common(NDB_SOCKET_TYPE sockfd) { if (!checkConnected()) { - DBUG_PRINT("error", ("Already connected to node %d", - remoteNodeId)); return false; } diff --git a/ndb/src/common/transporter/SHM_Transporter.hpp b/ndb/src/common/transporter/SHM_Transporter.hpp index e7a76225471..b25f9e538db 100644 --- a/ndb/src/common/transporter/SHM_Transporter.hpp +++ b/ndb/src/common/transporter/SHM_Transporter.hpp @@ -170,6 +170,8 @@ private: bool hasDataToRead() const { return reader->empty() == false; } + + void make_error_info(char info[], int sz); }; #endif diff --git a/ndb/src/common/transporter/SHM_Transporter.unix.cpp b/ndb/src/common/transporter/SHM_Transporter.unix.cpp index 28882324fc0..7277f9e13ef 100644 --- a/ndb/src/common/transporter/SHM_Transporter.unix.cpp +++ b/ndb/src/common/transporter/SHM_Transporter.unix.cpp @@ -26,6 +26,12 @@ #include <sys/ipc.h> #include <sys/shm.h> +void SHM_Transporter::make_error_info(char info[], int sz) +{ + snprintf(info,sz,"Shm key=%d sz=%d id=%d", + shmKey, shmSize, shmId); +} + bool SHM_Transporter::ndb_shm_create() { @@ -64,12 +70,30 @@ SHM_Transporter::checkConnected(){ struct shmid_ds info; const int res = shmctl(shmId, IPC_STAT, &info); if(res == -1){ - report_error(TE_SHM_IPC_STAT); + char buf[128]; + int r= snprintf(buf, sizeof(buf), + "shmctl(%d, IPC_STAT) errno: %d(%s). ", shmId, + errno, strerror(errno)); + make_error_info(buf+r, sizeof(buf)-r); + DBUG_PRINT("error",(buf)); + switch (errno) + { + case EACCES: + report_error(TE_SHM_IPC_PERMANENT, buf); + break; + default: + report_error(TE_SHM_IPC_STAT, buf); + break; + } return false; } if(info.shm_nattch != 2){ + char buf[128]; + make_error_info(buf, sizeof(buf)); report_error(TE_SHM_DISCONNECT); + DBUG_PRINT("error", ("Already connected to node %d", + remoteNodeId)); return false; } return true; @@ -91,6 +115,8 @@ SHM_Transporter::disconnectImpl(){ if(isServer && _shmSegCreated){ const int res = shmctl(shmId, IPC_RMID, 0); if(res == -1){ + char buf[64]; + make_error_info(buf, sizeof(buf)); report_error(TE_SHM_UNABLE_TO_REMOVE_SEGMENT); return; } diff --git a/ndb/src/common/transporter/SHM_Transporter.win32.cpp b/ndb/src/common/transporter/SHM_Transporter.win32.cpp index c289a85da0e..86029b17885 100644 --- a/ndb/src/common/transporter/SHM_Transporter.win32.cpp +++ b/ndb/src/common/transporter/SHM_Transporter.win32.cpp @@ -26,6 +26,12 @@ #include <windows.h> +void SHM_Transporter::make_error_info(char info[], int sz) +{ + snprintf(info,sz,"Shm key=%d sz=%d", + shmKey, shmSize); +} + bool SHM_Transporter::connectServer(Uint32 timeOutMillis){ if(!_shmSegCreated) diff --git a/ndb/src/common/transporter/Transporter.hpp b/ndb/src/common/transporter/Transporter.hpp index c9f4e9bda42..9e8bbd687ee 100644 --- a/ndb/src/common/transporter/Transporter.hpp +++ b/ndb/src/common/transporter/Transporter.hpp @@ -161,7 +161,8 @@ protected: TransporterRegistry &m_transporter_registry; void *get_callback_obj() { return m_transporter_registry.callbackObj; }; void report_disconnect(int err){m_transporter_registry.report_disconnect(remoteNodeId,err);}; - void report_error(enum TransporterError err){reportError(get_callback_obj(),remoteNodeId,err);}; + void report_error(enum TransporterError err, const char *info = 0) + { reportError(get_callback_obj(), remoteNodeId, err, info); }; }; inline diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp index 3937f1fc98b..f0e50729f8d 100644 --- a/ndb/src/common/transporter/TransporterRegistry.cpp +++ b/ndb/src/common/transporter/TransporterRegistry.cpp @@ -1508,8 +1508,8 @@ TransporterRegistry::startReceiving() { DBUG_PRINT("error",("Install failed")); g_eventLogger.error("Failed to install signal handler for" - " SHM transporter errno: %d (%s)", errno, - strerror(errno)); + " SHM transporter, signum %d, errno: %d (%s)", + g_ndb_shm_signum, errno, strerror(errno)); } } #endif // NDB_SHM_TRANSPORTER diff --git a/ndb/src/common/util/SimpleProperties.cpp b/ndb/src/common/util/SimpleProperties.cpp index c25aaea491a..c9251c6a854 100644 --- a/ndb/src/common/util/SimpleProperties.cpp +++ b/ndb/src/common/util/SimpleProperties.cpp @@ -51,11 +51,12 @@ SimpleProperties::Writer::add(const char * value, int len){ union { Uint32 lastWord; char lastBytes[4]; - }; - memcpy(lastBytes, + } tmp; + tmp.lastWord =0 ; + memcpy(tmp.lastBytes, value + putLen*4, len - putLen*4); - return putWord(lastWord); + return putWord(tmp.lastWord); } bool diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 34545d4c7ff..2379bd6cf21 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -69,6 +69,109 @@ static const Uint32 BACKUP_SEQUENCE = 0x1F000000; static Uint32 g_TypeOfStart = NodeState::ST_ILLEGAL_TYPE; +#define SEND_BACKUP_STARTED_FLAG(A) (((A) & 0x3) > 0) +#define SEND_BACKUP_COMPLETED_FLAG(A) (((A) & 0x3) > 1) + +void +Backup::execREAD_CONFIG_REQ(Signal* signal) +{ + jamEntry(); + + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + c_nodePool.setSize(MAX_NDB_NODES); + + Uint32 noBackups = 0, noTables = 0, noAttribs = 0; + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_DISCLESS, &m_diskless)); + ndb_mgm_get_int_parameter(p, CFG_DB_PARALLEL_BACKUPS, &noBackups); + // ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_TABLES, &noTables)); + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_TABLE, &noTables)); + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_ATTRIBUTES, &noAttribs)); + + noAttribs++; //RT 527 bug fix + + c_backupPool.setSize(noBackups); + c_backupFilePool.setSize(3 * noBackups); + c_tablePool.setSize(noBackups * noTables); + c_attributePool.setSize(noBackups * noAttribs); + c_triggerPool.setSize(noBackups * 3 * noTables); + + // 2 = no of replicas + c_fragmentPool.setSize(noBackups * 2 * NO_OF_FRAG_PER_NODE * noTables); + + Uint32 szMem = 0; + ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_MEM, &szMem); + Uint32 noPages = (szMem + sizeof(Page32) - 1) / sizeof(Page32); + // We need to allocate an additional of 2 pages. 1 page because of a bug in + // ArrayPool and another one for DICTTAINFO. + c_pagePool.setSize(noPages + NO_OF_PAGES_META_FILE + 2); + + Uint32 szDataBuf = (2 * 1024 * 1024); + Uint32 szLogBuf = (2 * 1024 * 1024); + Uint32 szWrite = 32768; + ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_DATA_BUFFER_MEM, &szDataBuf); + ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_LOG_BUFFER_MEM, &szLogBuf); + ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_WRITE_SIZE, &szWrite); + + c_defaults.m_logBufferSize = szLogBuf; + c_defaults.m_dataBufferSize = szDataBuf; + c_defaults.m_minWriteSize = szWrite; + c_defaults.m_maxWriteSize = szWrite; + + { // Init all tables + ArrayList<Table> tables(c_tablePool); + TablePtr ptr; + while(tables.seize(ptr)){ + new (ptr.p) Table(c_attributePool, c_fragmentPool); + } + tables.release(); + } + + { + ArrayList<BackupFile> ops(c_backupFilePool); + BackupFilePtr ptr; + while(ops.seize(ptr)){ + new (ptr.p) BackupFile(* this, c_pagePool); + } + ops.release(); + } + + { + ArrayList<BackupRecord> recs(c_backupPool); + BackupRecordPtr ptr; + while(recs.seize(ptr)){ + new (ptr.p) BackupRecord(* this, c_pagePool, c_tablePool, + c_backupFilePool, c_triggerPool); + } + recs.release(); + } + + // Initialize BAT for interface to file system + { + Page32Ptr p; + ndbrequire(c_pagePool.seizeId(p, 0)); + c_startOfPages = (Uint32 *)p.p; + c_pagePool.release(p); + + NewVARIABLE* bat = allocateBat(1); + bat[0].WA = c_startOfPages; + bat[0].nrr = c_pagePool.getSize()*sizeof(Page32)/sizeof(Uint32); + } + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +} + void Backup::execSTTOR(Signal* signal) { @@ -852,23 +955,24 @@ Backup::execBACKUP_REQ(Signal* signal) const Uint32 senderData = req->senderData; const BlockReference senderRef = signal->senderBlockRef(); const Uint32 dataLen32 = req->backupDataLen; // In 32 bit words - + const Uint32 flags = signal->getLength() > 2 ? req->flags : 2; + if(getOwnNodeId() != getMasterNodeId()) { jam(); - sendBackupRef(senderRef, signal, senderData, BackupRef::IAmNotMaster); + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::IAmNotMaster); return; }//if if (m_diskless) { - sendBackupRef(senderRef, signal, senderData, + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::CannotBackupDiskless); return; } if(dataLen32 != 0) { jam(); - sendBackupRef(senderRef, signal, senderData, + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::BackupDefinitionNotImplemented); return; }//if @@ -883,7 +987,7 @@ Backup::execBACKUP_REQ(Signal* signal) c_backups.seize(ptr); if(ptr.i == RNIL) { jam(); - sendBackupRef(senderRef, signal, senderData, BackupRef::OutOfBackupRecord); + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::OutOfBackupRecord); return; }//if @@ -894,6 +998,7 @@ Backup::execBACKUP_REQ(Signal* signal) ptr.p->errorCode = 0; ptr.p->clientRef = senderRef; ptr.p->clientData = senderData; + ptr.p->flags = flags; ptr.p->masterRef = reference(); ptr.p->nodes = c_aliveNodes; ptr.p->backupId = 0; @@ -931,20 +1036,23 @@ void Backup::sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode) { jam(); - sendBackupRef(ptr.p->clientRef, signal, ptr.p->clientData, errorCode); + sendBackupRef(ptr.p->clientRef, ptr.p->flags, signal, ptr.p->clientData, errorCode); cleanup(signal, ptr); } void -Backup::sendBackupRef(BlockReference senderRef, Signal *signal, +Backup::sendBackupRef(BlockReference senderRef, Uint32 flags, Signal *signal, Uint32 senderData, Uint32 errorCode) { jam(); - BackupRef* ref = (BackupRef*)signal->getDataPtrSend(); - ref->senderData = senderData; - ref->errorCode = errorCode; - ref->masterRef = numberToRef(BACKUP, getMasterNodeId()); - sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB); + if (SEND_BACKUP_STARTED_FLAG(flags)) + { + BackupRef* ref = (BackupRef*)signal->getDataPtrSend(); + ref->senderData = senderData; + ref->errorCode = errorCode; + ref->masterRef = numberToRef(BACKUP, getMasterNodeId()); + sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB); + } if(errorCode != BackupRef::IAmNotMaster){ signal->theData[0] = NDB_LE_BackupFailedToStart; @@ -1098,6 +1206,7 @@ Backup::sendDefineBackupReq(Signal *signal, BackupRecordPtr ptr) req->backupKey[1] = ptr.p->backupKey[1]; req->nodes = ptr.p->nodes; req->backupDataLen = ptr.p->backupDataLen; + req->flags = ptr.p->flags; ptr.p->masterData.gsn = GSN_DEFINE_BACKUP_REQ; ptr.p->masterData.sendCounter = ptr.p->nodes; @@ -1193,13 +1302,18 @@ Backup::defineBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) /** * Reply to client */ - BackupConf * conf = (BackupConf*)signal->getDataPtrSend(); - conf->backupId = ptr.p->backupId; - conf->senderData = ptr.p->clientData; - conf->nodes = ptr.p->nodes; - sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal, - BackupConf::SignalLength, JBB); - + CRASH_INSERTION((10034)); + + if (SEND_BACKUP_STARTED_FLAG(ptr.p->flags)) + { + BackupConf * conf = (BackupConf*)signal->getDataPtrSend(); + conf->backupId = ptr.p->backupId; + conf->senderData = ptr.p->clientData; + conf->nodes = ptr.p->nodes; + sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal, + BackupConf::SignalLength, JBB); + } + signal->theData[0] = NDB_LE_BackupStarted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2080,19 +2194,22 @@ Backup::stopBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) if(!ptr.p->checkError()) { - BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend(); - rep->backupId = ptr.p->backupId; - rep->senderData = ptr.p->clientData; - rep->startGCP = ptr.p->startGCP; - rep->stopGCP = ptr.p->stopGCP; - rep->noOfBytes = ptr.p->noOfBytes; - rep->noOfRecords = ptr.p->noOfRecords; - rep->noOfLogBytes = ptr.p->noOfLogBytes; - rep->noOfLogRecords = ptr.p->noOfLogRecords; - rep->nodes = ptr.p->nodes; - sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal, - BackupCompleteRep::SignalLength, JBB); - + if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) + { + BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend(); + rep->backupId = ptr.p->backupId; + rep->senderData = ptr.p->clientData; + rep->startGCP = ptr.p->startGCP; + rep->stopGCP = ptr.p->stopGCP; + rep->noOfBytes = ptr.p->noOfBytes; + rep->noOfRecords = ptr.p->noOfRecords; + rep->noOfLogBytes = ptr.p->noOfLogBytes; + rep->noOfLogRecords = ptr.p->noOfLogRecords; + rep->nodes = ptr.p->nodes; + sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal, + BackupCompleteRep::SignalLength, JBB); + } + signal->theData[0] = NDB_LE_BackupCompleted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2129,13 +2246,15 @@ Backup::masterAbort(Signal* signal, BackupRecordPtr ptr) return; } - BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend(); - rep->backupId = ptr.p->backupId; - rep->senderData = ptr.p->clientData; - rep->reason = ptr.p->errorCode; - sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal, - BackupAbortRep::SignalLength, JBB); - + if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) + { + BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend(); + rep->backupId = ptr.p->backupId; + rep->senderData = ptr.p->clientData; + rep->reason = ptr.p->errorCode; + sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal, + BackupAbortRep::SignalLength, JBB); + } signal->theData[0] = NDB_LE_BackupAborted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2267,6 +2386,13 @@ Backup::execDEFINE_BACKUP_REQ(Signal* signal) ptr.p->errorCode = 0; ptr.p->clientRef = req->clientRef; ptr.p->clientData = req->clientData; + if(senderRef == reference()) + ptr.p->flags = req->flags; + else + ptr.p->flags = req->flags & ~((Uint32)0x3); /* remove waitCompleted flags + * as non master should never + * reply + */ ptr.p->masterRef = senderRef; ptr.p->nodes = req->nodes; ptr.p->backupId = backupId; @@ -3236,6 +3362,7 @@ Backup::execBACKUP_FRAGMENT_REQ(Signal* signal) req->requestInfo = 0; req->savePointId = 0; req->tableId = table.tableId; + ScanFragReq::setReadCommittedFlag(req->requestInfo, 1); ScanFragReq::setLockMode(req->requestInfo, 0); ScanFragReq::setHoldLockFlag(req->requestInfo, 0); ScanFragReq::setKeyinfoFlag(req->requestInfo, 0); diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp index ab2bec7dad7..c455e32fa67 100644 --- a/ndb/src/kernel/blocks/backup/Backup.hpp +++ b/ndb/src/kernel/blocks/backup/Backup.hpp @@ -46,6 +46,7 @@ public: protected: void execSTTOR(Signal* signal); + void execREAD_CONFIG_REQ(Signal* signal); void execDUMP_STATE_ORD(Signal* signal); void execREAD_NODESCONF(Signal* signal); void execNODE_FAILREP(Signal* signal); @@ -412,6 +413,7 @@ public: Uint32 clientRef; Uint32 clientData; + Uint32 flags; Uint32 backupId; Uint32 backupKey[2]; Uint32 masterRef; @@ -592,7 +594,7 @@ public: bool insertFileHeader(BackupFormat::FileType, BackupRecord*, BackupFile*); void sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode); - void sendBackupRef(BlockReference ref, Signal *signal, + void sendBackupRef(BlockReference ref, Uint32 flags, Signal *signal, Uint32 senderData, Uint32 errorCode); void dumpUsedResources(); void cleanup(Signal*, BackupRecordPtr ptr); diff --git a/ndb/src/kernel/blocks/backup/BackupInit.cpp b/ndb/src/kernel/blocks/backup/BackupInit.cpp index 2c36896e34c..4c734d58c8e 100644 --- a/ndb/src/kernel/blocks/backup/BackupInit.cpp +++ b/ndb/src/kernel/blocks/backup/BackupInit.cpp @@ -34,90 +34,10 @@ Backup::Backup(const Configuration & conf) : { BLOCK_CONSTRUCTOR(Backup); - c_nodePool.setSize(MAX_NDB_NODES); c_masterNodeId = getOwnNodeId(); - const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator(); - ndbrequire(p != 0); - - Uint32 noBackups = 0, noTables = 0, noAttribs = 0; - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_DISCLESS, &m_diskless)); - ndb_mgm_get_int_parameter(p, CFG_DB_PARALLEL_BACKUPS, &noBackups); - // ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_TABLES, &noTables)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_TABLE, &noTables)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_ATTRIBUTES, &noAttribs)); - - noAttribs++; //RT 527 bug fix - - c_backupPool.setSize(noBackups); - c_backupFilePool.setSize(3 * noBackups); - c_tablePool.setSize(noBackups * noTables); - c_attributePool.setSize(noBackups * noAttribs); - c_triggerPool.setSize(noBackups * 3 * noTables); - - // 2 = no of replicas - c_fragmentPool.setSize(noBackups * 2 * NO_OF_FRAG_PER_NODE * noTables); - - Uint32 szMem = 0; - ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_MEM, &szMem); - Uint32 noPages = (szMem + sizeof(Page32) - 1) / sizeof(Page32); - // We need to allocate an additional of 2 pages. 1 page because of a bug in - // ArrayPool and another one for DICTTAINFO. - c_pagePool.setSize(noPages + NO_OF_PAGES_META_FILE + 2); - - Uint32 szDataBuf = (2 * 1024 * 1024); - Uint32 szLogBuf = (2 * 1024 * 1024); - Uint32 szWrite = 32768; - ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_DATA_BUFFER_MEM, &szDataBuf); - ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_LOG_BUFFER_MEM, &szLogBuf); - ndb_mgm_get_int_parameter(p, CFG_DB_BACKUP_WRITE_SIZE, &szWrite); - - c_defaults.m_logBufferSize = szLogBuf; - c_defaults.m_dataBufferSize = szDataBuf; - c_defaults.m_minWriteSize = szWrite; - c_defaults.m_maxWriteSize = szWrite; - - { // Init all tables - ArrayList<Table> tables(c_tablePool); - TablePtr ptr; - while(tables.seize(ptr)){ - new (ptr.p) Table(c_attributePool, c_fragmentPool); - } - tables.release(); - } - - { - ArrayList<BackupFile> ops(c_backupFilePool); - BackupFilePtr ptr; - while(ops.seize(ptr)){ - new (ptr.p) BackupFile(* this, c_pagePool); - } - ops.release(); - } - - { - ArrayList<BackupRecord> recs(c_backupPool); - BackupRecordPtr ptr; - while(recs.seize(ptr)){ - new (ptr.p) BackupRecord(* this, c_pagePool, c_tablePool, - c_backupFilePool, c_triggerPool); - } - recs.release(); - } - - // Initialize BAT for interface to file system - { - Page32Ptr p; - ndbrequire(c_pagePool.seizeId(p, 0)); - c_startOfPages = (Uint32 *)p.p; - c_pagePool.release(p); - - NewVARIABLE* bat = allocateBat(1); - bat[0].WA = c_startOfPages; - bat[0].nrr = c_pagePool.getSize()*sizeof(Page32)/sizeof(Uint32); - } - // Add received signals + addRecSignal(GSN_READ_CONFIG_REQ, &Backup::execREAD_CONFIG_REQ); addRecSignal(GSN_STTOR, &Backup::execSTTOR); addRecSignal(GSN_DUMP_STATE_ORD, &Backup::execDUMP_STATE_ORD); addRecSignal(GSN_READ_NODESCONF, &Backup::execREAD_NODESCONF); diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp index 6f6aee6a7f7..657fc8e5896 100644 --- a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp +++ b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp @@ -72,6 +72,7 @@ Cmvmi::Cmvmi(const Configuration & conf) : addRecSignal(GSN_SET_LOGLEVELORD, &Cmvmi::execSET_LOGLEVELORD); addRecSignal(GSN_EVENT_REP, &Cmvmi::execEVENT_REP); addRecSignal(GSN_STTOR, &Cmvmi::execSTTOR); + addRecSignal(GSN_READ_CONFIG_REQ, &Cmvmi::execREAD_CONFIG_REQ); addRecSignal(GSN_CLOSE_COMREQ, &Cmvmi::execCLOSE_COMREQ); addRecSignal(GSN_ENABLE_COMORD, &Cmvmi::execENABLE_COMORD); addRecSignal(GSN_OPEN_COMREQ, &Cmvmi::execOPEN_COMREQ); @@ -189,6 +190,12 @@ void Cmvmi::execEVENT_REP(Signal* signal) //----------------------------------------------------------------------- EventReport * const eventReport = (EventReport *)&signal->theData[0]; Ndb_logevent_type eventType = eventReport->getEventType(); + Uint32 nodeId= eventReport->getNodeId(); + if (nodeId == 0) + { + nodeId= refToNode(signal->getSendersBlockRef()); + eventReport->setNodeId(nodeId); + } jamEntry(); @@ -301,6 +308,27 @@ void Cmvmi::sendSTTORRY(Signal* signal) }//Cmvmi::sendSTTORRY +void +Cmvmi::execREAD_CONFIG_REQ(Signal* signal) +{ + jamEntry(); + + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +} + void Cmvmi::execSTTOR(Signal* signal) { Uint32 theStartPhase = signal->theData[1]; diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp index 1c91f564749..f89c8f15e86 100644 --- a/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp +++ b/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp @@ -48,6 +48,7 @@ private: void execNDB_TAMPER(Signal* signal); void execSET_LOGLEVELORD(Signal* signal); void execEVENT_REP(Signal* signal); + void execREAD_CONFIG_REQ(Signal* signal); void execSTTOR(Signal* signal); void execCLOSE_COMREQ(Signal* signal); void execENABLE_COMORD(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp index 1da6c56b0e3..afec0b9e3b1 100644 --- a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp +++ b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp @@ -1071,7 +1071,7 @@ private: void seizeRootfragrec(Signal* signal); void seizeScanRec(Signal* signal); void seizeSrVerRec(Signal* signal); - void sendSystemerror(Signal* signal); + void sendSystemerror(Signal* signal, int line); void takeRecOutOfFreeOverdir(Signal* signal); void takeRecOutOfFreeOverpage(Signal* signal); void sendScanHbRep(Signal* signal, Uint32); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp index d03f3b55d6a..59a622b60e6 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp @@ -59,10 +59,24 @@ void Dbacc::initData() void Dbacc::initRecords() { // Records with dynamic sizes + page8 = (Page8*)allocRecord("Page8", + sizeof(Page8), + cpagesize, + false); + + operationrec = (Operationrec*)allocRecord("Operationrec", + sizeof(Operationrec), + coprecsize); + dirRange = (DirRange*)allocRecord("DirRange", sizeof(DirRange), cdirrangesize); + undopage = (Undopage*)allocRecord("Undopage", + sizeof(Undopage), + cundopagesize, + false); + directoryarray = (Directoryarray*)allocRecord("Directoryarray", sizeof(Directoryarray), cdirarraysize); @@ -83,19 +97,10 @@ void Dbacc::initRecords() sizeof(LcpConnectrec), clcpConnectsize); - operationrec = (Operationrec*)allocRecord("Operationrec", - sizeof(Operationrec), - coprecsize); - overflowRecord = (OverflowRecord*)allocRecord("OverflowRecord", sizeof(OverflowRecord), coverflowrecsize); - page8 = (Page8*)allocRecord("Page8", - sizeof(Page8), - cpagesize, - false); - rootfragmentrec = (Rootfragmentrec*)allocRecord("Rootfragmentrec", sizeof(Rootfragmentrec), crootfragmentsize); @@ -112,11 +117,6 @@ void Dbacc::initRecords() sizeof(Tabrec), ctablesize); - undopage = (Undopage*)allocRecord("Undopage", - sizeof(Undopage), - cundopagesize, - false); - // Initialize BAT for interface to file system NewVARIABLE* bat = allocateBat(3); @@ -136,25 +136,8 @@ Dbacc::Dbacc(const class Configuration & conf): SimulatedBlock(DBACC, conf), c_tup(0) { - Uint32 log_page_size= 0; BLOCK_CONSTRUCTOR(Dbacc); - const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator(); - ndbrequire(p != 0); - - ndb_mgm_get_int_parameter(p, CFG_DB_UNDO_INDEX_BUFFER, - &log_page_size); - - /** - * Always set page size in half MBytes - */ - cundopagesize= (log_page_size / sizeof(Undopage)); - Uint32 mega_byte_part= cundopagesize & 15; - if (mega_byte_part != 0) { - jam(); - cundopagesize+= (16 - mega_byte_part); - } - // Transit signals addRecSignal(GSN_DUMP_STATE_ORD, &Dbacc::execDUMP_STATE_ORD); addRecSignal(GSN_DEBUG_SIG, &Dbacc::execDEBUG_SIG); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index f4b084c42fb..261a0acfa81 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -55,8 +55,7 @@ Dbacc::remainingUndoPages(){ // There can not be more than cundopagesize remaining if (Remaining <= 0){ // No more undolog, crash node - progError(__LINE__, - ERR_NO_MORE_UNDOLOG, + progError(__LINE__, NDBD_EXIT_NO_MORE_UNDOLOG, "There are more than 1Mbyte undolog writes outstanding"); } return Remaining; @@ -679,6 +678,20 @@ void Dbacc::execREAD_CONFIG_REQ(Signal* signal) theConfiguration.getOwnConfigIterator(); ndbrequire(p != 0); + Uint32 log_page_size= 0; + ndb_mgm_get_int_parameter(p, CFG_DB_UNDO_INDEX_BUFFER, + &log_page_size); + + /** + * Always set page size in half MBytes + */ + cundopagesize= (log_page_size / sizeof(Undopage)); + Uint32 mega_byte_part= cundopagesize & 15; + if (mega_byte_part != 0) { + jam(); + cundopagesize+= (16 - mega_byte_part); + } + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_DIR_RANGE, &cdirrangesize)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_DIR_ARRAY, &cdirarraysize)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_FRAGMENT, &cfragmentsize)); @@ -5303,8 +5316,7 @@ void Dbacc::execDEBUG_SIG(Signal* signal) jamEntry(); expPageptr.i = signal->theData[0]; - progError(__LINE__, - ERR_SR_UNDOLOG); + progError(__LINE__, NDBD_EXIT_SR_UNDOLOG); return; }//Dbacc::execDEBUG_SIG() @@ -5617,7 +5629,7 @@ Uint32 Dbacc::checkScanShrink(Signal* signal) //------------------------------------------------------------- } else { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); return TreturnCode; }//if }//if @@ -6045,7 +6057,7 @@ void Dbacc::shrinkcontainer(Signal* signal) fragrecptr.p->expReceiveForward = tidrForward; if (tshrRemLen < tshrInc) { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); }//if tshrRemLen = tshrRemLen - tshrInc; if (tshrRemLen != 0) { @@ -6080,7 +6092,7 @@ void Dbacc::nextcontainerinfoExp(Signal* signal) cexcForward = cminusOne; } else { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); cexcForward = 0; /* DUMMY FOR COMPILER */ }//if if (tnciNextSamePage == ZFALSE) { @@ -6579,7 +6591,7 @@ void Dbacc::execACC_SAVE_PAGES(Signal* signal) ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec); if (lcpConnectptr.p->lcpstate != LCP_ACTIVE) { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); return; }//if if (ERROR_INSERTED(3000)) { @@ -6765,7 +6777,7 @@ void Dbacc::saveOverPagesLab(Signal* signal) releaseOverpage(signal); } else { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); } }//if } @@ -6905,7 +6917,7 @@ void Dbacc::checkSyncUndoPagesLab(Signal* signal) break; default: jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); return; break; }//switch @@ -7188,7 +7200,7 @@ void Dbacc::lcpCopyPage(Signal* signal) /*empty*/; } else { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); return; }//if /*-----------------------------------------------------------------*/ @@ -7209,7 +7221,7 @@ void Dbacc::lcpCopyPage(Signal* signal) /*empty*/; } else { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); return; }//if lcnCopyPageptr.p->word32[ZPOS_CHECKSUM] = tlcnChecksum; @@ -7256,7 +7268,7 @@ void Dbacc::lcpUpdatePage(Signal* signal) }//while if (tlupConLen < ZCON_HEAD_SIZE) { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); }//if }//Dbacc::lcpUpdatePage() @@ -7529,7 +7541,7 @@ void Dbacc::undoWritingProcess(Signal* signal) /* ONLY PAGE INFO AND OVERFLOW PAGE INFO CAN BE LOGGED BY THIS ROUTINE. A */ /* SERIOUS ERROR. */ /* --------------------------------------------------------------------------- */ - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); } } else { if (fragrecptr.p->fragState == LCP_SEND_OVER_PAGES) { @@ -8159,7 +8171,7 @@ void Dbacc::srReadPagesLab(Signal* signal) for (Uint32 i = 0; i < limitLoop; i++) { jam(); seizePage(signal); - ndbrequire(tresult <= ZLIMIT_OF_ERROR); + ndbrequireErr(tresult <= ZLIMIT_OF_ERROR, NDBD_EXIT_SR_OUT_OF_INDEXMEMORY); fragrecptr.p->datapages[i] = spPageptr.i; signal->theData[i + 6] = spPageptr.i; }//for @@ -8532,7 +8544,7 @@ void Dbacc::startActiveUndo(Signal* signal) /*---------------------------------------------------------------------------*/ if (cfsFirstfreeconnect == RNIL) { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); }//if seizeFsConnectRec(signal); cactiveSrFsPtr = fsConnectptr.i; @@ -8709,7 +8721,8 @@ void Dbacc::srDoUndoLab(Signal* signal) ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec); } else { jam(); - progError(__LINE__, 0, "Invalid local fragment id in undo log"); + progError(__LINE__, NDBD_EXIT_SR_UNDOLOG, + "Invalid local fragment id in undo log"); return; }//if }//if @@ -8886,7 +8899,7 @@ void Dbacc::srDoUndoLab(Signal* signal) default: jam(); - progError(__LINE__, 0, "Invalid pagetype in undo log"); + progError(__LINE__, NDBD_EXIT_SR_UNDOLOG, "Invalid pagetype in undo log"); break; }//switch(tpageType) @@ -9356,7 +9369,7 @@ void Dbacc::checkNextBucketLab(Signal* signal) /* --------------------------------------------------------------------------------- */ if (scanPtr.p->minBucketIndexToRescan != 0) { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); return; }//if scanPtr.p->maxBucketIndexToRescan = fragrecptr.p->p + fragrecptr.p->maxp; @@ -9521,7 +9534,7 @@ void Dbacc::checkNextFragmentLab(Signal* signal) } else { jam(); /* ALL ELEMENTS ARE SENT */ - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); }//if }//if /* --------------------------------------------------------------------------------- */ @@ -10119,7 +10132,7 @@ void Dbacc::releaseScanContainer(Signal* signal) if (trscContainerlen < 4) { if (trscContainerlen != ZCON_HEAD_SIZE) { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); }//if return; /* 2 IS THE MINIMUM SIZE OF THE ELEMENT */ }//if @@ -10154,7 +10167,7 @@ void Dbacc::releaseScanContainer(Signal* signal) } while (trscElemlens > 1); if (trscElemlens != 0) { jam(); - sendSystemerror(signal); + sendSystemerror(signal, __LINE__); }//if }//Dbacc::releaseScanContainer() @@ -11271,9 +11284,9 @@ void Dbacc::seizeSrVerRec(Signal* signal) /* --------------------------------------------------------------------------------- */ /* SEND_SYSTEMERROR */ /* --------------------------------------------------------------------------------- */ -void Dbacc::sendSystemerror(Signal* signal) +void Dbacc::sendSystemerror(Signal* signal, int line) { - progError(0, 0); + progError(line, NDBD_EXIT_PRGERR); }//Dbacc::sendSystemerror() /* --------------------------------------------------------------------------------- */ diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 05c5d5d5198..45efaac30bc 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -3214,8 +3214,8 @@ Dbdict::alterTable_backup_mutex_locked(Signal* signal, lreq->gci = tablePtr.p->gciTableCreated; lreq->requestType = AlterTabReq::AlterTablePrepare; - sendSignal(rg, GSN_ALTER_TAB_REQ, signal, - AlterTabReq::SignalLength, JBB); + sendFragmentedSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); } void Dbdict::alterTableRef(Signal * signal, @@ -3699,8 +3699,8 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ lreq->gci = gci; lreq->requestType = AlterTabReq::AlterTableCommit; - sendSignal(rg, GSN_ALTER_TAB_REQ, signal, - AlterTabReq::SignalLength, JBB); + sendFragmentedSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); } } else { @@ -4346,6 +4346,44 @@ Dbdict::createTab_dih(Signal* signal, sendSignal(DBDIH_REF, GSN_DIADDTABREQ, signal, DiAddTabReq::SignalLength, JBB); + + /** + * Create KeyDescriptor + */ + KeyDescriptor* desc= g_key_descriptor_pool.getPtr(tabPtr.i); + new (desc) KeyDescriptor(); + + Uint32 key = 0; + Uint32 tAttr = tabPtr.p->firstAttribute; + while (tAttr != RNIL) + { + jam(); + AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); + if (aRec->tupleKey) + { + desc->noOfKeyAttr ++; + desc->keyAttr[key].attributeDescriptor = aRec->attributeDescriptor; + + Uint32 csNumber = (aRec->extPrecision >> 16); + if(csNumber) + { + desc->keyAttr[key].charsetInfo = all_charsets[csNumber]; + ndbrequire(all_charsets[csNumber]); + desc->hasCharAttr = 1; + } + else + { + desc->keyAttr[key].charsetInfo = 0; + } + if(AttributeDescriptor::getDKey(aRec->attributeDescriptor)) + { + desc->noOfDistrKeys ++; + } + key++; + } + tAttr = aRec->nextAttrInTable; + } + ndbrequire(key == tabPtr.p->noOfPrimkey); } static @@ -4448,44 +4486,6 @@ Dbdict::execADD_FRAGREQ(Signal* signal) { sendSignal(DBLQH_REF, GSN_LQHFRAGREQ, signal, LqhFragReq::SignalLength, JBB); } - - /** - * Create KeyDescriptor - */ - KeyDescriptor* desc= g_key_descriptor_pool.getPtr(tabPtr.i); - new (desc) KeyDescriptor(); - - Uint32 key = 0; - Uint32 tAttr = tabPtr.p->firstAttribute; - while (tAttr != RNIL) - { - jam(); - AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); - if (aRec->tupleKey) - { - desc->noOfKeyAttr ++; - desc->keyAttr[key].attributeDescriptor = aRec->attributeDescriptor; - - Uint32 csNumber = (aRec->extPrecision >> 16); - if(csNumber) - { - desc->keyAttr[key].charsetInfo = all_charsets[csNumber]; - ndbrequire(all_charsets[csNumber]); - desc->hasCharAttr = 1; - } - else - { - desc->keyAttr[key].charsetInfo = 0; - } - if(AttributeDescriptor::getDKey(aRec->attributeDescriptor)) - { - desc->noOfDistrKeys ++; - } - key++; - } - tAttr = aRec->nextAttrInTable; - } - ndbrequire(key == tabPtr.p->noOfPrimkey); } void @@ -5326,7 +5326,10 @@ void Dbdict::execWAIT_GCP_REF(Signal* signal) /* ---------------------------------------------------------------- */ // Error Handling code needed /* ---------------------------------------------------------------- */ - progError(ref->errorCode, 0); + char buf[32]; + BaseString::snprintf(buf, sizeof(buf), "WAIT_GCP_REF ErrorCode=%d", + ref->errorCode); + progError(__LINE__, NDBD_EXIT_NDBREQUIRE, buf); }//execWAIT_GCP_REF() diff --git a/ndb/src/kernel/blocks/dbdict/Makefile.am b/ndb/src/kernel/blocks/dbdict/Makefile.am index 9a0d68f8148..3c1cf6735d9 100644 --- a/ndb/src/kernel/blocks/dbdict/Makefile.am +++ b/ndb/src/kernel/blocks/dbdict/Makefile.am @@ -1,12 +1,20 @@ -#SUBDIRS = printSchemafile - noinst_LIBRARIES = libdbdict.a +EXTRA_PROGRAMS = printSchemaFile libdbdict_a_SOURCES = Dbdict.cpp +printSchemaFile_SOURCES = printSchemaFile.cpp + include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_kernel.mk.am +LDADD += \ + $(top_builddir)/ndb/src/common/util/libgeneral.la \ + $(top_builddir)/ndb/src/common/portlib/libportlib.la \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/strings/libmystrings.a + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp b/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp index 9858744a61d..f73654fd9d5 100644 --- a/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp +++ b/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp @@ -1,14 +1,3 @@ -#if 0 -make -f Makefile -f - printSchemaFile <<'_eof_' -printSchemaFile: printSchemaFile.cpp SchemaFile.hpp - $(CXXCOMPILE) -o $@ $@.cpp -L../../../common/util/.libs -lgeneral -ifneq ($(MYSQL_HOME),) - ln -sf `pwd`/$@ $(MYSQL_HOME)/bin/$@ -endif -_eof_ -exit $? -#endif - /* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -36,14 +25,19 @@ exit $? static const char* progname = 0; static bool allflag = false; static bool checkonly = false; -static int xitcode = 0; +static bool equalcontents = false; +static bool okquiet = false; static void usage() { - ndbout << "Usage " << progname - << " [-ac]" - << " P0.SchemaLog" << endl; + ndbout + << "Usage: " << progname << " [-aceq]" << " file ..." << endl + << "-a print also unused slots" << endl + << "-c check only (return status 1 on error)" << endl + << "-e check also that the files have identical contents" << endl + << "-q no output if file is ok" << endl + << "Example: " << progname << " -ceq ndb_*_fs/D[12]/DBDICT/P0.SchemaLog" << endl; } static void @@ -57,53 +51,78 @@ fill(const char * buf, int mod) } } -static void +static const char* +version(Uint32 v) +{ + static char buf[40]; + sprintf(buf, "%d.%d.%d", v >> 16, (v >> 8) & 0xFF, v & 0xFF); + return buf; +} + +static int print_head(const char * filename, const SchemaFile * sf) { + int retcode = 0; + if (! checkonly) { ndbout << "----- Schemafile: " << filename << " -----" << endl; - ndbout_c("Magic: %.*s ByteOrder: %.8x NdbVersion: %d.%d.%d FileSize: %d", + ndbout_c("Magic: %.*s ByteOrder: %.8x NdbVersion: %s FileSize: %d", sizeof(sf->Magic), sf->Magic, sf->ByteOrder, - sf->NdbVersion >> 16, - (sf->NdbVersion >> 8) & 0xFF, - sf->NdbVersion & 0xFF, + version(sf->NdbVersion), sf->FileSize); } + + if (memcmp(sf->Magic, "NDBSCHMA", sizeof(sf->Magic) != 0)) { + ndbout << filename << ": invalid header magic" << endl; + retcode = 1; + } + + if ((sf->NdbVersion >> 16) < 4 || (sf->NdbVersion >> 16) > 9) { + ndbout << filename << ": impossible version " << hex << sf->NdbVersion << endl; + retcode = 1; + } + + return retcode; } -static void -print_old(const char * filename, const SchemaFile * sf) +static int +print_old(const char * filename, const SchemaFile * sf, Uint32 sz) { - print_head(filename, sf); + int retcode = 0; + + if (print_head(filename, sf) != 0) + retcode = 1; for (Uint32 i = 0; i < sf->NoOfTableEntries; i++) { SchemaFile::TableEntry_old te = sf->TableEntries_old[i]; if (allflag || (te.m_tableState != SchemaFile::INIT && te.m_tableState != SchemaFile::DROP_TABLE_COMMITTED)) { - ndbout << "Table " << i << ":" - << " State = " << te.m_tableState - << " version = " << table_version_major(te.m_tableVersion) << - << "(" << table_version_minor(te.m_tableVersion) << ")" - << " type = " << te.m_tableType - << " noOfPages = " << te.m_noOfPages - << " gcp: " << te.m_gcp << endl; + if (! checkonly) + ndbout << "Table " << i << ":" + << " State = " << te.m_tableState + << " version = " << te.m_tableVersion + << " type = " << te.m_tableType + << " noOfPages = " << te.m_noOfPages + << " gcp: " << te.m_gcp << endl; } } + return retcode; } -static void +static int print(const char * filename, const SchemaFile * xsf, Uint32 sz) { int retcode = 0; - print_head(filename, xsf); + if (print_head(filename, xsf) != 0) + retcode = 1; assert(sizeof(SchemaFile) == NDB_SF_PAGE_SIZE); if (xsf->FileSize != sz || xsf->FileSize % NDB_SF_PAGE_SIZE != 0) { - ndbout << "***** invalid FileSize " << xsf->FileSize << endl; + ndbout << filename << ": invalid FileSize " << xsf->FileSize << endl; retcode = 1; } Uint32 noOfPages = xsf->FileSize / NDB_SF_PAGE_SIZE; @@ -112,19 +131,23 @@ print(const char * filename, const SchemaFile * xsf, Uint32 sz) ndbout << "----- Page: " << n << " (" << noOfPages << ") -----" << endl; } const SchemaFile * sf = &xsf[n]; + if (memcmp(sf->Magic, xsf->Magic, sizeof(sf->Magic)) != 0) { + ndbout << filename << ": page " << n << " invalid magic" << endl; + retcode = 1; + } if (sf->FileSize != xsf->FileSize) { - ndbout << "***** page " << n << " FileSize changed to " << sf->FileSize << "!=" << xsf->FileSize << endl; + ndbout << filename << ": page " << n << " FileSize changed to " << sf->FileSize << "!=" << xsf->FileSize << endl; retcode = 1; } Uint32 cs = 0; for (Uint32 j = 0; j < NDB_SF_PAGE_SIZE_IN_WORDS; j++) cs ^= ((const Uint32*)sf)[j]; if (cs != 0) { - ndbout << "***** page " << n << " invalid CheckSum" << endl; + ndbout << filename << ": page " << n << " invalid CheckSum" << endl; retcode = 1; } if (sf->NoOfTableEntries != NDB_SF_PAGE_ENTRIES) { - ndbout << "***** page " << n << " invalid NoOfTableEntries " << sf->NoOfTableEntries << endl; + ndbout << filename << ": page " << n << " invalid NoOfTableEntries " << sf->NoOfTableEntries << endl; retcode = 1; } for (Uint32 i = 0; i < NDB_SF_PAGE_ENTRIES; i++) { @@ -142,31 +165,41 @@ print(const char * filename, const SchemaFile * xsf, Uint32 sz) << " gcp: " << te.m_gcp << endl; } if (te.m_unused[0] != 0 || te.m_unused[1] != 0 || te.m_unused[2] != 0) { - ndbout << "***** entry " << j << " garbage in m_unused[3]" << endl; + ndbout << filename << ": entry " << j << " garbage in m_unused[3]" << endl; retcode = 1; } } } - if (retcode != 0) - xitcode = 1; - else if (checkonly) - ndbout << "ok: " << filename << endl; + return retcode; } NDB_COMMAND(printSchemafile, "printSchemafile", "printSchemafile", "Prints a schemafile", 16384) { progname = argv[0]; + int exitcode = 0; - while (argv[1][0] == '-') { + while (argc > 1 && argv[1][0] == '-') { if (strchr(argv[1], 'a') != 0) allflag = true; if (strchr(argv[1], 'c') != 0) checkonly = true; + if (strchr(argv[1], 'e') != 0) + equalcontents = true; + if (strchr(argv[1], 'q') != 0) + okquiet = true; + if (strchr(argv[1], 'h') != 0 || strchr(argv[1], '?') != 0) { + usage(); + return 0; + } argc--, argv++; } + const char * prevfilename = 0; + Uint32 * prevbuf = 0; + Uint32 prevbytes = 0; + while (argc > 1) { const char * filename = argv[1]; argc--, argv++; @@ -174,8 +207,9 @@ NDB_COMMAND(printSchemafile, struct stat sbuf; const int res = stat(filename, &sbuf); if (res != 0) { - ndbout << "Could not find file: \"" << filename << "\"" << endl; - return 1; + ndbout << filename << ": not found errno=" << errno << endl; + exitcode = 1; + continue; } const Uint32 bytes = sbuf.st_size; @@ -183,25 +217,56 @@ NDB_COMMAND(printSchemafile, FILE * f = fopen(filename, "rb"); if (f == 0) { - ndbout << "Failed to open file" << endl; + ndbout << filename << ": open failed errno=" << errno << endl; delete [] buf; - return 1; + exitcode = 1; + continue; } Uint32 sz = fread(buf, 1, bytes, f); fclose(f); if (sz != bytes) { - ndbout << "Failure while reading file" << endl; + ndbout << filename << ": read failed errno=" << errno << endl; + delete [] buf; + exitcode = 1; + continue; + } + + if (sz < 32) { + ndbout << filename << ": too short (no header)" << endl; delete [] buf; - return 1; + exitcode = 1; + continue; } SchemaFile* sf = (SchemaFile *)&buf[0]; + int ret; if (sf->NdbVersion < NDB_SF_VERSION_5_0_6) - print_old(filename, sf); + ret = print_old(filename, sf, sz); else - print(filename, sf, sz); - delete [] buf; + ret = print(filename, sf, sz); + + if (ret != 0) { + ndbout << filename << ": check failed" + << " version=" << version(sf->NdbVersion) << endl; + exitcode = 1; + } else if (! okquiet) { + ndbout << filename << ": ok" + << " version=" << version(sf->NdbVersion) << endl; + } + + if (equalcontents && prevfilename != 0) { + if (prevbytes != bytes || memcmp(prevbuf, buf, bytes) != 0) { + ndbout << filename << ": differs from " << prevfilename << endl; + exitcode = 1; + } + } + + prevfilename = filename; + delete [] prevbuf; + prevbuf = buf; + prevbytes = bytes; } - return xitcode; + delete [] prevbuf; + return exitcode; } diff --git a/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp b/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp index 1c14163fe76..d6f6b772516 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp @@ -262,8 +262,18 @@ Dbdih::Dbdih(const class Configuration & config): addRecSignal(GSN_CREATE_FRAGMENTATION_REQ, &Dbdih::execCREATE_FRAGMENTATION_REQ); - - initData(); + + apiConnectRecord = 0; + connectRecord = 0; + fileRecord = 0; + fragmentstore = 0; + pageRecord = 0; + replicaRecord = 0; + tabRecord = 0; + createReplicaRecord = 0; + nodeGroupRecord = 0; + nodeRecord = 0; + takeOverRecord = 0; }//Dbdih::Dbdih() Dbdih::~Dbdih() diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 55353dca0b5..29de0368212 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -1051,17 +1051,25 @@ void Dbdih::execREAD_CONFIG_REQ(Signal* signal) const ndb_mgm_configuration_iterator * p = theConfiguration.getOwnConfigIterator(); - ndbrequire(p != 0); - - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DIH_API_CONNECT, - &capiConnectFileSize)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DIH_CONNECT,&cconnectFileSize)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DIH_FRAG_CONNECT, - &cfragstoreFileSize)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DIH_REPLICAS, - &creplicaFileSize)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DIH_TABLE, &ctabFileSize)) - cfileFileSize = (2 * ctabFileSize) + 2; + ndbrequireErr(p != 0, NDBD_EXIT_INVALID_CONFIG); + + initData(); + + ndbrequireErr(!ndb_mgm_get_int_parameter(p, CFG_DIH_API_CONNECT, + &capiConnectFileSize), + NDBD_EXIT_INVALID_CONFIG); + ndbrequireErr(!ndb_mgm_get_int_parameter(p, CFG_DIH_CONNECT, + &cconnectFileSize), + NDBD_EXIT_INVALID_CONFIG); + ndbrequireErr(!ndb_mgm_get_int_parameter(p, CFG_DIH_FRAG_CONNECT, + &cfragstoreFileSize), + NDBD_EXIT_INVALID_CONFIG); + ndbrequireErr(!ndb_mgm_get_int_parameter(p, CFG_DIH_REPLICAS, + &creplicaFileSize), + NDBD_EXIT_INVALID_CONFIG); + ndbrequireErr(!ndb_mgm_get_int_parameter(p, CFG_DIH_TABLE, &ctabFileSize), + NDBD_EXIT_INVALID_CONFIG); + cfileFileSize = (2 * ctabFileSize) + 2; initRecords(); initialiseRecordsLab(signal, 0, ref, senderData); return; @@ -1465,9 +1473,7 @@ void Dbdih::execREAD_NODESCONF(Signal* signal) "Illegal configuration change." " Initial start needs to be performed " " when changing no of storage nodes (node %d)", i); - progError(__LINE__, - ERR_INVALID_CONFIG, - buf); + progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, buf); } } @@ -3528,9 +3534,7 @@ void Dbdih::selectMasterCandidateAndSend(Signal* signal) " Initial start needs to be performed " " when changing no of replicas (%d != %d)", node_groups[nodePtr.i], cnoReplicas); - progError(__LINE__, - ERR_INVALID_CONFIG, - buf); + progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, buf); } } }//Dbdih::selectMasterCandidate() @@ -3811,9 +3815,7 @@ void Dbdih::execNODE_FAILREP(Signal* signal) if(getNodeState().getNodeRestartInProgress()){ jam(); - progError(__LINE__, - ERR_SYSTEM_ERROR, - "Unhandle master failure during node restart"); + progError(__LINE__, NDBD_EXIT_MASTER_FAILURE_DURING_NR); } } @@ -8220,7 +8222,7 @@ Dbdih::resetReplicaSr(TabRecordPtr tabPtr){ /* --------------------------------------------------------------- */ /* THE NODE IS ALIVE AND KICKING AND ACTIVE, LET'S USE IT. */ /* --------------------------------------------------------------- */ - arrGuard(noCrashedReplicas, 8); + arrGuardErr(noCrashedReplicas, 8, NDBD_EXIT_MAX_CRASHED_REPLICAS); Uint32 lastGci = replicaPtr.p->replicaLastGci[noCrashedReplicas]; if(lastGci >= newestRestorableGCI){ jam(); @@ -8694,14 +8696,10 @@ void Dbdih::startFragment(Signal* signal, Uint32 tableId, Uint32 fragId) /* THIS WILL DECREASE THE GCI TO RESTORE WHICH HOPEFULLY WILL MAKE IT */ /* POSSIBLE TO RESTORE THE SYSTEM. */ /* --------------------------------------------------------------------- */ - char buf[100]; - BaseString::snprintf(buf, sizeof(buf), - "Unable to find restorable replica for " - "table: %d fragment: %d gci: %d", - tableId, fragId, SYSFILE->newestRestorableGCI); - progError(__LINE__, - ERR_SYSTEM_ERROR, - buf); + char buf[64]; + BaseString::snprintf(buf, sizeof(buf), "table: %d fragment: %d gci: %d", + tableId, fragId, SYSFILE->newestRestorableGCI); + progError(__LINE__, NDBD_EXIT_NO_RESTORABLE_REPLICA, buf); ndbrequire(false); return; }//if @@ -9673,6 +9671,9 @@ void Dbdih::execLCP_FRAG_REP(Signal* signal) } bool tableDone = reportLcpCompletion(lcpReport); + + Uint32 started = lcpReport->maxGciStarted; + Uint32 completed = lcpReport->maxGciCompleted; if(tableDone){ jam(); @@ -9706,7 +9707,9 @@ void Dbdih::execLCP_FRAG_REP(Signal* signal) signal->theData[1] = nodeId; signal->theData[2] = tableId; signal->theData[3] = fragId; - sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 4, JBB); + signal->theData[4] = started; + signal->theData[5] = completed; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 6, JBB); #endif bool ok = false; @@ -10544,7 +10547,7 @@ void Dbdih::calculateHotSpare() break; default: jam(); - progError(0, 0); + ndbrequire(false); break; }//switch }//Dbdih::calculateHotSpare() @@ -10577,7 +10580,7 @@ void Dbdih::checkEscalation() jam(); if (TnodeGroup[i] == ZFALSE) { jam(); - progError(__LINE__, ERR_SYSTEM_ERROR, "Lost node group"); + progError(__LINE__, NDBD_EXIT_LOST_NODE_GROUP, "Lost node group"); }//if }//for }//Dbdih::checkEscalation() @@ -10903,7 +10906,9 @@ void Dbdih::findMinGci(ReplicaRecordPtr fmgReplicaPtr, lcpNo = fmgReplicaPtr.p->nextLcp; do { ndbrequire(lcpNo < MAX_LCP_STORED); - if (fmgReplicaPtr.p->lcpStatus[lcpNo] == ZVALID) { + if (fmgReplicaPtr.p->lcpStatus[lcpNo] == ZVALID && + fmgReplicaPtr.p->maxGciStarted[lcpNo] <= coldgcp) + { jam(); keepGci = fmgReplicaPtr.p->maxGciCompleted[lcpNo]; oldestRestorableGci = fmgReplicaPtr.p->maxGciStarted[lcpNo]; @@ -10911,7 +10916,6 @@ void Dbdih::findMinGci(ReplicaRecordPtr fmgReplicaPtr, return; } else { jam(); - ndbrequire(fmgReplicaPtr.p->lcpStatus[lcpNo] == ZINVALID); if (fmgReplicaPtr.p->createGci[0] == fmgReplicaPtr.p->initialGci) { jam(); /*------------------------------------------------------------------- diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index 65d7df9ff7d..94a40adcd4a 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -89,6 +89,17 @@ #define ZCURR_PAGE_INDEX 8 #define ZLAST_LOG_PREP_REF 10 #define ZPOS_DIRTY 11 +/* A number of debug items written in the page header of all log files */ +#define ZPOS_LOG_TIMER 12 +#define ZPOS_PAGE_I 13 +#define ZPOS_PLACE_WRITTEN_FROM 14 +#define ZPOS_PAGE_NO 15 +#define ZPOS_PAGE_FILE_NO 16 +#define ZPOS_WORD_WRITTEN 17 +#define ZPOS_IN_WRITING 18 +#define ZPOS_PREV_PAGE_NO 19 +#define ZPOS_IN_FREE_LIST 20 + /* ------------------------------------------------------------------------- */ /* CONSTANTS FOR THE VARIOUS REPLICA AND NODE TYPES. */ /* ------------------------------------------------------------------------- */ @@ -2281,7 +2292,7 @@ private: const LogPartRecordPtr &sltLogPartPtr); void checkGcpCompleted(Signal* signal, Uint32 pageWritten, Uint32 wordWritten); void initFsopenconf(Signal* signal); - void initFsrwconf(Signal* signal); + void initFsrwconf(Signal* signal, bool write); void initLfo(Signal* signal); void initLogfile(Signal* signal, Uint32 fileNo); void initLogpage(Signal* signal); @@ -2297,7 +2308,8 @@ private: void writeFileDescriptor(Signal* signal); void writeFileHeaderOpen(Signal* signal, Uint32 type); void writeInitMbyte(Signal* signal); - void writeSinglePage(Signal* signal, Uint32 pageNo, Uint32 wordWritten); + void writeSinglePage(Signal* signal, Uint32 pageNo, + Uint32 wordWritten, Uint32 place); void buildLinkedLogPageList(Signal* signal); void changeMbyte(Signal* signal); Uint32 checkIfExecLog(Signal* signal); @@ -2306,7 +2318,7 @@ private: void checkScanTcCompleted(Signal* signal); void checkSrCompleted(Signal* signal); void closeFile(Signal* signal, LogFileRecordPtr logFilePtr); - void completedLogPage(Signal* signal, Uint32 clpType); + void completedLogPage(Signal* signal, Uint32 clpType, Uint32 place); void deleteFragrec(Uint32 fragId); void deleteTransidHash(Signal* signal); void findLogfile(Signal* signal, @@ -2400,11 +2412,13 @@ private: void startNextExecSr(Signal* signal); void startTimeSupervision(Signal* signal); void stepAhead(Signal* signal, Uint32 stepAheadWords); - void systemError(Signal* signal); + void systemError(Signal* signal, int line); void writeAbortLog(Signal* signal); void writeCommitLog(Signal* signal, LogPartRecordPtr regLogPartPtr); void writeCompletedGciLog(Signal* signal); - void writeDirty(Signal* signal); + void writeDbgInfoPageHeader(LogPageRecordPtr logPagePtr, Uint32 place, + Uint32 pageNo, Uint32 wordWritten); + void writeDirty(Signal* signal, Uint32 place); void writeKey(Signal* signal); void writeLogHeader(Signal* signal); void writeLogWord(Signal* signal, Uint32 data); @@ -2417,7 +2431,7 @@ private: Uint32 calcPageCheckSum(LogPageRecordPtr logP); // Generated statement blocks - void systemErrorLab(Signal* signal); + void systemErrorLab(Signal* signal, int line); void initFourth(Signal* signal); void packLqhkeyreqLab(Signal* signal); void sendNdbSttorryLab(Signal* signal); @@ -2427,7 +2441,6 @@ private: void srLogLimits(Signal* signal); void srGciLimits(Signal* signal); void srPhase3Start(Signal* signal); - void warningHandlerLab(Signal* signal); void checkStartCompletedLab(Signal* signal); void continueAbortLab(Signal* signal); void abortContinueAfterBlockedLab(Signal* signal, bool canBlock); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 5cf267a0632..2170f890f35 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -168,11 +168,11 @@ void Dblqh::execTUP_COM_UNBLOCK(Signal* signal) /* ------- SEND SYSTEM ERROR ------- */ /* */ /* ------------------------------------------------------------------------- */ -void Dblqh::systemError(Signal* signal) +void Dblqh::systemError(Signal* signal, int line) { signal->theData[0] = 2304; execDUMP_STATE_ORD(signal); - progError(0, 0); + progError(line, NDBD_EXIT_NDBREQUIRE); }//Dblqh::systemError() /* *************** */ @@ -5120,7 +5120,7 @@ void Dblqh::errorReport(Signal* signal, int place) jam(); break; }//switch - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Dblqh::errorReport() @@ -5181,7 +5181,7 @@ void Dblqh::execCOMMITREQ(Signal* signal) Uint32 transid2 = signal->theData[4]; Uint32 tcOprec = signal->theData[6]; if (ERROR_INSERTED(5004)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); } if (ERROR_INSERTED(5017)) { CLEAR_ERROR_INSERT_VALUE; @@ -5303,7 +5303,7 @@ void Dblqh::execCOMPLETEREQ(Signal* signal) Uint32 transid2 = signal->theData[3]; Uint32 tcOprec = signal->theData[5]; if (ERROR_INSERTED(5005)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); } if (ERROR_INSERTED(5018)) { CLEAR_ERROR_INSERT_VALUE; @@ -5932,7 +5932,7 @@ void Dblqh::execABORTREQ(Signal* signal) Uint32 transid2 = signal->theData[3]; Uint32 tcOprec = signal->theData[5]; if (ERROR_INSERTED(5006)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); } if (ERROR_INSERTED(5016)) { CLEAR_ERROR_INSERT_VALUE; @@ -6743,7 +6743,7 @@ void Dblqh::lqhTransNextLab(Signal* signal) /* ------------------------------------------------------------ * THIS IS AN ERROR THAT SHOULD NOT OCCUR. WE CRASH THE SYSTEM. * ------------------------------------------------------------ */ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if }//if @@ -6920,7 +6920,7 @@ void Dblqh::execNEXT_SCANCONF(Signal* signal) void Dblqh::execNEXT_SCANREF(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Dblqh::execNEXT_SCANREF() @@ -9199,7 +9199,7 @@ void Dblqh::storedProcConfCopyLab(Signal* signal) jam(); default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -9491,7 +9491,7 @@ void Dblqh::copyCompletedLab(Signal* signal) // Make sure that something is in progress. Otherwise we will simply stop // and nothing more will happen. /*---------------------------------------------------------------------------*/ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if return; @@ -9510,7 +9510,7 @@ void Dblqh::nextRecordCopy(Signal* signal) // scans on the same record and this will certainly lead to unexpected // behaviour. /*---------------------------------------------------------------------------*/ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY; @@ -9537,7 +9537,7 @@ void Dblqh::nextRecordCopy(Signal* signal) jam(); default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -9611,7 +9611,7 @@ void Dblqh::closeCopyLab(Signal* signal) jam(); default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -10632,7 +10632,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -11456,7 +11456,7 @@ void Dblqh::execGCP_SAVEREQ(Signal* signal) const GCPSaveReq * const saveReq = (GCPSaveReq *)&signal->theData[0]; if (ERROR_INSERTED(5000)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); } if (ERROR_INSERTED(5007)){ @@ -11796,42 +11796,34 @@ void Dblqh::execFSCLOSECONF(Signal* signal) ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); exitFromInvalidate(signal); return; - break; case LogFileRecord::CLOSING_INIT: jam(); closingInitLab(signal); return; - break; case LogFileRecord::CLOSING_SR: jam(); closingSrLab(signal); return; - break; case LogFileRecord::CLOSING_EXEC_SR: jam(); closeExecSrLab(signal); return; - break; case LogFileRecord::CLOSING_EXEC_SR_COMPLETED: jam(); closeExecSrCompletedLab(signal); return; - break; case LogFileRecord::CLOSING_WRITE_LOG: jam(); closeWriteLogLab(signal); return; - break; case LogFileRecord::CLOSING_EXEC_LOG: jam(); closeExecLogLab(signal); return; - break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; - break; }//switch }//Dblqh::execFSCLOSECONF() @@ -11849,77 +11841,64 @@ void Dblqh::execFSOPENCONF(Signal* signal) logFilePtr.p->logFileStatus = LogFileRecord::OPEN; readFileInInvalidate(signal); return; - break; case LogFileRecord::OPENING_INIT: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openFileInitLab(signal); return; - break; case LogFileRecord::OPEN_SR_FRONTPAGE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFrontpageLab(signal); return; - break; case LogFileRecord::OPEN_SR_LAST_FILE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrLastFileLab(signal); return; - break; case LogFileRecord::OPEN_SR_NEXT_FILE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrNextFileLab(signal); return; - break; case LogFileRecord::OPEN_EXEC_SR_START: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecSrStartLab(signal); return; - break; case LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecSrNewMbyteLab(signal); return; - break; case LogFileRecord::OPEN_SR_FOURTH_PHASE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthPhaseLab(signal); return; - break; case LogFileRecord::OPEN_SR_FOURTH_NEXT: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthNextLab(signal); return; - break; case LogFileRecord::OPEN_SR_FOURTH_ZERO: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthZeroLab(signal); return; - break; case LogFileRecord::OPENING_WRITE_LOG: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; return; - break; case LogFileRecord::OPEN_EXEC_LOG: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecLogLab(signal); return; - break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; - break; }//switch }//Dblqh::execFSOPENCONF() @@ -11930,7 +11909,7 @@ void Dblqh::execFSOPENCONF(Signal* signal) void Dblqh::execFSREADCONF(Signal* signal) { jamEntry(); - initFsrwconf(signal); + initFsrwconf(signal, false); switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::READ_SR_LAST_MBYTE: @@ -11938,57 +11917,47 @@ void Dblqh::execFSREADCONF(Signal* signal) releaseLfo(signal); readSrLastMbyteLab(signal); return; - break; case LogFileOperationRecord::READ_SR_FRONTPAGE: jam(); releaseLfo(signal); readSrFrontpageLab(signal); return; - break; case LogFileOperationRecord::READ_SR_LAST_FILE: jam(); releaseLfo(signal); readSrLastFileLab(signal); return; - break; case LogFileOperationRecord::READ_SR_NEXT_FILE: jam(); releaseLfo(signal); readSrNextFileLab(signal); return; - break; case LogFileOperationRecord::READ_EXEC_SR: jam(); readExecSrLab(signal); return; - break; case LogFileOperationRecord::READ_EXEC_LOG: jam(); readExecLogLab(signal); return; - break; case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: jam(); invalidateLogAfterLastGCI(signal); return; - break; case LogFileOperationRecord::READ_SR_FOURTH_PHASE: jam(); releaseLfo(signal); readSrFourthPhaseLab(signal); return; - break; case LogFileOperationRecord::READ_SR_FOURTH_ZERO: jam(); releaseLfo(signal); readSrFourthZeroLab(signal); return; - break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; - break; }//switch }//Dblqh::execFSREADCONF() @@ -12045,63 +12014,52 @@ void Dblqh::execFSREADREF(Signal* signal) void Dblqh::execFSWRITECONF(Signal* signal) { jamEntry(); - initFsrwconf(signal); + initFsrwconf(signal, true); switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: jam(); invalidateLogAfterLastGCI(signal); return; - break; case LogFileOperationRecord::WRITE_PAGE_ZERO: jam(); writePageZeroLab(signal); return; - break; case LogFileOperationRecord::LAST_WRITE_IN_FILE: jam(); lastWriteInFileLab(signal); return; - break; case LogFileOperationRecord::INIT_WRITE_AT_END: jam(); initWriteEndLab(signal); return; - break; case LogFileOperationRecord::INIT_FIRST_PAGE: jam(); initFirstPageLab(signal); return; - break; case LogFileOperationRecord::WRITE_GCI_ZERO: jam(); writeGciZeroLab(signal); return; - break; case LogFileOperationRecord::WRITE_DIRTY: jam(); writeDirtyLab(signal); return; - break; case LogFileOperationRecord::WRITE_INIT_MBYTE: jam(); writeInitMbyteLab(signal); return; - break; case LogFileOperationRecord::ACTIVE_WRITE_LOG: jam(); writeLogfileLab(signal); return; - break; case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE: jam(); firstPageWriteLab(signal); return; - break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; - break; }//switch }//Dblqh::execFSWRITECONF() @@ -12144,7 +12102,7 @@ void Dblqh::execFSWRITEREF(Signal* signal) break; case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); default: jam(); break; @@ -12177,16 +12135,35 @@ void Dblqh::initFsopenconf(Signal* signal) /* ======= INITIATE WHEN RECEIVING FSREADCONF AND FSWRITECONF ======= */ /* */ /* ========================================================================= */ -void Dblqh::initFsrwconf(Signal* signal) +void Dblqh::initFsrwconf(Signal* signal, bool write) { + LogPageRecordPtr logP; + Uint32 noPages, totPages; lfoPtr.i = signal->theData[0]; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); + totPages= lfoPtr.p->noPagesRw; logFilePtr.i = lfoPtr.p->logFileRec; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPartPtr.i = logFilePtr.p->logPartRec; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logPagePtr.i = lfoPtr.p->firstLfoPage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logP= logPagePtr; + noPages= 1; + ndbassert(totPages > 0); + for (;;) + { + logP.p->logPageWord[ZPOS_IN_WRITING]= 0; + logP.p->logPageWord[ZPOS_IN_FREE_LIST]= 0; + if (noPages == totPages) + return; + if (write) + logP.i= logP.p->logPageWord[ZNEXT_PAGE]; + else + logP.i= lfoPtr.p->logPageArray[noPages]; + ptrCheckGuard(logP, clogPageFileSize, logPageRecord); + noPages++; + } }//Dblqh::initFsrwconf() /* ######################################################################### */ @@ -12274,7 +12251,7 @@ void Dblqh::timeSup(Signal* signal) ndbrequire(wordWritten < ZPAGE_SIZE); if (logFilePtr.p->noLogpagesInBuffer > 0) { jam(); - completedLogPage(signal, ZENFORCE_WRITE); + completedLogPage(signal, ZENFORCE_WRITE, __LINE__); /*---------------------------------------------------------------------------*/ /*SINCE WE ARE ONLY WRITING PART OF THE LAST PAGE WE HAVE TO UPDATE THE WORD */ /*WRITTEN TO REFLECT THE REAL LAST WORD WRITTEN. WE ALSO HAVE TO MOVE THE */ @@ -12296,7 +12273,8 @@ void Dblqh::timeSup(Signal* signal) releaseLogpage(signal); } else { jam(); - writeSinglePage(signal, logFilePtr.p->currentFilepage, wordWritten); + writeSinglePage(signal, logFilePtr.p->currentFilepage, + wordWritten, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; }//if }//if @@ -12338,7 +12316,7 @@ void Dblqh::writeLogfileLab(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -12432,7 +12410,7 @@ void Dblqh::firstPageWriteLab(Signal* signal) logPagePtr.i = logFilePtr.p->logPageZero; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; - writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->logFileRec = currLogFile; lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; return; @@ -12521,7 +12499,7 @@ void Dblqh::lastWriteInFileLab(Signal* signal) logPagePtr.i = logFilePtr.p->logPageZero; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; - writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->logFileRec = currLogFile; lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; return; @@ -12572,7 +12550,8 @@ void Dblqh::openFileInitLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::OPEN_INIT; seizeLogpage(signal); - writeSinglePage(signal, (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE) - 1, ZPAGE_SIZE - 1); + writeSinglePage(signal, (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE) - 1, + ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::INIT_WRITE_AT_END; return; }//Dblqh::openFileInitLab() @@ -12613,7 +12592,7 @@ void Dblqh::initFirstPageLab(Signal* signal) logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE] = ZCOMPLETED_GCI_TYPE; logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + 1] = 1; - writeSinglePage(signal, 1, ZPAGE_SIZE - 1); + writeSinglePage(signal, 1, ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_GCI_ZERO; return; }//if @@ -12915,17 +12894,13 @@ void Dblqh::releaseLogpage(Signal* signal) { #ifdef VM_TRACE // Check that log page isn't already in free list - LogPageRecordPtr TlogPagePtr; - TlogPagePtr.i = cfirstfreeLogPage; - while (TlogPagePtr.i != RNIL){ - ptrCheckGuard(TlogPagePtr, clogPageFileSize, logPageRecord); - ndbrequire(TlogPagePtr.i != logPagePtr.i); - TlogPagePtr.i = TlogPagePtr.p->logPageWord[ZNEXT_PAGE]; - } + ndbrequire(logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST] == 0); #endif cnoOfLogPages++; logPagePtr.p->logPageWord[ZNEXT_PAGE] = cfirstfreeLogPage; + logPagePtr.p->logPageWord[ZPOS_IN_WRITING]= 0; + logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST]= 1; cfirstfreeLogPage = logPagePtr.i; }//Dblqh::releaseLogpage() @@ -12971,6 +12946,7 @@ void Dblqh::seizeLogpage(Signal* signal) /* ------------------------------------------------------------------------- */ cfirstfreeLogPage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; + logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST] = 0; }//Dblqh::seizeLogpage() /* ------------------------------------------------------------------------- */ @@ -13078,7 +13054,7 @@ WMO_LOOP: /* LOG FILE. THIS HAS SPECIAL SIGNIFANCE TO FIND */ /* THE END OF THE LOG AT SYSTEM RESTART. */ /* ------------------------------------------------------- */ - writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__); if (wmoType == ZINIT) { jam(); lfoPtr.p->lfoState = LogFileOperationRecord::INIT_FIRST_PAGE; @@ -13112,7 +13088,8 @@ WMO_LOOP: void Dblqh::writeInitMbyte(Signal* signal) { initLogpage(signal); - writeSinglePage(signal, logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE, ZPAGE_SIZE - 1); + writeSinglePage(signal, logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE, + ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_INIT_MBYTE; }//Dblqh::writeInitMbyte() @@ -13122,13 +13099,15 @@ void Dblqh::writeInitMbyte(Signal* signal) /* INPUT: TWSP_PAGE_NO THE PAGE NUMBER WRITTEN */ /* SUBROUTINE SHORT NAME: WSP */ /* ------------------------------------------------------------------------- */ -void Dblqh::writeSinglePage(Signal* signal, Uint32 pageNo, Uint32 wordWritten) +void Dblqh::writeSinglePage(Signal* signal, Uint32 pageNo, + Uint32 wordWritten, Uint32 place) { seizeLfo(signal); initLfo(signal); lfoPtr.p->firstLfoPage = logPagePtr.i; logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; + writeDbgInfoPageHeader(logPagePtr, place, pageNo, wordWritten); // Calculate checksum for page logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); @@ -13571,7 +13550,7 @@ void Dblqh::execACC_SRCONF(Signal* signal) ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (lcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_STARTED) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if @@ -13593,7 +13572,7 @@ void Dblqh::execACC_SRREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Dblqh::execACC_SRREF() @@ -13733,7 +13712,7 @@ void Dblqh::execTUP_SRREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Dblqh::execTUP_SRREF() @@ -14033,7 +14012,7 @@ void Dblqh::execEXEC_FRAGREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Dblqh::execEXEC_FRAGREF() @@ -14125,7 +14104,7 @@ void Dblqh::execSrCompletedLab(Signal* signal) * PROBLEM. THIS SHOULD NOT OCCUR. IF IT OCCURS ANYWAY THEN WE * HAVE TO FIND A CURE FOR THIS PROBLEM. * ----------------------------------------------------------------- */ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if signal->theData[0] = ZSR_LOG_LIMITS; @@ -14596,7 +14575,7 @@ void Dblqh::execSr(Signal* signal) * IN THIS WE HAVE COMPLETED EXECUTION OF THE CURRENT LOG PAGE * AND CAN WRITE IT TO DISK SINCE IT IS DIRTY. * ----------------------------------------------------------------- */ - writeDirty(signal); + writeDirty(signal, __LINE__); return; break; case LogPartRecord::LES_EXEC_LOG: @@ -14607,7 +14586,7 @@ void Dblqh::execSr(Signal* signal) * ------------------------------------------------------------------- */ if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) { jam(); - writeDirty(signal); + writeDirty(signal, __LINE__); return; }//if break; @@ -14652,7 +14631,7 @@ void Dblqh::execSr(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -14931,7 +14910,7 @@ void Dblqh::execDEBUG_SIG(Signal* signal) signal->theData[2], signal->theData[3], signal->theData[4], signal->theData[5], signal->theData[6], signal->theData[7]); - progError(__LINE__, ERR_SR_REDOLOG, buf); + progError(__LINE__, NDBD_EXIT_SR_REDOLOG, buf); return; }//Dblqh::execDEBUG_SIG() @@ -15003,12 +14982,12 @@ void Dblqh::invalidateLogAfterLastGCI(Signal* signal) { jam(); if (logPartPtr.p->logExecState != LogPartRecord::LES_EXEC_LOG_INVALIDATE) { jam(); - systemError(signal); + systemError(signal, __LINE__); } if (logFilePtr.p->fileNo != logPartPtr.p->invalidateFileNo) { jam(); - systemError(signal); + systemError(signal, __LINE__); } switch (lfoPtr.p->lfoState) { @@ -15051,7 +15030,8 @@ void Dblqh::invalidateLogAfterLastGCI(Signal* signal) { // This page must be invalidated. logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 0; // Contact NDBFS. Real time break. - writeSinglePage(signal, logPartPtr.p->invalidatePageNo, ZPAGE_SIZE - 1); + writeSinglePage(signal, logPartPtr.p->invalidatePageNo, + ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES; } else { // We are done with invalidating. Finish start phase 3.4. @@ -15062,7 +15042,7 @@ void Dblqh::invalidateLogAfterLastGCI(Signal* signal) { default: jam(); - systemError(signal); + systemError(signal, __LINE__); return; break; } @@ -15210,7 +15190,7 @@ void Dblqh::execLogComp(Signal* signal) if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_COMPLETED) { if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_STARTED) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; } else { jam(); @@ -15468,7 +15448,7 @@ void Dblqh::openSrFourthZeroSkipInitLab(Signal* signal) * THE HEADER PAGE IN THE LOG IS PAGE ZERO IN FILE ZERO. * THIS SHOULD NEVER OCCUR. * ------------------------------------------------------------------- */ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if }//if @@ -15522,7 +15502,7 @@ void Dblqh::srFourthComp(Signal* signal) if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_COMPLETED) { if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_STARTED) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; } else { jam(); @@ -15583,11 +15563,6 @@ void Dblqh::srFourthComp(Signal* signal) /* ####### ERROR MODULE ####### */ /* */ /* ######################################################################### */ -void Dblqh::warningHandlerLab(Signal* signal) -{ - systemErrorLab(signal); - return; -}//Dblqh::warningHandlerLab() /*---------------------------------------------------------------------------*/ /* AN ERROR OCCURRED THAT WE WILL NOT TREAT AS SYSTEM ERROR. MOST OFTEN THIS */ @@ -15608,10 +15583,10 @@ void Dblqh::warningHandlerLab(Signal* signal) /* THE COMMIT, COMPLETE OR ABORT PHASE, WE PERFORM A CRASH OF THE AXE VM*/ /*---------------------------------------------------------------------------*/ -void Dblqh::systemErrorLab(Signal* signal) +void Dblqh::systemErrorLab(Signal* signal, int line) { - systemError(signal); - progError(0, 0); + systemError(signal, line); + progError(line, NDBD_EXIT_NDBREQUIRE); /*************************************************************************>*/ /* WE WANT TO INVOKE AN IMMEDIATE ERROR HERE SO WE GET THAT BY */ /* INSERTING A CERTAIN POINTER OUT OF RANGE. */ @@ -15820,7 +15795,7 @@ void Dblqh::buildLinkedLogPageList(Signal* signal) // Uint32 checkSum = bllLogPagePtr.p->logPageWord[ZPOS_CHECKSUM]; // if (checkSum != calcCheckSum) { // ndbout << "Redolog: Checksum failure." << endl; -// progError(__LINE__, ERR_NDBREQUIRE, "Redolog: Checksum failure."); +// progError(__LINE__, NDBD_EXIT_NDBREQUIRE, "Redolog: Checksum failure."); // } // #endif @@ -15946,7 +15921,7 @@ CSC_ACC_DOWHILE: jam(); if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_STARTED) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if return; @@ -15963,7 +15938,7 @@ CSC_TUP_DOWHILE: jam(); if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_TUP_STARTED) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if return; @@ -16000,7 +15975,7 @@ void Dblqh::closeFile(Signal* signal, LogFileRecordPtr clfLogFilePtr) // logPartPtr // Defines lfoPtr /* ---------------------------------------------------------------- */ -void Dblqh::completedLogPage(Signal* signal, Uint32 clpType) +void Dblqh::completedLogPage(Signal* signal, Uint32 clpType, Uint32 place) { LogPageRecordPtr clpLogPagePtr; LogPageRecordPtr wlpLogPagePtr; @@ -16043,6 +16018,9 @@ void Dblqh::completedLogPage(Signal* signal, Uint32 clpType) twlpNoPages++; ptrCheckGuard(wlpLogPagePtr, clogPageFileSize, logPageRecord); + writeDbgInfoPageHeader(wlpLogPagePtr, place, + logFilePtr.p->filePosition + twlpNoPages - 1, + ZPAGE_SIZE); // Calculate checksum for page wlpLogPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(wlpLogPagePtr); wlpLogPagePtr.i = wlpLogPagePtr.p->logPageWord[ZNEXT_PAGE]; @@ -16445,6 +16423,8 @@ void Dblqh::initialiseLogPage(Signal* signal) refresh_watch_dog(); ptrAss(logPagePtr, logPageRecord); logPagePtr.p->logPageWord[ZNEXT_PAGE] = logPagePtr.i + 1; + logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST]= 1; + logPagePtr.p->logPageWord[ZPOS_IN_WRITING]= 0; }//for logPagePtr.i = clogPageFileSize - 1; ptrAss(logPagePtr, logPageRecord); @@ -17526,7 +17506,7 @@ void Dblqh::releaseAccList(Signal* signal) racTcNextConnectptr.i = tcConnectptr.p->nextTc; if (tcConnectptr.p->listState != TcConnectionrec::ACC_BLOCK_LIST) { jam(); - systemError(signal); + systemError(signal, __LINE__); }//if tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; if (racTcNextConnectptr.i != RNIL) { @@ -17705,7 +17685,7 @@ void Dblqh::releaseWaitQueue(Signal* signal) rwaTcNextConnectptr.i = tcConnectptr.p->nextTc; if (tcConnectptr.p->listState != TcConnectionrec::WAIT_QUEUE_LIST) { jam(); - systemError(signal); + systemError(signal, __LINE__); }//if tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; if (rwaTcNextConnectptr.i != RNIL) { @@ -18101,10 +18081,14 @@ void Dblqh::writeCompletedGciLog(Signal* signal) * * SUBROUTINE SHORT NAME: WD * ------------------------------------------------------------------------- */ -void Dblqh::writeDirty(Signal* signal) +void Dblqh::writeDirty(Signal* signal, Uint32 place) { logPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY; + ndbassert(logPartPtr.p->prevFilepage == + logPagePtr.p->logPageWord[ZPOS_PAGE_NO]); + writeDbgInfoPageHeader(logPagePtr, place, logPartPtr.p->prevFilepage, + ZPAGE_SIZE); // Calculate checksum for page logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); @@ -18138,7 +18122,7 @@ void Dblqh::writeLogWord(Signal* signal, Uint32 data) logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + 1; if ((logPos + 1) == ZPAGE_SIZE) { jam(); - completedLogPage(signal, ZNORMAL); + completedLogPage(signal, ZNORMAL, __LINE__); seizeLogpage(signal); initLogpage(signal); logFilePtr.p->currentLogpage = logPagePtr.i; @@ -18196,7 +18180,7 @@ void Dblqh::writeNextLog(Signal* signal) /* -------------------------------------------------- */ /* WE HAVE TO CHANGE LOG FILE */ /* -------------------------------------------------- */ - completedLogPage(signal, ZLAST_WRITE_IN_FILE); + completedLogPage(signal, ZLAST_WRITE_IN_FILE, __LINE__); if (wnlNextLogFilePtr.p->fileNo == 0) { jam(); /* -------------------------------------------------- */ @@ -18215,7 +18199,7 @@ void Dblqh::writeNextLog(Signal* signal) /* INCREMENT THE CURRENT MBYTE */ /* SET PAGE INDEX TO PAGE HEADER SIZE */ /* -------------------------------------------------- */ - completedLogPage(signal, ZENFORCE_WRITE); + completedLogPage(signal, ZENFORCE_WRITE, __LINE__); twnlNewMbyte = logFilePtr.p->currentMbyte + 1; }//if /* -------------------------------------------------- */ @@ -18265,7 +18249,7 @@ void Dblqh::writeNextLog(Signal* signal) /* CAN INVOKE THIS SYSTEM CRASH. HOWEVER ONLY */ /* VERY SERIOUS TIMING PROBLEMS. */ /* -------------------------------------------------- */ - systemError(signal); + systemError(signal, __LINE__); }//if }//if if (logFilePtr.p->currentMbyte == (ZNO_MBYTES_IN_FILE - 1)) { @@ -18530,7 +18514,10 @@ Dblqh::execDUMP_STATE_ORD(Signal* signal) if(arg== 2305) { - progError(__LINE__, ERR_SYSTEM_ERROR, + progError(__LINE__, NDBD_EXIT_SYSTEM_ERROR, + "Please report this as a bug. " + "Provide as much info as possible, expecially all the " + "ndb_*_out.log files, Thanks. " "Shutting down node due to failed handling of GCP_SAVEREQ"); } @@ -18640,3 +18627,16 @@ Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){ return checkSum; } +void Dblqh::writeDbgInfoPageHeader(LogPageRecordPtr logP, Uint32 place, + Uint32 pageNo, Uint32 wordWritten) +{ + logP.p->logPageWord[ZPOS_LOG_TIMER]= logPartPtr.p->logTimer; + logP.p->logPageWord[ZPOS_PREV_PAGE_NO]= logP.p->logPageWord[ZPOS_PAGE_NO]; + logP.p->logPageWord[ZPOS_PAGE_I]= logP.i; + logP.p->logPageWord[ZPOS_PLACE_WRITTEN_FROM]= place; + logP.p->logPageWord[ZPOS_PAGE_NO]= pageNo; + logP.p->logPageWord[ZPOS_PAGE_FILE_NO]= logFilePtr.p->fileNo; + logP.p->logPageWord[ZPOS_WORD_WRITTEN]= wordWritten; + logP.p->logPageWord[ZPOS_IN_WRITING]= 1; +} + diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp index ba6d65ca838..6eadefe5df5 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp @@ -134,7 +134,9 @@ bool PrepareOperationRecord::check() { return true; } -Uint32 PrepareOperationRecord::getLogRecordSize() { +Uint32 PrepareOperationRecord::getLogRecordSize(Uint32 wordsRead) { + if (wordsRead < 2) + return 2; // make sure we read more return m_logRecordSize; } @@ -264,7 +266,16 @@ NdbOut& operator<<(NdbOut& no, const PageHeader& ph) { printOut("Current page index:", ph.m_current_page_index); printOut("Oldest prepare op. file No.:", ph.m_old_prepare_file_number); printOut("Oldest prepare op. page ref.:", ph.m_old_prepare_page_reference); - printOut("Dirty flag:", ph.m_dirty_flag); + printOut("Dirty flag:", ph.m_dirty_flag); + printOut("Write Timer:", ph.m_log_timer); + printOut("Page i-val:", ph.m_page_i_value); + printOut("Place written:", ph.m_place_written_from); + printOut("Page No in File:", ph.m_page_no); + printOut("File No:", ph.m_file_no); + printOut("Word Written:", ph.m_word_written); + printOut("In Writing (should be 1)", ph.m_in_writing_flag); + printOut("Prev Page No (can be garbage)", ph.m_prev_page_no); + printOut("In Free List (should be 0):", ph.m_in_free_list); no << endl; return no; } diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp index 11b8dc4a6fa..06bf7a85d53 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp @@ -83,7 +83,7 @@ class PrepareOperationRecord { friend NdbOut& operator<<(NdbOut&, const PrepareOperationRecord&); public: bool check(); - Uint32 getLogRecordSize(); + Uint32 getLogRecordSize(Uint32 wordsRead); protected: Uint32 m_recordType; @@ -147,6 +147,17 @@ protected: Uint32 m_old_prepare_file_number; Uint32 m_old_prepare_page_reference; Uint32 m_dirty_flag; +/* Debug info Start */ + Uint32 m_log_timer; + Uint32 m_page_i_value; + Uint32 m_place_written_from; + Uint32 m_page_no; + Uint32 m_file_no; + Uint32 m_word_written; + Uint32 m_in_writing_flag; + Uint32 m_prev_page_no; + Uint32 m_in_free_list; +/* Debug info End */ }; //---------------------------------------------------------------- diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp index aa8b1d25e4e..751d27db74e 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp @@ -41,6 +41,7 @@ void doExit(); FILE * f= 0; char fileName[256]; +bool theDumpFlag = false; bool thePrintFlag = true; bool theCheckFlag = true; bool onlyPageHeaders = false; @@ -208,7 +209,7 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read case ZPREP_OP_TYPE: poRecord = (PrepareOperationRecord *) redoLogPagePos; - wordIndex += poRecord->getLogRecordSize(); + wordIndex += poRecord->getLogRecordSize(PAGESIZE-wordIndex); if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*poRecord); if (theCheckFlag) { @@ -277,10 +278,9 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read ndbout << " ------ERROR: UNKNOWN RECORD TYPE------" << endl; // Print out remaining data in this page - for (int j = wordIndex; j < PAGESIZE; j++){ - Uint32 unknown = redoLogPage[i*PAGESIZE + j]; - - ndbout_c("%-30d%-12u%-12x", j, unknown, unknown); + for (int k = wordIndex; k < PAGESIZE; k++){ + Uint32 unknown = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, unknown, unknown); } doExit(); @@ -289,8 +289,19 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read if (lastPage) + { + if (theDumpFlag) + { + ndbout << " ------PAGE END: DUMPING REST OF PAGE------" << endl; + for (int k = wordIndex > PAGESIZE ? oldWordIndex : wordIndex; + k < PAGESIZE; k++) + { + Uint32 word = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, word, word); + } + } break; - + } if (wordIndex > PAGESIZE) { words_from_previous_page = PAGESIZE - oldWordIndex; ndbout << " ----------- Record continues on next page -----------" << endl; @@ -353,6 +364,8 @@ void readArguments(int argc, const char** argv) { if (strcmp(argv[i], "-noprint") == 0) { thePrintFlag = false; + } else if (strcmp(argv[i], "-dump") == 0) { + theDumpFlag = true; } else if (strcmp(argv[i], "-nocheck") == 0) { theCheckFlag = false; } else if (strcmp(argv[i], "-mbyteheaders") == 0) { diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index bf9f421a0e3..8218acc0ea7 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -1465,7 +1465,7 @@ private: void sendContinueTimeOutControl(Signal* signal, Uint32 TapiConPtr); void sendKeyinfo(Signal* signal, BlockReference TBRef, Uint32 len); void sendlqhkeyreq(Signal* signal, BlockReference TBRef); - void sendSystemError(Signal* signal); + void sendSystemError(Signal* signal, int line); void sendtckeyconf(Signal* signal, UintR TcommitFlag); void sendTcIndxConf(Signal* signal, UintR TcommitFlag); void unlinkApiConnect(Signal* signal); @@ -1541,8 +1541,8 @@ private: bool holdOperation = false); void releaseFiredTriggerData(DLFifoList<TcFiredTriggerData>* triggers); // Generated statement blocks - void warningHandlerLab(Signal* signal); - void systemErrorLab(Signal* signal); + void warningHandlerLab(Signal* signal, int line); + void systemErrorLab(Signal* signal, int line); void sendSignalErrorRefuseLab(Signal* signal); void scanTabRefLab(Signal* signal, Uint32 errCode); void diFcountReqLab(Signal* signal, ScanRecordPtr); diff --git a/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp b/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp index f99b4bf15af..31f73e98142 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp @@ -291,8 +291,19 @@ Dbtc::Dbtc(const class Configuration & conf): addRecSignal(GSN_ALTER_TAB_REQ, &Dbtc::execALTER_TAB_REQ); - initData(); - + cacheRecord = 0; + apiConnectRecord = 0; + tcConnectRecord = 0; + hostRecord = 0; + tableRecord = 0; + scanRecord = 0; + databufRecord = 0; + attrbufRecord = 0; + gcpRecord = 0; + tcFailRecord = 0; + c_apiConTimer = 0; + c_apiConTimer_line = 0; + #ifdef VM_TRACE { void* tmp[] = { &apiConnectptr, diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 0ff6d8477b9..f2646fd4176 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -608,6 +608,8 @@ void Dbtc::execREAD_CONFIG_REQ(Signal* signal) theConfiguration.getOwnConfigIterator(); ndbrequire(p != 0); + initData(); + UintR apiConnect; UintR tcConnect; UintR tables; @@ -1029,7 +1031,7 @@ Dbtc::handleFailedApiNode(Signal* signal, /*********************************************************************/ // Not implemented yet. /*********************************************************************/ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; case CS_RESTART: jam(); @@ -1053,7 +1055,7 @@ Dbtc::handleFailedApiNode(Signal* signal, /*********************************************************************/ default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; }//switch } else { @@ -1392,7 +1394,7 @@ void Dbtc::printState(Signal* signal, int place) << " keylen = " << regCachePtr->keylen << endl; } else { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if }//if #endif @@ -1446,7 +1448,7 @@ Dbtc::TCKEY_abort(Signal* signal, int place) return; case 6: jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; case 7: @@ -1467,7 +1469,7 @@ Dbtc::TCKEY_abort(Signal* signal, int place) case 10: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 11: @@ -1498,7 +1500,7 @@ Dbtc::TCKEY_abort(Signal* signal, int place) /* PARTICULAR TC CONNECT RECORD. THIS MUST BE CAUSED BY NDB */ /* INTERNAL ERROR. */ /********************************************************************/ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch return; @@ -1511,17 +1513,17 @@ Dbtc::TCKEY_abort(Signal* signal, int place) case 16: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 17: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 18: jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; case 19: @@ -1530,22 +1532,22 @@ Dbtc::TCKEY_abort(Signal* signal, int place) case 20: jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; case 21: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 22: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 23: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 24: @@ -1555,7 +1557,7 @@ Dbtc::TCKEY_abort(Signal* signal, int place) case 25: jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; case 26: @@ -1563,7 +1565,7 @@ Dbtc::TCKEY_abort(Signal* signal, int place) return; case 27: - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); jam(); return; @@ -1574,92 +1576,92 @@ Dbtc::TCKEY_abort(Signal* signal, int place) case 29: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 30: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 31: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 32: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 33: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 34: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 35: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 36: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 37: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 38: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 39: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 40: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 41: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 42: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 43: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 44: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 45: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 46: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 47: @@ -1681,7 +1683,7 @@ Dbtc::TCKEY_abort(Signal* signal, int place) case 50: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; case 51: @@ -1757,7 +1759,7 @@ Dbtc::TCKEY_abort(Signal* signal, int place) default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch } @@ -1770,7 +1772,7 @@ void Dbtc::execKEYINFO(Signal* signal) tmaxData = 20; if (apiConnectptr.i >= capiConnectFilesize) { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//if ptrAss(apiConnectptr, apiConnectRecord); @@ -1817,7 +1819,7 @@ void Dbtc::execKEYINFO(Signal* signal) return; default: jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//switch @@ -3083,7 +3085,7 @@ void Dbtc::tckeyreq050Lab(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch attrinfoDihReceivedLab(signal); @@ -3150,7 +3152,7 @@ void Dbtc::sendlqhkeyreq(Signal* signal, CacheRecord * const regCachePtr = cachePtr.p; #ifdef ERROR_INSERT if (ERROR_INSERTED(8002)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8007)) { if (apiConnectptr.p->apiConnectstate == CS_STARTED) { @@ -3409,7 +3411,7 @@ void Dbtc::releaseAttrinfo() regApiPtr->cachePtr = RNIL; return; }//if - systemErrorLab(0); + systemErrorLab(0, __LINE__); return; }//Dbtc::releaseAttrinfo() @@ -3522,7 +3524,7 @@ void Dbtc::execPACKED_SIGNAL(Signal* signal) Tlength = signal->length(); if (Tlength > 25) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if Uint32* TpackDataPtr; @@ -3577,7 +3579,7 @@ void Dbtc::execPACKED_SIGNAL(Signal* signal) Tstep += LqhKeyConf::SignalLength; break; default: - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch }//while @@ -3655,7 +3657,7 @@ void Dbtc::execLQHKEYCONF(Signal* signal) #ifdef ERROR_INSERT if (ERROR_INSERTED(8029)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8003)) { if (regApiPtr->apiConnectstate == CS_STARTED) { @@ -4140,7 +4142,7 @@ void Dbtc::diverify010Lab(Signal* signal) signal->theData[0] = apiConnectptr.i; if (ERROR_INSERTED(8022)) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if if (TfirstfreeApiConnectCopy != RNIL) { seizeApiConnectCopy(signal); @@ -4454,7 +4456,7 @@ Dbtc::DIVER_node_fail_handling(Signal* signal, UintR Tgci) *------------------------------------------------------------------------*/ tabortInd = ZFALSE; setupFailData(signal); - if (tabortInd == ZFALSE) { + if (false && tabortInd == ZFALSE) { jam(); commitGciHandling(signal, Tgci); toCommitHandlingLab(signal); @@ -4488,7 +4490,7 @@ void Dbtc::execCOMMITTED(Signal* signal) return; }//if if (ERROR_INSERTED(8030)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8025)) { SET_ERROR_INSERT_VALUE(8026); @@ -4542,7 +4544,7 @@ void Dbtc::execCOMMITTED(Signal* signal) }//if if (ERROR_INSERTED(8020)) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if /*-------------------------------------------------------*/ /* THE ENTIRE TRANSACTION IS NOW COMMITED */ @@ -4658,6 +4660,7 @@ void Dbtc::copyApi(Signal* signal) regTmpApiPtr->commitAckMarker = RNIL; regTmpApiPtr->firstTcConnect = RNIL; regTmpApiPtr->lastTcConnect = RNIL; + releaseAllSeizedIndexOperations(regTmpApiPtr); }//Dbtc::copyApi() void Dbtc::unlinkApiConnect(Signal* signal) @@ -4779,7 +4782,7 @@ Dbtc::execTC_COMMIT_ACK(Signal* signal){ m_commitAckMarkerHash.release(removedMarker, key); if (removedMarker.i == RNIL) { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//if sendRemoveMarkers(signal, removedMarker.p); @@ -4841,7 +4844,7 @@ void Dbtc::execCOMPLETED(Signal* signal) #ifdef ERROR_INSERT if (ERROR_INSERTED(8031)) { - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8019)) { CLEAR_ERROR_INSERT_VALUE; @@ -4900,7 +4903,7 @@ void Dbtc::execCOMPLETED(Signal* signal) }//if if (ERROR_INSERTED(8021)) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if apiConnectptr = localApiConnectptr; releaseTransResources(signal); @@ -5340,7 +5343,7 @@ void Dbtc::execTC_COMMITREQ(Signal* signal) return; break; default: - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//switch TcCommitRef * const commitRef = (TcCommitRef*)&signal->theData[0]; @@ -5353,7 +5356,7 @@ void Dbtc::execTC_COMMITREQ(Signal* signal) return; } else /** apiConnectptr.i < capiConnectFilesize */ { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; } }//Dbtc::execTC_COMMITREQ() @@ -5449,12 +5452,12 @@ void Dbtc::execTCROLLBACKREQ(Signal* signal) TC_ROLL_warning: jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; TC_ROLL_system_error: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Dbtc::execTCROLLBACKREQ() @@ -5695,7 +5698,7 @@ void Dbtc::errorReport(Signal* signal, int place) jam(); break; }//switch - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Dbtc::errorReport() @@ -5752,7 +5755,7 @@ void Dbtc::execABORTED(Signal* signal) }//if if (ERROR_INSERTED(8024)) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if /** @@ -5925,12 +5928,12 @@ ABORT020: case OS_ABORT_SENT: jam(); DEBUG("ABORT_SENT state in abort015Lab(), not expected"); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; default: jam(); DEBUG("tcConnectstate = " << tcConnectptr.p->tcConnectstate); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch @@ -6046,7 +6049,7 @@ void Dbtc::checkStartTimeout(Signal* signal) ctimeOutMissedHeartbeats++; if (ctimeOutMissedHeartbeats > 100){ jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); } } ctimeOutCheckLastHeartbeat = ctimeOutCheckHeartbeat; @@ -6235,7 +6238,7 @@ void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr) if (((ctcTimer - getApiConTimer(apiConnectptr.i)) > (10 * ctimeOutValue)) && ((ctcTimer - getApiConTimer(apiConnectptr.i)) > 500)) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if break; case CS_COMMIT_SENT: @@ -6383,7 +6386,7 @@ void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr) /* AN IMPOSSIBLE STATE IS SET. CRASH THE SYSTEM. */ /*------------------------------------------------------------------*/ DEBUG("State = " << apiConnectptr.p->apiConnectstate); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch return; @@ -6653,7 +6656,7 @@ void Dbtc::execSCAN_HBREP(Signal* signal) break; default: DEBUG("execSCAN_HBREP: scanFragState="<<scanFragptr.p->scanFragState); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; } @@ -6751,7 +6754,7 @@ void Dbtc::timeOutFoundFragLab(Signal* signal, UintR TscanConPtr) * version. In a release version we will simply set the time-out to zero. *-----------------------------------------------------------------------*/ #ifdef VM_TRACE - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); #endif scanFragptr.p->stopFragTimer(); break; @@ -6760,7 +6763,7 @@ void Dbtc::timeOutFoundFragLab(Signal* signal, UintR TscanConPtr) /*----------------------------------------------------------------------- * Non-existent state. Crash. *-----------------------------------------------------------------------*/ - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; }//switch @@ -7098,7 +7101,7 @@ void Dbtc::execTAKE_OVERTCCONF(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch }//Dbtc::execTAKE_OVERTCCONF() @@ -7327,7 +7330,7 @@ void Dbtc::completeTransAtTakeOverDoLast(Signal* signal, UintR TtakeOverInd) arrGuard(TtakeOverInd, MAX_NDB_NODES); if (tcNodeFailptr.p->takeOverProcState[TtakeOverInd] != ZTAKE_OVER_ACTIVE) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if tcNodeFailptr.p->takeOverProcState[TtakeOverInd] = ZTAKE_OVER_IDLE; @@ -7454,7 +7457,7 @@ void Dbtc::completeTransAtTakeOverDoOne(Signal* signal, UintR TtakeOverInd) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch }//Dbtc::completeTransAtTakeOverDoOne() @@ -7580,7 +7583,7 @@ void Dbtc::toAbortHandlingLab(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//switch }//if @@ -7689,7 +7692,7 @@ void Dbtc::execCOMMITCONF(Signal* signal) }//if if (ERROR_INSERTED(8026)) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if tcurrentReplicaNo = (Uint8)Z8NIL; tcConnectptr.p->tcConnectstate = OS_COMMITTED; @@ -7739,7 +7742,7 @@ void Dbtc::toCommitHandlingLab(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -7834,7 +7837,7 @@ void Dbtc::execCOMPLETECONF(Signal* signal) }//if if (ERROR_INSERTED(8028)) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if tcConnectptr.p->tcConnectstate = OS_COMPLETED; tcurrentReplicaNo = (Uint8)Z8NIL; @@ -7949,7 +7952,7 @@ FAF_LOOP: jam(); if (cfirstfreeApiConnectFail == RNIL) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if seizeApiConnectFail(signal); @@ -7993,7 +7996,7 @@ void Dbtc::findTcConnectFail(Signal* signal) jam(); if (cfirstfreeTcConnectFail == RNIL) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if seizeTcConnectFail(signal); @@ -8052,7 +8055,7 @@ void Dbtc::initApiConnectFail(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if apiConnectptr.p->commitAckMarker = RNIL; if(LqhTransConf::getMarkerFlag(treqinfo)){ @@ -8174,7 +8177,7 @@ void Dbtc::setupFailData(Signal* signal) break; default: jam(); - sendSystemError(signal); + sendSystemError(signal, __LINE__); break; }//switch if (tabortInd != ZCOMMIT_SETUP) { @@ -8261,7 +8264,7 @@ void Dbtc::updateApiStateFail(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; }//switch break; @@ -8284,7 +8287,7 @@ void Dbtc::updateApiStateFail(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; }//switch break; @@ -8294,7 +8297,7 @@ void Dbtc::updateApiStateFail(Signal* signal) case CS_FAIL_COMMITTING: case CS_FAIL_COMMITTED: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; case CS_FAIL_PREPARED: jam(); @@ -8307,7 +8310,7 @@ void Dbtc::updateApiStateFail(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; }//switch break; @@ -8316,7 +8319,7 @@ void Dbtc::updateApiStateFail(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; }//switch }//Dbtc::updateApiStateFail() @@ -8434,14 +8437,14 @@ void Dbtc::releaseAtErrorLab(Signal* signal) abortErrorLab(signal); }//Dbtc::releaseAtErrorLab() -void Dbtc::warningHandlerLab(Signal* signal) +void Dbtc::warningHandlerLab(Signal* signal, int line) { ndbassert(false); }//Dbtc::warningHandlerLab() -void Dbtc::systemErrorLab(Signal* signal) +void Dbtc::systemErrorLab(Signal* signal, int line) { - progError(0, 0); + progError(line, NDBD_EXIT_NDBREQUIRE); }//Dbtc::systemErrorLab() @@ -8571,7 +8574,7 @@ void Dbtc::execSCAN_TABREQ(Signal* signal) if (apiConnectptr.i >= capiConnectFilesize) { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//if @@ -9211,7 +9214,7 @@ void Dbtc::execSCAN_FRAGREF(Signal* signal) transid1 = transid1 | transid2; if (transid1 != 0) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if /** @@ -9307,7 +9310,7 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) transid1 = transid1 | transid2; if (transid1 != 0) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE); @@ -9395,7 +9398,7 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal) apiConnectptr.i = req->apiConnectPtr; if (apiConnectptr.i >= capiConnectFilesize) { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//if ptrAss(apiConnectptr, apiConnectRecord); @@ -10044,7 +10047,7 @@ void Dbtc::initialiseRecordsLab(Signal* signal, UintR Tdata0, break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -10239,7 +10242,7 @@ void Dbtc::releaseAbortResources(Signal* signal) // apiConnectptr.p->apiConnectstate = CS_CONNECTED; apiConnectptr.p->apiConnectstate = CS_ABORTING; apiConnectptr.p->abortState = AS_IDLE; - + releaseAllSeizedIndexOperations(apiConnectptr.p); if(apiConnectptr.p->m_exec_flag || apiConnectptr.p->apiFailState == ZTRUE){ jam(); bool ok = false; @@ -10281,7 +10284,7 @@ void Dbtc::releaseAbortResources(Signal* signal) if(!ok){ jam(); ndbout_c("returnsignal = %d", apiConnectptr.p->returnsignal); - sendSystemError(signal); + sendSystemError(signal, __LINE__); }//if } @@ -10508,9 +10511,9 @@ void Dbtc::sendKeyinfo(Signal* signal, BlockReference TBRef, Uint32 len) sendSignal(TBRef, GSN_KEYINFO, signal, 3 + len, JBB); }//Dbtc::sendKeyinfo() -void Dbtc::sendSystemError(Signal* signal) +void Dbtc::sendSystemError(Signal* signal, int line) { - progError(0, 0); + progError(line, NDBD_EXIT_NDBREQUIRE); }//Dbtc::sendSystemError() /* ========================================================================= */ @@ -10531,7 +10534,7 @@ void Dbtc::unlinkGcp(Signal* signal) * WE ARE TRYING TO REMOVE A GLOBAL CHECKPOINT WHICH WAS NOT THE OLDEST. * THIS IS A SYSTEM ERROR. * ------------------------------------------------------------------- */ - sendSystemError(signal); + sendSystemError(signal, __LINE__); }//if gcpPtr.p->nextGcp = cfirstfreeGcp; cfirstfreeGcp = gcpPtr.i; @@ -10812,6 +10815,33 @@ Dbtc::execDUMP_STATE_ORD(Signal* signal) signal->theData[0] = TcContinueB::ZTRANS_EVENT_REP; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 1); } + + if (dumpState->args[0] == DumpStateOrd::TcStartDumpIndexOpCount) + { + static int frequency = 1; + if (signal->getLength() > 1) + frequency = signal->theData[1]; + else + if (refToBlock(signal->getSendersBlockRef()) != DBTC) + frequency = 1; + + if (frequency) + { + dumpState->args[0] = DumpStateOrd::TcDumpIndexOpCount; + execDUMP_STATE_ORD(signal); + dumpState->args[0] = DumpStateOrd::TcStartDumpIndexOpCount; + + Uint32 delay = 1000 * (frequency > 25 ? 25 : frequency); + sendSignalWithDelay(cownref, GSN_DUMP_STATE_ORD, signal, delay, 1); + } + } + + if (dumpState->args[0] == DumpStateOrd::TcDumpIndexOpCount) + { + infoEvent("IndexOpCount: pool: %d free: %d", + c_theIndexOperationPool.getSize(), + c_theIndexOperationPool.getNoOfFree()); + } }//Dbtc::execDUMP_STATE_ORD() void Dbtc::execSET_VAR_REQ(Signal* signal) @@ -11260,7 +11290,7 @@ void Dbtc::execTCINDXREQ(Signal* signal) transPtr.i = TapiIndex; if (transPtr.i >= capiConnectFilesize) { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//if ptrAss(transPtr, apiConnectRecord); @@ -11414,7 +11444,7 @@ void Dbtc::execINDXKEYINFO(Signal* signal) transPtr.i = TconnectIndex; if (transPtr.i >= capiConnectFilesize) { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//if ptrAss(transPtr, apiConnectRecord); @@ -11447,7 +11477,7 @@ void Dbtc::execINDXATTRINFO(Signal* signal) transPtr.i = TconnectIndex; if (transPtr.i >= capiConnectFilesize) { jam(); - warningHandlerLab(signal); + warningHandlerLab(signal, __LINE__); return; }//if ptrAss(transPtr, apiConnectRecord); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp index 52ac96bc5d3..66e98bd2805 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp @@ -75,25 +75,8 @@ Dbtup::Dbtup(const class Configuration & conf) c_storedProcPool(), c_buildIndexList(c_buildIndexPool) { - Uint32 log_page_size= 0; BLOCK_CONSTRUCTOR(Dbtup); - const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator(); - ndbrequire(p != 0); - - ndb_mgm_get_int_parameter(p, CFG_DB_UNDO_DATA_BUFFER, - &log_page_size); - - /** - * Always set page size in half MBytes - */ - cnoOfUndoPage= (log_page_size / sizeof(UndoPage)); - Uint32 mega_byte_part= cnoOfUndoPage & 15; - if (mega_byte_part != 0) { - jam(); - cnoOfUndoPage+= (16 - mega_byte_part); - } - addRecSignal(GSN_DEBUG_SIG, &Dbtup::execDEBUG_SIG); addRecSignal(GSN_CONTINUEB, &Dbtup::execCONTINUEB); @@ -143,6 +126,22 @@ Dbtup::Dbtup(const class Configuration & conf) addRecSignal(GSN_ACC_CHECK_SCAN, &Dbtup::execACC_CHECK_SCAN); initData(); + + attrbufrec = 0; + checkpointInfo = 0; + diskBufferSegmentInfo = 0; + fragoperrec = 0; + fragrecord = 0; + hostBuffer = 0; + localLogInfo = 0; + operationrec = 0; + page = 0; + pageRange = 0; + pendingFileOpenInfo = 0; + restartInfoRecord = 0; + tablerec = 0; + tableDescriptor = 0; + undoPage = 0; }//Dbtup::Dbtup() Dbtup::~Dbtup() @@ -603,6 +602,20 @@ void Dbtup::execREAD_CONFIG_REQ(Signal* signal) theConfiguration.getOwnConfigIterator(); ndbrequire(p != 0); + Uint32 log_page_size= 0; + ndb_mgm_get_int_parameter(p, CFG_DB_UNDO_DATA_BUFFER, + &log_page_size); + + /** + * Always set page size in half MBytes + */ + cnoOfUndoPage= (log_page_size / sizeof(UndoPage)); + Uint32 mega_byte_part= cnoOfUndoPage & 15; + if (mega_byte_part != 0) { + jam(); + cnoOfUndoPage+= (16 - mega_byte_part); + } + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUP_FRAG, &cnoOfFragrec)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUP_OP_RECS, &cnoOfOprec)); @@ -622,16 +635,19 @@ void Dbtup::execREAD_CONFIG_REQ(Signal* signal) ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_TRIGGERS, &noOfTriggers)); + Uint32 nScanOp; // use TUX config for now + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUX_SCAN_OP, &nScanOp)); + + cnoOfTabDescrRec = (cnoOfTabDescrRec & 0xFFFFFFF0) + 16; + + initRecords(); + c_storedProcPool.setSize(noOfStoredProc); c_buildIndexPool.setSize(c_noOfBuildIndexRec); c_triggerPool.setSize(noOfTriggers); - - Uint32 nScanOp; // use TUX config for now - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUX_SCAN_OP, &nScanOp)); c_scanOpPool.setSize(nScanOp); - initRecords(); czero = 0; cminusOne = czero - 1; clastBitMask = 1; @@ -656,6 +672,19 @@ void Dbtup::initRecords() unsigned i; // Records with dynamic sizes + page = (Page*)allocRecord("Page", + sizeof(Page), + cnoOfPage, + false); + + undoPage = (UndoPage*)allocRecord("UndoPage", + sizeof(UndoPage), + cnoOfUndoPage); + + operationrec = (Operationrec*)allocRecord("Operationrec", + sizeof(Operationrec), + cnoOfOprec); + attrbufrec = (Attrbufrec*)allocRecord("Attrbufrec", sizeof(Attrbufrec), cnoOfAttrbufrec); @@ -690,15 +719,6 @@ void Dbtup::initRecords() sizeof(LocalLogInfo), cnoOfParallellUndoFiles); - operationrec = (Operationrec*)allocRecord("Operationrec", - sizeof(Operationrec), - cnoOfOprec); - - page = (Page*)allocRecord("Page", - sizeof(Page), - cnoOfPage, - false); - pageRange = (PageRange*)allocRecord("PageRange", sizeof(PageRange), cnoOfPageRangeRec); @@ -728,11 +748,6 @@ void Dbtup::initRecords() sizeof(TableDescriptor), cnoOfTabDescrRec); - undoPage = (UndoPage*)allocRecord("UndoPage", - sizeof(UndoPage), - cnoOfUndoPage); - - // Initialize BAT for interface to file system NewVARIABLE* bat = allocateBat(3); bat[1].WA = &page->pageWord[0]; diff --git a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index 3170d23499a..acdad3f9f1a 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -1004,8 +1004,19 @@ Dbtup::read_psuedo(Uint32 attrId, Uint32* outBuffer){ return 1; case AttributeHeader::FRAGMENT_MEMORY: { - Uint64 tmp= fragptr.p->noOfPages; - tmp*= 32768; + Uint64 tmp = 0; + tmp += fragptr.p->noOfPages; + { + /** + * Each fragment is split into 2...get #pages from other as well + */ + Uint32 twin = fragptr.p->fragmentId ^ 1; + FragrecordPtr twinPtr; + getFragmentrec(twinPtr, twin, tabptr.p); + ndbrequire(twinPtr.p != 0); + tmp += twinPtr.p->noOfPages; + } + tmp *= 32768; memcpy(outBuffer,&tmp,8); } return 2; diff --git a/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp b/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp index 33d63e8ce49..35d1b75e573 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp @@ -187,7 +187,7 @@ Dbtup::rfrInitRestartInfoLab(Signal* signal, DiskBufferSegmentInfoPtr dbsiPtr) const Uint32 pageCount = riPtr.p->sriNumDataPages - regFragPtr.p->noOfPages; if(pageCount > 0){ Uint32 noAllocPages = allocFragPages(regFragPtr.p, pageCount); - ndbrequire(noAllocPages == pageCount); + ndbrequireErr(noAllocPages == pageCount, NDBD_EXIT_SR_OUT_OF_DATAMEMORY); }//if ndbrequire(getNoOfPages(regFragPtr.p) == riPtr.p->sriNumDataPages); diff --git a/ndb/src/kernel/blocks/dbutil/DbUtil.cpp b/ndb/src/kernel/blocks/dbutil/DbUtil.cpp index b94bb8e6d7e..0f45c407d83 100644 --- a/ndb/src/kernel/blocks/dbutil/DbUtil.cpp +++ b/ndb/src/kernel/blocks/dbutil/DbUtil.cpp @@ -60,6 +60,7 @@ DbUtil::DbUtil(const Configuration & conf) : BLOCK_CONSTRUCTOR(DbUtil); // Add received signals + addRecSignal(GSN_READ_CONFIG_REQ, &DbUtil::execREAD_CONFIG_REQ); addRecSignal(GSN_STTOR, &DbUtil::execSTTOR); addRecSignal(GSN_NDB_STTOR, &DbUtil::execNDB_STTOR); addRecSignal(GSN_DUMP_STATE_ORD, &DbUtil::execDUMP_STATE_ORD); @@ -111,47 +112,6 @@ DbUtil::DbUtil(const Configuration & conf) : addRecSignal(GSN_UTIL_RELEASE_REQ, &DbUtil::execUTIL_RELEASE_REQ); addRecSignal(GSN_UTIL_RELEASE_CONF, &DbUtil::execUTIL_RELEASE_CONF); addRecSignal(GSN_UTIL_RELEASE_REF, &DbUtil::execUTIL_RELEASE_REF); - - c_pagePool.setSize(10); - c_preparePool.setSize(1); // one parallel prepare at a time - c_preparedOperationPool.setSize(5); // three hardcoded, two for test - c_operationPool.setSize(64); // 64 parallel operations - c_transactionPool.setSize(32); // 16 parallel transactions - c_attrMappingPool.setSize(100); - c_dataBufPool.setSize(6000); // 6000*11*4 = 264K > 8k+8k*16 = 256k - { - SLList<Prepare> tmp(c_preparePool); - PreparePtr ptr; - while(tmp.seize(ptr)) - new (ptr.p) Prepare(c_pagePool); - tmp.release(); - } - { - SLList<Operation> tmp(c_operationPool); - OperationPtr ptr; - while(tmp.seize(ptr)) - new (ptr.p) Operation(c_dataBufPool, c_dataBufPool, c_dataBufPool); - tmp.release(); - } - { - SLList<PreparedOperation> tmp(c_preparedOperationPool); - PreparedOperationPtr ptr; - while(tmp.seize(ptr)) - new (ptr.p) PreparedOperation(c_attrMappingPool, - c_dataBufPool, c_dataBufPool); - tmp.release(); - } - { - SLList<Transaction> tmp(c_transactionPool); - TransactionPtr ptr; - while(tmp.seize(ptr)) - new (ptr.p) Transaction(c_pagePool, c_operationPool); - tmp.release(); - } - - c_lockQueuePool.setSize(5); - c_lockElementPool.setSize(5); - c_lockQueues.setSize(8); } DbUtil::~DbUtil() @@ -197,6 +157,68 @@ DbUtil::releaseTransaction(TransactionPtr transPtr){ c_runningTransactions.release(transPtr); } +void +DbUtil::execREAD_CONFIG_REQ(Signal* signal) +{ + jamEntry(); + + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + c_pagePool.setSize(10); + c_preparePool.setSize(1); // one parallel prepare at a time + c_preparedOperationPool.setSize(5); // three hardcoded, two for test + c_operationPool.setSize(64); // 64 parallel operations + c_transactionPool.setSize(32); // 16 parallel transactions + c_attrMappingPool.setSize(100); + c_dataBufPool.setSize(6000); // 6000*11*4 = 264K > 8k+8k*16 = 256k + { + SLList<Prepare> tmp(c_preparePool); + PreparePtr ptr; + while(tmp.seize(ptr)) + new (ptr.p) Prepare(c_pagePool); + tmp.release(); + } + { + SLList<Operation> tmp(c_operationPool); + OperationPtr ptr; + while(tmp.seize(ptr)) + new (ptr.p) Operation(c_dataBufPool, c_dataBufPool, c_dataBufPool); + tmp.release(); + } + { + SLList<PreparedOperation> tmp(c_preparedOperationPool); + PreparedOperationPtr ptr; + while(tmp.seize(ptr)) + new (ptr.p) PreparedOperation(c_attrMappingPool, + c_dataBufPool, c_dataBufPool); + tmp.release(); + } + { + SLList<Transaction> tmp(c_transactionPool); + TransactionPtr ptr; + while(tmp.seize(ptr)) + new (ptr.p) Transaction(c_pagePool, c_operationPool); + tmp.release(); + } + + c_lockQueuePool.setSize(5); + c_lockElementPool.setSize(5); + c_lockQueues.setSize(8); + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +} + void DbUtil::execSTTOR(Signal* signal) { diff --git a/ndb/src/kernel/blocks/dbutil/DbUtil.hpp b/ndb/src/kernel/blocks/dbutil/DbUtil.hpp index 5499970fde3..983dd4402a4 100644 --- a/ndb/src/kernel/blocks/dbutil/DbUtil.hpp +++ b/ndb/src/kernel/blocks/dbutil/DbUtil.hpp @@ -69,6 +69,7 @@ protected: /** * Startup & Misc */ + void execREAD_CONFIG_REQ(Signal* signal); void execSTTOR(Signal* signal); void execNDB_STTOR(Signal* signal); void execDUMP_STATE_ORD(Signal* signal); diff --git a/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp b/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp index 657133bda36..af19d8a83a4 100644 --- a/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp +++ b/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp @@ -173,6 +173,7 @@ private: // Received signals void execDUMP_STATE_ORD(Signal* signal); + void execREAD_CONFIG_REQ(Signal* signal); void execSTTOR(Signal* signal); void execTCSEIZECONF(Signal* signal); void execTCSEIZEREF(Signal* signal); @@ -224,7 +225,7 @@ private: CheckNodeGroups::Output checkNodeGroups(Signal*, const NdbNodeBitmask &); // Generated statement blocks - void systemErrorLab(Signal* signal); + void systemErrorLab(Signal* signal, int line); void createSystableLab(Signal* signal, unsigned index); void crSystab7Lab(Signal* signal); diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp index 97ca3f44b3a..5a939818d16 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp @@ -60,6 +60,7 @@ Ndbcntr::Ndbcntr(const class Configuration & conf): // Received signals addRecSignal(GSN_DUMP_STATE_ORD, &Ndbcntr::execDUMP_STATE_ORD); + addRecSignal(GSN_READ_CONFIG_REQ, &Ndbcntr::execREAD_CONFIG_REQ); addRecSignal(GSN_STTOR, &Ndbcntr::execSTTOR); addRecSignal(GSN_TCSEIZECONF, &Ndbcntr::execTCSEIZECONF); addRecSignal(GSN_TCSEIZEREF, &Ndbcntr::execTCSEIZEREF); diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index 6f28bb03537..bcf0839adc2 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -49,6 +49,10 @@ #include <NdbOut.hpp> #include <NdbTick.h> +// used during shutdown for reporting current startphase +// accessed from Emulator.cpp, NdbShutdown() +Uint32 g_currentStartPhase; + /** * ALL_BLOCKS Used during start phases and while changing node state * @@ -81,6 +85,24 @@ static BlockInfo ALL_BLOCKS[] = { static const Uint32 ALL_BLOCKS_SZ = sizeof(ALL_BLOCKS)/sizeof(BlockInfo); +static BlockReference readConfigOrder[ALL_BLOCKS_SZ] = { + DBTUP_REF, + DBACC_REF, + DBTC_REF, + DBLQH_REF, + DBTUX_REF, + DBDICT_REF, + DBDIH_REF, + NDBFS_REF, + NDBCNTR_REF, + QMGR_REF, + CMVMI_REF, + TRIX_REF, + BACKUP_REF, + DBUTIL_REF, + SUMA_REF +}; + /*******************************/ /* CONTINUEB */ /*******************************/ @@ -117,7 +139,7 @@ void Ndbcntr::execCONTINUEB(Signal* signal) else tmp.appfmt(" %d", to_3); - progError(__LINE__, ERR_SYSTEM_ERROR, tmp.c_str()); + progError(__LINE__, NDBD_EXIT_RESTART_TIMEOUT, tmp.c_str()); } signal->theData[0] = ZSTARTUP; @@ -130,7 +152,7 @@ void Ndbcntr::execCONTINUEB(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -148,13 +170,6 @@ void Ndbcntr::execSYSTEM_ERROR(Signal* signal) jamEntry(); switch (sysErr->errorCode){ - case SystemError::StartInProgressError: - BaseString::snprintf(buf, sizeof(buf), - "Node %d killed this node because " - "master start in progress error", - killingNode); - break; - case SystemError::GCPStopDetected: BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " @@ -162,20 +177,6 @@ void Ndbcntr::execSYSTEM_ERROR(Signal* signal) killingNode); break; - case SystemError::ScanfragTimeout: - BaseString::snprintf(buf, sizeof(buf), - "Node %d killed this node because " - "a fragment scan timed out and could not be stopped", - killingNode); - break; - - case SystemError::ScanfragStateError: - BaseString::snprintf(buf, sizeof(buf), - "Node %d killed this node because " - "the state of a fragment scan was out of sync.", - killingNode); - break; - case SystemError::CopyFragRefError: BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " @@ -191,12 +192,31 @@ void Ndbcntr::execSYSTEM_ERROR(Signal* signal) break; } - progError(__LINE__, - ERR_SYSTEM_ERROR, - buf); + progError(__LINE__, NDBD_EXIT_SYSTEM_ERROR, buf); return; }//Ndbcntr::execSYSTEM_ERROR() +void +Ndbcntr::execREAD_CONFIG_REQ(Signal* signal) +{ + jamEntry(); + + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +} + void Ndbcntr::execSTTOR(Signal* signal) { jamEntry(); @@ -320,7 +340,7 @@ void Ndbcntr::execNDB_STTORRY(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -360,7 +380,7 @@ void Ndbcntr::startPhase1Lab(Signal* signal) void Ndbcntr::execREAD_NODESREF(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Ndbcntr::execREAD_NODESREF() @@ -371,7 +391,7 @@ void Ndbcntr::execREAD_NODESREF(Signal* signal) void Ndbcntr::execNDB_STARTREF(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Ndbcntr::execNDB_STARTREF() @@ -505,6 +525,9 @@ Ndbcntr::execCNTR_START_REF(Signal * signal){ cmasterNodeId = ref->masterNodeId; sendCntrStartReq(signal); return; + case CntrStartRef::StopInProgress: + jam(); + progError(__LINE__, NDBD_EXIT_RESTART_DURING_SHUTDOWN); } ndbrequire(false); } @@ -1345,7 +1368,7 @@ void Ndbcntr::execCNTR_WAITREP(Signal* signal) break; default: jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); break; }//switch }//Ndbcntr::execCNTR_WAITREP() @@ -1401,22 +1424,19 @@ void Ndbcntr::execNODE_FAILREP(Signal* signal) const bool tStartConf = (phase > 2) || (phase == 2 && cndbBlocksCount > 0); if(tMasterFailed){ - progError(__LINE__, - ERR_SR_OTHERNODEFAILED, + progError(__LINE__, NDBD_EXIT_SR_OTHERNODEFAILED, "Unhandled node failure during restart"); } if(tStartConf && tStarting){ // One of other starting nodes has crashed... - progError(__LINE__, - ERR_SR_OTHERNODEFAILED, + progError(__LINE__, NDBD_EXIT_SR_OTHERNODEFAILED, "Unhandled node failure of starting node during restart"); } if(tStartConf && tStarted){ // One of other started nodes has crashed... - progError(__LINE__, - ERR_SR_OTHERNODEFAILED, + progError(__LINE__, NDBD_EXIT_SR_OTHERNODEFAILED, "Unhandled node failure of started node during restart"); } @@ -1525,9 +1545,9 @@ void Ndbcntr::execREAD_NODESREQ(Signal* signal) /*----------------------------------------------------------------------*/ // SENDS APPL_ERROR TO QMGR AND THEN SET A POINTER OUT OF BOUNDS /*----------------------------------------------------------------------*/ -void Ndbcntr::systemErrorLab(Signal* signal) +void Ndbcntr::systemErrorLab(Signal* signal, int line) { - progError(0, 0); /* BUG INSERTION */ + progError(line, NDBD_EXIT_NDBREQUIRE); /* BUG INSERTION */ return; }//Ndbcntr::systemErrorLab() @@ -1599,7 +1619,7 @@ void Ndbcntr::createSystableLab(Signal* signal, unsigned index) void Ndbcntr::execCREATE_TABLE_REF(Signal* signal) { jamEntry(); - progError(0,0); + progError(__LINE__,NDBD_EXIT_NDBREQUIRE, "CREATE_TABLE_REF"); return; }//Ndbcntr::execDICTTABREF() @@ -1800,28 +1820,28 @@ void Ndbcntr::execGETGCICONF(Signal* signal) void Ndbcntr::execTCKEYREF(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Ndbcntr::execTCKEYREF() void Ndbcntr::execTCROLLBACKREP(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Ndbcntr::execTCROLLBACKREP() void Ndbcntr::execTCRELEASEREF(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Ndbcntr::execTCRELEASEREF() void Ndbcntr::execTCSEIZEREF(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Ndbcntr::execTCSEIZEREF() @@ -1962,6 +1982,11 @@ Ndbcntr::execRESUME_REQ(Signal* signal){ //ResumeRef * const ref = (ResumeRef *)&signal->theData[0]; jamEntry(); + + signal->theData[0] = NDB_LE_SingleUser; + signal->theData[1] = 2; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB); + //Uint32 senderData = req->senderData; //BlockReference senderRef = req->senderRef; NodeState newState(NodeState::SL_STARTED); @@ -2000,12 +2025,13 @@ Ndbcntr::execSTOP_REQ(Signal* signal){ return; } - if(c_stopRec.stopReq.senderRef != 0 && !singleuser){ - jam(); + if(c_stopRec.stopReq.senderRef != 0 || + (cmasterNodeId == getOwnNodeId() && !c_start.m_starting.isclear())) + { /** * Requested a system shutdown */ - if(StopReq::getSystemStop(req->requestInfo)){ + if(!singleuser && StopReq::getSystemStop(req->requestInfo)){ jam(); sendSignalWithDelay(reference(), GSN_STOP_REQ, signal, 100, StopReq::SignalLength); @@ -2015,7 +2041,8 @@ Ndbcntr::execSTOP_REQ(Signal* signal){ /** * Requested a node shutdown */ - if(StopReq::getSystemStop(c_stopRec.stopReq.requestInfo)) + if(c_stopRec.stopReq.senderRef && + StopReq::getSystemStop(c_stopRec.stopReq.requestInfo)) ref->errorCode = StopRef::SystemShutdownInProgress; else ref->errorCode = StopRef::NodeShutdownInProgress; @@ -2027,23 +2054,28 @@ Ndbcntr::execSTOP_REQ(Signal* signal){ c_stopRec.stopReq = * req; c_stopRec.stopInitiatedTime = NdbTick_CurrentMillisecond(); - if(StopReq::getSystemStop(c_stopRec.stopReq.requestInfo) && !singleuser) { - jam(); - if(StopReq::getPerformRestart(c_stopRec.stopReq.requestInfo)){ - ((Configuration&)theConfiguration).stopOnError(false); - } - } if(!singleuser) { + if(StopReq::getSystemStop(c_stopRec.stopReq.requestInfo)) { + jam(); + if(StopReq::getPerformRestart(c_stopRec.stopReq.requestInfo)){ + ((Configuration&)theConfiguration).stopOnError(false); + } + } if(!c_stopRec.checkNodeFail(signal)){ jam(); return; } + signal->theData[0] = NDB_LE_NDBStopStarted; + signal->theData[1] = StopReq::getSystemStop(c_stopRec.stopReq.requestInfo) ? 1 : 0; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB); } - - signal->theData[0] = NDB_LE_NDBStopStarted; - signal->theData[1] = StopReq::getSystemStop(c_stopRec.stopReq.requestInfo) ? 1 : 0; - sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB); - + else + { + signal->theData[0] = NDB_LE_SingleUser; + signal->theData[1] = 0; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB); + } + NodeState newState(NodeState::SL_STOPPING_1, StopReq::getSystemStop(c_stopRec.stopReq.requestInfo)); @@ -2125,9 +2157,11 @@ Ndbcntr::StopRecord::checkNodeFail(Signal* signal){ stopReq.senderRef = 0; - NodeState newState(NodeState::SL_STARTED); - - cntr.updateNodeState(signal, newState); + if (cntr.getNodeState().startLevel != NodeState::SL_SINGLEUSER) + { + NodeState newState(NodeState::SL_STARTED); + cntr.updateNodeState(signal, newState); + } signal->theData[0] = NDB_LE_NDBStopAborted; cntr.sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 1, JBB); @@ -2223,12 +2257,24 @@ void Ndbcntr::execABORT_ALL_CONF(Signal* signal){ jamEntry(); if(c_stopRec.stopReq.singleuser) { jam(); + NodeState newState(NodeState::SL_SINGLEUSER); newState.setSingleUser(true); newState.setSingleUserApi(c_stopRec.stopReq.singleUserApi); updateNodeState(signal, newState); c_stopRec.stopInitiatedTime = NdbTick_CurrentMillisecond(); + StopConf * const stopConf = (StopConf *)&signal->theData[0]; + stopConf->senderData = c_stopRec.stopReq.senderData; + stopConf->nodeState = (Uint32) NodeState::SL_SINGLEUSER; + sendSignal(c_stopRec.stopReq.senderRef, GSN_STOP_CONF, signal, StopConf::SignalLength, JBB); + + c_stopRec.stopReq.senderRef = 0; // the command is done + + signal->theData[0] = NDB_LE_SingleUser; + signal->theData[1] = 1; + signal->theData[2] = c_stopRec.stopReq.singleUserApi; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB); } else { @@ -2246,7 +2292,13 @@ void Ndbcntr::execABORT_ALL_CONF(Signal* signal){ void Ndbcntr::execABORT_ALL_REF(Signal* signal){ jamEntry(); - ndbrequire(false); + AbortAllRef *abortAllRef = (AbortAllRef *)&signal->theData[0]; + AbortAllRef::ErrorCode errorCode = (AbortAllRef::ErrorCode) abortAllRef->errorCode; + + StopRef * const stopRef = (StopRef *)&signal->theData[0]; + stopRef->senderData = c_stopRec.stopReq.senderData; + stopRef->errorCode = StopRef::TransactionAbortFailed; + sendSignal(c_stopRec.stopReq.senderRef, GSN_STOP_REF, signal, StopRef::SignalLength, JBB); } void @@ -2425,7 +2477,7 @@ void Ndbcntr::Missra::sendNextREAD_CONFIG_REQ(Signal* signal){ req->senderRef = cntr.reference(); req->noOfParameters = 0; - const BlockReference ref = ALL_BLOCKS[currentBlockIndex].Ref; + const BlockReference ref = readConfigOrder[currentBlockIndex]; #if 0 ndbout_c("sending READ_CONFIG_REQ to %s(ref=%x index=%d)", @@ -2456,7 +2508,8 @@ void Ndbcntr::Missra::execREAD_CONFIG_CONF(Signal* signal){ const ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtr(); const Uint32 ref = conf->senderRef; - ndbrequire(refToBlock(ALL_BLOCKS[currentBlockIndex].Ref) == refToBlock(ref)); + ndbrequire(refToBlock(readConfigOrder[currentBlockIndex]) + == refToBlock(ref)); currentBlockIndex++; sendNextREAD_CONFIG_REQ(signal); @@ -2484,11 +2537,20 @@ void Ndbcntr::Missra::execSTTORRY(Signal* signal){ void Ndbcntr::Missra::sendNextSTTOR(Signal* signal){ - for(; currentStartPhase < 255 ; currentStartPhase++){ + for(; currentStartPhase < 255 ; + currentStartPhase++, g_currentStartPhase = currentStartPhase){ jam(); const Uint32 start = currentBlockIndex; - + + if (currentStartPhase == ZSTART_PHASE_6) + { + // Ndbd has passed the critical startphases. + // Change error handler from "startup" state + // to normal state. + ErrorReporter::setErrorHandlerShutdownType(); + } + for(; currentBlockIndex < ALL_BLOCKS_SZ; currentBlockIndex++){ jam(); if(ALL_BLOCKS[currentBlockIndex].NextSP == currentStartPhase){ @@ -2627,7 +2689,8 @@ UpgradeStartup::execCM_APPCHG(SimulatedBlock & block, Signal* signal){ return; } } - block.progError(0,0); + block.progError(__LINE__,NDBD_EXIT_NDBREQUIRE, + "UpgradeStartup::execCM_APPCHG"); } void @@ -2640,7 +2703,9 @@ UpgradeStartup::sendCntrMasterReq(Ndbcntr& cntr, Signal* signal, Uint32 n){ } if(node == NdbNodeBitmask::NotFound){ - cntr.progError(0,0); + cntr.progError(__LINE__,NDBD_EXIT_NDBREQUIRE, + "UpgradeStartup::sendCntrMasterReq " + "NdbNodeBitmask::NotFound"); } CntrMasterReq * const cntrMasterReq = (CntrMasterReq*)&signal->theData[0]; @@ -2682,5 +2747,6 @@ UpgradeStartup::execCNTR_MASTER_REPLY(SimulatedBlock & block, Signal* signal){ } } } - block.progError(0,0); + block.progError(__LINE__,NDBD_EXIT_NDBREQUIRE, + "UpgradeStartup::execCNTR_MASTER_REPLY"); } diff --git a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp index 45073b63a5d..ddf16024017 100644 --- a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp +++ b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp @@ -18,12 +18,11 @@ #include <my_sys.h> #include <my_pthread.h> -#include <Error.hpp> #include "AsyncFile.hpp" #include <ErrorHandlingMacros.hpp> #include <kernel_types.h> -#include <NdbMem.h> +#include <ndbd_malloc.hpp> #include <NdbThread.h> #include <signaldata/FsOpenReq.hpp> @@ -162,7 +161,7 @@ AsyncFile::run() theStartFlag = true; // Create write buffer for bigger writes theWriteBufferSize = WRITEBUFFERSIZE; - theWriteBuffer = (char *) NdbMem_Allocate(theWriteBufferSize); + theWriteBuffer = (char *) ndbd_malloc(theWriteBufferSize); NdbMutex_Unlock(theStartMutexPtr); NdbCondition_Signal(theStartConditionPtr); @@ -513,7 +512,7 @@ AsyncFile::extendfile(Request* request) { DEBUG(ndbout_c("extendfile: maxOffset=%d, size=%d", maxOffset, maxSize)); // Allocate a buffer and fill it with zeros - void* pbuf = NdbMem_Allocate(maxSize); + void* pbuf = ndbd_malloc(maxSize); memset(pbuf, 0, maxSize); for (int p = 0; p <= maxOffset; p = p + maxSize) { int return_value; @@ -521,16 +520,18 @@ AsyncFile::extendfile(Request* request) { p, SEEK_SET); if((return_value == -1 ) || (return_value != p)) { + ndbd_free(pbuf,maxSize); return -1; } return_value = ::write(theFd, pbuf, maxSize); if ((return_value == -1) || (return_value != maxSize)) { + ndbd_free(pbuf,maxSize); return -1; } } - free(pbuf); + ndbd_free(pbuf,maxSize); DEBUG(ndbout_c("extendfile: \"%s\" OK!", theFileName.c_str())); return 0; @@ -880,7 +881,7 @@ AsyncFile::rmrfReq(Request * request, char * path, bool removePath){ void AsyncFile::endReq() { // Thread is ended with return - if (theWriteBuffer) NdbMem_Free(theWriteBuffer); + if (theWriteBuffer) ndbd_free(theWriteBuffer, theWriteBufferSize); } diff --git a/ndb/src/kernel/blocks/ndbfs/Filename.cpp b/ndb/src/kernel/blocks/ndbfs/Filename.cpp index 15158ec19ef..238390f262c 100644 --- a/ndb/src/kernel/blocks/ndbfs/Filename.cpp +++ b/ndb/src/kernel/blocks/ndbfs/Filename.cpp @@ -20,7 +20,6 @@ #include "Filename.hpp" #include "ErrorHandlingMacros.hpp" -#include "Error.hpp" #include "RefConvert.hpp" #include "DebuggerNames.hpp" @@ -52,7 +51,7 @@ Filename::init(Uint32 nodeid, DBUG_ENTER("Filename::init"); if (pFileSystemPath == NULL) { - ERROR_SET(fatal, AFS_ERROR_NOPATH, ""," Filename::init()"); + ERROR_SET(fatal, NDBD_EXIT_AFS_NOPATH, "","Missing FileSystemPath"); return; } @@ -109,7 +108,7 @@ Filename::set(BlockReference blockReference, { const char* blockName = getBlockName( refToBlock(blockReference) ); if (blockName == NULL){ - ERROR_SET(ecError, AFS_ERROR_PARAMETER,"","No Block Name"); + ERROR_SET(ecError, NDBD_EXIT_AFS_PARAMETER,"","No Block Name"); return; } BaseString::snprintf(buf, sizeof(buf), "%s%s", blockName, DIR_SEPARATOR); @@ -165,7 +164,7 @@ Filename::set(BlockReference blockReference, const Uint32 diskNo = FsOpenReq::v1_getDisk(filenumber); if(diskNo == 0xFF){ - ERROR_SET(ecError, AFS_ERROR_PARAMETER,"","Invalid disk specification"); + ERROR_SET(ecError, NDBD_EXIT_AFS_PARAMETER,"","Invalid disk specification"); } BaseString::snprintf(buf, sizeof(buf), "D%d%s", diskNo, DIR_SEPARATOR); @@ -174,10 +173,10 @@ Filename::set(BlockReference blockReference, } break; default: - ERROR_SET(ecError, AFS_ERROR_PARAMETER,"","Wrong version"); + ERROR_SET(ecError, NDBD_EXIT_AFS_PARAMETER,"","Wrong version"); } if (type >= noOfExtensions){ - ERROR_SET(ecError, AFS_ERROR_PARAMETER,"","File Type doesn't exist"); + ERROR_SET(ecError, NDBD_EXIT_AFS_PARAMETER,"","File Type doesn't exist"); return; } strcat(theName, fileExtension[type]); diff --git a/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp b/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp index 9037bbad765..f46cc66fe16 100644 --- a/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp +++ b/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp @@ -70,7 +70,6 @@ #else #include "ErrorHandlingMacros.hpp" -#include "Error.hpp" #include "CircularIndex.hpp" #include "NdbMutex.h" #include "NdbCondition.h" diff --git a/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp b/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp index d6b19c8f872..5049c726315 100644 --- a/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp +++ b/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp @@ -19,7 +19,6 @@ #include "Ndbfs.hpp" #include "AsyncFile.hpp" #include "Filename.hpp" -#include "Error.hpp" #include <signaldata/FsOpenReq.hpp> #include <signaldata/FsCloseReq.hpp> @@ -57,26 +56,10 @@ Ndbfs::Ndbfs(const Configuration & conf) : theLastId(0), m_maxOpenedFiles(0) { - theFileSystemPath = conf.fileSystemPath(); - theBackupFilePath = conf.backupFilePath(); - - theRequestPool = new Pool<Request>; - - const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator(); - ndbrequire(p != 0); - - m_maxFiles = 40; - ndb_mgm_get_int_parameter(p, CFG_DB_MAX_OPEN_FILES, &m_maxFiles); - - // Create idle AsyncFiles - Uint32 noIdleFiles = m_maxFiles > 27 ? 27 : m_maxFiles ; - for (Uint32 i = 0; i < noIdleFiles; i++){ - theIdleFiles.push_back(createAsyncFile()); - } - BLOCK_CONSTRUCTOR(Ndbfs); // Set received signals + addRecSignal(GSN_READ_CONFIG_REQ, &Ndbfs::execREAD_CONFIG_REQ); addRecSignal(GSN_DUMP_STATE_ORD, &Ndbfs::execDUMP_STATE_ORD); addRecSignal(GSN_STTOR, &Ndbfs::execSTTOR); addRecSignal(GSN_FSOPENREQ, &Ndbfs::execFSOPENREQ); @@ -88,6 +71,8 @@ Ndbfs::Ndbfs(const Configuration & conf) : addRecSignal(GSN_FSAPPENDREQ, &Ndbfs::execFSAPPENDREQ); addRecSignal(GSN_FSREMOVEREQ, &Ndbfs::execFSREMOVEREQ); // Set send signals + + theRequestPool = 0; } Ndbfs::~Ndbfs() @@ -102,7 +87,41 @@ Ndbfs::~Ndbfs() }//for theFiles.clear(); - delete theRequestPool; + if (theRequestPool) + delete theRequestPool; +} + +void +Ndbfs::execREAD_CONFIG_REQ(Signal* signal) +{ + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + theFileSystemPath = theConfiguration.fileSystemPath(); + theBackupFilePath = theConfiguration.backupFilePath(); + + theRequestPool = new Pool<Request>; + + m_maxFiles = 40; + ndb_mgm_get_int_parameter(p, CFG_DB_MAX_OPEN_FILES, &m_maxFiles); + + // Create idle AsyncFiles + Uint32 noIdleFiles = m_maxFiles > 27 ? 27 : m_maxFiles ; + for (Uint32 i = 0; i < noIdleFiles; i++){ + theIdleFiles.push_back(createAsyncFile()); + } + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); } /* Received a restart signal. @@ -557,7 +576,7 @@ Ndbfs::createAsyncFile(){ AsyncFile* file = theFiles[i]; ndbout_c("%2d (0x%x): %s", i, file, file->isOpen()?"OPEN":"CLOSED"); } - ERROR_SET(fatal, AFS_ERROR_MAXOPEN,""," Ndbfs::createAsyncFile"); + ERROR_SET(fatal, NDBD_EXIT_AFS_MAXOPEN,""," Ndbfs::createAsyncFile"); } AsyncFile* file = new AsyncFile; diff --git a/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp b/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp index c5aaa4e5c49..17ce8fbd8aa 100644 --- a/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp +++ b/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp @@ -41,6 +41,7 @@ protected: BLOCK_DEFINES(Ndbfs); // The signal processing functions + void execREAD_CONFIG_REQ(Signal* signal); void execDUMP_STATE_ORD(Signal* signal); void execFSOPENREQ(Signal* signal); void execFSCLOSEREQ(Signal* signal); @@ -103,6 +104,7 @@ protected: BLOCK_DEFINES(VoidFs); // The signal processing functions + void execREAD_CONFIG_REQ(Signal* signal); void execDUMP_STATE_ORD(Signal* signal); void execFSOPENREQ(Signal* signal); void execFSCLOSEREQ(Signal* signal); diff --git a/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp b/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp index 0fee687f1bc..eacda6ec77d 100644 --- a/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp +++ b/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp @@ -88,7 +88,7 @@ inline bool OpenFiles::insert(AsyncFile* file, Uint16 id){ names.assfmt("open: >%s< existing: >%s<", file->theFileName.c_str(), m_files[i].m_file->theFileName.c_str()); - ERROR_SET(fatal, AFS_ERROR_ALLREADY_OPEN, names.c_str(), + ERROR_SET(fatal, NDBD_EXIT_AFS_ALREADY_OPEN, names.c_str(), "OpenFiles::insert()"); } } diff --git a/ndb/src/kernel/blocks/ndbfs/VoidFs.cpp b/ndb/src/kernel/blocks/ndbfs/VoidFs.cpp index d093089acfc..5a03d8bb1a0 100644 --- a/ndb/src/kernel/blocks/ndbfs/VoidFs.cpp +++ b/ndb/src/kernel/blocks/ndbfs/VoidFs.cpp @@ -20,7 +20,6 @@ #include "Ndbfs.hpp" #include "AsyncFile.hpp" #include "Filename.hpp" -#include "Error.hpp" #include <signaldata/FsOpenReq.hpp> #include <signaldata/FsCloseReq.hpp> @@ -45,6 +44,7 @@ VoidFs::VoidFs(const Configuration & conf) : BLOCK_CONSTRUCTOR(VoidFs); // Set received signals + addRecSignal(GSN_READ_CONFIG_REQ, &VoidFs::execREAD_CONFIG_REQ); addRecSignal(GSN_DUMP_STATE_ORD, &VoidFs::execDUMP_STATE_ORD); addRecSignal(GSN_STTOR, &VoidFs::execSTTOR); addRecSignal(GSN_FSOPENREQ, &VoidFs::execFSOPENREQ); @@ -61,6 +61,21 @@ VoidFs::~VoidFs() { } +void +VoidFs::execREAD_CONFIG_REQ(Signal* signal) +{ + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +} + void VoidFs::execSTTOR(Signal* signal) { diff --git a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp index f84fae02fc4..4a17d56d31e 100644 --- a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp +++ b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp @@ -209,6 +209,7 @@ private: void execDUMP_STATE_ORD(Signal* signal); void execCONNECT_REP(Signal* signal); void execNDB_FAILCONF(Signal* signal); + void execREAD_CONFIG_REQ(Signal* signal); void execSTTOR(Signal* signal); void execCM_INFOCONF(Signal* signal); void execCLOSE_COMCONF(Signal* signal); diff --git a/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp b/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp index 4061455092d..751641ae896 100644 --- a/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp +++ b/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp @@ -75,6 +75,7 @@ Qmgr::Qmgr(const class Configuration & conf) // Received signals addRecSignal(GSN_CONNECT_REP, &Qmgr::execCONNECT_REP); addRecSignal(GSN_NDB_FAILCONF, &Qmgr::execNDB_FAILCONF); + addRecSignal(GSN_READ_CONFIG_REQ, &Qmgr::execREAD_CONFIG_REQ); addRecSignal(GSN_STTOR, &Qmgr::execSTTOR); addRecSignal(GSN_CLOSE_COMCONF, &Qmgr::execCLOSE_COMCONF); addRecSignal(GSN_API_REGREQ, &Qmgr::execAPI_REGREQ); diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp index 7052e0da98a..7003d70e8b1 100644 --- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp +++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp @@ -166,6 +166,27 @@ void Qmgr::execPRES_TOREQ(Signal* signal) return; }//Qmgr::execPRES_TOREQ() +void +Qmgr::execREAD_CONFIG_REQ(Signal* signal) +{ + jamEntry(); + + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +} + /* 4.2 ADD NODE MODULE*/ /*##########################################################################*/ @@ -700,11 +721,11 @@ void Qmgr::execCM_REGREF(Signal* signal) break; case CmRegRef::ZNOT_IN_CFG: jam(); - progError(__LINE__, ERR_NODE_NOT_IN_CONFIG); + progError(__LINE__, NDBD_EXIT_NODE_NOT_IN_CONFIG); break; case CmRegRef::ZNOT_DEAD: jam(); - progError(__LINE__, ERR_NODE_NOT_DEAD); + progError(__LINE__, NDBD_EXIT_NODE_NOT_DEAD); break; case CmRegRef::ZELECTION: jam(); @@ -1802,11 +1823,14 @@ void Qmgr::execNDB_FAILCONF(Signal* signal) /*******************************/ /* DISCONNECT_REP */ /*******************************/ +const char *lookupConnectionError(Uint32 err); + void Qmgr::execDISCONNECT_REP(Signal* signal) { jamEntry(); const DisconnectRep * const rep = (DisconnectRep *)&signal->theData[0]; const Uint32 nodeId = rep->nodeId; + const Uint32 err = rep->err; c_connectedNodes.clear(nodeId); NodeRecPtr nodePtr; @@ -1817,10 +1841,17 @@ void Qmgr::execDISCONNECT_REP(Signal* signal) jam(); break; case ZINIT: + ndbrequire(false); case ZSTARTING: + progError(__LINE__, NDBD_EXIT_CONNECTION_SETUP_FAILED, + lookupConnectionError(err)); + ndbrequire(false); case ZPREPARE_FAIL: + ndbrequire(false); case ZFAIL_CLOSING: + ndbrequire(false); case ZAPI_ACTIVE: + ndbrequire(false); case ZAPI_INACTIVE: ndbrequire(false); } @@ -2013,6 +2044,8 @@ Qmgr::execAPI_VERSION_REQ(Signal * signal) { else conf->version = 0; conf->nodeId = nodeId; + struct in_addr in= globalTransporterRegistry.get_connect_address(nodeId); + conf->inet_addr= in.s_addr; sendSignal(senderRef, GSN_API_VERSION_CONF, @@ -2678,7 +2711,7 @@ void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal, Uint32 line, "Node was shutdown during startup because node %d failed", failedNodeId); - progError(line, ERR_SR_OTHERNODEFAILED, buf); + progError(line, NDBD_EXIT_SR_OTHERNODEFAILED, buf); } @@ -2690,7 +2723,7 @@ void Qmgr::systemErrorLab(Signal* signal, Uint32 line, const char * message) // If it's known why shutdown occured // an error message has been passed to this function - progError(line, 0, message); + progError(line, NDBD_EXIT_NDBREQUIRE, message); return; }//Qmgr::systemErrorLab() @@ -3784,7 +3817,8 @@ Qmgr::stateArbitCrash(Signal* signal) if (! (arbitRec.getTimediff() > getArbitTimeout())) return; #endif - progError(__LINE__, ERR_ARBIT_SHUTDOWN, "Arbitrator decided to shutdown this node"); + progError(__LINE__, NDBD_EXIT_ARBIT_SHUTDOWN, + "Arbitrator decided to shutdown this node"); } /** diff --git a/ndb/src/kernel/blocks/suma/Suma.cpp b/ndb/src/kernel/blocks/suma/Suma.cpp index c4225ad2a4c..3644bc0a03f 100644 --- a/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/ndb/src/kernel/blocks/suma/Suma.cpp @@ -120,6 +120,64 @@ Suma::getNodeGroupMembers(Signal* signal) { #endif } +void +Suma::execREAD_CONFIG_REQ(Signal* signal) +{ + jamEntry(); + + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + // SumaParticipant + Uint32 noTables; + ndb_mgm_get_int_parameter(p, CFG_DB_NO_TABLES, + &noTables); + + /** + * @todo: fix pool sizes + */ + c_tablePool_.setSize(noTables); + c_tables.setSize(noTables); + + c_subscriptions.setSize(20); //10 + c_subscriberPool.setSize(64); + + c_subscriptionPool.setSize(64); //2 + c_syncPool.setSize(20); //2 + c_dataBufferPool.setSize(128); + + { + SLList<SyncRecord> tmp(c_syncPool); + Ptr<SyncRecord> ptr; + while(tmp.seize(ptr)) + new (ptr.p) SyncRecord(* this, c_dataBufferPool); + tmp.release(); + } + + // Suma + c_nodePool.setSize(MAX_NDB_NODES); + c_masterNodeId = getOwnNodeId(); + + c_nodeGroup = c_noNodesInGroup = c_idInNodeGroup = 0; + for (int i = 0; i < MAX_REPLICAS; i++) { + c_nodesInGroup[i] = 0; + } + + c_subCoordinatorPool.setSize(10); + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +} + void Suma::execSTTOR(Signal* signal) { jamEntry(); @@ -272,40 +330,6 @@ Suma::execREAD_NODESCONF(Signal* signal){ sendSTTORRY(signal); } -#if 0 -void -Suma::execREAD_CONFIG_REQ(Signal* signal) -{ - const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); - Uint32 ref = req->senderRef; - Uint32 senderData = req->senderData; - ndbrequire(req->noOfParameters == 0); - - jamEntry(); - - const ndb_mgm_configuration_iterator * p = - theConfiguration.getOwnConfigIterator(); - ndbrequire(p != 0); - - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_REDOLOG_FILES, - &cnoLogFiles)); - ndbrequire(cnoLogFiles > 0); - - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_FRAG, &cfragrecFileSize)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TABLE, &ctabrecFileSize)); - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TC_CONNECT, - &ctcConnectrecFileSize)); - clogFileFileSize = 4 * cnoLogFiles; - ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_SCAN, &cscanrecFileSize)); - cmaxAccOps = cscanrecFileSize * MAX_PARALLEL_SCANS_PER_FRAG; - - initRecords(); - initialiseRecordsLab(signal, 0, ref, senderData); - - return; -}//Dblqh::execSIZEALT_REP() -#endif - void Suma::sendSTTORRY(Signal* signal){ signal->theData[0] = 0; diff --git a/ndb/src/kernel/blocks/suma/Suma.hpp b/ndb/src/kernel/blocks/suma/Suma.hpp index 65869f44423..0638bd4a006 100644 --- a/ndb/src/kernel/blocks/suma/Suma.hpp +++ b/ndb/src/kernel/blocks/suma/Suma.hpp @@ -442,6 +442,8 @@ private: void getNodeGroupMembers(Signal* signal); + void execREAD_CONFIG_REQ(Signal* signal); + void execSTTOR(Signal* signal); void sendSTTORRY(Signal*); void execNDB_STTOR(Signal* signal); diff --git a/ndb/src/kernel/blocks/suma/SumaInit.cpp b/ndb/src/kernel/blocks/suma/SumaInit.cpp index b5945db3811..ad8493ff908 100644 --- a/ndb/src/kernel/blocks/suma/SumaInit.cpp +++ b/ndb/src/kernel/blocks/suma/SumaInit.cpp @@ -90,34 +90,6 @@ SumaParticipant::SumaParticipant(const Configuration & conf) : addRecSignal(GSN_SUB_GCP_COMPLETE_REP, &SumaParticipant::execSUB_GCP_COMPLETE_REP); - /** - * @todo: fix pool sizes - */ - Uint32 noTables; - const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator(); - ndbrequire(p != 0); - - ndb_mgm_get_int_parameter(p, CFG_DB_NO_TABLES, - &noTables); - - c_tablePool_.setSize(noTables); - c_tables.setSize(noTables); - - c_subscriptions.setSize(20); //10 - c_subscriberPool.setSize(64); - - c_subscriptionPool.setSize(64); //2 - c_syncPool.setSize(20); //2 - c_dataBufferPool.setSize(128); - - { - SLList<SyncRecord> tmp(c_syncPool); - Ptr<SyncRecord> ptr; - while(tmp.seize(ptr)) - new (ptr.p) SyncRecord(* this, c_dataBufferPool); - tmp.release(); - } - for( int i = 0; i < NO_OF_BUCKETS; i++) { c_buckets[i].active = false; c_buckets[i].handover = false; @@ -142,18 +114,8 @@ Suma::Suma(const Configuration & conf) : c_nodes(c_nodePool), c_runningSubscriptions(c_subCoordinatorPool) { - - c_nodePool.setSize(MAX_NDB_NODES); - c_masterNodeId = getOwnNodeId(); - - c_nodeGroup = c_noNodesInGroup = c_idInNodeGroup = 0; - for (int i = 0; i < MAX_REPLICAS; i++) { - c_nodesInGroup[i] = 0; - } - - c_subCoordinatorPool.setSize(10); - // Add received signals + addRecSignal(GSN_READ_CONFIG_REQ, &Suma::execREAD_CONFIG_REQ); addRecSignal(GSN_STTOR, &Suma::execSTTOR); addRecSignal(GSN_NDB_STTOR, &Suma::execNDB_STTOR); addRecSignal(GSN_DUMP_STATE_ORD, &Suma::execDUMP_STATE_ORD); diff --git a/ndb/src/kernel/blocks/trix/Trix.cpp b/ndb/src/kernel/blocks/trix/Trix.cpp index cd11cb4d575..1d6e5adad62 100644 --- a/ndb/src/kernel/blocks/trix/Trix.cpp +++ b/ndb/src/kernel/blocks/trix/Trix.cpp @@ -52,6 +52,7 @@ Trix::Trix(const Configuration & conf) : BLOCK_CONSTRUCTOR(Trix); // Add received signals + addRecSignal(GSN_READ_CONFIG_REQ, &Trix::execREAD_CONFIG_REQ); addRecSignal(GSN_STTOR, &Trix::execSTTOR); addRecSignal(GSN_NDB_STTOR, &Trix::execNDB_STTOR); // Forwarded from DICT addRecSignal(GSN_READ_NODESCONF, &Trix::execREAD_NODESCONF); @@ -85,6 +86,28 @@ Trix::Trix(const Configuration & conf) : addRecSignal(GSN_SUB_SYNC_CONTINUE_REQ, &Trix::execSUB_SYNC_CONTINUE_REQ); addRecSignal(GSN_SUB_META_DATA, &Trix::execSUB_META_DATA); addRecSignal(GSN_SUB_TABLE_DATA, &Trix::execSUB_TABLE_DATA); +} + +/** + * + */ +Trix::~Trix() +{ +} + +void +Trix::execREAD_CONFIG_REQ(Signal* signal) +{ + jamEntry(); + + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); // Allocate pool sizes c_theAttrOrderBufferPool.setSize(100); @@ -96,13 +119,12 @@ Trix::Trix(const Configuration & conf) : new (subptr.p) SubscriptionRecord(c_theAttrOrderBufferPool); } subscriptions.release(); -} -/** - * - */ -Trix::~Trix() -{ + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); } /** diff --git a/ndb/src/kernel/blocks/trix/Trix.hpp b/ndb/src/kernel/blocks/trix/Trix.hpp index 8dc01375fa1..78c5b8b35c3 100644 --- a/ndb/src/kernel/blocks/trix/Trix.hpp +++ b/ndb/src/kernel/blocks/trix/Trix.hpp @@ -139,6 +139,7 @@ private: ArrayList<SubscriptionRecord> c_theSubscriptions; // System start + void execREAD_CONFIG_REQ(Signal* signal); void execSTTOR(Signal* signal); void execNDB_STTOR(Signal* signal); diff --git a/ndb/src/kernel/error/Error.hpp b/ndb/src/kernel/error/Error.hpp deleted file mode 100644 index e19d6782793..00000000000 --- a/ndb/src/kernel/error/Error.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef ERROR_H -#define ERROR_H - -/** - * Errorcodes for NDB - * - * These errorcodes should be used whenever a condition - * is detected where it's necesssary to shutdown NDB. - * - * Example: When another node fails while a NDB node are performing - * a system restart the node should be shutdown. This - * is kind of an error but the cause of the error is known - * and a proper errormessage describing the problem should - * be printed in error.log. It's therefore important to use - * the proper errorcode. - * - * TODO: In the future the errorcodes should be classified - * - */ - -enum ErrorCategory -{ - warning, - ecError, - fatal, - assert -}; - -const int ERR_BASE = 1000; - -// Errorcodes for all blocks except filseystem -const int ERR_ERR_BASE = ERR_BASE + 1300; -const int ERR_ERROR_PRGERR = ERR_ERR_BASE+1; -const int ERR_NODE_NOT_IN_CONFIG = ERR_ERR_BASE+2; -const int ERR_SYSTEM_ERROR = ERR_ERR_BASE+3; -const int ERR_INDEX_NOTINRANGE = ERR_ERR_BASE+4; -const int ERR_ARBIT_SHUTDOWN = ERR_ERR_BASE+5; -const int ERR_POINTER_NOTINRANGE = ERR_ERR_BASE+6; -const int ERR_PROGRAMERROR = ERR_ERR_BASE+7; -const int ERR_SR_OTHERNODEFAILED = ERR_ERR_BASE+8; -const int ERR_NODE_NOT_DEAD = ERR_ERR_BASE+9; -const int ERR_SR_REDOLOG = ERR_ERR_BASE+10; -const int ERR_SR_RESTARTCONFLICT = ERR_ERR_BASE+11; -const int ERR_NO_MORE_UNDOLOG = ERR_ERR_BASE+12; -const int ERR_SR_UNDOLOG = ERR_ERR_BASE+13; -const int ERR_MEMALLOC = ERR_ERR_BASE+27; -const int BLOCK_ERROR_JBUFCONGESTION = ERR_ERR_BASE+34; -const int ERROR_TIME_QUEUE_SHORT = ERR_ERR_BASE+35; -const int ERROR_TIME_QUEUE_LONG = ERR_ERR_BASE+36; -const int ERROR_TIME_QUEUE_DELAY = ERR_ERR_BASE+37; -const int ERROR_TIME_QUEUE_INDEX = ERR_ERR_BASE+38; -const int BLOCK_ERROR_BNR_ZERO = ERR_ERR_BASE+39; -const int ERROR_WRONG_PRIO_LEVEL = ERR_ERR_BASE+40; -const int ERR_NDBREQUIRE = ERR_ERR_BASE+41; -const int ERR_ERROR_INSERT = ERR_ERR_BASE+42; -const int ERR_INVALID_CONFIG = ERR_ERR_BASE+50; -const int ERR_OUT_OF_LONG_SIGNAL_MEMORY = ERR_ERR_BASE+51; - -// Errorcodes for NDB filesystem -const int AFS_ERR_BASE = ERR_BASE + 1800; -const int AFS_ERROR_NOPATH = AFS_ERR_BASE+1; -const int AFS_ERROR_CHANNALFULL = AFS_ERR_BASE+2; -const int AFS_ERROR_NOMORETHREADS = AFS_ERR_BASE+3; -const int AFS_ERROR_PARAMETER = AFS_ERR_BASE+4; -const int AFS_ERROR_INVALIDPATH = AFS_ERR_BASE+5; -const int AFS_ERROR_MAXOPEN = AFS_ERR_BASE+6; -const int AFS_ERROR_ALLREADY_OPEN = AFS_ERR_BASE+7; - -#endif // ERROR_H diff --git a/ndb/src/kernel/error/ErrorHandlingMacros.hpp b/ndb/src/kernel/error/ErrorHandlingMacros.hpp index d8bb7ff759b..8c3454b1ba1 100644 --- a/ndb/src/kernel/error/ErrorHandlingMacros.hpp +++ b/ndb/src/kernel/error/ErrorHandlingMacros.hpp @@ -17,22 +17,27 @@ #ifndef ERRORHANDLINGMACROS_H #define ERRORHANDLINGMACROS_H +#include <ndbd_exit_codes.h> #include "ErrorReporter.hpp" -#include "Error.hpp" extern const char programName[]; -#define ERROR_SET_SIGNAL(messageCategory, messageID, problemData, objectRef) \ - ErrorReporter::handleError(messageCategory, messageID, problemData, objectRef, NST_ErrorHandlerSignal) -#define ERROR_SET(messageCategory, messageID, problemData, objectRef) \ - ErrorReporter::handleError(messageCategory, messageID, problemData, objectRef) +enum NotUsed +{ + warning, + ecError, + fatal, + assert +}; + +#define ERROR_SET_SIGNAL(not_used, messageID, problemData, objectRef) \ + ErrorReporter::handleError(messageID, problemData, objectRef, NST_ErrorHandlerSignal) +#define ERROR_SET(not_used, messageID, problemData, objectRef) \ + ErrorReporter::handleError(messageID, problemData, objectRef) // Description: // Call ErrorHandler with the supplied arguments. The // ErrorHandler decides how to report the error. // Parameters: - // messageCategory IN A hint to the error handler how the - // error should be reported. Can be - // error, fatal (or warning, use WARNING_SET instead). // messageID IN Code identifying the error. If less // than 1000 a unix error is assumed. If // greater than 1000 the code is treated diff --git a/ndb/src/kernel/error/ErrorMessages.cpp b/ndb/src/kernel/error/ErrorMessages.cpp deleted file mode 100644 index 059aa4af61c..00000000000 --- a/ndb/src/kernel/error/ErrorMessages.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (C) 2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "ErrorMessages.hpp" - -struct ErrStruct { - int fauldId; - const char* text; -}; - -const ErrStruct errArray[] = { - - {2301, "Assertion, probably a programming error"}, - {2302, "Own Node Id not a NDB node, configuration error"}, - {2303, "System error"}, - {2304, "Index too large"}, - {2305, "Arbitrator shutdown"}, - {2306, "Pointer too large"}, - {2307, "Internal program error"}, - {2308, "Node failed during system restart"}, - {2309, "Node state conflict"}, - {2310, "Error while reading the REDO log"}, - {2311, "Conflict when selecting restart type"}, - {2312, "No more free UNDO log"}, - {2313, "Error while reading the datapages and UNDO log"}, - {2327, "Memory allocation failure"}, - {2334, "Job buffer congestion"}, - {2335, "Error in short time queue"}, - {2336, "Error in long time queue"}, - {2337, "Error in time queue, too long delay"}, - {2338, "Time queue index out of range"}, - {2339, "Send signal error"}, - {2340, "Wrong prio level when sending signal"}, - {2341, "Internal program error (failed ndbrequire)"}, - {2342, "Error insert executed" }, - {2350, "Invalid Configuration fetched from Management Server" }, - - // Ndbfs error messages - {2801, "No file system path"}, - {2802, "Channel is full"}, - {2803, "No more threads"}, - {2804, "Bad parameter"}, - {2805, "Illegal file system path"}, - {2806, "Max number of open files exceeded"}, - {2807, "File has already been opened"}, - - // Sentinel - {0, "No message slogan found"} - -}; - -const unsigned short NO_OF_ERROR_MESSAGES = sizeof(errArray)/sizeof(ErrStruct); - -const char* lookupErrorMessage(int faultId) -{ - int i = 0; - while (errArray[i].fauldId != faultId && errArray[i].fauldId != 0) - i++; - return errArray[i].text; -} - - diff --git a/ndb/src/kernel/error/ErrorReporter.cpp b/ndb/src/kernel/error/ErrorReporter.cpp index e4ead4ce34d..6c8bb1fe615 100644 --- a/ndb/src/kernel/error/ErrorReporter.cpp +++ b/ndb/src/kernel/error/ErrorReporter.cpp @@ -17,9 +17,8 @@ #include <ndb_global.h> -#include "Error.hpp" +#include <ndbd_exit_codes.h> #include "ErrorReporter.hpp" -#include "ErrorMessages.hpp" #include <FastScheduler.hpp> #include <DebuggerNames.hpp> @@ -29,17 +28,9 @@ #include <NdbAutoPtr.hpp> -#define MESSAGE_LENGTH 400 +#define MESSAGE_LENGTH 500 -const char* errorType[] = { - "warning", - "error", - "fatal", - "assert" -}; - - -static int WriteMessage(ErrorCategory thrdType, int thrdMessageID, +static int WriteMessage(int thrdMessageID, const char* thrdProblemData, const char* thrdObjRef, Uint32 thrdTheEmulatedJamIndex, @@ -116,24 +107,35 @@ ErrorReporter::get_trace_no(){ void -ErrorReporter::formatMessage(ErrorCategory type, - int faultID, +ErrorReporter::formatMessage(int faultID, const char* problemData, const char* objRef, const char* theNameOfTheTraceFile, char* messptr){ int processId; - + ndbd_exit_classification cl; + ndbd_exit_status st; + const char *exit_msg = ndbd_exit_message(faultID, &cl); + const char *exit_cl_msg = ndbd_exit_classification_message(cl, &st); + const char *exit_st_msg = ndbd_exit_status_message(st); + processId = NdbHost_GetProcessId(); BaseString::snprintf(messptr, MESSAGE_LENGTH, - "Date/Time: %s\nType of error: %s\n" - "Message: %s\nFault ID: %d\nProblem data: %s" - "\nObject of reference: %s\nProgramName: %s\n" - "ProcessID: %d\nTraceFile: %s\n%s\n***EOM***\n", + "Time: %s\n" + "Status: %s\n" + "Message: %s (%s)\n" + "Error: %d\n" + "Error data: %s\n" + "Error object: %s\n" + "Program: %s\n" + "Pid: %d\n" + "Trace: %s\n" + "Version: %s\n" + "***EOM***\n", formatTimeStampString() , - errorType[type], - lookupErrorMessage(faultID), + exit_st_msg, + exit_msg, exit_cl_msg, faultID, (problemData == NULL) ? "" : problemData, objRef, @@ -152,8 +154,18 @@ ErrorReporter::formatMessage(ErrorCategory type, return; } +NdbShutdownType ErrorReporter::s_errorHandlerShutdownType = NST_ErrorHandler; + +void +ErrorReporter::setErrorHandlerShutdownType(NdbShutdownType nst) +{ + s_errorHandlerShutdownType = nst; +} + +void childReportError(int error); + void -ErrorReporter::handleAssert(const char* message, const char* file, int line) +ErrorReporter::handleAssert(const char* message, const char* file, int line, int ec) { char refMessage[100]; @@ -167,46 +179,36 @@ ErrorReporter::handleAssert(const char* message, const char* file, int line) BaseString::snprintf(refMessage, 100, "%s line: %d (block: %s)", file, line, blockName); #endif - WriteMessage(assert, ERR_ERROR_PRGERR, message, refMessage, + WriteMessage(ec, message, refMessage, theEmulatedJamIndex, theEmulatedJam); - NdbShutdown(NST_ErrorHandler); -} - -void -ErrorReporter::handleThreadAssert(const char* message, - const char* file, - int line) -{ - char refMessage[100]; - BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d - %s", - file, line, message); - - NdbShutdown(NST_ErrorHandler); -}//ErrorReporter::handleThreadAssert() + childReportError(ec); + NdbShutdown(s_errorHandlerShutdownType); +} void -ErrorReporter::handleError(ErrorCategory type, int messageID, +ErrorReporter::handleError(int messageID, const char* problemData, const char* objRef, NdbShutdownType nst) { - type = ecError; - // The value for type is not always set correctly in the calling function. - // So, to correct this, we set it set it to the value corresponding to - // the function that is called. - WriteMessage(type, messageID, problemData, + WriteMessage(messageID, problemData, objRef, theEmulatedJamIndex, theEmulatedJam); - if(messageID == ERR_ERROR_INSERT){ + + childReportError(messageID); + + if(messageID == NDBD_EXIT_ERROR_INSERT){ NdbShutdown(NST_ErrorInsert); } else { + if (nst == NST_ErrorHandler) + nst = s_errorHandlerShutdownType; NdbShutdown(nst); } } int -WriteMessage(ErrorCategory thrdType, int thrdMessageID, +WriteMessage(int thrdMessageID, const char* thrdProblemData, const char* thrdObjRef, Uint32 thrdTheEmulatedJamIndex, Uint8 thrdTheEmulatedJam[]){ @@ -247,7 +249,7 @@ WriteMessage(ErrorCategory thrdType, int thrdMessageID, " \n\n\n"); // ...and write the error-message... - ErrorReporter::formatMessage(thrdType, thrdMessageID, + ErrorReporter::formatMessage(thrdMessageID, thrdProblemData, thrdObjRef, theTraceFileName, theMessage); fprintf(stream, "%s", theMessage); @@ -274,7 +276,7 @@ WriteMessage(ErrorCategory thrdType, int thrdMessageID, fseek(stream, offset, SEEK_SET); // ...and write the error-message there... - ErrorReporter::formatMessage(thrdType, thrdMessageID, + ErrorReporter::formatMessage(thrdMessageID, thrdProblemData, thrdObjRef, theTraceFileName, theMessage); fprintf(stream, "%s", theMessage); diff --git a/ndb/src/kernel/error/ErrorReporter.hpp b/ndb/src/kernel/error/ErrorReporter.hpp index 2c79f242eea..0ec84190238 100644 --- a/ndb/src/kernel/error/ErrorReporter.hpp +++ b/ndb/src/kernel/error/ErrorReporter.hpp @@ -18,35 +18,29 @@ #define ERRORREPORTER_H #include <ndb_global.h> +#include <ndbd_exit_codes.h> #include "TimeModule.hpp" -#include "Error.hpp" #include <Emulator.hpp> class ErrorReporter { public: + static void setErrorHandlerShutdownType(NdbShutdownType nst = NST_ErrorHandler); static void handleAssert(const char* message, const char* file, - int line); + int line, int ec = NDBD_EXIT_PRGERR); - static void handleThreadAssert(const char* message, - const char* file, - int line); - - static void handleError(ErrorCategory type, - int faultID, + static void handleError(int faultID, const char* problemData, const char* objRef, enum NdbShutdownType = NST_ErrorHandler); - static void handleWarning(ErrorCategory type, - int faultID, + static void handleWarning(int faultID, const char* problemData, const char* objRef); - static void formatMessage(ErrorCategory type, - int faultID, + static void formatMessage(int faultID, const char* problemData, const char* objRef, const char* theNameOfTheTraceFile, @@ -57,6 +51,7 @@ public: static const char* formatTimeStampString(); private: + static enum NdbShutdownType s_errorHandlerShutdownType; }; #endif diff --git a/ndb/src/kernel/error/Makefile.am b/ndb/src/kernel/error/Makefile.am index 54f3de2d76d..c58cdf80940 100644 --- a/ndb/src/kernel/error/Makefile.am +++ b/ndb/src/kernel/error/Makefile.am @@ -2,7 +2,7 @@ noinst_LIBRARIES = liberror.a liberror_a_SOURCES = TimeModule.cpp \ ErrorReporter.cpp \ - ErrorMessages.cpp + ndbd_exit_codes.c include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_kernel.mk.am diff --git a/ndb/src/kernel/error/ndbd_exit_codes.c b/ndb/src/kernel/error/ndbd_exit_codes.c new file mode 100644 index 00000000000..9b8c907cb7c --- /dev/null +++ b/ndb/src/kernel/error/ndbd_exit_codes.c @@ -0,0 +1,255 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndbd_exit_codes.h> + +typedef struct ErrStruct { + int faultId; + ndbd_exit_classification classification; + const char* text; +} ErrStruct; + +/** + * Shorter names in table below + */ + +#define XST_S ndbd_exit_st_success +#define XST_U ndbd_exit_st_unknown +#define XST_P ndbd_exit_st_permanent +#define XST_R ndbd_exit_st_temporary +#define XST_I ndbd_exit_st_filesystem_error + +#define XNE ndbd_exit_cl_none +#define XUE ndbd_exit_cl_unknown +#define XIE ndbd_exit_cl_internal_error +#define XCE ndbd_exit_cl_configuration_error +#define XAE ndbd_exit_cl_arbitration_error +#define XRE ndbd_exit_cl_restart_error +#define XCR ndbd_exit_cl_resource_configuration_error +#define XFF ndbd_exit_cl_filesystem_full_error +#define XFI ndbd_exit_cl_filesystem_inconsistency_error +#define XFL ndbd_exit_cl_filesystem_limit + +static const ErrStruct errArray[] = +{ + {NDBD_EXIT_PRGERR, XIE, "Assertion"}, + {NDBD_EXIT_NODE_NOT_IN_CONFIG, XCE, + "node id in the configuration has the wrong type, (i.e. not an NDB node)"}, + {NDBD_EXIT_SYSTEM_ERROR, XIE, + "System error, node killed during node restart by other node"}, + {NDBD_EXIT_INDEX_NOTINRANGE, XIE, "Array index out of range"}, + {NDBD_EXIT_ARBIT_SHUTDOWN, XAE, "Arbitrator shutdown, " + "please investigate error(s) on other node(s)"}, + {NDBD_EXIT_POINTER_NOTINRANGE, XIE, "Pointer too large"}, + {NDBD_EXIT_SR_OTHERNODEFAILED, XRE, "Another node failed during system " + "restart, please investigate error(s) on other node(s)"}, + {NDBD_EXIT_NODE_NOT_DEAD, XRE, "Internal node state conflict, " + "most probably resolved by restarting node again"}, + {NDBD_EXIT_SR_REDOLOG, XFI, "Error while reading the REDO log"}, + /* Currently unused? */ + {2311, XIE, "Conflict when selecting restart type"}, + {NDBD_EXIT_NO_MORE_UNDOLOG, XCR, + "No more free UNDO log, increase UndoIndexBuffer"}, + {NDBD_EXIT_SR_UNDOLOG, XFI, + "Error while reading the datapages and UNDO log"}, + {NDBD_EXIT_MEMALLOC, XCE, "Memory allocation failure, " + "please decrease some configuration parameters"}, + {NDBD_EXIT_BLOCK_JBUFCONGESTION, XIE, "Job buffer congestion"}, + {NDBD_EXIT_TIME_QUEUE_SHORT, XIE, "Error in short time queue"}, + {NDBD_EXIT_TIME_QUEUE_LONG, XIE, "Error in long time queue"}, + {NDBD_EXIT_TIME_QUEUE_DELAY, XIE, "Error in time queue, too long delay"}, + {NDBD_EXIT_TIME_QUEUE_INDEX, XIE, "Time queue index out of range"}, + {NDBD_EXIT_BLOCK_BNR_ZERO, XIE, "Send signal error"}, + {NDBD_EXIT_WRONG_PRIO_LEVEL, XIE, "Wrong priority level when sending signal"}, + {NDBD_EXIT_NDBREQUIRE, XIE, "Internal program error (failed ndbrequire)"}, + {NDBD_EXIT_NDBASSERT, XIE, "Internal program error (failed ndbassert)"}, + {NDBD_EXIT_ERROR_INSERT, XNE, "Error insert executed" }, + /* this error message is complemented by additional info when generated */ + {NDBD_EXIT_INVALID_CONFIG, XCE, + "Invalid configuration received from Management Server"}, + /* this error message is complemented by additional info when + generated, such as signal, and text + */ + {NDBD_EXIT_OS_SIGNAL_RECEIVED, XIE, "Error OS signal received"}, + + /* VM */ + {NDBD_EXIT_OUT_OF_LONG_SIGNAL_MEMORY, XCR, + "Signal lost, out of long signal memory, please increase LongMessageBuffer"}, + {NDBD_EXIT_WATCHDOG_TERMINATE, XIE, "WatchDog terminate, internal error " + "or massive overload on the machine running this node"}, + {NDBD_EXIT_SIGNAL_LOST_SEND_BUFFER_FULL, XCR, + "Signal lost, out of send buffer memory, please increase SendBufferMemory"}, + {NDBD_EXIT_SIGNAL_LOST, XIE, "Signal lost (unknown reason)"}, + {NDBD_EXIT_ILLEGAL_SIGNAL, XIE, + "Illegal signal (version mismatch a possibility)"}, + {NDBD_EXIT_CONNECTION_SETUP_FAILED, XCE, "Connection setup failed"}, + + /* Ndbcntr */ + {NDBD_EXIT_RESTART_TIMEOUT, XCE, + "Total restart time too long, consider increasing StartFailureTimeout " + "or investigate error(s) on other node(s)"}, + {NDBD_EXIT_RESTART_DURING_SHUTDOWN, XRE, + "Node started while node shutdown in progress. " + "Please wait until shutdown complete before starting node"}, + + /* DIH */ + {NDBD_EXIT_MAX_CRASHED_REPLICAS, XFL, + "Too many crashed replicas (8 consecutive node restart failures)"}, + {NDBD_EXIT_MASTER_FAILURE_DURING_NR, XRE, + "Unhandled master failure during node restart"}, + {NDBD_EXIT_LOST_NODE_GROUP, XAE, + "All nodes in a node group are unavailable"}, + {NDBD_EXIT_NO_RESTORABLE_REPLICA, XFI, + "Unable to find a restorable replica"}, + + /* ACC */ + {NDBD_EXIT_SR_OUT_OF_INDEXMEMORY, XCR, + "Out of index memory during system restart, please increase IndexMemory"}, + + /* TUP */ + {NDBD_EXIT_SR_OUT_OF_DATAMEMORY, XCR, + "Out of data memory during system restart, please increase DataMemory"}, + + /* Ndbfs error messages */ + /* Most codes will have additional info, such as OS error code */ + {NDBD_EXIT_AFS_NOPATH, XIE, "No file system path"}, + {2802, XIE, "Channel is full"}, + {2803, XIE, "No more threads"}, + {NDBD_EXIT_AFS_PARAMETER, XIE, "Bad parameter"}, + {NDBD_EXIT_AFS_INVALIDPATH, XCE, "Illegal file system path"}, + {NDBD_EXIT_AFS_MAXOPEN, XCR, + "Max number of open files exceeded, please increase MaxNoOfOpenFiles"}, + {NDBD_EXIT_AFS_ALREADY_OPEN, XIE, "File has already been opened"}, + + {NDBD_EXIT_AFS_ENVIRONMENT , XIE, "Environment error using file"}, + {NDBD_EXIT_AFS_TEMP_NO_ACCESS , XIE, "Temporary on access to file"}, + {NDBD_EXIT_AFS_DISK_FULL , XFF, "The file system is full"}, + {NDBD_EXIT_AFS_PERMISSION_DENIED , XCE, "Received permission denied for file"}, + {NDBD_EXIT_AFS_INVALID_PARAM , XCE, "Invalid parameter for file"}, + {NDBD_EXIT_AFS_UNKNOWN , XIE, "Unknown file system error"}, + {NDBD_EXIT_AFS_NO_MORE_RESOURCES , XIE, + "System reports no more file system resources"}, + {NDBD_EXIT_AFS_NO_SUCH_FILE , XFI, "File not found"}, + {NDBD_EXIT_AFS_READ_UNDERFLOW , XFI, "Read underflow"}, + + /* Sentinel */ + {0, XUE, + "No message slogan found (please report a bug if you get this error code)"} +}; + +typedef struct StatusExitMessage { + ndbd_exit_status status; + const char * message; +} StatusExitMessage; + +typedef struct StatusExitClassification { + ndbd_exit_status status; + ndbd_exit_classification classification; + const char * message; +} StatusExitClassification; + +/** + * Mapping between classification and status + */ +static +const +StatusExitMessage StatusExitMessageMapping[] = { + { XST_S, "Success"}, + { XST_U ,"Unknown"}, + { XST_P, "Permanent error, external action needed"}, + { XST_R, "Temporary error, restart node"}, + { XST_I, "Ndbd file system error, restart node initial"} +}; + +static +const +int NbExitStatus = sizeof(StatusExitMessageMapping)/sizeof(StatusExitMessage); + +static +const +StatusExitClassification StatusExitClassificationMapping[] = { + { XST_S, XNE, "No error"}, + { XST_U, XUE, "Unknown"}, + { XST_R, XIE, "Internal error, programming error or missing error message, " + "please report a bug"}, + { XST_P, XCE, "Configuration error"}, + { XST_R, XAE, "Arbitration error"}, + { XST_R, XRE, "Restart error"}, + { XST_P, XCR, "Resource configuration error"}, + { XST_P, XFF, "File system full"}, + { XST_I, XFI, "Ndbd file system inconsistency error, please report a bug"}, + { XST_I, XFL, "Ndbd file system limit exceeded"} +}; + +static const int NbExitClassification = +sizeof(StatusExitClassificationMapping)/sizeof(StatusExitClassification); + +const char *ndbd_exit_message(int faultId, ndbd_exit_classification *cl) +{ + int i = 0; + while (errArray[i].faultId != faultId && errArray[i].faultId != 0) + i++; + *cl = errArray[i].classification; + return errArray[i].text; +} + +static const char* empty_xstring = ""; + +const +char *ndbd_exit_classification_message(ndbd_exit_classification classification, + ndbd_exit_status *status) +{ + int i; + for (i= 0; i < NbExitClassification; i++) + { + if (StatusExitClassificationMapping[i].classification == classification) + { + *status = StatusExitClassificationMapping[i].status; + return StatusExitClassificationMapping[i].message; + } + } + *status = XST_U; + return empty_xstring; +} + +const char *ndbd_exit_status_message(ndbd_exit_status status) +{ + int i; + for (i= 0; i < NbExitStatus; i++) + if (StatusExitMessageMapping[i].status == status) + return StatusExitMessageMapping[i].message; + return empty_xstring; +} + +int ndbd_exit_string(int err_no, char *str, unsigned int size) +{ + unsigned int len; + + ndbd_exit_classification cl; + ndbd_exit_status st; + const char *msg = ndbd_exit_message(err_no, &cl); + if (msg[0] != '\0') + { + const char *cl_msg = ndbd_exit_classification_message(cl, &st); + const char *st_msg = ndbd_exit_status_message(st); + + len = my_snprintf(str, size-1, "%s: %s: %s", msg, st_msg, cl_msg); + str[size-1]= '\0'; + + return len; + } + return -1; +} diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index f679646e14a..2374cce5f35 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -37,6 +37,8 @@ #include <NdbAutoPtr.hpp> +#include <Properties.hpp> + #include <mgmapi_debug.h> #if defined NDB_SOLARIS // ok @@ -48,23 +50,194 @@ extern NdbMutex * theShutdownMutex; void catchsigs(bool ignore); // for process signal handling +#define MAX_FAILED_STARTUPS 3 +// Flag set by child through SIGUSR1 to signal a failed startup +static bool failed_startup_flag = false; +// Counter for consecutive failed startups +static Uint32 failed_startups = 0; extern "C" void handler_shutdown(int signum); // for process signal handling extern "C" void handler_error(int signum); // for process signal handling +extern "C" void handler_sigusr1(int signum); // child signalling failed restart // Shows system information void systemInfo(const Configuration & conf, const LogLevel & ll); +static FILE *child_info_file_r= 0; +static FILE *child_info_file_w= 0; + +static void writeChildInfo(const char *token, int val) +{ + fprintf(child_info_file_w, "%s=%d\n", token, val); + fflush(child_info_file_w); +} + +void childReportSignal(int signum) +{ + writeChildInfo("signal", signum); +} + +void childReportError(int error) +{ + writeChildInfo("error", error); +} + +void childExit(int code, Uint32 currentStartPhase) +{ + writeChildInfo("sphase", currentStartPhase); + writeChildInfo("exit", code); + fprintf(child_info_file_w, "\n"); + fclose(child_info_file_r); + fclose(child_info_file_w); + exit(code); +} + +void childAbort(int code, Uint32 currentStartPhase) +{ + writeChildInfo("sphase", currentStartPhase); + writeChildInfo("exit", code); + fprintf(child_info_file_w, "\n"); + fclose(child_info_file_r); + fclose(child_info_file_w); + signal(6, SIG_DFL); + abort(); +} + +static int insert(const char * pair, Properties & p) +{ + BaseString tmp(pair); + + tmp.trim(" \t\n\r"); + Vector<BaseString> split; + tmp.split(split, ":=", 2); + if(split.size() != 2) + return -1; + p.put(split[0].trim().c_str(), split[1].trim().c_str()); + return 0; +} + +static int readChildInfo(Properties &info) +{ + fclose(child_info_file_w); + char buf[128]; + while (fgets(buf,sizeof(buf),child_info_file_r)) + insert(buf,info); + fclose(child_info_file_r); + return 0; +} + +static bool get_int_property(Properties &info, + const char *token, Uint32 *int_val) +{ + const char *str_val= 0; + if (!info.get(token, &str_val)) + return false; + char *endptr; + long int tmp= strtol(str_val, &endptr, 10); + if (str_val == endptr) + return false; + *int_val = tmp; + return true; +} + +int reportShutdown(class Configuration *config, int error_exit, int restart) +{ + Uint32 error= 0, signum= 0, sphase= 256; + Properties info; + readChildInfo(info); + + get_int_property(info, "signal", &signum); + get_int_property(info, "error", &error); + get_int_property(info, "sphase", &sphase); + + Uint32 length, theData[25]; + EventReport *rep = (EventReport *)theData; + + rep->setNodeId(globalData.ownId); + if (restart) + theData[1] = 1 | + (globalData.theRestartFlag == initial_state ? 2 : 0) | + (config->getInitialStart() ? 4 : 0); + else + theData[1] = 0; + + if (error_exit == 0) + { + rep->setEventType(NDB_LE_NDBStopCompleted); + theData[2] = signum; + length = 3; + } + else + { + rep->setEventType(NDB_LE_NDBStopForced); + theData[2] = signum; + theData[3] = error; + theData[4] = sphase; + theData[5] = 0; // extra + length = 6; + } + + { // Log event + const EventReport * const eventReport = (EventReport *)&theData[0]; + g_eventLogger.log(eventReport->getEventType(), theData, + eventReport->getNodeId(), 0); + } + + for (unsigned n = 0; n < config->m_mgmds.size(); n++) + { + NdbMgmHandle h = ndb_mgm_create_handle(); + if (h == 0 || + ndb_mgm_set_connectstring(h, config->m_mgmds[n].c_str()) || + ndb_mgm_connect(h, + 1, //no_retries + 0, //retry_delay_in_seconds + 0 //verbose + )) + goto handle_error; + + { + if (ndb_mgm_report_event(h, theData, length)) + goto handle_error; + } + goto do_next; + +handle_error: + if (h) + { + BaseString tmp(ndb_mgm_get_latest_error_msg(h)); + tmp.append(" : "); + tmp.append(ndb_mgm_get_latest_error_desc(h)); + g_eventLogger.warning("Unable to report shutdown reason to %s: %s", + config->m_mgmds[n].c_str(), tmp.c_str()); + } + else + { + g_eventLogger.error("Unable to report shutdown reason to %s", + config->m_mgmds[n].c_str()); + } +do_next: + if (h) + { + ndb_mgm_disconnect(h); + ndb_mgm_destroy_handle(&h); + } + } + return 0; +} + int main(int argc, char** argv) { NDB_INIT(argv[0]); // Print to stdout/console g_eventLogger.createConsoleHandler(); - g_eventLogger.setCategory("NDB"); + g_eventLogger.setCategory("ndbd"); + g_eventLogger.enable(Logger::LL_ON, Logger::LL_INFO); g_eventLogger.enable(Logger::LL_ON, Logger::LL_CRITICAL); g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR); g_eventLogger.enable(Logger::LL_ON, Logger::LL_WARNING); + g_eventLogger.m_logLevel.setLogLevel(LogLevel::llStartUp, 15); + globalEmulatorData.create(); // Parse command line options @@ -95,10 +268,40 @@ int main(int argc, char** argv) } #ifndef NDB_WIN32 - for(pid_t child = fork(); child != 0; child = fork()){ + signal(SIGUSR1, handler_sigusr1); + + pid_t child; + while (1) + { + // setup reporting between child and parent + int filedes[2]; + if (pipe(filedes)) + { + g_eventLogger.error("pipe() failed with errno=%d (%s)", + errno, strerror(errno)); + return 1; + } + else + { + if (!(child_info_file_w= fdopen(filedes[1],"w"))) + { + g_eventLogger.error("fdopen() failed with errno=%d (%s)", + errno, strerror(errno)); + } + if (!(child_info_file_r= fdopen(filedes[0],"r"))) + { + g_eventLogger.error("fdopen() failed with errno=%d (%s)", + errno, strerror(errno)); + } + } + + if ((child = fork()) <= 0) + break; // child or error + /** * Parent */ + catchsigs(true); /** @@ -107,12 +310,13 @@ int main(int argc, char** argv) */ theConfig->closeConfiguration(); - int status = 0; + int status = 0, error_exit = 0, signum = 0; while(waitpid(child, &status, 0) != child); if(WIFEXITED(status)){ switch(WEXITSTATUS(status)){ case NRT_Default: g_eventLogger.info("Angel shutting down"); + reportShutdown(theConfig, 0, 0); exit(0); break; case NRT_NoStart_Restart: @@ -128,10 +332,12 @@ int main(int argc, char** argv) globalData.theRestartFlag = perform_start; break; default: + error_exit = 1; if(theConfig->stopOnError()){ /** * Error shutdown && stopOnError() */ + reportShutdown(theConfig, error_exit, 0); exit(0); } // Fall-through @@ -140,17 +346,52 @@ int main(int argc, char** argv) globalData.theRestartFlag = perform_start; break; } - } else if(theConfig->stopOnError()){ + } else { + error_exit = 1; + if (WIFSIGNALED(status)) + { + signum = WTERMSIG(status); + childReportSignal(signum); + } + else + { + signum = 127; + g_eventLogger.info("Unknown exit reason. Stopped."); + } + if(theConfig->stopOnError()){ + /** + * Error shutdown && stopOnError() + */ + reportShutdown(theConfig, error_exit, 0); + exit(0); + } + } + + if (!failed_startup_flag) + { + // Reset the counter for consecutive failed startups + failed_startups = 0; + } + else if (failed_startups >= MAX_FAILED_STARTUPS && !theConfig->stopOnError()) + { /** * Error shutdown && stopOnError() */ + g_eventLogger.alert("Ndbd has failed %u consecutive startups. " + "Not restarting", failed_startups); + reportShutdown(theConfig, error_exit, 0); exit(0); } + failed_startup_flag = false; + reportShutdown(theConfig, error_exit, 1); g_eventLogger.info("Ndb has terminated (pid %d) restarting", child); theConfig->fetch_configuration(); } - g_eventLogger.info("Angel pid: %d ndb pid: %d", getppid(), getpid()); + if (child >= 0) + g_eventLogger.info("Angel pid: %d ndb pid: %d", getppid(), getpid()); + else + g_eventLogger.info("Ndb pid: %d", getpid()); #else g_eventLogger.info("Ndb started"); #endif @@ -179,6 +420,9 @@ int main(int argc, char** argv) /** * Do startup */ + + ErrorReporter::setErrorHandlerShutdownType(NST_ErrorHandlerStartup); + switch(globalData.theRestartFlag){ case initial_state: globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI); @@ -201,7 +445,7 @@ int main(int argc, char** argv) // Re-use the mgm handle as a transporter if(!globalTransporterRegistry.connect_client( theConfig->get_config_retriever()->get_mgmHandlePtr())) - ERROR_SET(fatal, ERR_INVALID_CONFIG, + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Connection to mgmd terminated before setup was complete", "StopOnError missing"); @@ -346,6 +590,8 @@ extern "C" void handler_shutdown(int signum){ g_eventLogger.info("Received signal %d. Performing stop.", signum); + childReportError(0); + childReportSignal(signum); globalData.theRestartFlag = perform_stop; } @@ -370,8 +616,25 @@ handler_error(int signum){ NdbSleep_MilliSleep(10); thread_id= my_thread_id(); g_eventLogger.info("Received signal %d. Running error handler.", signum); + childReportSignal(signum); // restart the system - char errorData[40]; - BaseString::snprintf(errorData, 40, "Signal %d received", signum); - ERROR_SET_SIGNAL(fatal, 0, errorData, __FILE__); + char errorData[64], *info= 0; +#ifdef HAVE_STRSIGNAL + info= strsignal(signum); +#endif + BaseString::snprintf(errorData, sizeof(errorData), "Signal %d received; %s", signum, + info ? info : "No text for signal available"); + ERROR_SET_SIGNAL(fatal, NDBD_EXIT_OS_SIGNAL_RECEIVED, errorData, __FILE__); +} + +extern "C" +void +handler_sigusr1(int signum) +{ + if (!failed_startup_flag) + { + failed_startups++; + failed_startup_flag = true; + } + g_eventLogger.info("Angel received ndbd startup failure count %u.", failed_startups); } diff --git a/ndb/src/kernel/vm/ArrayPool.hpp b/ndb/src/kernel/vm/ArrayPool.hpp index 924ed51ee15..3b1264af8be 100644 --- a/ndb/src/kernel/vm/ArrayPool.hpp +++ b/ndb/src/kernel/vm/ArrayPool.hpp @@ -18,6 +18,7 @@ #define ARRAY_POOL_HPP #include <ndb_global.h> +#include "ndbd_malloc.hpp" #include <pc.hpp> #include <ErrorReporter.hpp> @@ -44,7 +45,7 @@ public: * * Note, can currently only be called once */ - bool setSize(Uint32 noOfElements); + bool setSize(Uint32 noOfElements, bool exit_on_error = true); inline Uint32 getNoOfFree() const { return noOfFree; @@ -201,7 +202,7 @@ template <class T> inline ArrayPool<T>::~ArrayPool(){ if(theArray != 0){ - NdbMem_Free(theArray); + ndbd_free(theArray, size * sizeof(T)); theArray = 0; #ifdef ARRAY_GUARD delete []theAllocatedBitmask; @@ -218,13 +219,19 @@ ArrayPool<T>::~ArrayPool(){ template <class T> inline bool -ArrayPool<T>::setSize(Uint32 noOfElements){ +ArrayPool<T>::setSize(Uint32 noOfElements, bool exit_on_error){ if(size == 0){ if(noOfElements == 0) return true; - theArray = (T *)NdbMem_Allocate(noOfElements * sizeof(T)); + theArray = (T *)ndbd_malloc(noOfElements * sizeof(T)); if(theArray == 0) - return false; + { + if (!exit_on_error) + return false; + ErrorReporter::handleAssert("ArrayPool<T>::setSize malloc failed", + __FILE__, __LINE__, NDBD_EXIT_MEMALLOC); + return false; // not reached + } size = noOfElements; noOfFree = noOfElements; @@ -247,7 +254,11 @@ ArrayPool<T>::setSize(Uint32 noOfElements){ return true; } - return false; + if (!exit_on_error) + return false; + + ErrorReporter::handleAssert("ArrayPool<T>::setSize called twice", __FILE__, __LINE__); + return false; // not reached } template <class T> diff --git a/ndb/src/kernel/vm/CArray.hpp b/ndb/src/kernel/vm/CArray.hpp index a6e84e2c041..93f75056b50 100644 --- a/ndb/src/kernel/vm/CArray.hpp +++ b/ndb/src/kernel/vm/CArray.hpp @@ -17,6 +17,8 @@ #ifndef CARRAY_HPP #define CARRAY_HPP +#include "ndbd_malloc.hpp" + /** * Template class used for implementing an c - array */ @@ -31,7 +33,7 @@ public: * * Note, can currently only be called once */ - bool setSize(Uint32 noOfElements); + bool setSize(Uint32 noOfElements, bool exit_on_error = true); /** * Get size @@ -69,7 +71,7 @@ template <class T> inline CArray<T>::~CArray(){ if(theArray != 0){ - NdbMem_Free(theArray); + ndbd_free(theArray, size * sizeof(T)); theArray = 0; } } @@ -82,13 +84,19 @@ CArray<T>::~CArray(){ template <class T> inline bool -CArray<T>::setSize(Uint32 noOfElements){ +CArray<T>::setSize(Uint32 noOfElements, bool exit_on_error){ if(size == noOfElements) return true; - theArray = (T *)NdbMem_Allocate(noOfElements * sizeof(T)); + theArray = (T *)ndbd_malloc(noOfElements * sizeof(T)); if(theArray == 0) - return false; + { + if (!exit_on_error) + return false; + ErrorReporter::handleAssert("CArray<T>::setSize malloc failed", + __FILE__, __LINE__, NDBD_EXIT_MEMALLOC); + return false; // not reached + } size = noOfElements; return true; } diff --git a/ndb/src/kernel/vm/ClusterConfiguration.cpp b/ndb/src/kernel/vm/ClusterConfiguration.cpp index d5bd03f69d5..813407b497e 100644 --- a/ndb/src/kernel/vm/ClusterConfiguration.cpp +++ b/ndb/src/kernel/vm/ClusterConfiguration.cpp @@ -359,12 +359,12 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ if(!db.get(tmp[i].attrib, tmp[i].storage)){ char buf[255]; BaseString::snprintf(buf, sizeof(buf), "%s not found", tmp[i].attrib); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } } if(!p.get("NoOfNodes", &cd.SizeAltData.noOfNodes)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, "NoOfNodes missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "NoOfNodes missing"); } Properties::Iterator it(&p); @@ -378,36 +378,36 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ const Properties * node; if(!p.get(name, &node)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, "Node data missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "Node data missing"); } if(!node->get("Id", &nodeId)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, "Node data (Id) missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "Node data (Id) missing"); } if(!node->get("Type", &nodeType)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, "Node data (Type) missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "Node data (Type) missing"); } if(nodeId > MAX_NODES){ char buf[255]; snprintf(buf, sizeof(buf), "Maximum DB node id allowed is: %d", MAX_NDB_NODES); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } if(nodeId == 0){ char buf[255]; snprintf(buf, sizeof(buf), "Minimum node id allowed in the cluster is: 1"); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } for(unsigned j = 0; j<nodeNo; j++){ if(cd.nodeData[j].nodeId == nodeId){ char buf[255]; BaseString::snprintf(buf, sizeof(buf), "Two node can not have the same node id"); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } } @@ -430,14 +430,14 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ if(nodeId > MAX_NDB_NODES){ char buf[255]; BaseString::snprintf(buf, sizeof(buf), "Maximum node id for a ndb node is: %d", MAX_NDB_NODES); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } if(cd.SizeAltData.noOfNDBNodes > MAX_NDB_NODES){ char buf[255]; BaseString::snprintf(buf, sizeof(buf), "Maximum %d ndb nodes is allowed in the cluster", MAX_NDB_NODES); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } } else if(strcmp("API", nodeType) == 0){ cd.nodeData[nodeNo].nodeType = NodeInfo::API; @@ -452,7 +452,7 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ cd.SizeAltData.noOfMGMNodes++; // No of MGM processes tmpApiMgmProperties = "MGM"; } else { - ERROR_SET(fatal, ERR_INVALID_CONFIG, + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration: Unknown node type", nodeType); } @@ -462,7 +462,7 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ const Properties* q = 0; if (!p.get(tmpApiMgmProperties, nodeId, &q)) { - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, tmpApiMgmProperties); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, tmpApiMgmProperties); } else { */ Uint32 rank = 0; diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index 650d914035f..46e237d1fe6 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -194,7 +194,7 @@ Configuration::fetch_configuration(){ if (m_config_retriever->hasError()) { - ERROR_SET(fatal, ERR_INVALID_CONFIG, + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Could not connect initialize handle to management server", m_config_retriever->getErrorString()); } @@ -206,7 +206,7 @@ Configuration::fetch_configuration(){ /* Set stop on error to true otherwise NDB will go into an restart loop... */ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Could not connect to ndb_mgmd", s); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Could not connect to ndb_mgmd", s); } m_mgmd_port= m_config_retriever->get_mgmd_port(); @@ -224,7 +224,7 @@ Configuration::fetch_configuration(){ globalData.ownId = cr.allocNodeId(2 /*retry*/,3 /*delay*/); if(globalData.ownId == 0){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Unable to alloc node id", m_config_retriever->getErrorString()); } @@ -238,7 +238,7 @@ Configuration::fetch_configuration(){ go into an restart loop... */ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Could not fetch configuration" + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Could not fetch configuration" "/invalid configuration", s); } if(m_clusterConfig) @@ -248,13 +248,36 @@ Configuration::fetch_configuration(){ ndb_mgm_configuration_iterator iter(* p, CFG_SECTION_NODE); if (iter.find(CFG_NODE_ID, globalData.ownId)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", "DB missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "DB missing"); } if(iter.get(CFG_DB_STOP_ON_ERROR, &_stopOnError)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "StopOnError missing"); } + + m_mgmds.clear(); + for(ndb_mgm_first(&iter); ndb_mgm_valid(&iter); ndb_mgm_next(&iter)) + { + Uint32 nodeType, port; + char const *hostname; + + ndb_mgm_get_int_parameter(&iter,CFG_TYPE_OF_SECTION,&nodeType); + + if (nodeType != NodeInfo::MGM) + continue; + + if (ndb_mgm_get_string_parameter(&iter,CFG_NODE_HOST, &hostname) || + ndb_mgm_get_int_parameter(&iter,CFG_MGM_PORT, &port) || + hostname == 0 || hostname[0] == 0) + { + continue; + } + BaseString connectstring(hostname); + connectstring.appfmt(":%d", port); + + m_mgmds.push_back(connectstring); + } } static char * get_and_validate_path(ndb_mgm_configuration_iterator &iter, @@ -262,12 +285,12 @@ static char * get_and_validate_path(ndb_mgm_configuration_iterator &iter, { const char* path = NULL; if(iter.get(param, &path)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched missing ", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched missing ", param_string); } if(path == 0 || strlen(path) == 0){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched. Configuration does not contain valid ", param_string); } @@ -285,7 +308,7 @@ static char * get_and_validate_path(ndb_mgm_configuration_iterator &iter, (::access(buf2, W_OK) != 0)) #endif { - ERROR_SET(fatal, AFS_ERROR_INVALIDPATH, path, " Filename::init()"); + ERROR_SET(fatal, NDBD_EXIT_AFS_INVALIDPATH, path, param_string); } if (strcmp(&buf2[strlen(buf2) - 1], DIR_SEPARATOR)) @@ -309,7 +332,7 @@ Configuration::setupConfiguration(){ * p, globalTransporterRegistry); if(res <= 0){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "No transporters configured"); } } @@ -319,27 +342,27 @@ Configuration::setupConfiguration(){ */ ndb_mgm_configuration_iterator iter(* p, CFG_SECTION_NODE); if (iter.find(CFG_NODE_ID, globalData.ownId)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", "DB missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "DB missing"); } unsigned type; if(!(iter.get(CFG_TYPE_OF_SECTION, &type) == 0 && type == NODE_TYPE_DB)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "I'm wrong type of node"); } if(iter.get(CFG_DB_NO_SAVE_MSGS, &_maxErrorLogs)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "MaxNoOfSavedMessages missing"); } if(iter.get(CFG_DB_MEMLOCK, &_lockPagesInMainMemory)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "LockPagesInMainMemory missing"); } if(iter.get(CFG_DB_WATCHDOG_INTERVAL, &_timeBetweenWatchDogCheck)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "TimeBetweenWatchDogCheck missing"); } @@ -354,7 +377,7 @@ Configuration::setupConfiguration(){ _backupPath= get_and_validate_path(iter, CFG_DB_BACKUP_DATADIR, "BackupDataDir"); if(iter.get(CFG_DB_STOP_ON_ERROR_INSERT, &m_restartOnErrorInsert)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Invalid configuration fetched", + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched", "RestartOnErrorInsert missing"); } @@ -496,7 +519,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ *tmp[i].storage = 0; } else { BaseString::snprintf(buf, sizeof(buf),"ConfigParam: %d not found", tmp[i].paramId); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } } } @@ -506,12 +529,12 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ ndb_mgm_get_int64_parameter(&db, CFG_DB_INDEX_MEM, &indexMem); if(dataMem == 0){ BaseString::snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_DATA_MEM); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } if(indexMem == 0){ BaseString::snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_INDEX_MEM); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } noOfDataPages = (dataMem / 32768); @@ -535,23 +558,23 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ Uint32 nodeType; if(ndb_mgm_get_int_parameter(p, CFG_NODE_ID, &nodeId)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, "Node data (Id) missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "Node data (Id) missing"); } if(ndb_mgm_get_int_parameter(p, CFG_TYPE_OF_SECTION, &nodeType)){ - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, "Node data (Type) missing"); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, "Node data (Type) missing"); } if(nodeId > MAX_NODES || nodeId == 0){ BaseString::snprintf(buf, sizeof(buf), "Invalid node id: %d", nodeId); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } if(nodes.get(nodeId)){ BaseString::snprintf(buf, sizeof(buf), "Two node can not have the same node id: %d", nodeId); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } nodes.set(nodeId); @@ -562,7 +585,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ if(nodeId > MAX_NDB_NODES){ BaseString::snprintf(buf, sizeof(buf), "Maximum node id for a ndb node is: %d", MAX_NDB_NODES); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } break; case NODE_TYPE_API: @@ -577,7 +600,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ break; default: BaseString::snprintf(buf, sizeof(buf), "Unknown node type: %d", nodeType); - ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); + ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, msg, buf); } } noOfNodes = nodeNo; diff --git a/ndb/src/kernel/vm/Configuration.hpp b/ndb/src/kernel/vm/Configuration.hpp index 6ca6d9a1f17..5043d1f0bee 100644 --- a/ndb/src/kernel/vm/Configuration.hpp +++ b/ndb/src/kernel/vm/Configuration.hpp @@ -75,6 +75,8 @@ public: private: friend class Cmvmi; friend class Qmgr; + friend int reportShutdown(class Configuration *config, int error, int restart); + ndb_mgm_configuration_iterator * getClusterConfigIterator() const; Uint32 _stopOnError; @@ -91,6 +93,8 @@ private: ConfigRetriever *m_config_retriever; + Vector<BaseString> m_mgmds; + /** * arguments to NDB process */ diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index d6ed6c0dafd..2105b7ddb5e 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -30,13 +30,21 @@ #include <NodeState.hpp> #include <NdbMem.h> -#include <NdbOut.hpp> #include <NdbMutex.h> #include <NdbSleep.h> +#include <EventLogger.hpp> + +void childExit(int code, Uint32 currentStartPhase); +void childAbort(int code, Uint32 currentStartPhase); + extern "C" { extern void (* ndb_new_handler)(); } +extern EventLogger g_eventLogger; +extern my_bool opt_core; +// instantiated and updated in NdbcntrMain.cpp +extern Uint32 g_currentStartPhase; /** * Declare the global variables @@ -73,7 +81,7 @@ EmulatorData::EmulatorData(){ void ndb_new_handler_impl(){ - ERROR_SET(fatal, ERR_MEMALLOC, "New handler", ""); + ERROR_SET(fatal, NDBD_EXIT_MEMALLOC, "New handler", ""); } void @@ -108,8 +116,8 @@ EmulatorData::destroy(){ void NdbShutdown(NdbShutdownType type, - NdbRestartType restartType){ - + NdbRestartType restartType) +{ if(type == NST_ErrorInsert){ type = NST_Restart; restartType = (NdbRestartType) @@ -141,45 +149,49 @@ NdbShutdown(NdbShutdownType type, switch(type){ case NST_Normal: - ndbout << "Shutdown initiated" << endl; + g_eventLogger.info("Shutdown initiated"); break; case NST_Watchdog: - ndbout << "Watchdog " << shutting << " system" << endl; + g_eventLogger.info("Watchdog %s system", shutting); break; case NST_ErrorHandler: - ndbout << "Error handler " << shutting << " system" << endl; + g_eventLogger.info("Error handler %s system", shutting); break; case NST_ErrorHandlerSignal: - ndbout << "Error handler signal " << shutting << " system" << endl; + g_eventLogger.info("Error handler signal %s system", shutting); + break; + case NST_ErrorHandlerStartup: + g_eventLogger.info("Error handler startup %s system", shutting); break; case NST_Restart: - ndbout << "Restarting system" << endl; + g_eventLogger.info("Restarting system"); break; default: - ndbout << "Error handler " << shutting << " system" - << " (unknown type: " << (unsigned)type << ")" << endl; + g_eventLogger.info("Error handler %s system (unknown type: %u)", + shutting, (unsigned)type); type = NST_ErrorHandler; break; } const char * exitAbort = 0; -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - exitAbort = "aborting"; -#else - exitAbort = "exiting"; -#endif + if (opt_core) + exitAbort = "aborting"; + else + exitAbort = "exiting"; if(type == NST_Watchdog){ /** * Very serious, don't attempt to free, just die!! */ - ndbout << "Watchdog shutdown completed - " << exitAbort << endl; -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + g_eventLogger.info("Watchdog shutdown completed - %s", exitAbort); + if (opt_core) + { + childAbort(-1,g_currentStartPhase); + } + else + { + childExit(-1,g_currentStartPhase); + } } #ifndef NDB_WIN32 @@ -227,23 +239,28 @@ NdbShutdown(NdbShutdownType type, } if(type != NST_Normal && type != NST_Restart){ - ndbout << "Error handler shutdown completed - " << exitAbort << endl; -#if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + // Signal parent that error occured during startup + if (type == NST_ErrorHandlerStartup) + kill(getppid(), SIGUSR1); + g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); + if (opt_core) + { + childAbort(-1,g_currentStartPhase); + } + else + { + childExit(-1,g_currentStartPhase); + } } /** * This is a normal restart, depend on angel */ if(type == NST_Restart){ - exit(restartType); + childExit(restartType,g_currentStartPhase); } - ndbout << "Shutdown completed - exiting" << endl; + g_eventLogger.info("Shutdown completed - exiting"); } else { /** * Shutdown is already in progress @@ -253,12 +270,11 @@ NdbShutdown(NdbShutdownType type, * If this is the watchdog, kill system the hard way */ if (type== NST_Watchdog){ - ndbout << "Watchdog is killing system the hard way" << endl; + g_eventLogger.info("Watchdog is killing system the hard way"); #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); + childAbort(-1,g_currentStartPhase); #else - exit(-1); + childExit(-1,g_currentStartPhase); #endif } diff --git a/ndb/src/kernel/vm/Emulator.hpp b/ndb/src/kernel/vm/Emulator.hpp index dba8cb3ab9b..cd194202d85 100644 --- a/ndb/src/kernel/vm/Emulator.hpp +++ b/ndb/src/kernel/vm/Emulator.hpp @@ -83,7 +83,8 @@ enum NdbShutdownType { NST_ErrorHandler, NST_ErrorHandlerSignal, NST_Restart, - NST_ErrorInsert + NST_ErrorInsert, + NST_ErrorHandlerStartup }; enum NdbRestartType { diff --git a/ndb/src/kernel/vm/FastScheduler.cpp b/ndb/src/kernel/vm/FastScheduler.cpp index a2d806571fe..ad24a6795a4 100644 --- a/ndb/src/kernel/vm/FastScheduler.cpp +++ b/ndb/src/kernel/vm/FastScheduler.cpp @@ -19,7 +19,6 @@ #include "Emulator.hpp" #include "VMSignal.hpp" -#include <Error.hpp> #include <SignalLoggerManager.hpp> #include <BlockNumbers.h> @@ -395,7 +394,8 @@ void print_restart(FILE * output, Signal* signal, Uint32 aLevel); void FastScheduler::dumpSignalMemory(FILE * output) { - Signal signal; + SignalT<25> signalT; + Signal &signal= *(Signal*)&signalT; Uint32 ReadPtr[5]; Uint32 tJob; Uint32 tLastJob; @@ -444,21 +444,21 @@ void FastScheduler::dumpSignalMemory(FILE * output) void FastScheduler::prio_level_error() { - ERROR_SET(ecError, ERROR_WRONG_PRIO_LEVEL, + ERROR_SET(ecError, NDBD_EXIT_WRONG_PRIO_LEVEL, "Wrong Priority Level", "FastScheduler.C"); } void jbuf_error() { - ERROR_SET(ecError, BLOCK_ERROR_JBUFCONGESTION, + ERROR_SET(ecError, NDBD_EXIT_BLOCK_JBUFCONGESTION, "Job Buffer Full", "APZJobBuffer.C"); } void bnr_error() { - ERROR_SET(ecError, BLOCK_ERROR_BNR_ZERO, + ERROR_SET(ecError, NDBD_EXIT_BLOCK_BNR_ZERO, "Block Number Zero", "FastScheduler.C"); } @@ -484,17 +484,17 @@ print_restart(FILE * output, Signal* signal, Uint32 aLevel) */ void FastScheduler::reportDoJobStatistics(Uint32 tMeanLoopCount) { - Signal signal; + SignalT<2> signalT; + Signal &signal= *(Signal*)&signalT; + memset(&signal.header, 0, sizeof(signal.header)); + signal.header.theLength = 2; + signal.header.theSendersSignalId = 0; + signal.header.theSendersBlockRef = numberToRef(0, 0); signal.theData[0] = NDB_LE_JobStatistic; signal.theData[1] = tMeanLoopCount; - memset(&signal.header, 0, sizeof(SignalHeader)); - signal.header.theLength = 2; - signal.header.theSendersSignalId = 0; - signal.header.theSendersBlockRef = numberToRef(0, 0); - execute(&signal, JBA, CMVMI, GSN_EVENT_REP); } diff --git a/ndb/src/kernel/vm/Makefile.am b/ndb/src/kernel/vm/Makefile.am index 0dce9285ae3..8f9bf92cb01 100644 --- a/ndb/src/kernel/vm/Makefile.am +++ b/ndb/src/kernel/vm/Makefile.am @@ -18,7 +18,7 @@ libkernel_a_SOURCES = \ SimplePropertiesSection.cpp \ SectionReader.cpp \ MetaData.cpp \ - Mutex.cpp SafeCounter.cpp + Mutex.cpp SafeCounter.cpp ndbd_malloc.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi diff --git a/ndb/src/kernel/vm/SafeCounter.cpp b/ndb/src/kernel/vm/SafeCounter.cpp index b09ad08b026..542e43f9172 100644 --- a/ndb/src/kernel/vm/SafeCounter.cpp +++ b/ndb/src/kernel/vm/SafeCounter.cpp @@ -25,8 +25,8 @@ SafeCounterManager::SafeCounterManager(class SimulatedBlock & block) {} bool -SafeCounterManager::setSize(Uint32 maxNoOfActiveMutexes) { - return m_counterPool.setSize(maxNoOfActiveMutexes); +SafeCounterManager::setSize(Uint32 maxNoOfActiveMutexes, bool exit_on_error) { + return m_counterPool.setSize(maxNoOfActiveMutexes, exit_on_error); } Uint32 diff --git a/ndb/src/kernel/vm/SafeCounter.hpp b/ndb/src/kernel/vm/SafeCounter.hpp index 1f3cc15c2d6..3ee5e076ab8 100644 --- a/ndb/src/kernel/vm/SafeCounter.hpp +++ b/ndb/src/kernel/vm/SafeCounter.hpp @@ -63,7 +63,7 @@ class SafeCounterManager { public: SafeCounterManager(class SimulatedBlock &); - bool setSize(Uint32 maxNoOfActiveMutexes); + bool setSize(Uint32 maxNoOfActiveMutexes, bool exit_on_error = true); Uint32 getSize() const ; void execNODE_FAILREP(Signal*); diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp index 57a4032e40b..d708052ca4e 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.cpp +++ b/ndb/src/kernel/vm/SimulatedBlock.cpp @@ -25,11 +25,12 @@ #include <TransporterRegistry.hpp> #include <SignalLoggerManager.hpp> #include <FastScheduler.hpp> -#include <NdbMem.h> +#include "ndbd_malloc.hpp" #include <signaldata/EventReport.hpp> #include <signaldata/ContinueFragmented.hpp> #include <signaldata/NodeStateSignalData.hpp> #include <signaldata/FsRef.hpp> +#include <signaldata/SignalDroppedRep.hpp> #include <DebuggerNames.hpp> #include "LongSignal.hpp" @@ -140,7 +141,6 @@ SimulatedBlock::installSimulatedBlockFunctions(){ a[GSN_UTIL_LOCK_CONF] = &SimulatedBlock::execUTIL_LOCK_CONF; a[GSN_UTIL_UNLOCK_REF] = &SimulatedBlock::execUTIL_UNLOCK_REF; a[GSN_UTIL_UNLOCK_CONF] = &SimulatedBlock::execUTIL_UNLOCK_CONF; - a[GSN_READ_CONFIG_REQ] = &SimulatedBlock::execREAD_CONFIG_REQ; a[GSN_FSOPENREF] = &SimulatedBlock::execFSOPENREF; a[GSN_FSCLOSEREF] = &SimulatedBlock::execFSCLOSEREF; a[GSN_FSWRITEREF] = &SimulatedBlock::execFSWRITEREF; @@ -156,8 +156,8 @@ SimulatedBlock::addRecSignalImpl(GlobalSignalNumber gsn, if(gsn > MAX_GSN || (!force && theExecArray[gsn] != 0)){ char errorMsg[255]; BaseString::snprintf(errorMsg, 255, - "Illeagal signal (%d %d)", gsn, MAX_GSN); - ERROR_SET(fatal, ERR_ERROR_PRGERR, errorMsg, errorMsg); + "GSN %d(%d))", gsn, MAX_GSN); + ERROR_SET(fatal, NDBD_EXIT_ILLEGAL_SIGNAL, errorMsg, errorMsg); } theExecArray[gsn] = f; } @@ -173,8 +173,7 @@ SimulatedBlock::signal_error(Uint32 gsn, Uint32 len, Uint32 recBlockNo, "Signal (GSN: %d, Length: %d, Rec Block No: %d)", gsn, len, recBlockNo); - ErrorReporter::handleError(ecError, - BLOCK_ERROR_BNR_ZERO, + ErrorReporter::handleError(NDBD_EXIT_BLOCK_BNR_ZERO, probData, objRef); } @@ -668,7 +667,7 @@ SimulatedBlock::allocRecord(const char * type, size_t s, size_t n, bool clear) n, size); #endif - p = NdbMem_Allocate(size); + p = ndbd_malloc(size); if (p == NULL){ char buf1[255]; char buf2[255]; @@ -676,7 +675,7 @@ SimulatedBlock::allocRecord(const char * type, size_t s, size_t n, bool clear) getBlockName(number()), type); BaseString::snprintf(buf2, sizeof(buf2), "Requested: %ux%u = %u bytes", (Uint32)s, (Uint32)n, (Uint32)size); - ERROR_SET(fatal, ERR_MEMALLOC, buf1, buf2); + ERROR_SET(fatal, NDBD_EXIT_MEMALLOC, buf1, buf2); } if(clear){ @@ -699,11 +698,9 @@ void SimulatedBlock::deallocRecord(void ** ptr, const char * type, size_t s, size_t n){ (void)type; - (void)s; - (void)n; if(* ptr != 0){ - NdbMem_Free(* ptr); + ndbd_free(* ptr, n*s); * ptr = 0; } } @@ -733,7 +730,7 @@ SimulatedBlock::progError(int line, int err_code, const char* extra) const { BaseString::snprintf(&buf[0], 100, "%s (Line: %d) 0x%.8x", aBlockName, line, magicStatus); - ErrorReporter::handleError(ecError, err_code, extra, buf); + ErrorReporter::handleError(err_code, extra, buf); } @@ -854,9 +851,12 @@ SimulatedBlock::execNDB_TAMPER(Signal * signal){ void SimulatedBlock::execSIGNAL_DROPPED_REP(Signal * signal){ - ErrorReporter::handleError(ecError, - ERR_OUT_OF_LONG_SIGNAL_MEMORY, - "Signal lost, out of long signal memory", + char msg[64]; + const SignalDroppedRep * const rep = (SignalDroppedRep *)&signal->theData[0]; + snprintf(msg, sizeof(msg), "%s GSN: %u (%u,%u)", getBlockName(number()), + rep->originalGsn, rep->originalLength,rep->originalSectionCount); + ErrorReporter::handleError(NDBD_EXIT_OUT_OF_LONG_SIGNAL_MEMORY, + msg, __FILE__, NST_ErrorHandler); } @@ -1739,20 +1739,6 @@ void SimulatedBlock::execUTIL_UNLOCK_CONF(Signal* signal){ c_mutexMgr.execUTIL_UNLOCK_CONF(signal); } -void -SimulatedBlock::execREAD_CONFIG_REQ(Signal* signal){ - const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); - - Uint32 ref = req->senderRef; - Uint32 senderData = req->senderData; - - ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); - conf->senderRef = reference(); - conf->senderData = senderData; - sendSignal(ref, GSN_READ_CONFIG_CONF, signal, - ReadConfigConf::SignalLength, JBB); -} - void SimulatedBlock::ignoreMutexUnlockCallback(Signal* signal, Uint32 ptrI, Uint32 retVal){ diff --git a/ndb/src/kernel/vm/SimulatedBlock.hpp b/ndb/src/kernel/vm/SimulatedBlock.hpp index bba92ca7c31..ce77fa916d8 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.hpp +++ b/ndb/src/kernel/vm/SimulatedBlock.hpp @@ -34,7 +34,6 @@ #include "LongSignal.hpp" #include <SignalLoggerManager.hpp> -#include <Error.hpp> #include <ErrorReporter.hpp> #include <ErrorHandlingMacros.hpp> @@ -503,7 +502,6 @@ private: void execUTIL_UNLOCK_REF(Signal* signal); void execUTIL_UNLOCK_CONF(Signal* signal); - void execREAD_CONFIG_REQ(Signal* signal); protected: void execUPGRADE(Signal* signal); @@ -564,11 +562,11 @@ SimulatedBlock::executeFunction(GlobalSignalNumber gsn, Signal* signal){ char errorMsg[255]; if (!(gsn <= MAX_GSN)) { BaseString::snprintf(errorMsg, 255, "Illegal signal received (GSN %d too high)", gsn); - ERROR_SET(fatal, ERR_ERROR_PRGERR, errorMsg, errorMsg); + ERROR_SET(fatal, NDBD_EXIT_PRGERR, errorMsg, errorMsg); } if (!(theExecArray[gsn] != 0)) { BaseString::snprintf(errorMsg, 255, "Illegal signal received (GSN %d not added)", gsn); - ERROR_SET(fatal, ERR_ERROR_PRGERR, errorMsg, errorMsg); + ERROR_SET(fatal, NDBD_EXIT_PRGERR, errorMsg, errorMsg); } ndbrequire(false); } diff --git a/ndb/src/kernel/vm/TimeQueue.cpp b/ndb/src/kernel/vm/TimeQueue.cpp index 56988c2e3da..0b620c75d52 100644 --- a/ndb/src/kernel/vm/TimeQueue.cpp +++ b/ndb/src/kernel/vm/TimeQueue.cpp @@ -19,7 +19,6 @@ #include <GlobalData.hpp> #include <FastScheduler.hpp> #include <VMSignal.hpp> -#include <Error.hpp> static const int MAX_TIME_QUEUE_VALUE = 32000; @@ -70,7 +69,7 @@ TimeQueue::insert(Signal* signal, BlockNumber bnr, if (regShortIndex == 0){ theShortQueue[0].copy_struct = newEntry.copy_struct; } else if (regShortIndex >= MAX_NO_OF_SHORT_TQ - 1) { - ERROR_SET(ecError, ERROR_TIME_QUEUE_SHORT, + ERROR_SET(ecError, NDBD_EXIT_TIME_QUEUE_SHORT, "Too many in Short Time Queue", "TimeQueue.C" ); } else { for (i = 0; i < regShortIndex; i++) { @@ -99,7 +98,7 @@ TimeQueue::insert(Signal* signal, BlockNumber bnr, if (regLongIndex == 0) { theLongQueue[0].copy_struct = newEntry.copy_struct; } else if (regLongIndex >= MAX_NO_OF_LONG_TQ - 1) { - ERROR_SET(ecError, ERROR_TIME_QUEUE_LONG, + ERROR_SET(ecError, NDBD_EXIT_TIME_QUEUE_LONG, "Too many in Long Time Queue", "TimeQueue.C" ); } else { for (i = 0; i < regLongIndex; i++) { @@ -124,7 +123,7 @@ TimeQueue::insert(Signal* signal, BlockNumber bnr, } globalData.theLongTQIndex = regLongIndex + 1; } else { - ERROR_SET(ecError, ERROR_TIME_QUEUE_DELAY, + ERROR_SET(ecError, NDBD_EXIT_TIME_QUEUE_DELAY, "Too long delay for Time Queue", "TimeQueue.C" ); } } @@ -194,7 +193,7 @@ TimeQueue::getIndex() Uint32 retValue = globalData.theFirstFreeTQIndex; globalData.theFirstFreeTQIndex = (Uint32)theFreeIndex[retValue]; if (retValue >= MAX_NO_OF_TQ) - ERROR_SET(fatal, ERROR_TIME_QUEUE_INDEX, + ERROR_SET(fatal, NDBD_EXIT_TIME_QUEUE_INDEX, "Index out of range", "TimeQueue.C" ); return retValue; } diff --git a/ndb/src/kernel/vm/TransporterCallback.cpp b/ndb/src/kernel/vm/TransporterCallback.cpp index e5322edaecc..aab81957d07 100644 --- a/ndb/src/kernel/vm/TransporterCallback.cpp +++ b/ndb/src/kernel/vm/TransporterCallback.cpp @@ -39,6 +39,26 @@ */ SectionSegmentPool g_sectionSegmentPool; +struct ConnectionError +{ + enum TransporterError err; + const char *text; +}; + +static const ConnectionError connectionError[] = +{ + { TE_NO_ERROR, "No error"}, + { TE_SHM_UNABLE_TO_CREATE_SEGMENT, "Unable to create shared memory segment"}, + { (enum TransporterError) -1, "No connection error message available (please report a bug)"} +}; + +const char *lookupConnectionError(Uint32 err) +{ + int i= 0; + while ((Uint32)connectionError[i].err != err && (Uint32)connectionError[i].err != -1); + return connectionError[i].text; +} + bool import(Ptr<SectionSegment> & first, const Uint32 * src, Uint32 len){ /** @@ -306,38 +326,58 @@ checkJobBuffer() { } void -reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode){ +reportError(void * callbackObj, NodeId nodeId, + TransporterError errorCode, const char *info) +{ #ifdef DEBUG_TRANSPORTER - char buf[255]; - sprintf(buf, "reportError (%d, 0x%x)", nodeId, errorCode); - ndbout << buf << endl; + ndbout_c("reportError (%d, 0x%x) %s", nodeId, errorCode, info ? info : "") #endif - if(errorCode == TE_SIGNAL_LOST_SEND_BUFFER_FULL){ - ErrorReporter::handleError(ecError, - ERR_PROGRAMERROR, - "Signal lost, send buffer full", - __FILE__, - NST_ErrorHandler); + DBUG_ENTER("reportError"); + DBUG_PRINT("info",("nodeId %d errorCode: 0x%x info: %s", + nodeId, errorCode, info)); + + switch (errorCode) + { + case TE_SIGNAL_LOST_SEND_BUFFER_FULL: + { + char msg[64]; + snprintf(msg, sizeof(msg), "Remote note id %d.%s%s", nodeId, + info ? " " : "", info ? info : ""); + ErrorReporter::handleError(NDBD_EXIT_SIGNAL_LOST_SEND_BUFFER_FULL, + msg, __FILE__, NST_ErrorHandler); } - - if(errorCode == TE_SIGNAL_LOST){ - ErrorReporter::handleError(ecError, - ERR_PROGRAMERROR, - "Signal lost (unknown reason)", - __FILE__, - NST_ErrorHandler); + case TE_SIGNAL_LOST: + { + char msg[64]; + snprintf(msg, sizeof(msg), "Remote node id %d,%s%s", nodeId, + info ? " " : "", info ? info : ""); + ErrorReporter::handleError(NDBD_EXIT_SIGNAL_LOST, + msg, __FILE__, NST_ErrorHandler); } - - if(errorCode & 0x8000){ + case TE_SHM_IPC_PERMANENT: + { + char msg[128]; + snprintf(msg, sizeof(msg), + "Remote node id %d.%s%s", + nodeId, info ? " " : "", info ? info : ""); + ErrorReporter::handleError(NDBD_EXIT_CONNECTION_SETUP_FAILED, + msg, __FILE__, NST_ErrorHandler); + } + default: + break; + } + + if(errorCode & TE_DO_DISCONNECT){ reportDisconnect(callbackObj, nodeId, errorCode); } - Signal signal; + SignalT<3> signalT; + Signal &signal= *(Signal*)&signalT; memset(&signal.header, 0, sizeof(signal.header)); - if(errorCode & 0x8000) + if(errorCode & TE_DO_DISCONNECT) signal.theData[0] = NDB_LE_TransporterError; else signal.theData[0] = NDB_LE_TransporterWarning; @@ -349,6 +389,8 @@ reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode){ signal.header.theSendersSignalId = 0; signal.header.theSendersBlockRef = numberToRef(0, globalData.ownId); globalScheduler.execute(&signal, JBA, CMVMI, GSN_EVENT_REP); + + DBUG_VOID_RETURN; } /** @@ -358,7 +400,8 @@ void reportSendLen(void * callbackObj, NodeId nodeId, Uint32 count, Uint64 bytes){ - Signal signal; + SignalT<3> signalT; + Signal &signal= *(Signal*)&signalT; memset(&signal.header, 0, sizeof(signal.header)); signal.header.theLength = 3; @@ -377,7 +420,8 @@ void reportReceiveLen(void * callbackObj, NodeId nodeId, Uint32 count, Uint64 bytes){ - Signal signal; + SignalT<3> signalT; + Signal &signal= *(Signal*)&signalT; memset(&signal.header, 0, sizeof(signal.header)); signal.header.theLength = 3; @@ -396,7 +440,8 @@ reportReceiveLen(void * callbackObj, void reportConnect(void * callbackObj, NodeId nodeId){ - Signal signal; + SignalT<1> signalT; + Signal &signal= *(Signal*)&signalT; memset(&signal.header, 0, sizeof(signal.header)); signal.header.theLength = 1; @@ -413,7 +458,10 @@ reportConnect(void * callbackObj, NodeId nodeId){ void reportDisconnect(void * callbackObj, NodeId nodeId, Uint32 errNo){ - Signal signal; + DBUG_ENTER("reportDisconnect"); + + SignalT<sizeof(DisconnectRep)/4> signalT; + Signal &signal= *(Signal*)&signalT; memset(&signal.header, 0, sizeof(signal.header)); signal.header.theLength = DisconnectRep::SignalLength; @@ -426,6 +474,8 @@ reportDisconnect(void * callbackObj, NodeId nodeId, Uint32 errNo){ rep->err = errNo; globalScheduler.execute(&signal, JBA, CMVMI, GSN_DISCONNECT_REP); + + DBUG_VOID_RETURN; } void diff --git a/ndb/src/kernel/vm/VMSignal.hpp b/ndb/src/kernel/vm/VMSignal.hpp index 45543c5d174..33f8a9f25c0 100644 --- a/ndb/src/kernel/vm/VMSignal.hpp +++ b/ndb/src/kernel/vm/VMSignal.hpp @@ -42,6 +42,16 @@ struct NodeReceiverGroup { NodeBitmask m_nodes; }; +template <unsigned T> struct SignalT +{ + SignalHeader header; + SegmentedSectionPtr m_sectionPtr[3]; + union { + Uint32 theData[T]; + Uint64 dummyAlign; + }; +}; + /** * class used for passing argumentes to blocks */ diff --git a/ndb/src/kernel/vm/WatchDog.cpp b/ndb/src/kernel/vm/WatchDog.cpp index 23475a478d3..c80317e1725 100644 --- a/ndb/src/kernel/vm/WatchDog.cpp +++ b/ndb/src/kernel/vm/WatchDog.cpp @@ -95,39 +95,40 @@ WatchDog::run(){ globalData.incrementWatchDogCounter(0); alerts = 0; } else { + const char *last_stuck_action; alerts++; - ndbout << "Ndb kernel is stuck in: "; switch (oldIPValue) { case 1: - ndbout << "Job Handling" << endl; + last_stuck_action = "Job Handling"; break; case 2: - ndbout << "Scanning Timers" << endl; + last_stuck_action = "Scanning Timers"; break; case 3: - ndbout << "External I/O" << endl; + last_stuck_action = "External I/O"; break; case 4: - ndbout << "Print Job Buffers at crash" << endl; + last_stuck_action = "Print Job Buffers at crash"; break; case 5: - ndbout << "Checking connections" << endl; + last_stuck_action = "Checking connections"; break; case 6: - ndbout << "Performing Send" << endl; + last_stuck_action = "Performing Send"; break; case 7: - ndbout << "Polling for Receive" << endl; + last_stuck_action = "Polling for Receive"; break; case 8: - ndbout << "Performing Receive" << endl; + last_stuck_action = "Performing Receive"; break; default: - ndbout << "Unknown place" << endl; + last_stuck_action = "Unknown place"; break; }//switch + ndbout << "Ndb kernel is stuck in: " << last_stuck_action << endl; if(alerts == 3){ - shutdownSystem(); + shutdownSystem(last_stuck_action); } } } @@ -135,11 +136,10 @@ WatchDog::run(){ } void -WatchDog::shutdownSystem(){ +WatchDog::shutdownSystem(const char *last_stuck_action){ - ErrorReporter::handleError(ecError, - ERR_PROGRAMERROR, - "WatchDog terminate", + ErrorReporter::handleError(NDBD_EXIT_WATCHDOG_TERMINATE, + last_stuck_action, __FILE__, NST_Watchdog); } diff --git a/ndb/src/kernel/vm/WatchDog.hpp b/ndb/src/kernel/vm/WatchDog.hpp index 4b44b1a96a2..65b23dafdb1 100644 --- a/ndb/src/kernel/vm/WatchDog.hpp +++ b/ndb/src/kernel/vm/WatchDog.hpp @@ -50,7 +50,7 @@ private: bool theStop; void run(); - void shutdownSystem(); + void shutdownSystem(const char *last_stuck_action); }; #endif // WatchDog_H diff --git a/ndb/src/kernel/vm/ndbd_malloc.cpp b/ndb/src/kernel/vm/ndbd_malloc.cpp new file mode 100644 index 00000000000..4bfccf828fc --- /dev/null +++ b/ndb/src/kernel/vm/ndbd_malloc.cpp @@ -0,0 +1,63 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> +#include "ndbd_malloc.hpp" +#include <NdbMem.h> + +//#define TRACE_MALLOC +#ifdef TRACE_MALLOC +#include <stdio.h> +#endif + +static void xxx(size_t size, size_t *s_m, size_t *s_k, size_t *s_b) +{ + *s_m = size/1024/1024; + *s_k = (size - *s_m*1024*1024)/1024; + *s_b = size - *s_m*1024*1024-*s_k*1024; +} + +static Uint64 g_allocated_memory; +void *ndbd_malloc(size_t size) +{ + void *p = NdbMem_Allocate(size); + if (p) + { + g_allocated_memory += size; +#ifdef TRACE_MALLOC + { + size_t s_m, s_k, s_b; + xxx(size, &s_m, &s_k, &s_b); + fprintf(stderr, "%p malloc(%um %uk %ub)", p, s_m, s_k, s_b); + xxx(g_allocated_memory, &s_m, &s_k, &s_b); + fprintf(stderr, "\t\ttotal(%um %uk %ub)\n", s_m, s_k, s_b); + } +#endif + } + return p; +} + +void ndbd_free(void *p, size_t size) +{ + NdbMem_Free(p); + if (p) + { + g_allocated_memory -= size; +#ifdef TRACE_MALLOC + fprintf(stderr, "%p free(%d)\n", p, size); +#endif + } +} diff --git a/ndb/src/kernel/error/ErrorMessages.hpp b/ndb/src/kernel/vm/ndbd_malloc.hpp index 38c8eec636b..136e9f0c372 100644 --- a/ndb/src/kernel/error/ErrorMessages.hpp +++ b/ndb/src/kernel/vm/ndbd_malloc.hpp @@ -14,9 +14,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef ERROR_MESSAGES_H -#define ERROR_MESSAGES_H +#ifndef NDBD_MALLOC_H +#define NDBD_MALLOC_H -const char* lookupErrorMessage(int faultId); +/** + * common memory allocation function for ndbd kernel + */ +void *ndbd_malloc(size_t size); +void ndbd_free(void *p, size_t size); -#endif +#endif diff --git a/ndb/src/kernel/vm/pc.hpp b/ndb/src/kernel/vm/pc.hpp index 2d745d26b1c..6aeda59224f 100644 --- a/ndb/src/kernel/vm/pc.hpp +++ b/ndb/src/kernel/vm/pc.hpp @@ -90,7 +90,7 @@ * @param limit max no of records in rec * @param rec pointer to first record in an array of records */ -#define ptrCheckGuard(ptr, limit, rec) {\ +#define ptrCheckGuardErr(ptr, limit, rec, error) {\ UintR TxxzLimit; \ TxxzLimit = (limit); \ UintR TxxxPtr; \ @@ -99,24 +99,28 @@ if (TxxxPtr < (TxxzLimit)) { \ ; \ } else { \ - progError(__LINE__, ERR_POINTER_NOTINRANGE, __FILE__); \ + progError(__LINE__, error, __FILE__); \ }} - #define ptrAss(ptr, rec) ptr.p = &rec[ptr.i] #define ptrNull(ptr) ptr.p = NULL -#define ptrGuard(ptr) if (ptr.p == NULL) \ - progError(__LINE__, ERR_POINTER_NOTINRANGE, __FILE__) -#define arrGuard(ind, size) if ((ind) >= (size)) \ - progError(__LINE__, ERR_INDEX_NOTINRANGE, __FILE__) +#define ptrGuardErr(ptr, error) if (ptr.p == NULL) \ + progError(__LINE__, error, __FILE__) +#define arrGuardErr(ind, size, error) if ((ind) >= (size)) \ + progError(__LINE__, error, __FILE__) #else #define ptrCheck(ptr, limit, rec) ptr.p = &rec[ptr.i] -#define ptrCheckGuard(ptr, limit, rec) ptr.p = &rec[ptr.i] +#define ptrCheckGuardErr(ptr, limit, rec, error) ptr.p = &rec[ptr.i] #define ptrAss(ptr, rec) ptr.p = &rec[ptr.i] #define ptrNull(ptr) ptr.p = NULL -#define ptrGuard(ptr) -#define arrGuard(ind, size) +#define ptrGuardErr(ptr, error) +#define arrGuardErr(ind, size, error) #endif +#define ptrCheckGuard(ptr, limit, rec) \ + ptrCheckGuardErr(ptr, limit, rec, NDBD_EXIT_POINTER_NOTINRANGE) +#define ptrGuard(ptr) ptrGuardErr(ptr, NDBD_EXIT_POINTER_NOTINRANGE) +#define arrGuard(ind, size) arrGuardErr(ind, size, NDBD_EXIT_INDEX_NOTINRANGE) + // -------- ERROR INSERT MACROS ------- #ifdef ERROR_INSERT #define ERROR_INSERT_VARIABLE UintR cerrorInsert @@ -197,34 +201,31 @@ #define ndbassert(check) \ if((check)){ \ } else { \ - progError(__LINE__, ERR_NDBREQUIRE, __FILE__); \ - } - -#define ndbrequire(check) \ - if((check)){ \ - } else { \ - progError(__LINE__, ERR_NDBREQUIRE, __FILE__); \ - } + progError(__LINE__, NDBD_EXIT_NDBASSERT, __FILE__); \ + } #else #define ndbassert(check) +#endif -#define ndbrequire(check) \ +#define ndbrequireErr(check, error) \ if((check)){ \ } else { \ - progError(__LINE__, ERR_NDBREQUIRE, __FILE__); \ - } -#endif + progError(__LINE__, error, __FILE__); \ + } + +#define ndbrequire(check) \ + ndbrequireErr(check, NDBD_EXIT_NDBREQUIRE) #define CRASH_INSERTION(errorType) \ if (!ERROR_INSERTED((errorType))) { \ } else { \ - progError(__LINE__, ERR_ERROR_INSERT, __FILE__); \ + progError(__LINE__, NDBD_EXIT_ERROR_INSERT, __FILE__); \ } #define CRASH_INSERTION2(errorNum, condition) \ if (!(ERROR_INSERTED(errorNum) && condition)) { \ } else { \ - progError(__LINE__, ERR_ERROR_INSERT, __FILE__); \ + progError(__LINE__, NDBD_EXIT_ERROR_INSERT, __FILE__); \ } #define MEMCOPY_PAGE(to, from, page_size_in_bytes) \ diff --git a/ndb/src/mgmapi/Makefile.am b/ndb/src/mgmapi/Makefile.am index db730bf8c89..efe1b8ea2d5 100644 --- a/ndb/src/mgmapi/Makefile.am +++ b/ndb/src/mgmapi/Makefile.am @@ -1,7 +1,7 @@ noinst_LTLIBRARIES = libmgmapi.la -libmgmapi_la_SOURCES = mgmapi.cpp ndb_logevent.cpp mgmapi_configuration.cpp LocalConfig.cpp +libmgmapi_la_SOURCES = mgmapi.cpp ndb_logevent.cpp mgmapi_configuration.cpp LocalConfig.cpp ../kernel/error/ndbd_exit_codes.c INCLUDES_LOC = -I$(top_srcdir)/ndb/include/mgmapi diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index c10eb073855..d5a821c2287 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -678,12 +678,10 @@ ndb_mgm_get_status(NdbMgmHandle handle) Vector<BaseString> split; tmp.split(split, ":"); if(split.size() != 2){ - abort(); return NULL; } if(!(split[0].trim() == "nodes")){ - abort(); return NULL; } @@ -731,7 +729,6 @@ ndb_mgm_get_status(NdbMgmHandle handle) if(i+1 != noOfNodes){ free(state); - abort(); return NULL; } @@ -2285,4 +2282,33 @@ ndb_mgm_get_mgmd_nodeid(NdbMgmHandle handle) DBUG_RETURN(nodeid); } +extern "C" +int ndb_mgm_report_event(NdbMgmHandle handle, Uint32 *data, Uint32 length) +{ + DBUG_ENTER("ndb_mgm_report_event"); + CHECK_HANDLE(handle, 0); + CHECK_CONNECTED(handle, 0); + + Properties args; + args.put("length", length); + BaseString data_string; + + for (int i = 0; i < length; i++) + data_string.appfmt(" %u", data[i]); + + args.put("data", data_string.c_str()); + + const ParserRow<ParserDummy> reply[]= { + MGM_CMD("report event reply", NULL, ""), + MGM_ARG("result", String, Mandatory, "Result"), + MGM_END() + }; + + const Properties *prop; + prop = ndb_mgm_call(handle, reply, "report event", &args); + CHECK_REPLY(prop, -1); + + DBUG_RETURN(0); +} + template class Vector<const ParserRow<ParserDummy>*>; diff --git a/ndb/src/mgmapi/ndb_logevent.cpp b/ndb/src/mgmapi/ndb_logevent.cpp index 27e7c1f36f5..a90d5658506 100644 --- a/ndb/src/mgmapi/ndb_logevent.cpp +++ b/ndb/src/mgmapi/ndb_logevent.cpp @@ -152,6 +152,15 @@ struct Ndb_logevent_body_row ndb_logevent_body[]= { ROW( NDBStopStarted, "stoptype", 1, stoptype), + ROW( NDBStopCompleted, "action", 1, action), + ROW( NDBStopCompleted, "signum", 2, signum), + + ROW( NDBStopForced, "action", 1, action), + ROW( NDBStopForced, "signum", 2, signum), + ROW( NDBStopForced, "error", 3, error), + ROW( NDBStopForced, "sphase", 4, sphase), + ROW( NDBStopForced, "extra", 5, extra), + // ROW( NDBStopAborted), ROW( StartREDOLog, "node", 1, node), @@ -289,6 +298,8 @@ struct Ndb_logevent_body_row ndb_logevent_body[]= { ROW( BackupAborted, "backup_id", 2, backup_id), ROW( BackupAborted, "error", 3, error), + ROW( SingleUser, "type", 1, type), + ROW( SingleUser, "node_id", 2, node_id), { NDB_LE_ILLEGAL_TYPE, 0, 0, 0, 0, 0} }; diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index b4bbb3531ad..0b1b2e3a087 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -459,7 +459,9 @@ event_thread_run(void* m) NdbMgmHandle handle= *(NdbMgmHandle*)m; - int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 }; + int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, + 1, NDB_MGM_EVENT_CATEGORY_STARTUP, + 0 }; int fd = ndb_mgm_listen_event(handle, filter); if (fd != NDB_INVALID_SOCKET) { @@ -1443,9 +1445,8 @@ CommandInterpreter::executeEnterSingleUser(char* parameters) ndbout_c("Entering single user mode for node %d failed", nodeId); printError(); } else { - ndbout_c("Entering single user mode"); - ndbout_c("Access will be granted for API node %d only.", nodeId); - ndbout_c("Use ALL STATUS to see when single user mode has been entered."); + ndbout_c("Single user mode entered"); + ndbout_c("Access is granted for API node %d only.", nodeId); } } @@ -1458,7 +1459,7 @@ CommandInterpreter::executeExitSingleUser(char* parameters) printError(); } else { ndbout_c("Exiting single user mode in progress."); - ndbout_c("Use ALL STATUS to see when single user mode has been exited."); + ndbout_c("Use ALL STATUS or SHOW to see when single user mode has been exited."); } } diff --git a/ndb/src/mgmsrv/Config.cpp b/ndb/src/mgmsrv/Config.cpp index 5ff9cbe04ad..6ff5fb789f0 100644 --- a/ndb/src/mgmsrv/Config.cpp +++ b/ndb/src/mgmsrv/Config.cpp @@ -179,90 +179,3 @@ void Config::printConfigFile(NdbOut &out) const { } #endif } - -Uint32 -Config::getGenerationNumber() const { -#if 0 - Uint32 ret; - const Properties *prop = NULL; - - get("SYSTEM", &prop); - - if(prop != NULL) - if(prop->get("ConfigGenerationNumber", &ret)) - return ret; - - return 0; -#else - return 0; -#endif -} - -int -Config::setGenerationNumber(Uint32 gen) { -#if 0 - Properties *prop = NULL; - - getCopy("SYSTEM", &prop); - - if(prop != NULL) { - MGM_REQUIRE(prop->put("ConfigGenerationNumber", gen, true)); - MGM_REQUIRE(put("SYSTEM", prop, true)); - return 0; - } - return -1; -#else - return -1; -#endif -} - -bool -Config::change(const BaseString §ion, - const BaseString ¶m, - const BaseString &value) { -#if 0 - const char *name; - Properties::Iterator it(this); - - for(name = it.first(); name != NULL; name = it.next()) { - Properties *prop = NULL; - if(strcasecmp(section.c_str(), name) == 0) { - getCopy(name, &prop); - if(prop == NULL) /* doesn't exist */ - return false; - if(value == "") { - prop->remove(param.c_str()); - put(section.c_str(), prop, true); - } else { - PropertiesType t; - if(!prop->getTypeOf(param.c_str(), &t)) /* doesn't exist */ - return false; - switch(t) { - case PropertiesType_Uint32: - long val; - char *ep; - errno = 0; - val = strtol(value.c_str(), &ep, 0); - if(value.length() == 0 || *ep != '\0') /* not a number */ - return false; - if(errno == ERANGE) - return false; - prop->put(param.c_str(), (unsigned int)val, true); - put(section.c_str(), prop, true); - break; - case PropertiesType_char: - prop->put(param.c_str(), value.c_str(), true); - put(section.c_str(), prop, true); - break; - default: - return false; - } - } - break; - } - } - return true; -#else - return false; -#endif -} diff --git a/ndb/src/mgmsrv/Config.hpp b/ndb/src/mgmsrv/Config.hpp index b5e1e17b027..8e16ddf1810 100644 --- a/ndb/src/mgmsrv/Config.hpp +++ b/ndb/src/mgmsrv/Config.hpp @@ -60,16 +60,6 @@ public: printConfigFile(ndb); } - Uint32 getGenerationNumber() const; - int setGenerationNumber(Uint32); - - /** Change configuration - */ - bool change(const BaseString §ion, - const BaseString ¶m, - const BaseString &value); - - /** * Info */ diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index 7d4ca4bc98f..817943f5e51 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -25,6 +25,7 @@ #include <m_string.h> extern my_bool opt_ndb_shm; +extern my_bool opt_core; #define MAX_LINE_LENGTH 255 #define KEY_INTERNAL 0 @@ -56,7 +57,6 @@ ConfigInfo::m_sectionNameAliases[]={ const char* ConfigInfo::m_sectionNames[]={ "SYSTEM", - "EXTERNAL SYSTEM", "COMPUTER", DB_TOKEN, @@ -77,9 +77,7 @@ sizeof(m_sectionNames)/sizeof(char*); ****************************************************************************/ static bool transformComputer(InitConfigFileParser::Context & ctx, const char *); static bool transformSystem(InitConfigFileParser::Context & ctx, const char *); -static bool transformExternalSystem(InitConfigFileParser::Context & ctx, const char *); static bool transformNode(InitConfigFileParser::Context & ctx, const char *); -static bool transformExtNode(InitConfigFileParser::Context & ctx, const char *); static bool checkConnectionSupport(InitConfigFileParser::Context & ctx, const char *); static bool transformConnection(InitConfigFileParser::Context & ctx, const char *); static bool applyDefaultValues(InitConfigFileParser::Context & ctx, const char *); @@ -92,7 +90,6 @@ static bool checkTCPConstraints(InitConfigFileParser::Context &, const char *); static bool fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data); static bool fixHostname(InitConfigFileParser::Context & ctx, const char * data); static bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data); -static bool fixExtConnection(InitConfigFileParser::Context & ctx, const char * data); static bool fixDepricated(InitConfigFileParser::Context & ctx, const char *); static bool saveInConfigValues(InitConfigFileParser::Context & ctx, const char *); static bool fixFileSystemPath(InitConfigFileParser::Context & ctx, const char * data); @@ -103,7 +100,6 @@ static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx, const const ConfigInfo::SectionRule ConfigInfo::m_SectionRules[] = { { "SYSTEM", transformSystem, 0 }, - { "EXTERNAL SYSTEM", transformExternalSystem, 0 }, { "COMPUTER", transformComputer, 0 }, { DB_TOKEN, transformNode, 0 }, @@ -149,20 +145,13 @@ ConfigInfo::m_SectionRules[] = { { "TCP", fixPortNumber, 0 }, // has to come after fixHostName { "SHM", fixPortNumber, 0 }, // has to come after fixHostName { "SCI", fixPortNumber, 0 }, // has to come after fixHostName - { "SHM", fixShmKey, 0 }, - /** - * fixExtConnection must be after fixNodeId - */ - { "TCP", fixExtConnection, 0 }, - { "SHM", fixExtConnection, 0 }, - { "SCI", fixExtConnection, 0 }, - { "OSE", fixExtConnection, 0 }, - { "*", applyDefaultValues, "user" }, { "*", fixDepricated, 0 }, { "*", applyDefaultValues, "system" }, + { "SHM", fixShmKey, 0 }, // has to come after apply default values + { DB_TOKEN, checkLocalhostHostnameMix, 0 }, { API_TOKEN, checkLocalhostHostnameMix, 0 }, { MGM_TOKEN, checkLocalhostHostnameMix, 0 }, @@ -172,9 +161,6 @@ ConfigInfo::m_SectionRules[] = { { DB_TOKEN, checkDbConstraints, 0 }, - /** - * checkConnectionConstraints must be after fixExtConnection - */ { "TCP", checkConnectionConstraints, 0 }, { "SHM", checkConnectionConstraints, 0 }, { "SCI", checkConnectionConstraints, 0 }, @@ -212,9 +198,6 @@ static bool add_node_connections(Vector<ConfigInfo::ConfigRuleSection>§ions, static bool set_connection_priorities(Vector<ConfigInfo::ConfigRuleSection>§ions, struct InitConfigFileParser::Context &ctx, const char * rule_data); -static bool add_server_ports(Vector<ConfigInfo::ConfigRuleSection>§ions, - struct InitConfigFileParser::Context &ctx, - const char * rule_data); static bool check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection>§ions, struct InitConfigFileParser::Context &ctx, const char * rule_data); @@ -224,7 +207,6 @@ ConfigInfo::m_ConfigRules[] = { { sanity_checks, 0 }, { add_node_connections, 0 }, { set_connection_priorities, 0 }, - { add_server_ports, 0 }, { check_node_vs_replicas, 0 }, { 0, 0 } }; @@ -240,6 +222,9 @@ struct DepricationTransform { static const DepricationTransform f_deprication[] = { { DB_TOKEN, "Discless", "Diskless", 0, 1 }, + { DB_TOKEN, "Id", "NodeId", 0, 1 }, + { API_TOKEN, "Id", "NodeId", 0, 1 }, + { MGM_TOKEN, "Id", "NodeId", 0, 1 }, { 0, 0, 0, 0, 0} }; @@ -404,9 +389,21 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { 0, 0 }, { - CFG_NODE_ID, + KEY_INTERNAL, "Id", DB_TOKEN, + "", + ConfigInfo::CI_DEPRICATED, + false, + ConfigInfo::CI_INT, + MANDATORY, + "1", + STR_VALUE(MAX_NODES) }, + + { + CFG_NODE_ID, + "NodeId", + DB_TOKEN, "Number identifying the database node ("DB_TOKEN_PRINT")", ConfigInfo::CI_USED, false, @@ -1243,9 +1240,21 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { 0, 0 }, { - CFG_NODE_ID, + KEY_INTERNAL, "Id", API_TOKEN, + "", + ConfigInfo::CI_DEPRICATED, + false, + ConfigInfo::CI_INT, + MANDATORY, + "1", + STR_VALUE(MAX_NODES) }, + + { + CFG_NODE_ID, + "NodeId", + API_TOKEN, "Number identifying application node ("API_TOKEN_PRINT")", ConfigInfo::CI_USED, false, @@ -1374,9 +1383,21 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { 0, 0 }, { - CFG_NODE_ID, + KEY_INTERNAL, "Id", MGM_TOKEN, + "", + ConfigInfo::CI_DEPRICATED, + false, + ConfigInfo::CI_INT, + MANDATORY, + "1", + STR_VALUE(MAX_NODES) }, + + { + CFG_NODE_ID, + "NodeId", + MGM_TOKEN, "Number identifying the management server node ("MGM_TOKEN_PRINT")", ConfigInfo::CI_USED, false, @@ -1538,6 +1559,17 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { "0", "200" }, { + CFG_CONNECTION_NODE_ID_SERVER, + "NodeIdServer", + "TCP", + "", + ConfigInfo::CI_USED, + false, + ConfigInfo::CI_INT, + MANDATORY, + "1", "63" }, + + { CFG_CONNECTION_SEND_SIGNAL_ID, "SendSignalId", "TCP", @@ -1726,6 +1758,17 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { "0", "200" }, { + CFG_CONNECTION_NODE_ID_SERVER, + "NodeIdServer", + "SHM", + "", + ConfigInfo::CI_USED, + false, + ConfigInfo::CI_INT, + MANDATORY, + "1", "63" }, + + { CFG_CONNECTION_SEND_SIGNAL_ID, "SendSignalId", "SHM", @@ -1758,7 +1801,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_USED, false, ConfigInfo::CI_INT, - "0", + UNDEFINED, "0", STR_VALUE(MAX_INT_RNIL) }, @@ -1847,6 +1890,17 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { "0", "200" }, { + CFG_CONNECTION_NODE_ID_SERVER, + "NodeIdServer", + "SCI", + "", + ConfigInfo::CI_USED, + false, + ConfigInfo::CI_INT, + MANDATORY, + "1", "63" }, + + { CFG_CONNECTION_HOSTNAME_1, "HostName1", "SCI", @@ -2152,11 +2206,10 @@ static void require(bool v) { if(!v) { -#ifndef DBUG_OFF - abort(); -#else - exit(-1); -#endif + if (opt_core) + abort(); + else + exit(-1); } } @@ -2226,7 +2279,7 @@ ConfigInfo::ConfigInfo() ndbout << "Error: Parameter " << param._fname << " defined twice in section " << param._section << "." << endl; - exit(-1); + require(false); } // Add new pinfo to section @@ -2276,7 +2329,7 @@ ConfigInfo::ConfigInfo() ndbout << "Check that each entry has a section failed." << endl; ndbout << "Parameter \"" << m_ParamInfo[i]._fname << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } if(m_ParamInfo[i]._type == ConfigInfo::CI_SECTION) @@ -2289,7 +2342,7 @@ ConfigInfo::ConfigInfo() << "\" does not exist in section \"" << m_ParamInfo[i]._section << "\"." << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } } } @@ -2515,29 +2568,32 @@ void ConfigInfo::print(const Properties * section, bool transformNode(InitConfigFileParser::Context & ctx, const char * data){ - Uint32 id; - if(!ctx.m_currentSection->get("Id", &id)){ + Uint32 id, line; + if(!ctx.m_currentSection->get("NodeId", &id) && !ctx.m_currentSection->get("Id", &id)){ Uint32 nextNodeId= 1; ctx.m_userProperties.get("NextNodeId", &nextNodeId); id= nextNodeId; - while (ctx.m_userProperties.get("AllocatedNodeId_", id, &id)) + while (ctx.m_userProperties.get("AllocatedNodeId_", id, &line)) id++; - ctx.m_userProperties.put("NextNodeId", id+1, true); - ctx.m_currentSection->put("Id", id); -#if 0 - ctx.reportError("Mandatory parameter Id missing from section " - "[%s] starting at line: %d", - ctx.fname, ctx.m_sectionLineno); - return false; -#endif - } else if(ctx.m_userProperties.get("AllocatedNodeId_", id, &id)) { - ctx.reportError("Duplicate Id in section " - "[%s] starting at line: %d", - ctx.fname, ctx.m_sectionLineno); + if (id != nextNodeId) + { + fprintf(stderr,"Cluster configuration warning line %d: " + "Could not use next node id %d for section [%s], " + "using next unused node id %d.\n", + ctx.m_sectionLineno, nextNodeId, ctx.fname, id); + } + ctx.m_currentSection->put("NodeId", id); + } else if(ctx.m_userProperties.get("AllocatedNodeId_", id, &line)) { + ctx.reportError("Duplicate nodeid in section " + "[%s] starting at line: %d. Previously used on line %d.", + ctx.fname, ctx.m_sectionLineno, line); return false; } - ctx.m_userProperties.put("AllocatedNodeId_", id, id); + // next node id _always_ next numbers after last used id + ctx.m_userProperties.put("NextNodeId", id+1, true); + + ctx.m_userProperties.put("AllocatedNodeId_", id, ctx.m_sectionLineno); BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Node_%d", id); ctx.m_currentSection->put("Type", ctx.fname); @@ -2651,38 +2707,6 @@ fixBackupDataDir(InitConfigFileParser::Context & ctx, const char * data){ return false; } -bool -transformExtNode(InitConfigFileParser::Context & ctx, const char * data){ - - Uint32 id; - const char * systemName; - - if(!ctx.m_currentSection->get("Id", &id)){ - ctx.reportError("Mandatory parameter 'Id' missing from section " - "[%s] starting at line: %d", - ctx.fname, ctx.m_sectionLineno); - return false; - } - - if(!ctx.m_currentSection->get("System", &systemName)){ - ctx.reportError("Mandatory parameter 'System' missing from section " - "[%s] starting at line: %d", - ctx.fname, ctx.m_sectionLineno); - return false; - } - - ctx.m_currentSection->put("Type", ctx.fname); - - Uint32 nodes = 0; - ctx.m_userProperties.get("ExtNoOfNodes", &nodes); - require(ctx.m_userProperties.put("ExtNoOfNodes",++nodes, true)); - - BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s:Node_%d", - systemName, id); - - return true; -} - /** * Connection rule: Check support of connection */ @@ -2759,23 +2783,6 @@ transformSystem(InitConfigFileParser::Context & ctx, const char * data){ } /** - * External system rule: Just add it - */ -bool -transformExternalSystem(InitConfigFileParser::Context & ctx, const char * data){ - const char * name; - if(!ctx.m_currentSection->get("Name", &name)){ - ctx.reportError("Mandatory parameter Name missing from section " - "[%s] starting at line: %d", - ctx.fname, ctx.m_sectionLineno); - return false; - } - BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s", name); - - return true; -} - -/** * Computer rule: Update "NoOfComputers", add "Type" */ bool @@ -2951,87 +2958,6 @@ static bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data) } /** - * @returns true if connection is external (one node is external) - * Also returns: - * - name of external system in parameter extSystemName, and - * - nodeId of external node in parameter extSystemNodeId. - */ -static bool -isExtConnection(InitConfigFileParser::Context & ctx, - const char **extSystemName, Uint32 * extSystemNodeId){ - - Uint32 nodeId1, nodeId2; - - if (ctx.m_currentSection->contains("System1") && - ctx.m_currentSection->get("System1", extSystemName) && - ctx.m_currentSection->get("NodeId1", &nodeId1)) { - *extSystemNodeId = nodeId1; - return true; - } - - if (ctx.m_currentSection->contains("System2") && - ctx.m_currentSection->get("System2", extSystemName) && - ctx.m_currentSection->get("NodeId2", &nodeId2)) { - *extSystemNodeId = nodeId2; - return true; - } - - return false; -} - -/** - * External Connection Rule: - * If connection is to an external system, then move connection into - * external system configuration (i.e. a sub-property). - */ -static bool -fixExtConnection(InitConfigFileParser::Context & ctx, const char * data){ - - const char * extSystemName; - Uint32 extSystemNodeId; - - if (isExtConnection(ctx, &extSystemName, &extSystemNodeId)) { - - Uint32 connections = 0; - ctx.m_userProperties.get("ExtNoOfConnections", &connections); - require(ctx.m_userProperties.put("ExtNoOfConnections",++connections, true)); - - char tmpLine1[MAX_LINE_LENGTH]; - BaseString::snprintf(tmpLine1, MAX_LINE_LENGTH, "Connection_%d", connections-1); - - /** - * Section: EXTERNAL SYSTEM_<Ext System Name> - */ - char extSystemPropName[MAX_LINE_LENGTH]; - strncpy(extSystemPropName, "EXTERNAL SYSTEM_", MAX_LINE_LENGTH); - strncat(extSystemPropName, extSystemName, MAX_LINE_LENGTH); - strncat(extSystemPropName, ":", MAX_LINE_LENGTH); - strncat(extSystemPropName, tmpLine1, MAX_LINE_LENGTH); - - /** - * Increase number of external connections for the system - * - * @todo Limitation: Only one external system is allowed - */ - require(ctx.m_userProperties.put("ExtSystem", extSystemName, true)); - - /** - * Make sure section is stored in right place - */ - strncpy(ctx.pname, extSystemPropName, MAX_LINE_LENGTH); - - /** - * Since this is an external connection, - * decrease number of internal connections - */ - require(ctx.m_userProperties.get("NoOfConnections", &connections)); - require(ctx.m_userProperties.put("NoOfConnections", --connections, true)); - } - - return true; -} - -/** * Connection rule: Fix hostname * * Unless Hostname is not already specified, do steps: @@ -3073,7 +2999,7 @@ fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){ DBUG_ENTER("fixPortNumber"); - Uint32 id1= 0, id2= 0; + Uint32 id1, id2; const char *hostName1; const char *hostName2; require(ctx.m_currentSection->get("NodeId1", &id1)); @@ -3083,17 +3009,46 @@ fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){ DBUG_PRINT("info",("NodeId1=%d HostName1=\"%s\"",id1,hostName1)); DBUG_PRINT("info",("NodeId2=%d HostName2=\"%s\"",id2,hostName2)); - if (id1 > id2) { - Uint32 tmp= id1; - const char *tmp_name= hostName1; - hostName1= hostName2; - id1= id2; - hostName2= tmp_name; - id2= tmp; - } + const Properties *node1, *node2; + require(ctx.m_config->get("Node", id1, &node1)); + require(ctx.m_config->get("Node", id2, &node2)); - const Properties * node; - require(ctx.m_config->get("Node", id1, &node)); + const char *type1, *type2; + require(node1->get("Type", &type1)); + require(node2->get("Type", &type2)); + + /* add NodeIdServer info */ + { + Uint32 nodeIdServer = id1 < id2 ? id1 : id2; + if(strcmp(type1, API_TOKEN) == 0 || strcmp(type2, MGM_TOKEN) == 0) + nodeIdServer = id2; + else if(strcmp(type2, API_TOKEN) == 0 || strcmp(type1, MGM_TOKEN) == 0) + nodeIdServer = id1; + ctx.m_currentSection->put("NodeIdServer", nodeIdServer); + + if (id2 == nodeIdServer) { + { + const char *tmp= hostName1; + hostName1= hostName2; + hostName2= tmp; + } + { + Uint32 tmp= id1; + id1= id2; + id2= tmp; + } + { + const Properties *tmp= node1; + node1= node2; + node2= tmp; + } + { + const char *tmp= type1; + type1= type2; + type2= tmp; + } + } + } BaseString hostname(hostName1); @@ -3104,21 +3059,13 @@ fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){ } Uint32 port= 0; - const char * type1; - const char * type2; - const Properties * node2; - - node->get("Type", &type1); - ctx.m_config->get("Node", id2, &node2); - node2->get("Type", &type2); - if(strcmp(type1, MGM_TOKEN)==0) - node->get("PortNumber",&port); + node1->get("PortNumber",&port); else if(strcmp(type2, MGM_TOKEN)==0) node2->get("PortNumber",&port); if (!port && - !node->get("ServerPort", &port) && + !node1->get("ServerPort", &port) && !ctx.m_userProperties.get("ServerPort_", id1, &port)) { Uint32 base= 0; @@ -3269,11 +3216,6 @@ checkConnectionConstraints(InitConfigFileParser::Context & ctx, const char *){ ctx.m_currentSection->get("NodeId1", &id1); ctx.m_currentSection->get("NodeId2", &id2); - // If external connection, just accept it - if (ctx.m_currentSection->contains("System1") || - ctx.m_currentSection->contains("System2")) - return true; - if(id1 == id2){ ctx.reportError("Illegal connection from node to itself" " - [%s] starting at line: %d", @@ -3306,12 +3248,10 @@ checkConnectionConstraints(InitConfigFileParser::Context & ctx, const char *){ * Report error if the following are true * -# None of the nodes is of type DB * -# Not both of them are MGMs - * -# None of them contain a "SystemX" name */ if((strcmp(type1, DB_TOKEN) != 0 && strcmp(type2, DB_TOKEN) != 0) && - !(strcmp(type1, MGM_TOKEN) == 0 && strcmp(type2, MGM_TOKEN) == 0) && - !ctx.m_currentSection->contains("System1") && - !ctx.m_currentSection->contains("System2")){ + !(strcmp(type1, MGM_TOKEN) == 0 && strcmp(type2, MGM_TOKEN) == 0)) + { ctx.reportError("Invalid connection between node %d (%s) and node %d (%s)" " - [%s] starting at line: %d", id1, type1, id2, type2, @@ -3356,6 +3296,7 @@ transform(InitConfigFileParser::Context & ctx, PropertiesType oldType; require(ctx.m_currentSection->getTypeOf(oldName, &oldType)); ConfigInfo::Type newType = ctx.m_info->getType(ctx.m_currentInfo, newName); + if(!((oldType == PropertiesType_Uint32 || oldType == PropertiesType_Uint64) && (newType == ConfigInfo::CI_INT || newType == ConfigInfo::CI_INT64 || newType == ConfigInfo::CI_BOOL))){ ndbout << "oldType: " << (int)oldType << ", newType: " << (int)newType << endl; @@ -3400,11 +3341,11 @@ fixDepricated(InitConfigFileParser::Context & ctx, const char * data){ if(strcmp(p->m_section, ctx.fname) == 0){ double mul = p->m_mul; double add = p->m_add; - if(strcmp(name, p->m_oldName) == 0){ + if(strcasecmp(name, p->m_oldName) == 0){ if(!transform(ctx, tmp, name, p->m_newName, add, mul)){ return false; } - } else if(strcmp(name, p->m_newName) == 0) { + } else if(strcasecmp(name, p->m_newName) == 0) { if(!transform(ctx, tmp, name, p->m_oldName, -add/mul,1.0/mul)){ return false; } @@ -3683,45 +3624,6 @@ static bool set_connection_priorities(Vector<ConfigInfo::ConfigRuleSection>§ DBUG_RETURN(true); } -static bool add_server_ports(Vector<ConfigInfo::ConfigRuleSection>§ions, - struct InitConfigFileParser::Context &ctx, - const char * rule_data) -{ -#if 0 - Properties * props= ctx.m_config; - Properties computers(true); - Uint32 port_base = NDB_TCP_BASE_PORT; - - Uint32 nNodes; - ctx.m_userProperties.get("NoOfNodes", &nNodes); - - for (Uint32 i= 0, n= 0; n < nNodes; i++){ - Properties * tmp; - if(!props->get("Node", i, &tmp)) continue; - n++; - - const char * type; - if(!tmp->get("Type", &type)) continue; - - Uint32 port; - if (tmp->get("ServerPort", &port)) continue; - - Uint32 computer; - if (!tmp->get("ExecuteOnComputer", &computer)) continue; - - Uint32 adder= 0; - computers.get("",computer, &adder); - - if (strcmp(type,DB_TOKEN) == 0) { - adder++; - tmp->put("ServerPort", port_base+adder); - computers.put("",computer, adder); - } - } -#endif - return true; -} - static bool check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection>§ions, struct InitConfigFileParser::Context &ctx, diff --git a/ndb/src/mgmsrv/InitConfigFileParser.cpp b/ndb/src/mgmsrv/InitConfigFileParser.cpp index 822e10c89aa..f937daf8620 100644 --- a/ndb/src/mgmsrv/InitConfigFileParser.cpp +++ b/ndb/src/mgmsrv/InitConfigFileParser.cpp @@ -31,8 +31,10 @@ static void require(bool v) { if(!v) abort();} //**************************************************************************** // Ctor / Dtor //**************************************************************************** -InitConfigFileParser::InitConfigFileParser(){ +InitConfigFileParser::InitConfigFileParser(FILE * out) +{ m_info = new ConfigInfo(); + m_errstream = out ? out : stdout; } InitConfigFileParser::~InitConfigFileParser() { @@ -42,11 +44,12 @@ InitConfigFileParser::~InitConfigFileParser() { //**************************************************************************** // Read Config File //**************************************************************************** -InitConfigFileParser::Context::Context(const ConfigInfo * info) +InitConfigFileParser::Context::Context(const ConfigInfo * info, FILE * out) : m_userProperties(true), m_configValues(1000, 20) { m_config = new Properties(true); m_defaults = new Properties(true); + m_errstream = out; } InitConfigFileParser::Context::~Context(){ @@ -61,10 +64,10 @@ Config * InitConfigFileParser::parseConfig(const char * filename) { FILE * file = fopen(filename, "r"); if(file == 0){ - ndbout << "Error opening file: " << filename << endl; + fprintf(m_errstream, "Error opening file: %s\n", filename); return 0; } - + Config * ret = parseConfig(file); fclose(file); return ret; @@ -75,7 +78,7 @@ InitConfigFileParser::parseConfig(FILE * file) { char line[MAX_LINE_LENGTH]; - Context ctx(m_info); + Context ctx(m_info, m_errstream); ctx.m_lineno = 0; ctx.m_currentSection = 0; @@ -160,6 +163,13 @@ InitConfigFileParser::parseConfig(FILE * file) { ctx.reportError("Could not store section of configuration file."); return 0; } + + return run_config_rules(ctx); +} + +Config* +InitConfigFileParser::run_config_rules(Context& ctx) +{ for(size_t i = 0; ConfigInfo::m_ConfigRules[i].m_configRule != 0; i++){ ctx.type = InitConfigFileParser::Undefined; ctx.m_currentSection = 0; @@ -267,10 +277,10 @@ bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) } if (status == ConfigInfo::CI_DEPRICATED) { const char * desc = m_info->getDescription(ctx.m_currentInfo, fname); - if(desc){ + if(desc && desc[0]){ ctx.reportWarning("[%s] %s is depricated, use %s instead", ctx.fname, fname, desc); - } else { + } else if (desc == 0){ ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname); } } @@ -555,8 +565,12 @@ InitConfigFileParser::storeSection(Context& ctx){ } } } - if(ctx.type == InitConfigFileParser::DefaultSection) - require(ctx.m_defaults->put(ctx.pname, ctx.m_currentSection)); + if(ctx.type == InitConfigFileParser::DefaultSection && + !ctx.m_defaults->put(ctx.pname, ctx.m_currentSection)) + { + ctx.reportError("Duplicate default section not allowed"); + return false; + } if(ctx.type == InitConfigFileParser::Section) require(ctx.m_config->put(ctx.pname, ctx.m_currentSection)); delete ctx.m_currentSection; ctx.m_currentSection = NULL; @@ -571,8 +585,9 @@ InitConfigFileParser::Context::reportError(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); - ndbout << "Error line " << m_lineno << ": " << buf << endl; va_end(ap); + fprintf(m_errstream, "Error line %d: %s\n", + m_lineno, buf); //m_currentSection->print(); } @@ -585,6 +600,357 @@ InitConfigFileParser::Context::reportWarning(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); - ndbout << "Warning line " << m_lineno << ": " << buf << endl; va_end(ap); + fprintf(m_errstream, "Warning line %d: %s\n", + m_lineno, buf); } + +#include <my_sys.h> +#include <my_getopt.h> + +static int order = 1; +static +my_bool +parse_mycnf_opt(int, const struct my_option * opt, char * value) +{ + if(opt->comment) + ((struct my_option *)opt)->app_type++; + else + ((struct my_option *)opt)->app_type = order++; + return 0; +} + +bool +InitConfigFileParser::store_in_properties(Vector<struct my_option>& options, + InitConfigFileParser::Context& ctx, + const char * name) +{ + for(unsigned i = 0; i<options.size(); i++) + { + if(options[i].comment && + options[i].app_type && + strcmp(options[i].comment, name) == 0) + { + Uint64 value_int; + switch(options[i].var_type){ + case GET_INT: + value_int = *(Uint32*)options[i].value; + break; + case GET_LL: + value_int = *(Uint64*)options[i].value; + break; + case GET_STR: + ctx.m_currentSection->put(options[i].name, *(char**)options[i].value); + continue; + default: + abort(); + } + + const char * fname = options[i].name; + if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) { + ctx.reportError("Illegal value %lld for parameter %s.\n" + "Legal values are between %Lu and %Lu", + value_int, fname, + m_info->getMin(ctx.m_currentInfo, fname), + m_info->getMax(ctx.m_currentInfo, fname)); + return false; + } + if (options[i].var_type == GET_INT) + ctx.m_currentSection->put(options[i].name, (Uint32)value_int); + else + ctx.m_currentSection->put(options[i].name, value_int); + } + } + return true; +} + +bool +InitConfigFileParser::handle_mycnf_defaults(Vector<struct my_option>& options, + InitConfigFileParser::Context& ctx, + const char * name) +{ + strcpy(ctx.fname, name); + ctx.type = InitConfigFileParser::DefaultSection; + ctx.m_currentSection = new Properties(true); + ctx.m_userDefaults = NULL; + require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0); + require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0); + if(store_in_properties(options, ctx, name)) + return storeSection(ctx); + return false; +} + +static +int +load_defaults(Vector<struct my_option>& options, const char* groups[]) +{ + int argc = 1; + const char * argv[] = { "ndb_mgmd", 0, 0, 0, 0 }; + BaseString file; + BaseString extra_file; + BaseString group_suffix; + + const char *save_file = defaults_file; + char *save_extra_file = defaults_extra_file; + const char *save_group_suffix = defaults_group_suffix; + + if (defaults_file) + { + file.assfmt("--defaults-file=%s", defaults_file); + argv[argc++] = file.c_str(); + } + + if (defaults_extra_file) + { + extra_file.assfmt("--defaults-extra-file=%s", defaults_extra_file); + argv[argc++] = extra_file.c_str(); + } + + if (defaults_group_suffix) + { + group_suffix.assfmt("--defaults-group-suffix=%s", defaults_group_suffix); + argv[argc++] = group_suffix.c_str(); + } + + char ** tmp = (char**)argv; + int ret = load_defaults("my", groups, &argc, &tmp); + + defaults_file = save_file; + defaults_extra_file = save_extra_file; + defaults_group_suffix = save_group_suffix; + + if (ret == 0) + { + return handle_options(&argc, &tmp, options.getBase(), parse_mycnf_opt); + } + + return ret; +} + +bool +InitConfigFileParser::load_mycnf_groups(Vector<struct my_option> & options, + InitConfigFileParser::Context& ctx, + const char * name, + const char *groups[]) +{ + unsigned i; + Vector<struct my_option> copy; + for(i = 0; i<options.size(); i++) + { + if(options[i].comment && strcmp(options[i].comment, name) == 0) + { + options[i].app_type = 0; + copy.push_back(options[i]); + } + } + + struct my_option end; + bzero(&end, sizeof(end)); + copy.push_back(end); + + if (load_defaults(copy, groups)) + return false; + + return store_in_properties(copy, ctx, name); +} + +Config * +InitConfigFileParser::parse_mycnf() +{ + int i; + Config * res = 0; + Vector<struct my_option> options; + for(i = 0; i<ConfigInfo::m_NoOfParams; i++) + { + { + struct my_option opt; + bzero(&opt, sizeof(opt)); + const ConfigInfo::ParamInfo& param = ConfigInfo::m_ParamInfo[i]; + switch(param._type){ + case ConfigInfo::CI_BOOL: + opt.value = (gptr*)malloc(sizeof(int)); + opt.var_type = GET_INT; + break; + case ConfigInfo::CI_INT: + opt.value = (gptr*)malloc(sizeof(int)); + opt.var_type = GET_INT; + break; + case ConfigInfo::CI_INT64: + opt.value = (gptr*)malloc(sizeof(Int64)); + opt.var_type = GET_LL; + break; + case ConfigInfo::CI_STRING: + opt.value = (gptr*)malloc(sizeof(char *)); + opt.var_type = GET_STR; + break; + default: + continue; + } + opt.name = param._fname; + opt.id = 256; + opt.app_type = 0; + opt.arg_type = REQUIRED_ARG; + opt.comment = param._section; + options.push_back(opt); + } + } + + struct my_option *ndbd, *ndb_mgmd, *mysqld, *api; + + /** + * Add ndbd, ndb_mgmd, api/mysqld + */ + { + struct my_option opt; + bzero(&opt, sizeof(opt)); + opt.name = "ndbd"; + opt.id = 256; + opt.value = (gptr*)malloc(sizeof(char*)); + opt.var_type = GET_STR; + opt.arg_type = REQUIRED_ARG; + options.push_back(opt); + ndbd = &options.back(); + + opt.name = "ndb_mgmd"; + opt.id = 256; + opt.value = (gptr*)malloc(sizeof(char*)); + opt.var_type = GET_STR; + opt.arg_type = REQUIRED_ARG; + options.push_back(opt); + ndb_mgmd = &options.back(); + + opt.name = "mysqld"; + opt.id = 256; + opt.value = (gptr*)malloc(sizeof(char*)); + opt.var_type = GET_STR; + opt.arg_type = REQUIRED_ARG; + options.push_back(opt); + mysqld = &options.back(); + + opt.name = "api"; + opt.id = 256; + opt.value = (gptr*)malloc(sizeof(char*)); + opt.var_type = GET_STR; + opt.arg_type = REQUIRED_ARG; + options.push_back(opt); + api = &options.back(); + + bzero(&opt, sizeof(opt)); + options.push_back(opt); + } + + + Context ctx(m_info, m_errstream); + const char *groups[]= { "cluster_config", 0 }; + if (load_defaults(options, groups)) + goto end; + + ctx.m_lineno = 0; + if(!handle_mycnf_defaults(options, ctx, "DB")) + goto end; + if(!handle_mycnf_defaults(options, ctx, "API")) + goto end; + if(!handle_mycnf_defaults(options, ctx, "MGM")) + goto end; + if(!handle_mycnf_defaults(options, ctx, "TCP")) + goto end; + if(!handle_mycnf_defaults(options, ctx, "SHM")) + goto end; + if(!handle_mycnf_defaults(options, ctx, "SCI")) + goto end; + + { + struct sect { struct my_option* src; const char * name; } sections[] = + { + { ndb_mgmd, "MGM" } + ,{ ndbd, "DB" } + ,{ mysqld, "API" } + ,{ api, "API" } + ,{ 0, 0 }, { 0, 0 } + }; + + for(i = 0; sections[i].src; i++) + { + for(int j = i + 1; sections[j].src; j++) + { + if (sections[j].src->app_type < sections[i].src->app_type) + { + sect swap = sections[i]; + sections[i] = sections[j]; + sections[j] = swap; + } + } + } + + ctx.type = InitConfigFileParser::Section; + ctx.m_sectionLineno = ctx.m_lineno; + for(i = 0; sections[i].src; i++) + { + if (sections[i].src->app_type) + { + strcpy(ctx.fname, sections[i].name); + BaseString str(*(char**)sections[i].src->value); + Vector<BaseString> list; + str.split(list, ","); + + const char * defaults_groups[] = { 0, 0, 0 }; + for(unsigned j = 0; j<list.size(); j++) + { + BaseString group_idx; + BaseString group_host; + group_idx.assfmt("%s.%s.%d", groups[0], + sections[i].src->name, j + 1); + group_host.assfmt("%s.%s.%s", groups[0], + sections[i].src->name, list[j].c_str()); + defaults_groups[0] = group_idx.c_str(); + if(list[j].length()) + defaults_groups[1] = group_host.c_str(); + else + defaults_groups[1] = 0; + + ctx.m_currentSection = new Properties(true); + ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults); + require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0); + require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname))!= 0); + ctx.m_currentSection->put("HostName", list[j].c_str()); + if(!load_mycnf_groups(options, ctx, sections[i].name, + defaults_groups)) + goto end; + + if(!storeSection(ctx)) + goto end; + } + } + } + } + + res = run_config_rules(ctx); + +end: + for(i = 0; options[i].name; i++) + free(options[i].value); + + return res; +} + +template class Vector<struct my_option>; + +#if 0 +struct my_option +{ + const char *name; /* Name of the option */ + int id; /* unique id or short option */ + const char *comment; /* option comment, for autom. --help */ + gptr *value; /* The variable value */ + gptr *u_max_value; /* The user def. max variable value */ + const char **str_values; /* Pointer to possible values */ + ulong var_type; + enum get_opt_arg_type arg_type; + longlong def_value; /* Default value */ + longlong min_value; /* Min allowed value */ + longlong max_value; /* Max allowed value */ + longlong sub_size; /* Subtract this from given value */ + long block_size; /* Value should be a mult. of this */ + int app_type; /* To be used by an application */ +}; +#endif diff --git a/ndb/src/mgmsrv/InitConfigFileParser.hpp b/ndb/src/mgmsrv/InitConfigFileParser.hpp index 1ea0a094ccd..616fd5a62fb 100644 --- a/ndb/src/mgmsrv/InitConfigFileParser.hpp +++ b/ndb/src/mgmsrv/InitConfigFileParser.hpp @@ -34,11 +34,12 @@ class ConfigInfo; * object if the config file has correct syntax and semantic. */ class InitConfigFileParser { + FILE * m_errstream; public: /** * Constructor */ - InitConfigFileParser(); + InitConfigFileParser(FILE * errstream = stdout); ~InitConfigFileParser(); /** @@ -50,6 +51,7 @@ public: */ Config * parseConfig(FILE * file); Config * parseConfig(const char * filename); + Config * parse_mycnf(); /** * Parser context struct @@ -60,7 +62,7 @@ public: * Context = Which section in init config file we are currently parsing */ struct Context { - Context(const ConfigInfo *); + Context(const ConfigInfo *, FILE * out); ~Context(); ContextSectionType type; ///< Section type (e.g. default section,section) @@ -82,6 +84,7 @@ public: ConfigValuesFactory m_configValues; // public: + FILE * m_errstream; void reportError(const char * msg, ...); void reportWarning(const char * msg, ...); }; @@ -122,6 +125,21 @@ private: * Information about parameters (min, max values etc) */ ConfigInfo* m_info; + + bool handle_mycnf_defaults(Vector<struct my_option>& options, + InitConfigFileParser::Context& ctx, + const char * name); + + bool load_mycnf_groups(Vector<struct my_option> & options, + InitConfigFileParser::Context& ctx, + const char * name, + const char *groups[]); + + bool store_in_properties(Vector<struct my_option>& options, + InitConfigFileParser::Context& ctx, + const char * name); + + Config* run_config_rules(Context& ctx); }; #endif // InitConfigFileParser_H diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 14d4f768c86..34a0adf46b9 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -39,6 +39,8 @@ #include <signaldata/BackupSignalData.hpp> #include <signaldata/GrepImpl.hpp> #include <signaldata/ManagementServer.hpp> +#include <signaldata/NFCompleteRep.hpp> +#include <signaldata/NodeFailRep.hpp> #include <NdbSleep.h> #include <EventLogger.hpp> #include <DebuggerNames.hpp> @@ -56,6 +58,8 @@ #include <mgmapi_config_parameters.h> #include <m_string.h> +#include <SignalSender.hpp> + //#define MGM_SRV_DEBUG #ifdef MGM_SRV_DEBUG #define DEBUG(x) do ndbout << x << endl; while(0) @@ -63,66 +67,39 @@ #define DEBUG(x) #endif +#define INIT_SIGNAL_SENDER(ss,nodeId) \ + SignalSender ss(theFacade); \ + ss.lock(); /* lock will be released on exit */ \ + {\ + int result = okToSendTo(nodeId, true);\ + if (result != 0) {\ + return result;\ + }\ + } + extern int global_flag_send_heartbeat_now; extern int g_no_nodeid_checks; +extern my_bool opt_core; -void * -MgmtSrvr::logLevelThread_C(void* m) +static void require(bool v) { - MgmtSrvr *mgm = (MgmtSrvr*)m; - mgm->logLevelThreadRun(); - return 0; + if(!v) + { + if (opt_core) + abort(); + else + exit(-1); + } } void * -MgmtSrvr::signalRecvThread_C(void *m) +MgmtSrvr::logLevelThread_C(void* m) { MgmtSrvr *mgm = (MgmtSrvr*)m; - mgm->signalRecvThreadRun(); + mgm->logLevelThreadRun(); return 0; } -class SigMatch -{ -public: - int gsn; - void (MgmtSrvr::* function)(NdbApiSignal *signal); - - SigMatch() { gsn = 0; function = NULL; }; - - SigMatch(int _gsn, - void (MgmtSrvr::* _function)(NdbApiSignal *signal)) { - gsn = _gsn; - function = _function; - }; - - bool check(NdbApiSignal *signal) { - if(signal->readSignalNumber() == gsn) - return true; - return false; - }; - -}; - -void -MgmtSrvr::signalRecvThreadRun() -{ - Vector<SigMatch> siglist; - siglist.push_back(SigMatch(GSN_MGM_LOCK_CONFIG_REQ, - &MgmtSrvr::handle_MGM_LOCK_CONFIG_REQ)); - siglist.push_back(SigMatch(GSN_MGM_UNLOCK_CONFIG_REQ, - &MgmtSrvr::handle_MGM_UNLOCK_CONFIG_REQ)); - - while(!_isStopThread) { - SigMatch *handler = NULL; - NdbApiSignal *signal = NULL; - if(m_signalRecvQueue.waitFor(siglist, &handler, &signal, DEFAULT_TIMEOUT)) { - if(handler->function != 0) - (this->*handler->function)(signal); - } - } -} - extern EventLogger g_eventLogger; static NdbOut& @@ -300,15 +277,13 @@ static ErrorItem errorTable[] = {MgmtSrvr::NOT_POSSIBLE_TO_SEND_CONFIG_UPDATE_TO_PROCESS_TYPE, "It is not possible to send an update of a configuration variable " "to this kind of process."}, - {5026, "Node shutdown in progress" }, - {5027, "System shutdown in progress" }, - {5028, "Node shutdown would cause system crash" }, - {5029, "Only one shutdown at a time is possible via mgm server" }, - {5060, "Operation not allowed in single user mode." }, - {5061, "DB is not in single user mode." }, - {5062, "The specified node is not an API node." }, - {5063, - "Cannot enter single user mode. DB nodes in inconsistent startlevel."}, + {MgmtSrvr::NODE_SHUTDOWN_IN_PROGESS, "Node shutdown in progress" }, + {MgmtSrvr::SYSTEM_SHUTDOWN_IN_PROGRESS, "System shutdown in progress" }, + {MgmtSrvr::NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH, + "Node shutdown would cause system crash" }, + {MgmtSrvr::NODE_NOT_API_NODE, "The specified node is not an API node." }, + {MgmtSrvr::OPERATION_NOT_ALLOWED_START_STOP, + "Operation not allowed while nodes are starting or stopping."}, {MgmtSrvr::NO_CONTACT_WITH_DB_NODES, "No contact with database nodes" } }; @@ -316,13 +291,13 @@ int MgmtSrvr::translateStopRef(Uint32 errCode) { switch(errCode){ case StopRef::NodeShutdownInProgress: - return 5026; + return NODE_SHUTDOWN_IN_PROGESS; break; case StopRef::SystemShutdownInProgress: - return 5027; + return SYSTEM_SHUTDOWN_IN_PROGRESS; break; case StopRef::NodeShutdownWouldCauseSystemCrash: - return 5028; + return NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH; break; } return 4999; @@ -410,15 +385,12 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _isStopThread = false; _logLevelThread = NULL; _logLevelThreadSleep = 500; - m_signalRecvThread = NULL; theFacade = 0; m_newConfig = NULL; if (config_filename) m_configFilename.assign(config_filename); - else - m_configFilename.assign("config.ini"); m_nextConfigGenerationNumber = 0; @@ -435,14 +407,14 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if (tmp_nodeid == 0) { ndbout_c(m_config_retriever->getErrorString()); - exit(-1); + require(false); } // read config from other managent server _config= fetchConfig(); if (_config == 0) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } _ownNodeId= tmp_nodeid; } @@ -509,7 +481,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if ((m_node_id_mutex = NdbMutex_Create()) == 0) { ndbout << "mutex creation failed line = " << __LINE__ << endl; - exit(-1); + require(false); } if (_ownNodeId == 0) // we did not get node id from other server @@ -520,7 +492,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, 0, 0, error_string)){ ndbout << "Unable to obtain requested nodeid: " << error_string.c_str() << endl; - exit(-1); + require(false); } _ownNodeId = tmp; } @@ -531,7 +503,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _ownNodeId)) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } } @@ -638,12 +610,6 @@ MgmtSrvr::start(BaseString &error_string) "MgmtSrvr_Loglevel", NDB_THREAD_PRIO_LOW); - m_signalRecvThread = NdbThread_Create(signalRecvThread_C, - (void **)this, - 32768, - "MgmtSrvr_Service", - NDB_THREAD_PRIO_LOW); - DBUG_RETURN(true); } @@ -652,10 +618,6 @@ MgmtSrvr::start(BaseString &error_string) //**************************************************************************** MgmtSrvr::~MgmtSrvr() { - while (theSignalIdleList != NULL) { - freeSignal(); - } - if(theFacade != 0){ theFacade->stop_instance(); delete theFacade; @@ -683,10 +645,6 @@ MgmtSrvr::~MgmtSrvr() NdbThread_Destroy(&_logLevelThread); } - if (m_signalRecvThread != NULL) { - NdbThread_WaitFor(m_signalRecvThread, &res); - NdbThread_Destroy(&m_signalRecvThread); - } if (m_config_retriever) delete m_config_retriever; } @@ -694,267 +652,501 @@ MgmtSrvr::~MgmtSrvr() //**************************************************************************** //**************************************************************************** -int MgmtSrvr::okToSendTo(NodeId processId, bool unCond) +int MgmtSrvr::okToSendTo(NodeId nodeId, bool unCond) { - if(processId == 0) + if(nodeId == 0) return 0; - if (getNodeType(processId) != NDB_MGM_NODE_TYPE_NDB) + if (getNodeType(nodeId) != NDB_MGM_NODE_TYPE_NDB) return WRONG_PROCESS_TYPE; // Check if we have contact with it if(unCond){ - if(theFacade->theClusterMgr->getNodeInfo(processId).connected) + if(theFacade->theClusterMgr->getNodeInfo(nodeId).connected) return 0; return NO_CONTACT_WITH_PROCESS; } - if (theFacade->get_node_alive(processId) == 0) { + if (theFacade->get_node_alive(nodeId) == 0) { return NO_CONTACT_WITH_PROCESS; } else { return 0; } } +void report_unknown_signal(SimpleSignal *signal) +{ + g_eventLogger.error("Unknown signal received. SignalNumber: " + "%i from (%d, %x)", + signal->readSignalNumber(), + refToNode(signal->header.theSendersBlockRef), + refToBlock(signal->header.theSendersBlockRef)); +} + /***************************************************************************** * Starting and stopping database nodes ****************************************************************************/ int -MgmtSrvr::start(int processId) +MgmtSrvr::start(int nodeId) { - int result; - - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - StartOrd* const startOrd = CAST_PTR(StartOrd, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, CMVMI, GSN_START_ORD, StartOrd::SignalLength); + INIT_SIGNAL_SENDER(ss,nodeId); + SimpleSignal ssig; + StartOrd* const startOrd = CAST_PTR(StartOrd, ssig.getDataPtrSend()); + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_START_ORD, StartOrd::SignalLength); startOrd->restartInfo = 0; - result = sendSignal(processId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; +} + +/***************************************************************************** + * Version handling + *****************************************************************************/ + +int +MgmtSrvr::versionNode(int nodeId, Uint32 &version, const char **address) +{ + version= 0; + if (getOwnNodeId() == nodeId) + { + /** + * If we're inquiring about our own node id, + * We know what version we are (version implies connected for mgm) + * but would like to find out from elsewhere what address they're using + * to connect to us. This means that secondary mgm servers + * can list ip addresses for mgm servers. + * + * If we don't get an address (i.e. no db nodes), + * we get the address from the configuration. + */ + sendVersionReq(nodeId, version, address); + version= NDB_VERSION; + if(!*address) + { + ndb_mgm_configuration_iterator + iter(*_config->m_configValues, CFG_SECTION_NODE); + unsigned tmp= 0; + for(iter.first();iter.valid();iter.next()) + { + if(iter.get(CFG_NODE_ID, &tmp)) require(false); + if((unsigned)nodeId!=tmp) + continue; + if(iter.get(CFG_NODE_HOST, address)) require(false); + break; + } + } } - + else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB) + { + ClusterMgr::Node node= theFacade->theClusterMgr->getNodeInfo(nodeId); + if(node.connected) + version= node.m_info.m_version; + *address= get_connect_address(nodeId); + } + else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API || + getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM) + { + return sendVersionReq(nodeId, version, address); + } + return 0; } -/** - * Restart one database node +int +MgmtSrvr::sendVersionReq(int v_nodeId, Uint32 &version, const char **address) +{ + SignalSender ss(theFacade); + ss.lock(); + + SimpleSignal ssig; + ApiVersionReq* req = CAST_PTR(ApiVersionReq, ssig.getDataPtrSend()); + req->senderRef = ss.getOwnRef(); + req->nodeId = v_nodeId; + ssig.set(ss, TestOrd::TraceAPI, QMGR, GSN_API_VERSION_REQ, + ApiVersionReq::SignalLength); + + int do_send = 1; + NodeId nodeId; + + while (1) + { + if (do_send) + { + bool next; + nodeId = 0; + + while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true && + okToSendTo(nodeId, true) != 0); + + const ClusterMgr::Node &node= + theFacade->theClusterMgr->getNodeInfo(nodeId); + if(next && node.m_state.startLevel != NodeState::SL_STARTED) + { + NodeId tmp=nodeId; + while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true && + okToSendTo(nodeId, true) != 0); + if(!next) + nodeId= tmp; + } + + if(!next) return NO_CONTACT_WITH_DB_NODES; + + if (ss.sendSignal(nodeId, &ssig) != SEND_OK) { + return SEND_OR_RECEIVE_FAILED; + } + do_send = 0; + } + + SimpleSignal *signal = ss.waitFor(); + + int gsn = signal->readSignalNumber(); + switch (gsn) { + case GSN_API_VERSION_CONF: { + const ApiVersionConf * const conf = + CAST_CONSTPTR(ApiVersionConf, signal->getDataPtr()); + assert(conf->nodeId == v_nodeId); + version = conf->version; + struct in_addr in; + in.s_addr= conf->inet_addr; + *address= inet_ntoa(in); + return 0; + } + case GSN_NF_COMPLETEREP:{ + const NFCompleteRep * const rep = + CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr()); + if (rep->failedNodeId == nodeId) + do_send = 1; // retry with other node + continue; + } + case GSN_NODE_FAILREP:{ + const NodeFailRep * const rep = + CAST_CONSTPTR(NodeFailRep, signal->getDataPtr()); + if (NodeBitmask::get(rep->theNodes,nodeId)) + do_send = 1; // retry with other node + continue; + } + default: + report_unknown_signal(signal); + return SEND_OR_RECEIVE_FAILED; + } + break; + } // while(1) + + return 0; +} + +/* + * Common method for handeling all STOP_REQ signalling that + * is used by Stopping, Restarting and Single user commands */ -int -MgmtSrvr::restartNode(int processId, bool nostart, - bool initalStart, bool abort, - StopCallback callback, void * anyData) + +int MgmtSrvr::sendSTOP_REQ(NodeId nodeId, + NodeBitmask &stoppedNodes, + Uint32 singleUserNodeId, + bool abort, + bool stop, + bool restart, + bool nostart, + bool initialStart) { - int result; + stoppedNodes.clear(); - if(m_stopRec.singleUserMode) - return 5060; + SignalSender ss(theFacade); + ss.lock(); // lock will be released on exit - if(m_stopRec.inUse){ - return 5029; - } - - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + SimpleSignal ssig; + StopReq* const stopReq = CAST_PTR(StopReq, ssig.getDataPtrSend()); + ssig.set(ss, TestOrd::TraceAPI, NDBCNTR, GSN_STOP_REQ, StopReq::SignalLength); - StopReq* const stopReq = CAST_PTR(StopReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, NDBCNTR, GSN_STOP_REQ, StopReq::SignalLength); - stopReq->requestInfo = 0; - StopReq::setSystemStop(stopReq->requestInfo, false); - StopReq::setPerformRestart(stopReq->requestInfo, true); - StopReq::setNoStart(stopReq->requestInfo, nostart); - StopReq::setInitialStart(stopReq->requestInfo, initalStart); - StopReq::setStopAbort(stopReq->requestInfo, abort); - stopReq->singleuser = 0; stopReq->apiTimeout = 5000; stopReq->transactionTimeout = 1000; stopReq->readOperationTimeout = 1000; stopReq->operationTimeout = 1000; stopReq->senderData = 12; - stopReq->senderRef = _ownReference; - - m_stopRec.singleUserMode = false; - m_stopRec.sentCount = 1; - m_stopRec.reply = 0; - m_stopRec.nodeId = processId; - m_stopRec.anyData = anyData; - m_stopRec.callback = callback; - m_stopRec.inUse = true; - - if(callback == NULL){ - Uint32 timeOut = 0; - timeOut += stopReq->apiTimeout; - timeOut += stopReq->transactionTimeout; - timeOut += stopReq->readOperationTimeout; - timeOut += stopReq->operationTimeout; - timeOut *= 3; - result = sendRecSignal(processId, WAIT_STOP, signal, true, timeOut); - } else { - result = sendSignal(processId, NO_WAIT, signal, true); + stopReq->senderRef = ss.getOwnRef(); + if (singleUserNodeId) + { + stopReq->singleuser = 1; + stopReq->singleUserApi = singleUserNodeId; + StopReq::setSystemStop(stopReq->requestInfo, false); + StopReq::setPerformRestart(stopReq->requestInfo, false); + StopReq::setStopAbort(stopReq->requestInfo, false); } - - if (result == -1 && theWaitState != WAIT_NODEFAILURE) { - m_stopRec.inUse = false; - return SEND_OR_RECEIVE_FAILED; + else + { + stopReq->singleuser = 0; + StopReq::setSystemStop(stopReq->requestInfo, stop); + StopReq::setPerformRestart(stopReq->requestInfo, restart); + StopReq::setStopAbort(stopReq->requestInfo, abort); + StopReq::setNoStart(stopReq->requestInfo, nostart); + StopReq::setInitialStart(stopReq->requestInfo, initialStart); } - if(callback == 0){ - m_stopRec.inUse = false; - return m_stopRec.reply; - } else { - return 0; + // send the signals + NodeBitmask nodes; + if (nodeId) + { + { + int r; + if((r = okToSendTo(nodeId, true)) != 0) + return r; + } + { + if (ss.sendSignal(nodeId, &ssig) != SEND_OK) + return SEND_OR_RECEIVE_FAILED; + } + nodes.set(nodeId); } + else + while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) + { + if(okToSendTo(nodeId, true) == 0) + { + SendStatus result = ss.sendSignal(nodeId, &ssig); + if (result == SEND_OK) + nodes.set(nodeId); + } + } + + // now wait for the replies + int error = 0; + while (!nodes.isclear()) + { + SimpleSignal *signal = ss.waitFor(); + int gsn = signal->readSignalNumber(); + switch (gsn) { + case GSN_STOP_REF:{ + const StopRef * const ref = CAST_CONSTPTR(StopRef, signal->getDataPtr()); + const NodeId nodeId = refToNode(signal->header.theSendersBlockRef); +#ifdef VM_TRACE + ndbout_c("Node %d refused stop", nodeId); +#endif + assert(nodes.get(nodeId)); + nodes.clear(nodeId); + error = translateStopRef(ref->errorCode); + break; + } + case GSN_STOP_CONF:{ + const StopConf * const ref = CAST_CONSTPTR(StopConf, signal->getDataPtr()); + const NodeId nodeId = refToNode(signal->header.theSendersBlockRef); +#ifdef VM_TRACE + ndbout_c("Node %d single user mode", nodeId); +#endif + assert(nodes.get(nodeId)); + assert(singleUserNodeId != 0); + nodes.clear(nodeId); + stoppedNodes.set(nodeId); + break; + } + case GSN_NF_COMPLETEREP:{ + const NFCompleteRep * const rep = + CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Node %d fail completed", rep->failedNodeId); +#endif + break; + } + case GSN_NODE_FAILREP:{ + const NodeFailRep * const rep = + CAST_CONSTPTR(NodeFailRep, signal->getDataPtr()); + NodeBitmask failedNodes; + failedNodes.assign(NodeBitmask::Size, rep->theNodes); +#ifdef VM_TRACE + { + ndbout << "Failed nodes:"; + for (unsigned i = 0; i < 32*NodeBitmask::Size; i++) + if(failedNodes.get(i)) + ndbout << " " << i; + ndbout << endl; + } +#endif + failedNodes.bitAND(nodes); + if (!failedNodes.isclear()) + { + nodes.bitANDC(failedNodes); // clear the failed nodes + if (singleUserNodeId == 0) + stoppedNodes.bitOR(failedNodes); + } + break; + } + default: + report_unknown_signal(signal); +#ifdef VM_TRACE + ndbout_c("Unknown signal %d", gsn); +#endif + return SEND_OR_RECEIVE_FAILED; + } + } + return error; } -/** - * Restart all database nodes +/* + * Stop one node */ -int -MgmtSrvr::restart(bool nostart, bool initalStart, bool abort, - int * stopCount, StopCallback callback, void * anyData) -{ - if(m_stopRec.singleUserMode) - return 5060; - if(m_stopRec.inUse){ - return 5029; +int MgmtSrvr::stopNode(int nodeId, bool abort) +{ + if (!abort) + { + NodeId nodeId = 0; + ClusterMgr::Node node; + while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) + { + node = theFacade->theClusterMgr->getNodeInfo(nodeId); + if((node.m_state.startLevel != NodeState::SL_STARTED) && + (node.m_state.startLevel != NodeState::SL_NOTHING)) + return OPERATION_NOT_ALLOWED_START_STOP; + } } - - m_stopRec.singleUserMode = false; - m_stopRec.sentCount = 0; - m_stopRec.reply = 0; - m_stopRec.nodeId = 0; - m_stopRec.anyData = anyData; - m_stopRec.callback = callback; - m_stopRec.inUse = true; - - /** - * Restart all database nodes into idle ("no-started") state - */ - Uint32 timeOut = 0; - NodeId nodeId = 0; NodeBitmask nodes; - while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){ - if(okToSendTo(nodeId, true) == 0){ + return sendSTOP_REQ(nodeId, + nodes, + 0, + abort, + false, + false, + false, + false); +} + +/* + * Perform system shutdown + */ - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - StopReq* const stopReq = CAST_PTR(StopReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, NDBCNTR, GSN_STOP_REQ, - StopReq::SignalLength); - - stopReq->requestInfo = 0; - stopReq->singleuser = 0; - StopReq::setSystemStop(stopReq->requestInfo, true); - StopReq::setPerformRestart(stopReq->requestInfo, true); - if (callback == 0) { - // Start node in idle ("no-started") state - StopReq::setNoStart(stopReq->requestInfo, 1); - } else { - StopReq::setNoStart(stopReq->requestInfo, nostart); - } - StopReq::setInitialStart(stopReq->requestInfo, initalStart); - StopReq::setStopAbort(stopReq->requestInfo, abort); - - stopReq->apiTimeout = 5000; - stopReq->transactionTimeout = 1000; - stopReq->readOperationTimeout = 1000; - stopReq->operationTimeout = 1000; - stopReq->senderData = 12; - stopReq->senderRef = _ownReference; - - timeOut += stopReq->apiTimeout; - timeOut += stopReq->transactionTimeout; - timeOut += stopReq->readOperationTimeout; - timeOut += stopReq->operationTimeout; - timeOut *= 3; - - m_stopRec.sentCount++; - int res; - if(callback == 0){ - res = sendSignal(nodeId, WAIT_STOP, signal, true); - } else { - res = sendSignal(nodeId, NO_WAIT, signal, true); - } - - if(res != -1){ - nodes.set(nodeId); - } - } - } - - if(stopCount != 0){ - * stopCount = m_stopRec.sentCount; - } +int MgmtSrvr::stop(int * stopCount, bool abort) +{ + NodeBitmask nodes; + int ret = sendSTOP_REQ(0, + nodes, + 0, + abort, + true, + false, + false, + false); + if (stopCount) + *stopCount = nodes.count(); + return ret; +} + +/* + * Enter single user mode on all live nodes + */ - if(m_stopRec.sentCount == 0){ - m_stopRec.inUse = false; - return 0; - } - - if(callback != 0){ - return 0; - } - - theFacade->lock_mutex(); - int waitTime = timeOut/m_stopRec.sentCount; - if (receiveOptimisedResponse(waitTime) != 0) { - m_stopRec.inUse = false; - return -1; +int MgmtSrvr::enterSingleUser(int * stopCount, Uint32 singleUserNodeId) +{ + if (getNodeType(singleUserNodeId) != NDB_MGM_NODE_TYPE_API) + return NODE_NOT_API_NODE; + NodeId nodeId = 0; + ClusterMgr::Node node; + while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) + { + node = theFacade->theClusterMgr->getNodeInfo(nodeId); + if((node.m_state.startLevel != NodeState::SL_STARTED) && + (node.m_state.startLevel != NodeState::SL_NOTHING)) + return OPERATION_NOT_ALLOWED_START_STOP; } - + NodeBitmask nodes; + int ret = sendSTOP_REQ(0, + nodes, + singleUserNodeId, + false, + false, + false, + false, + false); + if (stopCount) + *stopCount = nodes.count(); + return ret; +} + +/* + * Perform node restart + */ + +int MgmtSrvr::restartNode(int nodeId, bool nostart, bool initialStart, + bool abort) +{ + NodeBitmask nodes; + return sendSTOP_REQ(nodeId, + nodes, + 0, + abort, + false, + true, + nostart, + initialStart); +} + +/* + * Perform system restart + */ + +int MgmtSrvr::restart(bool nostart, bool initialStart, + bool abort, int * stopCount ) +{ + NodeBitmask nodes; + int ret = sendSTOP_REQ(0, + nodes, + 0, + abort, + true, + true, + true, + initialStart); + + if (ret) + return ret; + + if (stopCount) + *stopCount = nodes.count(); + +#ifdef VM_TRACE + ndbout_c("Stopped %d nodes", nodes.count()); +#endif /** * Here all nodes were correctly stopped, * so we wait for all nodes to be contactable */ - nodeId = 0; + int waitTime = 12000; + NodeId nodeId = 0; NDB_TICKS maxTime = NdbTick_CurrentMillisecond() + waitTime; - while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB) && nodes.get(nodeId)) { + + ndbout_c(" %d", nodes.get(1)); + ndbout_c(" %d", nodes.get(2)); + + while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) { + if (!nodes.get(nodeId)) + continue; enum ndb_mgm_node_status s; s = NDB_MGM_NODE_STATUS_NO_CONTACT; +#ifdef VM_TRACE + ndbout_c("Waiting for %d not started", nodeId); +#endif while (s != NDB_MGM_NODE_STATUS_NOT_STARTED && waitTime > 0) { Uint32 startPhase = 0, version = 0, dynamicId = 0, nodeGroup = 0; Uint32 connectCount = 0; bool system; + const char *address; status(nodeId, &s, &version, &startPhase, - &system, &dynamicId, &nodeGroup, &connectCount); + &system, &dynamicId, &nodeGroup, &connectCount, &address); NdbSleep_MilliSleep(100); waitTime = (maxTime - NdbTick_CurrentMillisecond()); } } - if(nostart){ - m_stopRec.inUse = false; + if(nostart) return 0; - } /** * Now we start all database nodes (i.e. we make them non-idle) * We ignore the result we get from the start command. */ nodeId = 0; - while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB) && nodes.get(nodeId)) { + while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) { + if (!nodes.get(nodeId)) + continue; int result; result = start(nodeId); DEBUG("Starting node " << nodeId << " with result " << result); @@ -963,455 +1155,43 @@ MgmtSrvr::restart(bool nostart, bool initalStart, bool abort, * Maybe the user only wanted to restart a subset of the nodes. * It is also easy for the user to check which nodes have * started and which nodes have not. - * - * if (result != 0) { - * m_stopRec.inUse = false; - * return result; - * } */ } - m_stopRec.inUse = false; - return 0; -} - -/***************************************************************************** - * Version handling - *****************************************************************************/ - -int -MgmtSrvr::versionNode(int processId, bool abort, - VersionCallback callback, void * anyData) -{ - int version; - - if(m_versionRec.inUse) - return OPERATION_IN_PROGRESS; - - m_versionRec.callback = callback; - m_versionRec.inUse = true ; - - if (getOwnNodeId() == processId) - { - version= NDB_VERSION; - } - else if (getNodeType(processId) == NDB_MGM_NODE_TYPE_NDB) - { - ClusterMgr::Node node= theFacade->theClusterMgr->getNodeInfo(processId); - if(node.connected) - version= node.m_info.m_version; - else - version= 0; - } - else if (getNodeType(processId) == NDB_MGM_NODE_TYPE_API || - getNodeType(processId) == NDB_MGM_NODE_TYPE_MGM) - { - return sendVersionReq(processId); - } - else - version= 0; - - if(m_versionRec.callback != 0) - m_versionRec.callback(processId, version, this,0); - m_versionRec.inUse = false ; - - m_versionRec.version[processId]= version; - - return 0; -} - -int -MgmtSrvr::sendVersionReq(int processId) -{ - Uint32 ndbnode=0; - int result; - for(Uint32 i = 0; i<MAX_NODES; i++) { - if (getNodeType(i) == NDB_MGM_NODE_TYPE_NDB) { - if(okToSendTo(i, true) == 0) - { - ndbnode = i; - break; - } - } - } - - if (ndbnode == 0) { - m_versionRec.inUse = false; - if(m_versionRec.callback != 0) - m_versionRec.callback(processId, 0, this,0); - return NO_CONTACT_WITH_CLUSTER; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - m_versionRec.inUse = false; - if(m_versionRec.callback != 0) - m_versionRec.callback(processId, 0, this,0); - return COULD_NOT_ALLOCATE_MEMORY; - } - ApiVersionReq* req = CAST_PTR(ApiVersionReq, signal->getDataPtrSend()); - req->senderRef = _ownReference; - req->nodeId = processId; - - signal->set(TestOrd::TraceAPI, QMGR, GSN_API_VERSION_REQ, - ApiVersionReq::SignalLength); - - - // if(m_versionRec.callback == 0){ - Uint32 timeOut = 0; - timeOut = 10000; - result = sendRecSignal(ndbnode, WAIT_VERSION, signal, true, timeOut); - //} else { - //result = sendSignal(processId, NO_WAIT, signal, true); - // } - - if (result == -1) { - m_versionRec.inUse = false; - if(m_versionRec.callback != 0) - m_versionRec.callback(processId, 0, this,0); - m_versionRec.version[processId] = 0; - return SEND_OR_RECEIVE_FAILED; - } - - m_versionRec.inUse = false; return 0; } int -MgmtSrvr::version(int * stopCount, bool abort, - VersionCallback callback, void * anyData) -{ - ClusterMgr::Node node; - int version; - - if(m_versionRec.inUse) - return 1; - - m_versionRec.callback = callback; - m_versionRec.inUse = true ; - Uint32 i; - for(i = 0; i<MAX_NODES; i++) { - if (getNodeType(i) == NDB_MGM_NODE_TYPE_MGM) { - m_versionRec.callback(i, NDB_VERSION, this,0); - } - } - for(i = 0; i<MAX_NODES; i++) { - if (getNodeType(i) == NDB_MGM_NODE_TYPE_NDB) { - node = theFacade->theClusterMgr->getNodeInfo(i); - version = node.m_info.m_version; - if(theFacade->theClusterMgr->getNodeInfo(i).connected) - m_versionRec.callback(i, version, this,0); - else - m_versionRec.callback(i, 0, this,0); - - } - } - for(i = 0; i<MAX_NODES; i++) { - if (getNodeType(i) == NDB_MGM_NODE_TYPE_API) { - return sendVersionReq(i); - } - } - - return 0; -} - -int -MgmtSrvr::stopNode(int processId, bool abort, StopCallback callback, - void * anyData) - -{ - if(m_stopRec.singleUserMode) - return 5060; - - if(m_stopRec.inUse) - return 5029; - - int result; - - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - StopReq* const stopReq = CAST_PTR(StopReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, NDBCNTR, GSN_STOP_REQ, StopReq::SignalLength); - - stopReq->requestInfo = 0; - stopReq->singleuser = 0; - StopReq::setPerformRestart(stopReq->requestInfo, false); - StopReq::setSystemStop(stopReq->requestInfo, false); - StopReq::setStopAbort(stopReq->requestInfo, abort); - - stopReq->apiTimeout = 5000; - stopReq->transactionTimeout = 1000; - stopReq->readOperationTimeout = 1000; - stopReq->operationTimeout = 1000; - stopReq->senderData = 12; - stopReq->senderRef = _ownReference; - - m_stopRec.sentCount = 1; - m_stopRec.reply = 0; - m_stopRec.nodeId = processId; - m_stopRec.anyData = anyData; - m_stopRec.callback = callback; - m_stopRec.inUse = true; - - if(callback == NULL){ - Uint32 timeOut = 0; - timeOut += stopReq->apiTimeout; - timeOut += stopReq->transactionTimeout; - timeOut += stopReq->readOperationTimeout; - timeOut += stopReq->operationTimeout; - timeOut *= 3; - result = sendRecSignal(processId, WAIT_STOP, signal, true, timeOut); - } else { - result = sendSignal(processId, NO_WAIT, signal, true); - } - - if (result == -1) { - m_stopRec.inUse = false; - return SEND_OR_RECEIVE_FAILED; - } - - if(callback == 0){ - m_stopRec.inUse = false; - return m_stopRec.reply; - } else { - return 0; - } -} - -int -MgmtSrvr::stop(int * stopCount, bool abort, StopCallback callback, - void * anyData) +MgmtSrvr::exitSingleUser(int * stopCount, bool abort) { - if(m_stopRec.singleUserMode) - return 5060; - - if(m_stopRec.inUse){ - return 5029; - } - - m_stopRec.singleUserMode = false; - m_stopRec.sentCount = 0; - m_stopRec.reply = 0; - m_stopRec.nodeId = 0; - m_stopRec.anyData = anyData; - m_stopRec.callback = callback; - m_stopRec.inUse = true; - NodeId nodeId = 0; - Uint32 timeOut = 0; - while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){ - if(okToSendTo(nodeId, true) == 0){ - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - StopReq* const stopReq = CAST_PTR(StopReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, NDBCNTR, GSN_STOP_REQ, - StopReq::SignalLength); - - stopReq->requestInfo = 0; - stopReq->singleuser = 0; - StopReq::setSystemStop(stopReq->requestInfo, true); - StopReq::setPerformRestart(stopReq->requestInfo, false); - StopReq::setStopAbort(stopReq->requestInfo, abort); - - stopReq->apiTimeout = 5000; - stopReq->transactionTimeout = 1000; - stopReq->readOperationTimeout = 1000; - stopReq->operationTimeout = 1000; - stopReq->senderData = 12; - stopReq->senderRef = _ownReference; - - timeOut += stopReq->apiTimeout; - timeOut += stopReq->transactionTimeout; - timeOut += stopReq->readOperationTimeout; - timeOut += stopReq->operationTimeout; - timeOut *= 3; - - m_stopRec.sentCount++; - if(callback == 0) - sendSignal(nodeId, WAIT_STOP, signal, true); - else - sendSignal(nodeId, NO_WAIT, signal, true); - } - } - - if(stopCount != 0) - * stopCount = m_stopRec.sentCount; - - if(m_stopRec.sentCount > 0){ - if(callback == 0){ - theFacade->lock_mutex(); - receiveOptimisedResponse(timeOut / m_stopRec.sentCount); - } else { - return 0; - } - } - - m_stopRec.inUse = false; - return m_stopRec.reply; -} - -/***************************************************************************** - * Single user mode - ****************************************************************************/ - -int -MgmtSrvr::enterSingleUser(int * stopCount, Uint32 singleUserNodeId, - EnterSingleCallback callback, void * anyData) -{ - if(m_stopRec.singleUserMode) { - return 5060; - } - - if (getNodeType(singleUserNodeId) != NDB_MGM_NODE_TYPE_API) { - return 5062; - } - ClusterMgr::Node node; - - for(Uint32 i = 0; i<MAX_NODES; i++) { - if (getNodeType(i) == NDB_MGM_NODE_TYPE_NDB) { - node = theFacade->theClusterMgr->getNodeInfo(i); - if((node.m_state.startLevel != NodeState::SL_STARTED) && - (node.m_state.startLevel != NodeState::SL_NOTHING)) { - return 5063; - } - } - } - - if(m_stopRec.inUse){ - return 5029; - } - - if(singleUserNodeId == 0) - return 1; - m_stopRec.singleUserMode = true; - m_stopRec.sentCount = 0; - m_stopRec.reply = 0; - m_stopRec.nodeId = 0; - m_stopRec.anyData = anyData; - m_stopRec.callback = callback; - m_stopRec.inUse = true; - - NodeId nodeId = 0; - Uint32 timeOut = 0; - while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){ - if(okToSendTo(nodeId, true) == 0){ - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - StopReq* const stopReq = CAST_PTR(StopReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, NDBCNTR, GSN_STOP_REQ, - StopReq::SignalLength); - - stopReq->requestInfo = 0; - stopReq->singleuser = 1; - stopReq->singleUserApi = singleUserNodeId; - StopReq::setSystemStop(stopReq->requestInfo, false); - StopReq::setPerformRestart(stopReq->requestInfo, false); - StopReq::setStopAbort(stopReq->requestInfo, false); - - stopReq->apiTimeout = 5000; - stopReq->transactionTimeout = 1000; - stopReq->readOperationTimeout = 1000; - stopReq->operationTimeout = 1000; - stopReq->senderData = 12; - stopReq->senderRef = _ownReference; - timeOut += stopReq->apiTimeout; - timeOut += stopReq->transactionTimeout; - timeOut += stopReq->readOperationTimeout; - timeOut += stopReq->operationTimeout; - timeOut *= 3; - - m_stopRec.sentCount++; - if(callback == 0) - sendSignal(nodeId, WAIT_STOP, signal, true); - else - sendSignal(nodeId, NO_WAIT, signal, true); - } - } - - if(stopCount != 0) - * stopCount = m_stopRec.sentCount; + int count = 0; - if(callback == 0){ - m_stopRec.inUse = false; - return 0; - // return m_stopRec.reply; - } else { - return 0; - } + SignalSender ss(theFacade); + ss.lock(); // lock will be released on exit - m_stopRec.inUse = false; - return m_stopRec.reply; -} + SimpleSignal ssig; + ResumeReq* const resumeReq = + CAST_PTR(ResumeReq, ssig.getDataPtrSend()); + ssig.set(ss,TestOrd::TraceAPI, NDBCNTR, GSN_RESUME_REQ, + ResumeReq::SignalLength); + resumeReq->senderData = 12; + resumeReq->senderRef = ss.getOwnRef(); -int -MgmtSrvr::exitSingleUser(int * stopCount, bool abort, - ExitSingleCallback callback, void * anyData) -{ - m_stopRec.sentCount = 0; - m_stopRec.reply = 0; - m_stopRec.nodeId = 0; - m_stopRec.anyData = anyData; - m_stopRec.callback = callback; - m_stopRec.inUse = true; - - NodeId nodeId = 0; while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){ if(okToSendTo(nodeId, true) == 0){ - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - ResumeReq* const resumeReq = - CAST_PTR(ResumeReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, NDBCNTR, GSN_RESUME_REQ, - StopReq::SignalLength); - resumeReq->senderData = 12; - resumeReq->senderRef = _ownReference; - - m_stopRec.sentCount++; - if(callback == 0) - sendSignal(nodeId, WAIT_STOP, signal, true); - else - sendSignal(nodeId, NO_WAIT, signal, true); + SendStatus result = ss.sendSignal(nodeId, &ssig); + if (result == SEND_OK) + count++; } } - m_stopRec.singleUserMode = false; - if(stopCount != 0) - * stopCount = m_stopRec.sentCount; - - - if(callback == 0){ - m_stopRec.inUse = false; - return m_stopRec.reply; - } else { - return 0; - } + * stopCount = count; - m_stopRec.inUse = false; - return m_stopRec.reply; + return 0; } - /***************************************************************************** * Status ****************************************************************************/ @@ -1419,32 +1199,32 @@ MgmtSrvr::exitSingleUser(int * stopCount, bool abort, #include <ClusterMgr.hpp> int -MgmtSrvr::status(int processId, +MgmtSrvr::status(int nodeId, ndb_mgm_node_status * _status, Uint32 * version, Uint32 * _phase, bool * _system, Uint32 * dynamic, Uint32 * nodegroup, - Uint32 * connectCount) + Uint32 * connectCount, + const char **address) { - if (getNodeType(processId) == NDB_MGM_NODE_TYPE_API || - getNodeType(processId) == NDB_MGM_NODE_TYPE_MGM) { - if(versionNode(processId, false,0,0) ==0) - * version = m_versionRec.version[processId]; - else - * version = 0; + if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API || + getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM) { + versionNode(nodeId, *version, address); + } else { + *address= get_connect_address(nodeId); } const ClusterMgr::Node node = - theFacade->theClusterMgr->getNodeInfo(processId); + theFacade->theClusterMgr->getNodeInfo(nodeId); if(!node.connected){ * _status = NDB_MGM_NODE_STATUS_NO_CONTACT; return 0; } - if (getNodeType(processId) == NDB_MGM_NODE_TYPE_NDB) { + if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB) { * version = node.m_info.m_version; } @@ -1507,67 +1287,81 @@ MgmtSrvr::status(int processId, } int -MgmtSrvr::setEventReportingLevelImpl(int processId, +MgmtSrvr::setEventReportingLevelImpl(int nodeId, const EventSubscribeReq& ll) { - - int result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal signal(_ownReference); + INIT_SIGNAL_SENDER(ss,nodeId); + SimpleSignal ssig; EventSubscribeReq * dst = - CAST_PTR(EventSubscribeReq, signal.getDataPtrSend()); - - * dst = ll; - - signal.set(TestOrd::TraceAPI, CMVMI, GSN_EVENT_SUBSCRIBE_REQ, - EventSubscribeReq::SignalLength); - - theFacade->lock_mutex(); - send(&signal, processId, NODE_TYPE_DB); - theFacade->unlock_mutex(); - + CAST_PTR(EventSubscribeReq, ssig.getDataPtrSend()); + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_EVENT_SUBSCRIBE_REQ, + EventSubscribeReq::SignalLength); + *dst = ll; + + send(ss,ssig,nodeId,NODE_TYPE_DB); + +#if 0 + while (1) + { + SimpleSignal *signal = ss.waitFor(); + int gsn = signal->readSignalNumber(); + switch (gsn) { + case GSN_EVENT_SUBSCRIBE_CONF:{ + break; + } + case GSN_EVENT_SUBSCRIBE_REF:{ + return SEND_OR_RECEIVE_FAILED; + } + case GSN_NF_COMPLETEREP:{ + const NFCompleteRep * const rep = + CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr()); + if (rep->failedNodeId == nodeId) + return SEND_OR_RECEIVE_FAILED; + break; + } + case GSN_NODE_FAILREP:{ + const NodeFailRep * const rep = + CAST_CONSTPTR(NodeFailRep, signal->getDataPtr()); + if (NodeBitmask::get(rep->theNodes,nodeId)) + return SEND_OR_RECEIVE_FAILED; + break; + } + default: + report_unknown_signal(signal); + return SEND_OR_RECEIVE_FAILED; + } + + } +#endif return 0; } //**************************************************************************** //**************************************************************************** int -MgmtSrvr::setNodeLogLevelImpl(int processId, const SetLogLevelOrd & ll) +MgmtSrvr::setNodeLogLevelImpl(int nodeId, const SetLogLevelOrd & ll) { - int result = okToSendTo(processId, true); - if (result != 0) { - return result; - } + INIT_SIGNAL_SENDER(ss,nodeId); - NdbApiSignal signal(_ownReference); + SimpleSignal ssig; + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_SET_LOGLEVELORD, + SetLogLevelOrd::SignalLength); + SetLogLevelOrd* const dst = CAST_PTR(SetLogLevelOrd, ssig.getDataPtrSend()); + *dst = ll; - SetLogLevelOrd * dst = CAST_PTR(SetLogLevelOrd, signal.getDataPtrSend()); - - * dst = ll; - - signal.set(TestOrd::TraceAPI, CMVMI, GSN_SET_LOGLEVELORD, - SetLogLevelOrd::SignalLength); - - theFacade->lock_mutex(); - theFacade->sendSignalUnCond(&signal, processId); - theFacade->unlock_mutex(); - - return 0; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } int -MgmtSrvr::send(NdbApiSignal* signal, Uint32 node, Uint32 node_type){ +MgmtSrvr::send(SignalSender &ss, SimpleSignal &ssig, Uint32 node, Uint32 node_type){ Uint32 max = (node == 0) ? MAX_NODES : node + 1; for(; node < max; node++){ while(nodeTypes[node] != (int)node_type && node < max) node++; if(nodeTypes[node] != (int)node_type) break; - theFacade->sendSignalUnCond(signal, node); + ss.sendSignal(node, &ssig); } return 0; } @@ -1576,34 +1370,21 @@ MgmtSrvr::send(NdbApiSignal* signal, Uint32 node, Uint32 node_type){ //**************************************************************************** int -MgmtSrvr::insertError(int processId, int errorNo) +MgmtSrvr::insertError(int nodeId, int errorNo) { if (errorNo < 0) { return INVALID_ERROR_NUMBER; } - int result; - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } + INIT_SIGNAL_SENDER(ss,nodeId); - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - TamperOrd* const tamperOrd = CAST_PTR(TamperOrd, signal->getDataPtrSend()); + SimpleSignal ssig; + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TAMPER_ORD, + TamperOrd::SignalLength); + TamperOrd* const tamperOrd = CAST_PTR(TamperOrd, ssig.getDataPtrSend()); tamperOrd->errorNo = errorNo; - signal->set(TestOrd::TraceAPI, CMVMI, GSN_TAMPER_ORD, - TamperOrd::SignalLength); - result = sendSignal(processId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - return 0; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } @@ -1612,37 +1393,23 @@ MgmtSrvr::insertError(int processId, int errorNo) //**************************************************************************** int -MgmtSrvr::setTraceNo(int processId, int traceNo) +MgmtSrvr::setTraceNo(int nodeId, int traceNo) { if (traceNo < 0) { return INVALID_TRACE_NUMBER; } - int result; - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + INIT_SIGNAL_SENDER(ss,nodeId); - TestOrd* const testOrd = CAST_PTR(TestOrd, signal->getDataPtrSend()); + SimpleSignal ssig; + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); + TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend()); testOrd->clear(); - // Assume TRACE command causes toggling. Not really defined... ? TODO testOrd->setTraceCommand(TestOrd::Toggle, (TestOrd::TraceSpecification)traceNo); - signal->set(TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); - - result = sendSignal(processId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - return 0; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } //**************************************************************************** @@ -1661,14 +1428,10 @@ MgmtSrvr::getBlockNumber(const BaseString &blockName) //**************************************************************************** int -MgmtSrvr::setSignalLoggingMode(int processId, LogMode mode, +MgmtSrvr::setSignalLoggingMode(int nodeId, LogMode mode, const Vector<BaseString>& blocks) { - int result; - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } + INIT_SIGNAL_SENDER(ss,nodeId); // Convert from MgmtSrvr format... @@ -1703,12 +1466,10 @@ MgmtSrvr::setSignalLoggingMode(int processId, LogMode mode, return -1; } - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + SimpleSignal ssig; + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); - TestOrd* const testOrd = CAST_PTR(TestOrd, signal->getDataPtrSend()); + TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend()); testOrd->clear(); if (blocks.size() == 0 || blocks[0] == "ALL") { @@ -1718,78 +1479,44 @@ MgmtSrvr::setSignalLoggingMode(int processId, LogMode mode, for(unsigned i = 0; i < blocks.size(); i++){ int blockNumber = getBlockNumber(blocks[i]); if (blockNumber == -1) { - releaseSignal(signal); return INVALID_BLOCK_NAME; } testOrd->addSignalLoggerCommand(blockNumber, command, logSpec); } // for } // else - - signal->set(TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); - result = sendSignal(processId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - return 0; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } - /***************************************************************************** * Signal tracing *****************************************************************************/ -int MgmtSrvr::startSignalTracing(int processId) +int MgmtSrvr::startSignalTracing(int nodeId) { - int result; - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - + INIT_SIGNAL_SENDER(ss,nodeId); - TestOrd* const testOrd = CAST_PTR(TestOrd, signal->getDataPtrSend()); + SimpleSignal ssig; + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); + + TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend()); testOrd->clear(); testOrd->setTestCommand(TestOrd::On); - signal->set(TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); - result = sendSignal(processId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - return 0; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } int -MgmtSrvr::stopSignalTracing(int processId) +MgmtSrvr::stopSignalTracing(int nodeId) { - int result; - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + INIT_SIGNAL_SENDER(ss,nodeId); - TestOrd* const testOrd = CAST_PTR(TestOrd, signal->getDataPtrSend()); + SimpleSignal ssig; + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); + TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend()); testOrd->clear(); testOrd->setTestCommand(TestOrd::Off); - signal->set(TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength); - result = sendSignal(processId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - return 0; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } @@ -1798,7 +1525,7 @@ MgmtSrvr::stopSignalTracing(int processId) *****************************************************************************/ int -MgmtSrvr::dumpState(int processId, const char* args) +MgmtSrvr::dumpState(int nodeId, const char* args) { // Convert the space separeted args // string to an int array @@ -1820,29 +1547,20 @@ MgmtSrvr::dumpState(int processId, const char* args) } } - return dumpState(processId, args_array, numArgs); + return dumpState(nodeId, args_array, numArgs); } int -MgmtSrvr::dumpState(int processId, const Uint32 args[], Uint32 no) +MgmtSrvr::dumpState(int nodeId, const Uint32 args[], Uint32 no) { - int result; - - result = okToSendTo(processId, true); - if (result != 0) { - return result; - } - - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + INIT_SIGNAL_SENDER(ss,nodeId); const Uint32 len = no > 25 ? 25 : no; + SimpleSignal ssig; DumpStateOrd * const dumpOrd = - CAST_PTR(DumpStateOrd, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, CMVMI, GSN_DUMP_STATE_ORD, len); + CAST_PTR(DumpStateOrd, ssig.getDataPtrSend()); + ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_DUMP_STATE_ORD, len); for(Uint32 i = 0; i<25; i++){ if (i < len) dumpOrd->args[i] = args[i]; @@ -1850,12 +1568,7 @@ MgmtSrvr::dumpState(int processId, const Uint32 args[], Uint32 no) dumpOrd->args[i] = 0; } - result = sendSignal(processId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - return 0; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } @@ -1886,117 +1599,23 @@ MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal) int gsn = signal->readSignalNumber(); switch (gsn) { - case GSN_API_VERSION_CONF: { - if (theWaitState == WAIT_VERSION) { - const ApiVersionConf * const conf = - CAST_CONSTPTR(ApiVersionConf, signal->getDataPtr()); - if(m_versionRec.callback != 0) - m_versionRec.callback(conf->nodeId, conf->version, this, 0); - else { - m_versionRec.version[conf->nodeId]=conf->version; - } - } else return; - theWaitState = NO_WAIT; - } - break; - case GSN_EVENT_SUBSCRIBE_CONF: break; - - case GSN_EVENT_REP: - eventReport(refToNode(signal->theSendersBlockRef), signal->getDataPtr()); + case GSN_EVENT_SUBSCRIBE_REF: break; - - case GSN_STOP_REF:{ - const StopRef * const ref = CAST_CONSTPTR(StopRef, signal->getDataPtr()); - const NodeId nodeId = refToNode(signal->theSendersBlockRef); - handleStopReply(nodeId, ref->errorCode); - return; - } - break; - - case GSN_BACKUP_CONF:{ - const BackupConf * const conf = - CAST_CONSTPTR(BackupConf, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupStarted; - event.Started.BackupId = conf->backupId; - event.Nodes = conf->nodes; -#ifdef VM_TRACE - ndbout_c("Backup master is %d", refToNode(signal->theSendersBlockRef)); -#endif - backupCallback(event); - } - break; - - case GSN_BACKUP_REF:{ - const BackupRef * const ref = - CAST_CONSTPTR(BackupRef, signal->getDataPtr()); - Uint32 errCode = ref->errorCode; - if(ref->errorCode == BackupRef::IAmNotMaster){ - const Uint32 aNodeId = refToNode(ref->masterRef); -#ifdef VM_TRACE - ndbout_c("I'm not master resending to %d", aNodeId); -#endif - theWaitNode= aNodeId; - NdbApiSignal aSignal(_ownReference); - BackupReq* req = CAST_PTR(BackupReq, aSignal.getDataPtrSend()); - aSignal.set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, - BackupReq::SignalLength); - req->senderData = 19; - req->backupDataLen = 0; - - int i = theFacade->sendSignalUnCond(&aSignal, aNodeId); - if(i == 0){ - return; - } - errCode = 5030; - } - BackupEvent event; - event.Event = BackupEvent::BackupFailedToStart; - event.FailedToStart.ErrorCode = errCode; - backupCallback(event); + case GSN_EVENT_REP: + { + EventReport *rep = CAST_PTR(EventReport, signal->getDataPtrSend()); + if (rep->getNodeId() == 0) + rep->setNodeId(refToNode(signal->theSendersBlockRef)); + eventReport(signal->getDataPtr()); break; } - case GSN_BACKUP_ABORT_REP:{ - const BackupAbortRep * const rep = - CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupAborted; - event.Aborted.Reason = rep->reason; - event.Aborted.BackupId = rep->backupId; - event.Aborted.ErrorCode = rep->reason; - backupCallback(event); - } - break; - - case GSN_BACKUP_COMPLETE_REP:{ - const BackupCompleteRep * const rep = - CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupCompleted; - event.Completed.BackupId = rep->backupId; - - event.Completed.NoOfBytes = rep->noOfBytes; - event.Completed.NoOfLogBytes = rep->noOfLogBytes; - event.Completed.NoOfRecords = rep->noOfRecords; - event.Completed.NoOfLogRecords = rep->noOfLogRecords; - event.Completed.stopGCP = rep->stopGCP; - event.Completed.startGCP = rep->startGCP; - event.Nodes = rep->nodes; - - backupCallback(event); - } + case GSN_NF_COMPLETEREP: break; - - case GSN_MGM_LOCK_CONFIG_REP: - case GSN_MGM_LOCK_CONFIG_REQ: - case GSN_MGM_UNLOCK_CONFIG_REP: - case GSN_MGM_UNLOCK_CONFIG_REQ: { - m_signalRecvQueue.receive(new NdbApiSignal(*signal)); + case GSN_NODE_FAILREP: break; - } default: g_eventLogger.error("Unknown signal received. SignalNumber: " @@ -2011,101 +1630,27 @@ MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal) } } -/** - * A database node was either stopped or there was some error - */ -void -MgmtSrvr::handleStopReply(NodeId nodeId, Uint32 errCode) -{ - /** - * If we are in single user mode and get a stop reply from a - * DB node, then we have had a node crash. - * If all DB nodes are gone, and we are still in single user mode, - * the set m_stopRec.singleUserMode = false; - */ - if(m_stopRec.singleUserMode) { - ClusterMgr::Node node; - bool failure = true; - for(Uint32 i = 0; i<MAX_NODES; i++) { - if (getNodeType(i) == NDB_MGM_NODE_TYPE_NDB) { - node = theFacade->theClusterMgr->getNodeInfo(i); - if((node.m_state.startLevel == NodeState::SL_NOTHING)) - failure = true; - else - failure = false; - } - } - if(failure) { - m_stopRec.singleUserMode = false; - } - } - if(m_stopRec.inUse == false) - return; - - if(!(m_stopRec.nodeId == 0 || m_stopRec.nodeId == nodeId)) - goto error; - - if(m_stopRec.sentCount <= 0) - goto error; - - if(!(theWaitState == WAIT_STOP || m_stopRec.callback != 0)) - goto error; - - if(errCode != 0) - m_stopRec.reply = translateStopRef(errCode); - - m_stopRec.sentCount --; - if(m_stopRec.sentCount == 0){ - if(theWaitState == WAIT_STOP){ - theWaitState = NO_WAIT; - NdbCondition_Signal(theMgmtWaitForResponseCondPtr); - return; - } - if(m_stopRec.callback != 0){ - m_stopRec.inUse = false; - StopCallback callback = m_stopRec.callback; - m_stopRec.callback = NULL; - (* callback)(m_stopRec.nodeId, - m_stopRec.anyData, - m_stopRec.reply); - return; - } - } - return; - - error: - if(errCode != 0){ - g_eventLogger.error("Unexpected signal received. SignalNumber: %i from %d", - GSN_STOP_REF, nodeId); - } -} - void MgmtSrvr::handleStatus(NodeId nodeId, bool alive, bool nfComplete) { DBUG_ENTER("MgmtSrvr::handleStatus"); Uint32 theData[25]; + EventReport *rep = (EventReport *)theData; + theData[1] = nodeId; if (alive) { m_started_nodes.push_back(nodeId); - theData[0] = NDB_LE_Connected; + rep->setEventType(NDB_LE_Connected); } else { - theData[0] = NDB_LE_Disconnected; + rep->setEventType(NDB_LE_Connected); if(nfComplete) { - handleStopReply(nodeId, 0); DBUG_VOID_RETURN; } - - if(theWaitNode == nodeId && - theWaitState != NO_WAIT && theWaitState != WAIT_STOP) - { - theWaitState = WAIT_NODEFAILURE; - NdbCondition_Signal(theMgmtWaitForResponseCondPtr); - } } - eventReport(_ownNodeId, theData); + rep->setNodeId(_ownNodeId); + eventReport(theData); DBUG_VOID_RETURN; } @@ -2221,18 +1766,18 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, iter(* _config->m_configValues, CFG_SECTION_NODE); for(iter.first(); iter.valid(); iter.next()) { unsigned tmp= 0; - if(iter.get(CFG_NODE_ID, &tmp)) abort(); + if(iter.get(CFG_NODE_ID, &tmp)) require(false); if (*nodeId && *nodeId != tmp) continue; found_matching_id= true; - if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) abort(); + if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) require(false); if(type_c != (unsigned)type) continue; found_matching_type= true; if (connected_nodes.get(tmp)) continue; found_free_node= true; - if(iter.get(CFG_NODE_HOST, &config_hostname)) abort(); + if(iter.get(CFG_NODE_HOST, &config_hostname)) require(false); if (config_hostname && config_hostname[0] == 0) config_hostname= 0; else if (client_addr) { @@ -2437,10 +1982,11 @@ MgmtSrvr::getNextNodeId(NodeId * nodeId, enum ndb_mgm_node_type type) const #include "Services.hpp" void -MgmtSrvr::eventReport(NodeId nodeId, const Uint32 * theData) +MgmtSrvr::eventReport(const Uint32 * theData) { const EventReport * const eventReport = (EventReport *)&theData[0]; + NodeId nodeId = eventReport->getNodeId(); Ndb_logevent_type type = eventReport->getEventType(); // Log event g_eventLogger.log(type, theData, nodeId, @@ -2451,9 +1997,13 @@ MgmtSrvr::eventReport(NodeId nodeId, const Uint32 * theData) /*************************************************************************** * Backup ***************************************************************************/ + int MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) { + SignalSender ss(theFacade); + ss.lock(); // lock will be released on exit + bool next; NodeId nodeId = 0; while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true && @@ -2461,58 +2011,130 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) if(!next) return NO_CONTACT_WITH_DB_NODES; - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } - - BackupReq* req = CAST_PTR(BackupReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, - BackupReq::SignalLength); + SimpleSignal ssig; + BackupReq* req = CAST_PTR(BackupReq, ssig.getDataPtrSend()); + ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, + BackupReq::SignalLength); req->senderData = 19; req->backupDataLen = 0; + assert(waitCompleted < 3); + req->flags = waitCompleted & 0x3; - int result; - if (waitCompleted == 2) { - result = sendRecSignal(nodeId, WAIT_BACKUP_COMPLETED, - signal, true, 48*60*60*1000 /* 48 hours */); - } - else if (waitCompleted == 1) { - result = sendRecSignal(nodeId, WAIT_BACKUP_STARTED, - signal, true, 5*60*1000 /*5 mins*/); - } - else { - result = sendRecSignal(nodeId, NO_WAIT, signal, true); - } - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - if (waitCompleted){ - switch(m_lastBackupEvent.Event){ - case BackupEvent::BackupCompleted: - backupId = m_lastBackupEvent.Completed.BackupId; + BackupEvent event; + int do_send = 1; + while (1) { + if (do_send) + { + if (ss.sendSignal(nodeId, &ssig) != SEND_OK) { + return SEND_OR_RECEIVE_FAILED; + } + if (waitCompleted == 0) + return 0; + do_send = 0; + } + SimpleSignal *signal = ss.waitFor(); + + int gsn = signal->readSignalNumber(); + switch (gsn) { + case GSN_BACKUP_CONF:{ + const BackupConf * const conf = + CAST_CONSTPTR(BackupConf, signal->getDataPtr()); + event.Event = BackupEvent::BackupStarted; + event.Started.BackupId = conf->backupId; + event.Nodes = conf->nodes; +#ifdef VM_TRACE + ndbout_c("Backup(%d) master is %d", conf->backupId, + refToNode(signal->header.theSendersBlockRef)); +#endif + backupId = conf->backupId; + if (waitCompleted == 1) + return 0; + // wait for next signal break; - case BackupEvent::BackupStarted: - backupId = m_lastBackupEvent.Started.BackupId; + } + case GSN_BACKUP_COMPLETE_REP:{ + const BackupCompleteRep * const rep = + CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Backup(%d) completed %d", rep->backupId); +#endif + event.Event = BackupEvent::BackupCompleted; + event.Completed.BackupId = rep->backupId; + + event.Completed.NoOfBytes = rep->noOfBytes; + event.Completed.NoOfLogBytes = rep->noOfLogBytes; + event.Completed.NoOfRecords = rep->noOfRecords; + event.Completed.NoOfLogRecords = rep->noOfLogRecords; + event.Completed.stopGCP = rep->stopGCP; + event.Completed.startGCP = rep->startGCP; + event.Nodes = rep->nodes; + + backupId = rep->backupId; + return 0; + } + case GSN_BACKUP_REF:{ + const BackupRef * const ref = + CAST_CONSTPTR(BackupRef, signal->getDataPtr()); + if(ref->errorCode == BackupRef::IAmNotMaster){ + nodeId = refToNode(ref->masterRef); +#ifdef VM_TRACE + ndbout_c("I'm not master resending to %d", nodeId); +#endif + do_send = 1; // try again + continue; + } + event.Event = BackupEvent::BackupFailedToStart; + event.FailedToStart.ErrorCode = ref->errorCode; + return ref->errorCode; + } + case GSN_BACKUP_ABORT_REP:{ + const BackupAbortRep * const rep = + CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr()); + event.Event = BackupEvent::BackupAborted; + event.Aborted.Reason = rep->reason; + event.Aborted.BackupId = rep->backupId; + event.Aborted.ErrorCode = rep->reason; +#ifdef VM_TRACE + ndbout_c("Backup %d aborted", rep->backupId); +#endif + return rep->reason; + } + case GSN_NF_COMPLETEREP:{ + const NFCompleteRep * const rep = + CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Node %d fail completed", rep->failedNodeId); +#endif + if (rep->failedNodeId == nodeId || + waitCompleted == 1) + return 1326; + // wait for next signal + // master node will report aborted backup break; - case BackupEvent::BackupFailedToStart: - return m_lastBackupEvent.FailedToStart.ErrorCode; - case BackupEvent::BackupAborted: - return m_lastBackupEvent.Aborted.ErrorCode; - default: - return -1; + } + case GSN_NODE_FAILREP:{ + const NodeFailRep * const rep = + CAST_CONSTPTR(NodeFailRep, signal->getDataPtr()); + if (NodeBitmask::get(rep->theNodes,nodeId) || + waitCompleted == 1) + return 1326; + // wait for next signal + // master node will report aborted backup break; } + default: + report_unknown_signal(signal); + return SEND_OR_RECEIVE_FAILED; + } } - - return 0; } int MgmtSrvr::abortBackup(Uint32 backupId) { + SignalSender ss(theFacade); + bool next; NodeId nodeId = 0; while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true && @@ -2522,55 +2144,17 @@ MgmtSrvr::abortBackup(Uint32 backupId) return NO_CONTACT_WITH_DB_NODES; } - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + SimpleSignal ssig; - AbortBackupOrd* ord = CAST_PTR(AbortBackupOrd, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, BACKUP, GSN_ABORT_BACKUP_ORD, - AbortBackupOrd::SignalLength); + AbortBackupOrd* ord = CAST_PTR(AbortBackupOrd, ssig.getDataPtrSend()); + ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_ABORT_BACKUP_ORD, + AbortBackupOrd::SignalLength); ord->requestType = AbortBackupOrd::ClientAbort; ord->senderData = 19; ord->backupId = backupId; - int result = sendSignal(nodeId, NO_WAIT, signal, true); - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - return 0; -} - -void -MgmtSrvr::backupCallback(BackupEvent & event) -{ - DBUG_ENTER("MgmtSrvr::backupCallback"); - m_lastBackupEvent = event; - switch(event.Event){ - case BackupEvent::BackupFailedToStart: - DBUG_PRINT("info",("BackupEvent::BackupFailedToStart")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupAborted: - DBUG_PRINT("info",("BackupEvent::BackupAborted")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupCompleted: - DBUG_PRINT("info",("BackupEvent::BackupCompleted")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupStarted: - if(theWaitState == WAIT_BACKUP_STARTED) - { - DBUG_PRINT("info",("BackupEvent::BackupStarted NO_WAIT")); - theWaitState = NO_WAIT; - } else { - DBUG_PRINT("info",("BackupEvent::BackupStarted")); - } - } - DBUG_VOID_RETURN; + return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED; } @@ -2581,30 +2165,10 @@ MgmtSrvr::backupCallback(BackupEvent & event) int MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted) { - abort(); - return 0; -} - - -NodeId -MgmtSrvr::getPrimaryNode() const { -#if 0 - Uint32 tmp; - const Properties *prop = NULL; - - getConfig()->get("SYSTEM", &prop); - if(prop == NULL) - return 0; - - prop->get("PrimaryMGMNode", &tmp); - - return tmp; -#else + require(false); return 0; -#endif } - MgmtSrvr::Allocated_resources::Allocated_resources(MgmtSrvr &m) : m_mgmsrv(m) { @@ -2745,7 +2309,7 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value, ndbout_c("Updating node %d param: %d to %s", node, param, val_char); break; default: - abort(); + require(false); } assert(res); } while(node == 0 && iter.next() == 0); @@ -2754,7 +2318,6 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value, NdbMutex_Unlock(m_configMutex); return 0; } - int MgmtSrvr::setConnectionDbParameter(int node1, int node2, @@ -2889,10 +2452,6 @@ int MgmtSrvr::set_connect_string(const char *str) } -template class Vector<SigMatch>; -#if __SUNPRO_CC != 0x560 -template bool SignalQueue::waitFor<SigMatch>(Vector<SigMatch>&, SigMatch**, NdbApiSignal**, unsigned); -#endif template class MutexVector<unsigned short>; template class MutexVector<Ndb_mgmd_event_service::Event_listener>; diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp index b7983e6b441..600d168ee08 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.hpp +++ b/ndb/src/mgmsrv/MgmtSrvr.hpp @@ -22,15 +22,17 @@ #include <NdbCondition.h> #include <mgmapi.h> - +#include <NdbTCP.h> +#include <ConfigRetriever.hpp> #include <Vector.hpp> #include <NodeBitmask.hpp> #include <signaldata/ManagementServer.hpp> -#include "SignalQueue.hpp" #include <ndb_version.h> #include <EventLogger.hpp> #include <signaldata/EventSubscribeReq.hpp> +#include <SignalSender.hpp> + /** * @desc Block number for Management server. * @todo This should probably be somewhere else. I don't know where atm. @@ -172,10 +174,12 @@ public: STATIC_CONST( NODE_SHUTDOWN_IN_PROGESS = 5026 ); STATIC_CONST( SYSTEM_SHUTDOWN_IN_PROGRESS = 5027 ); STATIC_CONST( NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH = 5028 ); - STATIC_CONST( NO_CONTACT_WITH_CLUSTER = 6666 ); - STATIC_CONST( OPERATION_IN_PROGRESS = 6667 ); - + STATIC_CONST( NO_CONTACT_WITH_DB_NODES = 5030 ); + + STATIC_CONST( NODE_NOT_API_NODE = 5062 ); + STATIC_CONST( OPERATION_NOT_ALLOWED_START_STOP = 5063 ); + /** * This enum specifies the different signal loggig modes possible to set * with the setSignalLoggingMode method. @@ -200,51 +204,26 @@ public: ~MgmtSrvr(); - int status(int processId, - ndb_mgm_node_status * status, + /** + * Get status on a node. + * address may point to a common area (e.g. from inet_addr) + * There is no gaurentee that it is preserved across calls. + * Copy the string if you are not going to use it immediately. + */ + int status(int nodeId, + ndb_mgm_node_status * status, Uint32 * version, Uint32 * phase, bool * systemShutdown, Uint32 * dynamicId, Uint32 * nodeGroup, - Uint32 * connectCount); + Uint32 * connectCount, + const char **address); // All the functions below may return any of this error codes: // NO_CONTACT_WITH_PROCESS, PROCESS_NOT_CONFIGURED, WRONG_PROCESS_TYPE, // COULD_NOT_ALLOCATE_MEMORY, SEND_OR_RECEIVE_FAILED - - typedef void (* StopCallback)(int nodeId, void * anyData, int errorCode); - - typedef void (* VersionCallback)(int nodeId, int version, - void * anyData, int errorCode); - - - typedef void (* EnterSingleCallback)(int nodeId, void * anyData, - int errorCode); - typedef void (* ExitSingleCallback)(int nodeId, void * anyData, - int errorCode); - - /** - * Lock configuration - */ - int lockConf(); - - /** - * Unlock configuration, and commit it if commit is true - */ - int unlockConf(bool commit); - - /** - * Commit new configuration - */ - int commitConfig(); - - /** - * Rollback configuration - */ - int rollbackConfig(); - /** * Save a configuration to permanent storage */ @@ -273,12 +252,12 @@ public: * @param processId: Id of the DB process to stop * @return 0 if succeeded, otherwise: as stated above, plus: */ - int stopNode(int nodeId, bool abort = false, StopCallback = 0, void *any= 0); + int stopNode(int nodeId, bool abort = false); /** * Stop the system */ - int stop(int * cnt = 0, bool abort = false, StopCallback = 0, void *any = 0); + int stop(int * cnt = 0, bool abort = false); /** * print version info about a node @@ -286,27 +265,18 @@ public: * @param processId: Id of the DB process to stop * @return 0 if succeeded, otherwise: as stated above, plus: */ - int versionNode(int nodeId, bool abort = false, - VersionCallback = 0, void *any= 0); + int versionNode(int nodeId, Uint32 &version, const char **address); /** - * print version info about all node in the system - */ - int version(int * cnt = 0, bool abort = false, - VersionCallback = 0, void *any = 0); - - /** * Maintenance on the system */ - int enterSingleUser(int * cnt = 0, Uint32 singleuserNodeId = 0, - EnterSingleCallback = 0, void *any = 0); + int enterSingleUser(int * cnt = 0, Uint32 singleuserNodeId = 0); /** * Resume from maintenance on the system */ - int exitSingleUser(int * cnt = 0, bool abort = false, - ExitSingleCallback = 0, void *any = 0); + int exitSingleUser(int * cnt = 0, bool abort = false); /** * Start DB process. @@ -320,15 +290,14 @@ public: * @param processId: Id of the DB process to start */ int restartNode(int processId, bool nostart, bool initialStart, - bool abort = false, - StopCallback = 0, void * anyData = 0); + bool abort = false); /** * Restart the system */ int restart(bool nostart, bool initialStart, bool abort = false, - int * stopCount = 0, StopCallback = 0, void * anyData = 0); + int * stopCount = 0); struct BackupEvent { enum Event { @@ -483,13 +452,6 @@ public: const Config * getConfig() const; /** - * Change configuration paramter - */ - bool changeConfig(const BaseString §ion, - const BaseString ¶m, - const BaseString &value); - - /** * Returns the node count for the specified node type. * * @param type The node type. @@ -498,11 +460,6 @@ public: int getNodeCount(enum ndb_mgm_node_type type) const; /** - * Returns the nodeId of the management master - */ - NodeId getPrimaryNode() const; - - /** * Returns the port number. * @return port number. */ @@ -528,8 +485,17 @@ public: private: //************************************************************************** - int setEventReportingLevel(int processId, LogLevel::EventCategory, Uint32); - + int send(SignalSender &ss, SimpleSignal &ssig, Uint32 node, Uint32 node_type); + + int sendSTOP_REQ(NodeId nodeId, + NodeBitmask &stoppedNodes, + Uint32 singleUserNodeId, + bool abort, + bool stop, + bool restart, + bool nostart, + bool initialStart); + /** * Check if it is possible to send a signal to a (DB) process * @@ -593,9 +559,6 @@ private: // Returns: - //************************************************************************** - void handle_MGM_LOCK_CONFIG_REQ(NdbApiSignal *signal); - void handle_MGM_UNLOCK_CONFIG_REQ(NdbApiSignal *signal); - //************************************************************************** // Specific signal handling data //************************************************************************** @@ -619,59 +582,8 @@ private: enum WaitSignalType { NO_WAIT, // We don't expect to receive any signal WAIT_SET_VAR, // Accept SET_VAR_CONF and SET_VAR_REF - WAIT_SUBSCRIBE_CONF, // Accept event subscription confirmation - WAIT_STOP, - WAIT_BACKUP_STARTED, - WAIT_BACKUP_COMPLETED, - WAIT_VERSION, - WAIT_NODEFAILURE + WAIT_SUBSCRIBE_CONF // Accept event subscription confirmation }; - - /** - * Get an unused signal - * @return A signal if succeeded, NULL otherwise - */ - NdbApiSignal* getSignal(); - - /** - * Add a signal to the list of unused signals - * @param signal: The signal to add - */ - void releaseSignal(NdbApiSignal* signal); - - /** - * Remove a signal from the list of unused signals and delete - * the memory for it. - */ - void freeSignal(); - - /** - * Send a signal - * @param processId: Id of the receiver process - * @param waitState: State denoting a set of signals we accept to receive - * @param signal: The signal to send - * @return 0 if succeeded, -1 otherwise - */ - int sendSignal(Uint16 processId, WaitSignalType waitState, - NdbApiSignal* signal, bool force = false); - - /** - * Send a signal and wait for an answer signal - * @param processId: Id of the receiver process - * @param waitState: State denoting a set of signals we accept to receive. - * @param signal: The signal to send - * @return 0 if succeeded, -1 otherwise (for example failed to send or - * failed to receive expected signal). - */ - int sendRecSignal(Uint16 processId, WaitSignalType waitState, - NdbApiSignal* signal, bool force = false, - int waitTime = WAIT_FOR_RESPONSE_TIMEOUT); - - /** - * Wait for a signal to arrive. - * @return 0 if signal arrived, -1 otherwise - */ - int receiveOptimisedResponse(int waitTime); /** * This function is called from "outside" of MgmtSrvr @@ -682,7 +594,7 @@ private: static void signalReceivedNotification(void* mgmtSrvr, NdbApiSignal* signal, struct LinearSectionPtr ptr[3]); - + /** * Called from "outside" of MgmtSrvr when a DB process has died. * @param mgmtSrvr: The MgmtSrvr object wreceiveOptimisedResponsehich @@ -695,7 +607,7 @@ private: /** * An event from <i>nodeId</i> has arrived */ - void eventReport(NodeId nodeId, const Uint32 * theData); + void eventReport(const Uint32 * theData); //************************************************************************** @@ -719,31 +631,7 @@ private: class TransporterFacade * theFacade; - class SignalQueue m_signalRecvQueue; - - struct StopRecord { - StopRecord(){ inUse = false; callback = 0; singleUserMode = false;} - bool inUse; - bool singleUserMode; - int sentCount; - int reply; - int nodeId; - void * anyData; - StopCallback callback; - }; - StopRecord m_stopRec; - - struct VersionRecord { - VersionRecord(){ inUse = false; callback = 0;} - bool inUse; - Uint32 version[MAX_NODES]; - VersionCallback callback; - }; - VersionRecord m_versionRec; - int sendVersionReq( int processId); - - - void handleStopReply(NodeId nodeId, Uint32 errCode); + int sendVersionReq( int processId, Uint32 &version, const char **address); int translateStopRef(Uint32 errCode); bool _isStopThread; @@ -764,17 +652,8 @@ private: static void *logLevelThread_C(void *); void logLevelThreadRun(); - struct NdbThread *m_signalRecvThread; - static void *signalRecvThread_C(void *); - void signalRecvThreadRun(); - - void backupCallback(BackupEvent &); - BackupEvent m_lastBackupEvent; - Config *_props; - int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type); - ConfigRetriever *m_config_retriever; }; diff --git a/ndb/src/mgmsrv/MgmtSrvrConfig.cpp b/ndb/src/mgmsrv/MgmtSrvrConfig.cpp index 6c4b4e9ae3c..e56643a3d7e 100644 --- a/ndb/src/mgmsrv/MgmtSrvrConfig.cpp +++ b/ndb/src/mgmsrv/MgmtSrvrConfig.cpp @@ -23,228 +23,6 @@ #include <ConfigRetriever.hpp> #include <ndb_version.h> -void -MgmtSrvr::handle_MGM_LOCK_CONFIG_REQ(NdbApiSignal *signal) { - NodeId sender = refToNode(signal->theSendersBlockRef); - const MgmLockConfigReq * const req = CAST_CONSTPTR(MgmLockConfigReq, signal->getDataPtr()); - - NdbApiSignal *reply = getSignal(); - if(signal == NULL) - return; /** @todo handle allocation failure */ - - reply->set(TestOrd::TraceAPI, - MGMSRV, - GSN_MGM_LOCK_CONFIG_REP, - MgmLockConfigRep::SignalLength); - - MgmLockConfigRep *lockRep = CAST_PTR(MgmLockConfigRep, reply->getDataPtrSend()); - - lockRep->errorCode = MgmLockConfigRep::UNKNOWN_ERROR; - - if(req->newConfigGeneration < m_nextConfigGenerationNumber) { - lockRep->errorCode = MgmLockConfigRep::GENERATION_MISMATCH; - goto done; - } - NdbMutex_Lock(m_configMutex); - - m_nextConfigGenerationNumber = req->newConfigGeneration+1; - - lockRep->errorCode = MgmLockConfigRep::OK; - - done: - sendSignal(sender, NO_WAIT, reply, true); - NdbMutex_Unlock(m_configMutex); - return; -} - -void -MgmtSrvr::handle_MGM_UNLOCK_CONFIG_REQ(NdbApiSignal *signal) { - NodeId sender = refToNode(signal->theSendersBlockRef); - const MgmUnlockConfigReq * const req = CAST_CONSTPTR(MgmUnlockConfigReq, signal->getDataPtr()); - MgmUnlockConfigRep *unlockRep; - - NdbApiSignal *reply = getSignal(); - if(signal == NULL) - goto error; /** @todo handle allocation failure */ - - reply->set(TestOrd::TraceAPI, - MGMSRV, - GSN_MGM_UNLOCK_CONFIG_REP, - MgmUnlockConfigRep::SignalLength); - - unlockRep = CAST_PTR(MgmUnlockConfigRep, reply->getDataPtrSend()); - - unlockRep->errorCode = MgmUnlockConfigRep::UNKNOWN_ERROR; - - - NdbMutex_Lock(m_configMutex); - - if(req->commitConfig == 1) { - m_newConfig = fetchConfig(); - commitConfig(); - } else - rollbackConfig(); - - unlockRep->errorCode = MgmUnlockConfigRep::OK; - - sendSignal(sender, NO_WAIT, reply, true); - error: - NdbMutex_Unlock(m_configMutex); - return; -} - - -/** - * Prepare all MGM nodes for configuration changes - * - * @returns 0 on success, or -1 on failure - */ -int -MgmtSrvr::lockConf() { - int result = -1; - MgmLockConfigReq* lockReq; - NodeId node = 0; - - /* Check if this is the master node */ - if(getPrimaryNode() != _ownNodeId) - goto done; - - if(NdbMutex_Trylock(m_configMutex) != 0) - return -1; - - m_newConfig = new Config(*_config); /* copy the existing config */ - _config = m_newConfig; - - m_newConfig = new Config(*_config); - - m_nextConfigGenerationNumber++; - - /* Make sure the new configuration _always_ is at least one step older */ - if(m_nextConfigGenerationNumber < m_newConfig->getGenerationNumber()+1) - m_nextConfigGenerationNumber = _config->getGenerationNumber()+1; - - m_newConfig->setGenerationNumber(m_nextConfigGenerationNumber); - - node = 0; - while(getNextNodeId(&node, NDB_MGM_NODE_TYPE_MGM)) { - if(node != _ownNodeId) { - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - result = COULD_NOT_ALLOCATE_MEMORY; - goto done; - } - - lockReq = CAST_PTR(MgmLockConfigReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, - MGMSRV, - GSN_MGM_LOCK_CONFIG_REQ, - MgmLockConfigReq::SignalLength); - - lockReq->newConfigGeneration = m_nextConfigGenerationNumber; - - result = sendSignal(node, NO_WAIT, signal, true); - - NdbApiSignal *reply = - m_signalRecvQueue.waitFor(GSN_MGM_LOCK_CONFIG_REP, 0); - - if(reply == NULL) { - /** @todo handle timeout/error */ - ndbout << __FILE__ << ":" << __LINE__ << endl; - result = -1; - goto done; - } - - } - } - - done: - NdbMutex_Unlock(m_configMutex); - return result; -} - -/** - * Unlocks configuration - * - * @returns 0 on success, ! 0 on error - */ -int -MgmtSrvr::unlockConf(bool commit) { - int result = -1; - MgmUnlockConfigReq* unlockReq; - NodeId node = 0; - - /* Check if this is the master node */ - if(getPrimaryNode() != _ownNodeId) - goto done; - - errno = 0; - if(NdbMutex_Lock(m_configMutex) != 0) - return -1; - - if(commit) - commitConfig(); - else - rollbackConfig(); - - node = 0; - while(getNextNodeId(&node, NDB_MGM_NODE_TYPE_MGM)) { - if(node != _ownNodeId) { - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - result = COULD_NOT_ALLOCATE_MEMORY; - goto done; - } - - unlockReq = CAST_PTR(MgmUnlockConfigReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, - MGMSRV, - GSN_MGM_UNLOCK_CONFIG_REQ, - MgmUnlockConfigReq::SignalLength); - unlockReq->commitConfig = commit; - - result = sendSignal(node, NO_WAIT, signal, true); - - NdbApiSignal *reply = - m_signalRecvQueue.waitFor(GSN_MGM_UNLOCK_CONFIG_REP, 0); - - if(reply == NULL) { - /** @todo handle timeout/error */ - result = -1; - goto done; - } - - } - } - - done: - NdbMutex_Unlock(m_configMutex); - return result; -} - -/** - * Commit the new configuration - */ -int -MgmtSrvr::commitConfig() { - int ret = saveConfig(m_newConfig); - delete _config; - _config = m_newConfig; - m_newConfig = NULL; - ndbout << "commit " << ret << endl; - return ret; -} - -/** - * Rollback to the old configuration - */ -int -MgmtSrvr::rollbackConfig() { - delete m_newConfig; - m_newConfig = NULL; - ndbout << "rollback" << endl; - return saveConfig(_config); -} - /** * Save a configuration to the running configuration file */ @@ -274,7 +52,15 @@ Config * MgmtSrvr::readConfig() { Config *conf; InitConfigFileParser parser; - conf = parser.parseConfig(m_configFilename.c_str()); + if (m_configFilename.length()) + { + conf = parser.parseConfig(m_configFilename.c_str()); + } + else + { + ndbout_c("Reading cluster configuration using my.cnf"); + conf = parser.parse_mycnf(); + } return conf; } @@ -288,12 +74,3 @@ MgmtSrvr::fetchConfig() { } return 0; } - -bool -MgmtSrvr::changeConfig(const BaseString §ion, - const BaseString ¶m, - const BaseString &value) { - if(m_newConfig == NULL) - return false; - return m_newConfig->change(section, param, value); -} diff --git a/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp b/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp index f93948abc75..c99936e1861 100644 --- a/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp +++ b/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp @@ -20,123 +20,3 @@ // Some kind of reuse should be preferred. //****************************************************************************** -#include "MgmtSrvr.hpp" -#include <NdbApiSignal.hpp> -#include <NdbTick.h> - - -NdbApiSignal* -MgmtSrvr::getSignal() -{ - NdbApiSignal* tSignal; - tSignal = theSignalIdleList; - if (tSignal != NULL){ - NdbApiSignal* tSignalNext = tSignal->next(); - tSignal->next(NULL); - theSignalIdleList = tSignalNext; - return tSignal; - } else - { - tSignal = new NdbApiSignal(_ownReference); - if (tSignal != NULL) - tSignal->next(NULL); - } - return tSignal; -} - - -void -MgmtSrvr::releaseSignal(NdbApiSignal* aSignal) -{ - aSignal->next(theSignalIdleList); - theSignalIdleList = aSignal; -} - - -void -MgmtSrvr::freeSignal() -{ - NdbApiSignal* tSignal = theSignalIdleList; - theSignalIdleList = tSignal->next(); - delete tSignal; -} - - -int -MgmtSrvr::sendSignal(Uint16 aNodeId, - WaitSignalType aWaitState, - NdbApiSignal* aSignal, - bool force) -{ - int tReturnCode; - theFacade->lock_mutex(); - if(force){ - tReturnCode = theFacade->sendSignalUnCond(aSignal, - aNodeId); - } else { - tReturnCode = theFacade->sendSignal(aSignal, - aNodeId); - } - releaseSignal(aSignal); - if (tReturnCode == -1) { - theFacade->unlock_mutex(); - return -1; - } - theWaitState = aWaitState; - theFacade->unlock_mutex(); - return 0; -} - - -int -MgmtSrvr::sendRecSignal(Uint16 aNodeId, - WaitSignalType aWaitState, - NdbApiSignal* aSignal, - bool force, - int waitTime) -{ - int tReturnCode; - theFacade->lock_mutex(); - if(force){ - tReturnCode = theFacade->sendSignalUnCond(aSignal, aNodeId); - } else { - tReturnCode = theFacade->sendSignalUnCond(aSignal, aNodeId); - } - releaseSignal(aSignal); - if (tReturnCode == -1) { - theFacade->unlock_mutex(); - return -1; - } - theWaitState = aWaitState; - theWaitNode = aNodeId; - return receiveOptimisedResponse(waitTime); -} - - -int -MgmtSrvr::receiveOptimisedResponse(int waitTime) -{ - int tResultCode; - theFacade->checkForceSend(_blockNumber); - NDB_TICKS maxTime = NdbTick_CurrentMillisecond() + waitTime; - - while (theWaitState != NO_WAIT && theWaitState != WAIT_NODEFAILURE - && waitTime > 0) { - NdbCondition_WaitTimeout(theMgmtWaitForResponseCondPtr, - theFacade->theMutexPtr, - waitTime); - if(theWaitState == NO_WAIT || theWaitState == WAIT_NODEFAILURE) - break; - waitTime = (maxTime - NdbTick_CurrentMillisecond()); - }//while - - if(theWaitState == NO_WAIT) { - tResultCode = 0; - } else { - tResultCode = -1; - } - theFacade->unlock_mutex(); - return tResultCode; -} - - diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index 270d7f716dd..b94eaa93ea5 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -182,12 +182,6 @@ ParserRow<MgmApiSession> commands[] = { MGM_CMD("abort backup", &MgmApiSession::abortBackup, ""), MGM_ARG("id", Int, Mandatory, "Backup id"), - /** - * Global Replication - */ - MGM_CMD("rep", &MgmApiSession::repCommand, ""), - MGM_ARG("request", Int, Mandatory, "Command"), - MGM_CMD("stop", &MgmApiSession::stop, ""), MGM_ARG("node", String, Mandatory, "Node"), MGM_ARG("abort", Int, Mandatory, "Node"), @@ -222,21 +216,6 @@ ParserRow<MgmApiSession> commands[] = { MGM_ARG("level", Int, Mandatory, "Severety level"), MGM_ARG("enable", Int, Mandatory, "1=disable, 0=enable, -1=toggle"), - MGM_CMD("config lock", &MgmApiSession::configLock, ""), - - MGM_CMD("config unlock", &MgmApiSession::configUnlock, ""), - MGM_ARG("commit", Int, Mandatory, "Commit changes"), - - MGM_CMD("config change", &MgmApiSession::configChange, ""), - MGM_ARG("section", String, Mandatory, "Section"), - MGM_ARG("parameter", String, Mandatory, "Parameter"), - MGM_ARG("value", String, Mandatory, "Value"), - - MGM_CMD("config lock", &MgmApiSession::configLock, ""), - - MGM_CMD("config unlock", &MgmApiSession::configUnlock, ""), - MGM_ARG("commit", Int, Mandatory, "Commit changes"), - MGM_CMD("set parameter", &MgmApiSession::setParameter, ""), MGM_ARG("node", String, Mandatory, "Node"), MGM_ARG("parameter", String, Mandatory, "Parameter"), @@ -268,6 +247,10 @@ ParserRow<MgmApiSession> commands[] = { MGM_CMD("get mgmd nodeid", &MgmApiSession::get_mgmd_nodeid, ""), + MGM_CMD("report event", &MgmApiSession::report_event, ""), + MGM_ARG("length", Int, Mandatory, "Length"), + MGM_ARG("data", String, Mandatory, "Data"), + MGM_END() }; @@ -362,8 +345,6 @@ MgmApiSession::getConfig_old(Parser_t::Context &ctx) { } #endif /* MGM_GET_CONFIG_BACKWARDS_COMPAT */ -inline void require(bool b){ if(!b) abort(); } - void MgmApiSession::getConfig(Parser_t::Context &ctx, const class Properties &args) { @@ -713,30 +694,6 @@ MgmApiSession::abortBackup(Parser<MgmApiSession>::Context &, m_output->println(""); } -/***************************************************************************** - * Global Replication - *****************************************************************************/ - -void -MgmApiSession::repCommand(Parser<MgmApiSession>::Context &, - Properties const &args) { - - Uint32 request = 0; - args.get("request", &request); - - Uint32 repReqId; - int result = m_mgmsrv.repCommand(&repReqId, request, true); - - m_output->println("global replication reply"); - if(result != 0) - m_output->println("result: %s", get_error_text(result)); - else{ - m_output->println("result: Ok"); - m_output->println("id: %d", repReqId); - } - m_output->println(""); -} - /*****************************************************************************/ void @@ -942,8 +899,10 @@ printNodeStatus(OutputStream *output, nodeGroup = 0, connectCount = 0; bool system; - mgmsrv.status(nodeId, &status, &version, &startPhase, - &system, &dynamicId, &nodeGroup, &connectCount); + const char *address= NULL; + mgmsrv.status(nodeId, &status, &version, &startPhase, + &system, &dynamicId, &nodeGroup, &connectCount, + &address); output->println("node.%d.type: %s", nodeId, ndb_mgm_get_node_type_string(type)); @@ -955,7 +914,7 @@ printNodeStatus(OutputStream *output, output->println("node.%d.dynamic_id: %d", nodeId, dynamicId); output->println("node.%d.node_group: %d", nodeId, nodeGroup); output->println("node.%d.connect_count: %d", nodeId, connectCount); - output->println("node.%d.address: %s", nodeId, mgmsrv.get_connect_address(nodeId)); + output->println("node.%d.address: %s", nodeId, address ? address : ""); } } @@ -1224,42 +1183,6 @@ MgmApiSession::setLogFilter(Parser_t::Context &ctx, m_output->println(""); } -void -MgmApiSession::configLock(Parser_t::Context &, - Properties const &) { - int ret = m_mgmsrv.lockConf(); - m_output->println("config lock reply"); - m_output->println("result: %d", ret); - m_output->println(""); -} - -void -MgmApiSession::configUnlock(Parser_t::Context &, - Properties const &args) { - Uint32 commit; - args.get("commit", &commit); - int ret = m_mgmsrv.unlockConf(commit == 1); - m_output->println("config unlock reply"); - m_output->println("result: %d", ret); - m_output->println(""); -} - -void -MgmApiSession::configChange(Parser_t::Context &, - Properties const &args) { - BaseString section, param, value; - args.get("section", section); - args.get("parameter", param); - args.get("value", value); - - int ret = m_mgmsrv.changeConfig(section.c_str(), - param.c_str(), - value.c_str()); - m_output->println("config change reply"); - m_output->println("result: %d", ret); - m_output->println(""); -} - static NdbOut& operator<<(NdbOut& out, const LogLevel & ll) { @@ -1624,5 +1547,30 @@ MgmApiSession::get_mgmd_nodeid(Parser_t::Context &ctx, m_output->println(""); } +void +MgmApiSession::report_event(Parser_t::Context &ctx, + Properties const &args) +{ + Uint32 length; + const char *data_string; + Uint32 data[25]; + + args.get("length", &length); + args.get("data", &data_string); + + BaseString tmp(data_string); + Vector<BaseString> item; + tmp.split(item, " "); + for (int i = 0; i < length ; i++) + { + sscanf(item[i].c_str(), "%u", data+i); + } + + m_mgmsrv.eventReport(data); + m_output->println("report event reply"); + m_output->println("result: ok"); + m_output->println(""); +} + template class MutexVector<int>; template class Vector<ParserRow<MgmApiSession> const*>; diff --git a/ndb/src/mgmsrv/Services.hpp b/ndb/src/mgmsrv/Services.hpp index ff9008b05a8..30f220cd060 100644 --- a/ndb/src/mgmsrv/Services.hpp +++ b/ndb/src/mgmsrv/Services.hpp @@ -83,9 +83,6 @@ public: void setClusterLogLevel(Parser_t::Context &ctx, const class Properties &args); void setLogFilter(Parser_t::Context &ctx, const class Properties &args); - void configLock(Parser_t::Context &ctx, const class Properties &args); - void configUnlock(Parser_t::Context &ctx, const class Properties &args); - void configChange(Parser_t::Context &ctx, const class Properties &args); void setParameter(Parser_t::Context &ctx, const class Properties &args); void setConnectionParameter(Parser_t::Context &ctx, @@ -101,8 +98,8 @@ public: void transporter_connect(Parser_t::Context &ctx, Properties const &args); void get_mgmd_nodeid(Parser_t::Context &ctx, Properties const &args); - - void repCommand(Parser_t::Context &ctx, const class Properties &args); + + void report_event(Parser_t::Context &ctx, Properties const &args); }; class MgmApiService : public SocketServer::Service { diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index ec20101493e..f0c2ac298a5 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -102,6 +102,7 @@ static int opt_daemon; // NOT bool, bool need not be int static int opt_non_interactive; static int opt_interactive; static const char * opt_config_filename= 0; +static int opt_mycnf = 0; struct MgmGlobals { MgmGlobals(); @@ -166,6 +167,10 @@ static struct my_option my_long_options[] = "Don't run as daemon, but don't read from stdin", (gptr*) &opt_non_interactive, (gptr*) &opt_non_interactive, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "mycnf", 256, + "Read cluster config from my.cnf", + (gptr*) &opt_mycnf, (gptr*) &opt_mycnf, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -199,7 +204,7 @@ int main(int argc, char** argv) #endif global_mgmt_server_check = 1; - + const char *load_default_groups[]= { "mysql_cluster","ndb_mgmd",0 }; load_defaults("my",load_default_groups,&argc,&argv); @@ -217,13 +222,26 @@ int main(int argc, char** argv) opt_daemon= 0; } + if (opt_mycnf && opt_config_filename) + { + ndbout_c("Both --mycnf and -f is not supported"); + return 0; + } + + if (opt_mycnf == 0 && opt_config_filename == 0) + { + struct stat buf; + if (stat("config.ini", &buf) != -1) + opt_config_filename = "config.ini"; + } + glob->socketServer = new SocketServer(); MgmApiService * mapi = new MgmApiService(); glob->mgmObject = new MgmtSrvr(glob->socketServer, - opt_config_filename, - opt_connect_str); + opt_config_filename, + opt_connect_str); if (g_print_full_config) goto the_end; diff --git a/ndb/src/ndbapi/Makefile.am b/ndb/src/ndbapi/Makefile.am index b734e058b87..99b75ffbd53 100644 --- a/ndb/src/ndbapi/Makefile.am +++ b/ndb/src/ndbapi/Makefile.am @@ -34,7 +34,8 @@ libndbapi_la_SOURCES = \ NdbDictionaryImpl.cpp \ DictCache.cpp \ ndb_cluster_connection.cpp \ - NdbBlob.cpp + NdbBlob.cpp \ + SignalSender.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi diff --git a/ndb/src/ndbapi/NdbApiSignal.cpp b/ndb/src/ndbapi/NdbApiSignal.cpp index b1671e593e1..94695185224 100644 --- a/ndb/src/ndbapi/NdbApiSignal.cpp +++ b/ndb/src/ndbapi/NdbApiSignal.cpp @@ -62,6 +62,25 @@ NdbApiSignal::NdbApiSignal(BlockReference ref) theNextSignal = 0; } +NdbApiSignal::NdbApiSignal(Ndb* ndb) +{ + BlockReference ref = ndb->theMyRef; + theVerId_signalNumber = 0; // 4 bit ver id - 16 bit gsn + theReceiversBlockNumber = 0; // Only 16 bit blocknum + theSendersBlockRef = refToBlock(ref); + theLength = 0; + theSendersSignalId = 0; + theSignalId = 0; + theTrace = 0; + m_noOfSections = 0; + m_fragmentInfo = 0; + for (int i = 0; i < 25; i++) + theData[i] = 0x13579753; + + setDataPtr(&theData[0]); + theNextSignal = 0; +} + /** * Copy constructor */ diff --git a/ndb/src/ndbapi/NdbApiSignal.hpp b/ndb/src/ndbapi/NdbApiSignal.hpp index 353c575d420..9d04a8594a8 100644 --- a/ndb/src/ndbapi/NdbApiSignal.hpp +++ b/ndb/src/ndbapi/NdbApiSignal.hpp @@ -46,7 +46,8 @@ class NdbApiSignal : public SignalHeader { public: - NdbApiSignal(BlockReference myRef); + NdbApiSignal(Ndb* ndb); + NdbApiSignal(BlockReference ref); NdbApiSignal(const NdbApiSignal &); NdbApiSignal(const SignalHeader &header) : SignalHeader(header), theNextSignal(0), theRealData(0) {}; diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp index d06d6b4ef4d..d1aa4e61c40 100644 --- a/ndb/src/ndbapi/NdbBlob.cpp +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -111,7 +111,7 @@ NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnIm // initialization -NdbBlob::NdbBlob() +NdbBlob::NdbBlob(Ndb*) { init(); } diff --git a/ndb/src/ndbapi/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp index d73b8afe10c..d50f1fa84fe 100644 --- a/ndb/src/ndbapi/NdbImpl.hpp +++ b/ndb/src/ndbapi/NdbImpl.hpp @@ -32,6 +32,21 @@ #include "NdbDictionaryImpl.hpp" #include "ObjectMap.hpp" +template <class T> +struct Ndb_free_list_t +{ + Ndb_free_list_t(); + ~Ndb_free_list_t(); + + void fill(Ndb*, Uint32 cnt); + T* seize(Ndb*); + void release(T*); + void clear(); + Uint32 get_sizeof() const { return sizeof(T); } + T * m_free_list; + Uint32 m_alloc_cnt, m_free_cnt; +}; + /** * Private parts of the Ndb object (corresponding to Ndb.hpp in public API) */ @@ -60,7 +75,6 @@ public: int m_optimized_node_selection; - BaseString m_dbname; // Database name BaseString m_schemaname; // Schema name @@ -72,6 +86,22 @@ public: m_schemaname.c_str(), table_name_separator); } + /** + * NOTE free lists must be _after_ theNdbObjectIdMap take + * assure that destructors are run in correct order + */ + Ndb_free_list_t<NdbTransaction> theConIdleList; + Ndb_free_list_t<NdbOperation> theOpIdleList; + Ndb_free_list_t<NdbIndexScanOperation> theScanOpIdleList; + Ndb_free_list_t<NdbIndexOperation> theIndexOpIdleList; + Ndb_free_list_t<NdbRecAttr> theRecAttrIdleList; + Ndb_free_list_t<NdbApiSignal> theSignalIdleList; + Ndb_free_list_t<NdbLabel> theLabelList; + Ndb_free_list_t<NdbBranch> theBranchList; + Ndb_free_list_t<NdbSubroutine> theSubroutineList; + Ndb_free_list_t<NdbCall> theCallList; + Ndb_free_list_t<NdbBlob> theNdbBlobIdleList; + Ndb_free_list_t<NdbReceiver> theScanList; }; #ifdef VM_TRACE @@ -146,4 +176,91 @@ enum LockMode { Delete }; +template<class T> +inline +Ndb_free_list_t<T>::Ndb_free_list_t() +{ + m_free_list= 0; + m_alloc_cnt= m_free_cnt= 0; +} + +template<class T> +inline +Ndb_free_list_t<T>::~Ndb_free_list_t() +{ + clear(); +} + +template<class T> +inline +void +Ndb_free_list_t<T>::fill(Ndb* ndb, Uint32 cnt) +{ + if (m_free_list == 0) + { + m_free_cnt++; + m_alloc_cnt++; + m_free_list = new T(ndb); + } + while(m_alloc_cnt < cnt) + { + T* obj= new T(ndb); + if(obj == 0) + return; + + obj->next(m_free_list); + m_free_cnt++; + m_alloc_cnt++; + m_free_list = obj; + } +} + +template<class T> +inline +T* +Ndb_free_list_t<T>::seize(Ndb* ndb) +{ + T* tmp = m_free_list; + if (tmp) + { + m_free_list = (T*)tmp->next(); + tmp->next(NULL); + m_free_cnt--; + return tmp; + } + + if((tmp = new T(ndb))) + { + m_alloc_cnt++; + } + + return tmp; +} + +template<class T> +inline +void +Ndb_free_list_t<T>::release(T* obj) +{ + obj->next(m_free_list); + m_free_list = obj; + m_free_cnt++; +} + + +template<class T> +inline +void +Ndb_free_list_t<T>::clear() +{ + T* obj = m_free_list; + while(obj) + { + T* curr = obj; + obj = (T*)obj->next(); + delete curr; + m_alloc_cnt--; + } +} + #endif diff --git a/ndb/src/ndbapi/NdbRecAttr.cpp b/ndb/src/ndbapi/NdbRecAttr.cpp index 5e5306fc33a..2245707bf65 100644 --- a/ndb/src/ndbapi/NdbRecAttr.cpp +++ b/ndb/src/ndbapi/NdbRecAttr.cpp @@ -22,7 +22,7 @@ #include "NdbDictionaryImpl.hpp" #include <NdbTCP.h> -NdbRecAttr::NdbRecAttr() +NdbRecAttr::NdbRecAttr(Ndb*) { init(); } @@ -98,7 +98,7 @@ NdbRecAttr::copyout() NdbRecAttr * NdbRecAttr::clone() const { - NdbRecAttr * ret = new NdbRecAttr(); + NdbRecAttr * ret = new NdbRecAttr(0); ret->theAttrId = theAttrId; ret->theNULLind = theNULLind; @@ -233,6 +233,13 @@ NdbOut& operator<<(NdbOut& out, const NdbRecAttr &r) j = length; } break; + case NdbDictionary::Column::Varbinary: + { + unsigned len = *(const unsigned char*)r.aRef(); + ndbrecattr_print_string(out,"Varbinary", r.aRef()+1,len); + j = length; + } + break; case NdbDictionary::Column::Float: out << r.float_value(); break; diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp index 675c9383c6e..294012d780c 100644 --- a/ndb/src/ndbapi/NdbTransaction.cpp +++ b/ndb/src/ndbapi/NdbTransaction.cpp @@ -264,6 +264,7 @@ NdbTransaction::execute(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { + NdbError savedError= theError; DBUG_ENTER("NdbTransaction::execute"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); @@ -293,7 +294,11 @@ NdbTransaction::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tPrepOp->theBlobList; while (tBlob != NULL) { if (tBlob->preExecute(tExecType, batch) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } if (batch) { @@ -322,7 +327,11 @@ NdbTransaction::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tOp->theBlobList; while (tBlob != NULL) { if (tBlob->preCommit() == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -344,7 +353,12 @@ NdbTransaction::execute(ExecType aTypeOfExec, } if (executeNoBlobs(tExecType, abortOption, forceSend) == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } + #ifdef ndb_api_crash_on_complex_blob_abort assert(theFirstOpInList == NULL && theLastOpInList == NULL); #else @@ -359,7 +373,11 @@ NdbTransaction::execute(ExecType aTypeOfExec, while (tBlob != NULL) { // may add new operations if batch if (tBlob->postExecute(tExecType) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -390,6 +408,10 @@ NdbTransaction::execute(ExecType aTypeOfExec, ndbout << "completed ops: " << n << endl; } #endif + + if(savedError.code!=0 && theError.code==4350) // Trans already aborted + theError= savedError; + DBUG_RETURN(ret); } diff --git a/ndb/src/ndbapi/NdbUtil.cpp b/ndb/src/ndbapi/NdbUtil.cpp index 5c74d251ff9..6019ea675a1 100644 --- a/ndb/src/ndbapi/NdbUtil.cpp +++ b/ndb/src/ndbapi/NdbUtil.cpp @@ -30,8 +30,7 @@ Comment: #include "NdbUtil.hpp" -NdbLabel::NdbLabel() : - theNext(NULL) +NdbLabel::NdbLabel(Ndb*) { } @@ -39,8 +38,7 @@ NdbLabel::~NdbLabel() { } -NdbSubroutine::NdbSubroutine() : - theNext(NULL) +NdbSubroutine::NdbSubroutine(Ndb*) { } @@ -48,9 +46,8 @@ NdbSubroutine::~NdbSubroutine() { } -NdbBranch::NdbBranch() : - theSignal(NULL), - theNext(NULL) +NdbBranch::NdbBranch(Ndb*) : + theSignal(NULL) { } @@ -58,9 +55,8 @@ NdbBranch::~NdbBranch() { } -NdbCall::NdbCall() : - theSignal(NULL), - theNext(NULL) +NdbCall::NdbCall(Ndb*) : + theSignal(NULL) { } diff --git a/ndb/src/ndbapi/NdbUtil.hpp b/ndb/src/ndbapi/NdbUtil.hpp index 80fc15ddd8c..268f6c69e6f 100644 --- a/ndb/src/ndbapi/NdbUtil.hpp +++ b/ndb/src/ndbapi/NdbUtil.hpp @@ -31,44 +31,53 @@ Comment: #include <ndb_global.h> +class Ndb; class NdbApiSignal; class NdbOperation; -class NdbLabel +template<class T> +struct Free_list_element +{ + Free_list_element() { theNext = 0;} + void next(T* obj) { theNext = obj;} + T* next() { return theNext;} + + T* theNext; +}; + +class NdbLabel : public Free_list_element<NdbLabel> { friend class NdbOperation; friend class Ndb; - -private: - NdbLabel(); +public: + NdbLabel(Ndb*); ~NdbLabel(); - NdbLabel* theNext; +private: Uint32 theSubroutine[16]; Uint32 theLabelAddress[16]; Uint32 theLabelNo[16]; }; -class NdbSubroutine +class NdbSubroutine : public Free_list_element<NdbSubroutine> { friend class NdbOperation; friend class Ndb; -private: - NdbSubroutine(); +public: + NdbSubroutine(Ndb*); ~NdbSubroutine(); - NdbSubroutine* theNext; Uint32 theSubroutineAddress[16]; }; -class NdbBranch +class NdbBranch : public Free_list_element<NdbBranch> { friend class NdbOperation; friend class Ndb; -private: - NdbBranch(); +public: + NdbBranch(Ndb*); ~NdbBranch(); NdbApiSignal* theSignal; @@ -76,22 +85,20 @@ private: Uint32 theBranchAddress; Uint32 theBranchLabel; Uint32 theSubroutine; - NdbBranch* theNext; }; -class NdbCall +class NdbCall : public Free_list_element<NdbCall> { friend class NdbOperation; friend class Ndb; -private: - NdbCall(); +public: + NdbCall(Ndb*); ~NdbCall(); NdbApiSignal* theSignal; Uint32 theSignalAddress; Uint32 theSubroutine; - NdbCall* theNext; }; #endif diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index fee6f0930ad..bfbf98d1b3a 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -141,15 +141,6 @@ Ndb::init(int aMaxNoOfTransactions) error_handler: ndbout << "error_handler" << endl; releaseTransactionArrays(); - while ( theConIdleList != NULL ) - freeNdbCon(); - while ( theSignalIdleList != NULL ) - freeSignal(); - while (theRecAttrIdleList != NULL) - freeRecAttr(); - while (theOpIdleList != NULL) - freeOperation(); - delete theDictionary; TransporterFacade::instance()->close(theNdbBlockNumber, 0); DBUG_RETURN(-1); diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index bbc1474f45d..d4ab30aec4e 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -29,6 +29,10 @@ #include <NdbOut.hpp> #include <NdbSleep.h> #include "ObjectMap.hpp" +#include <NdbIndexScanOperation.hpp> +#include <NdbIndexOperation.hpp> +#include "NdbUtil.hpp" +#include <NdbBlob.hpp> class NdbGlobalEventBufferHandle; NdbGlobalEventBufferHandle *NdbGlobalEventBuffer_init(int); @@ -62,20 +66,8 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, theRemainingStartTransactions= 0; theMaxNoOfTransactions= 0; theMinNoOfEventsToWakeUp= 0; - theConIdleList= NULL; - theOpIdleList= NULL; - theScanOpIdleList= NULL; - theIndexOpIdleList= NULL; theTransactionList= NULL; theConnectionArray= NULL; - theRecAttrIdleList= NULL; - theSignalIdleList= NULL; - theLabelList= NULL; - theBranchList= NULL; - theSubroutineList= NULL; - theCallList= NULL; - theScanList= NULL; - theNdbBlobIdleList= NULL; the_last_check_time= 0; theFirstTransId= 0; theRestartGCI= 0; @@ -150,33 +142,6 @@ Ndb::~Ndb() TransporterFacade::instance()->close(theNdbBlockNumber, theFirstTransId); } -// if (theSchemaConToNdbList != NULL) -// closeSchemaTransaction(theSchemaConToNdbList); - while ( theConIdleList != NULL ) - freeNdbCon(); - while (theOpIdleList != NULL) - freeOperation(); - while (theScanOpIdleList != NULL) - freeScanOperation(); - while (theIndexOpIdleList != NULL) - freeIndexOperation(); - while (theLabelList != NULL) - freeNdbLabel(); - while (theBranchList != NULL) - freeNdbBranch(); - while (theSubroutineList != NULL) - freeNdbSubroutine(); - while (theCallList != NULL) - freeNdbCall(); - while (theScanList != NULL) - freeNdbScanRec(); - while (theNdbBlobIdleList != NULL) - freeNdbBlob(); - while (theRecAttrIdleList != NULL) - freeRecAttr(); - while ( theSignalIdleList != NULL ) - freeSignal(); - releaseTransactionArrays(); delete []theConnectionArray; @@ -229,7 +194,8 @@ NdbImpl::NdbImpl(Ndb_cluster_connection *ndb_cluster_connection, : m_ndb_cluster_connection(ndb_cluster_connection->m_impl), m_dictionary(ndb), theCurrentConnectIndex(0), - theNdbObjectIdMap(1024,1024), + theNdbObjectIdMap(ndb_cluster_connection->m_impl.m_transporter_facade->theMutexPtr, + 1024,1024), theNoOfDBnodes(0) { int i; diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp index 96d0f4d7de5..f82348fc91d 100644 --- a/ndb/src/ndbapi/Ndblist.cpp +++ b/ndb/src/ndbapi/Ndblist.cpp @@ -75,24 +75,7 @@ Ndb::checkFailedNode() int Ndb::createConIdleList(int aNrOfCon) { - for (int i = 0; i < aNrOfCon; i++) - { - NdbTransaction* tNdbCon = new NdbTransaction(this); - if (tNdbCon == NULL) - { - return -1; - } - if (theConIdleList == NULL) - { - theConIdleList = tNdbCon; - theConIdleList->next(NULL); - } else - { - tNdbCon->next(theConIdleList); - theConIdleList = tNdbCon; - } - tNdbCon->Status(NdbTransaction::NotConnected); - } + theImpl->theConIdleList.fill(this, aNrOfCon); return aNrOfCon; } @@ -108,19 +91,7 @@ Ndb::createConIdleList(int aNrOfCon) int Ndb::createOpIdleList(int aNrOfOp) { - for (int i = 0; i < aNrOfOp; i++){ - NdbOperation* tOp = new NdbOperation(this); - if ( tOp == NULL ){ - return -1; - } - if (theOpIdleList == NULL){ - theOpIdleList = tOp; - theOpIdleList->next(NULL); - } else{ - tOp->next(theOpIdleList); - theOpIdleList = tOp; - } - } + theImpl->theOpIdleList.fill(this, aNrOfOp); return aNrOfOp; } @@ -134,22 +105,7 @@ Ndb::createOpIdleList(int aNrOfOp) NdbBranch* Ndb::getNdbBranch() { - NdbBranch* tNdbBranch; - if ( theBranchList == NULL ) - { - tNdbBranch = new NdbBranch; - if (tNdbBranch == NULL) - { - return NULL; - } - tNdbBranch->theNext = NULL; - } else - { - tNdbBranch = theBranchList; - theBranchList = tNdbBranch->theNext; - tNdbBranch->theNext = NULL; - } - return tNdbBranch; + return theImpl->theBranchList.seize(this); } /*************************************************************************** @@ -162,22 +118,7 @@ Ndb::getNdbBranch() NdbCall* Ndb::getNdbCall() { - NdbCall* tNdbCall; - if ( theCallList == NULL ) - { - tNdbCall = new NdbCall; - if (tNdbCall == NULL) - { - return NULL; - } - tNdbCall->theNext = NULL; - } else - { - tNdbCall = theCallList; - theCallList = tNdbCall->theNext; - tNdbCall->theNext = NULL; - } - return tNdbCall; + return theImpl->theCallList.seize(this); } /*************************************************************************** @@ -190,19 +131,7 @@ Ndb::getNdbCall() NdbTransaction* Ndb::getNdbCon() { - NdbTransaction* tNdbCon; - if ( theConIdleList == NULL ) { - tNdbCon = new NdbTransaction(this); - if (tNdbCon == NULL) { - return NULL; - }//if - tNdbCon->next(NULL); - } else - { - tNdbCon = theConIdleList; - theConIdleList = tNdbCon->next(); - tNdbCon->next(NULL); - } + NdbTransaction* tNdbCon = theImpl->theConIdleList.seize(this); tNdbCon->theMagicNumber = 0x37412619; return tNdbCon; } @@ -217,22 +146,7 @@ Ndb::getNdbCon() NdbLabel* Ndb::getNdbLabel() { - NdbLabel* tNdbLabel; - if ( theLabelList == NULL ) - { - tNdbLabel = new NdbLabel; - if (tNdbLabel == NULL) - { - return NULL; - } - tNdbLabel->theNext = NULL; - } else - { - tNdbLabel = theLabelList; - theLabelList = tNdbLabel->theNext; - tNdbLabel->theNext = NULL; - } - return tNdbLabel; + return theImpl->theLabelList.seize(this); } /*************************************************************************** @@ -246,23 +160,7 @@ Ndb::getNdbLabel() NdbReceiver* Ndb::getNdbScanRec() { - NdbReceiver* tNdbScanRec; - if ( theScanList == NULL ) - { - tNdbScanRec = new NdbReceiver(this); - if (tNdbScanRec == NULL) - { - return NULL; - } - tNdbScanRec->next(NULL); - } else - { - tNdbScanRec = theScanList; - theScanList = tNdbScanRec->next(); - tNdbScanRec->next(NULL); - } - - return tNdbScanRec; + return theImpl->theScanList.seize(this); } /*************************************************************************** @@ -275,22 +173,7 @@ Ndb::getNdbScanRec() NdbSubroutine* Ndb::getNdbSubroutine() { - NdbSubroutine* tNdbSubroutine; - if ( theSubroutineList == NULL ) - { - tNdbSubroutine = new NdbSubroutine; - if (tNdbSubroutine == NULL) - { - return NULL; - } - tNdbSubroutine->theNext = NULL; - } else - { - tNdbSubroutine = theSubroutineList; - theSubroutineList = tNdbSubroutine->theNext; - tNdbSubroutine->theNext = NULL; - } - return tNdbSubroutine; + return theImpl->theSubroutineList.seize(this); } /*************************************************************************** @@ -303,18 +186,7 @@ Remark: Get an operation from theOpIdleList and return the object . NdbOperation* Ndb::getOperation() { - NdbOperation* tOp = theOpIdleList; - if (tOp != NULL ) { - NdbOperation* tOpNext = tOp->next(); - tOp->next(NULL); - theOpIdleList = tOpNext; - return tOp; - } else { - tOp = new NdbOperation(this); - if (tOp != NULL) - tOp->next(NULL); - } - return tOp; + return theImpl->theOpIdleList.seize(this); } /*************************************************************************** @@ -327,18 +199,7 @@ Remark: Get an operation from theScanOpIdleList and return the object . NdbIndexScanOperation* Ndb::getScanOperation() { - NdbIndexScanOperation* tOp = theScanOpIdleList; - if (tOp != NULL ) { - NdbIndexScanOperation* tOpNext = (NdbIndexScanOperation*)tOp->next(); - tOp->next(NULL); - theScanOpIdleList = tOpNext; - return tOp; - } else { - tOp = new NdbIndexScanOperation(this); - if (tOp != NULL) - tOp->next(NULL); - } - return tOp; + return theImpl->theScanOpIdleList.seize(this); } /*************************************************************************** @@ -351,18 +212,7 @@ Remark: Get an operation from theIndexOpIdleList and return the object . NdbIndexOperation* Ndb::getIndexOperation() { - NdbIndexOperation* tOp = theIndexOpIdleList; - if (tOp != NULL ) { - NdbIndexOperation* tOpNext = (NdbIndexOperation*) tOp->next(); - tOp->next(NULL); - theIndexOpIdleList = tOpNext; - return tOp; - } else { - tOp = new NdbIndexOperation(this); - if (tOp != NULL) - tOp->next(NULL); - } - return tOp; + return theImpl->theIndexOpIdleList.seize(this); } /*************************************************************************** @@ -374,21 +224,14 @@ Return Value: Return a reference to a receive attribute object. NdbRecAttr* Ndb::getRecAttr() { - NdbRecAttr* tRecAttr; - tRecAttr = theRecAttrIdleList; - if (tRecAttr != NULL) { - NdbRecAttr* tRecAttrNext = tRecAttr->next(); + NdbRecAttr* tRecAttr = theImpl->theRecAttrIdleList.seize(this); + if (tRecAttr != NULL) + { tRecAttr->init(); - theRecAttrIdleList = tRecAttrNext; return tRecAttr; - } else { - tRecAttr = new NdbRecAttr; - if (tRecAttr == NULL) - return NULL; - tRecAttr->next(NULL); - }//if - tRecAttr->init(); - return tRecAttr; + } + + return NULL; } /*************************************************************************** @@ -400,34 +243,16 @@ Return Value: Return a reference to a signal object. NdbApiSignal* Ndb::getSignal() { - NdbApiSignal* tSignal = theSignalIdleList; - if (tSignal != NULL){ - NdbApiSignal* tSignalNext = tSignal->next(); - tSignal->next(NULL); - theSignalIdleList = tSignalNext; - } else { - tSignal = new NdbApiSignal(theMyRef); -#ifdef POORMANSPURIFY - cnewSignals++; -#endif - if (tSignal != NULL) - tSignal->next(NULL); - } -#ifdef POORMANSPURIFY - cgetSignals++; -#endif - return tSignal; + return theImpl->theSignalIdleList.seize(this); } NdbBlob* Ndb::getNdbBlob() { - NdbBlob* tBlob = theNdbBlobIdleList; - if (tBlob != NULL) { - theNdbBlobIdleList = tBlob->theNext; + NdbBlob* tBlob = theImpl->theNdbBlobIdleList.seize(this); + if(tBlob) + { tBlob->init(); - } else { - tBlob = new NdbBlob; } return tBlob; } @@ -441,8 +266,7 @@ Remark: Add a NdbBranch object into the Branch idlelist. void Ndb::releaseNdbBranch(NdbBranch* aNdbBranch) { - aNdbBranch->theNext = theBranchList; - theBranchList = aNdbBranch; + theImpl->theBranchList.release(aNdbBranch); } /*************************************************************************** @@ -454,8 +278,7 @@ Remark: Add a NdbBranch object into the Branch idlelist. void Ndb::releaseNdbCall(NdbCall* aNdbCall) { - aNdbCall->theNext = theCallList; - theCallList = aNdbCall; + theImpl->theCallList.release(aNdbCall); } /*************************************************************************** @@ -467,9 +290,8 @@ Remark: Add a Connection object into the signal idlelist. void Ndb::releaseNdbCon(NdbTransaction* aNdbCon) { - aNdbCon->next(theConIdleList); aNdbCon->theMagicNumber = 0xFE11DD; - theConIdleList = aNdbCon; + theImpl->theConIdleList.release(aNdbCon); } /*************************************************************************** @@ -481,8 +303,7 @@ Remark: Add a NdbLabel object into the Label idlelist. void Ndb::releaseNdbLabel(NdbLabel* aNdbLabel) { - aNdbLabel->theNext = theLabelList; - theLabelList = aNdbLabel; + theImpl->theLabelList.release(aNdbLabel); } /*************************************************************************** @@ -494,8 +315,7 @@ Remark: Add a NdbScanReceiver object into the Scan idlelist. void Ndb::releaseNdbScanRec(NdbReceiver* aNdbScanRec) { - aNdbScanRec->next(theScanList); - theScanList = aNdbScanRec; + theImpl->theScanList.release(aNdbScanRec); } /*************************************************************************** @@ -507,8 +327,7 @@ Remark: Add a NdbSubroutine object into theSubroutine idlelist. void Ndb::releaseNdbSubroutine(NdbSubroutine* aNdbSubroutine) { - aNdbSubroutine->theNext = theSubroutineList; - theSubroutineList = aNdbSubroutine; + theImpl->theSubroutineList.release(aNdbSubroutine); } /*************************************************************************** @@ -521,16 +340,14 @@ void Ndb::releaseOperation(NdbOperation* anOperation) { if(anOperation->m_tcReqGSN == GSN_TCKEYREQ){ - anOperation->next(theOpIdleList); anOperation->theNdbCon = NULL; anOperation->theMagicNumber = 0xFE11D0; - theOpIdleList = anOperation; + theImpl->theOpIdleList.release(anOperation); } else { assert(anOperation->m_tcReqGSN == GSN_TCINDXREQ); - anOperation->next(theIndexOpIdleList); anOperation->theNdbCon = NULL; anOperation->theMagicNumber = 0xFE11D1; - theIndexOpIdleList = (NdbIndexOperation*)anOperation; + theImpl->theIndexOpIdleList.release((NdbIndexOperation*)anOperation); } } @@ -553,10 +370,9 @@ Ndb::releaseScanOperation(NdbIndexScanOperation* aScanOperation) } } #endif - aScanOperation->next(theScanOpIdleList); aScanOperation->theNdbCon = NULL; aScanOperation->theMagicNumber = 0xFE11D2; - theScanOpIdleList = aScanOperation; + theImpl->theScanOpIdleList.release(aScanOperation); DBUG_VOID_RETURN; } @@ -570,8 +386,7 @@ void Ndb::releaseRecAttr(NdbRecAttr* aRecAttr) { aRecAttr->release(); - aRecAttr->next(theRecAttrIdleList); - theRecAttrIdleList = aRecAttr; + theImpl->theRecAttrIdleList.release(aRecAttr); } /*************************************************************************** @@ -598,8 +413,7 @@ Ndb::releaseSignal(NdbApiSignal* aSignal) #ifdef POORMANSPURIFY creleaseSignals++; #endif - aSignal->next(theSignalIdleList); - theSignalIdleList = aSignal; + theImpl->theSignalIdleList.release(aSignal); } void @@ -616,162 +430,7 @@ void Ndb::releaseNdbBlob(NdbBlob* aBlob) { aBlob->release(); - aBlob->theNext = theNdbBlobIdleList; - theNdbBlobIdleList = aBlob; -} - -/*************************************************************************** -void freeOperation(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeOperation() -{ - NdbOperation* tOp = theOpIdleList; - theOpIdleList = theOpIdleList->next(); - delete tOp; -} - -/*************************************************************************** -void freeScanOperation(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeScanOperation() -{ - NdbIndexScanOperation* tOp = theScanOpIdleList; - theScanOpIdleList = (NdbIndexScanOperation *)tOp->next(); - delete tOp; -} - -/*************************************************************************** -void freeIndexOperation(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeIndexOperation() -{ - NdbIndexOperation* tOp = theIndexOpIdleList; - theIndexOpIdleList = (NdbIndexOperation *) theIndexOpIdleList->next(); - delete tOp; -} - -/*************************************************************************** -void freeNdbBranch(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbBranch() -{ - NdbBranch* tNdbBranch = theBranchList; - theBranchList = theBranchList->theNext; - delete tNdbBranch; -} - -/*************************************************************************** -void freeNdbCall(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbCall() -{ - NdbCall* tNdbCall = theCallList; - theCallList = theCallList->theNext; - delete tNdbCall; -} - -/*************************************************************************** -void freeNdbScanRec(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbScanRec() -{ - NdbReceiver* tNdbScanRec = theScanList; - theScanList = theScanList->next(); - delete tNdbScanRec; -} - -/*************************************************************************** -void freeNdbCon(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbCon() -{ - NdbTransaction* tNdbCon = theConIdleList; - theConIdleList = theConIdleList->next(); - delete tNdbCon; -} - -/*************************************************************************** -void freeNdbLabel(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbLabel() -{ - NdbLabel* tNdbLabel = theLabelList; - theLabelList = theLabelList->theNext; - delete tNdbLabel; -} - -/*************************************************************************** -void freeNdbSubroutine(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbSubroutine() -{ - NdbSubroutine* tNdbSubroutine = theSubroutineList; - theSubroutineList = theSubroutineList->theNext; - delete tNdbSubroutine; -} - -/*************************************************************************** -void freeRecAttr(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeRecAttr() -{ - NdbRecAttr* tRecAttr = theRecAttrIdleList; - theRecAttrIdleList = theRecAttrIdleList->next(); - delete tRecAttr; -} - -/*************************************************************************** -void freeSignal(); - -Remark: Delete a signal object from the signal idlelist. -***************************************************************************/ -void -Ndb::freeSignal() -{ - NdbApiSignal* tSignal = theSignalIdleList; - theSignalIdleList = tSignal->next(); - delete tSignal; -#ifdef POORMANSPURIFY - cfreeSignals++; -#endif -} - -void -Ndb::freeNdbBlob() -{ - NdbBlob* tBlob = theNdbBlobIdleList; - theNdbBlobIdleList = tBlob->theNext; - delete tBlob; + theImpl->theNdbBlobIdleList.release(aBlob); } /**************************************************************************** @@ -826,3 +485,102 @@ Ndb::releaseConnectToNdb(NdbTransaction* a_con) DBUG_VOID_RETURN; } +template<class T> +static +Ndb::Free_list_usage* +update(Ndb::Free_list_usage* curr, + Ndb_free_list_t<T> & list, + const char * name) +{ + curr->m_name = name; + curr->m_created = list.m_alloc_cnt; + curr->m_free = list.m_free_cnt; + curr->m_sizeof = sizeof(T); + return curr; +} + +Ndb::Free_list_usage* +Ndb::get_free_list_usage(Ndb::Free_list_usage* curr) +{ + if (curr == 0) + { + return 0; + } + + if(curr->m_name == 0) + { + update(curr, theImpl->theConIdleList, "NdbTransaction"); + } + else if(!strcmp(curr->m_name, "NdbTransaction")) + { + update(curr, theImpl->theOpIdleList, "NdbOperation"); + } + else if(!strcmp(curr->m_name, "NdbOperation")) + { + update(curr, theImpl->theScanOpIdleList, "NdbIndexScanOperation"); + } + else if(!strcmp(curr->m_name, "NdbIndexScanOperation")) + { + update(curr, theImpl->theIndexOpIdleList, "NdbIndexOperation"); + } + else if(!strcmp(curr->m_name, "NdbIndexOperation")) + { + update(curr, theImpl->theRecAttrIdleList, "NdbRecAttr"); + } + else if(!strcmp(curr->m_name, "NdbRecAttr")) + { + update(curr, theImpl->theSignalIdleList, "NdbApiSignal"); + } + else if(!strcmp(curr->m_name, "NdbApiSignal")) + { + update(curr, theImpl->theLabelList, "NdbLabel"); + } + else if(!strcmp(curr->m_name, "NdbLabel")) + { + update(curr, theImpl->theBranchList, "NdbBranch"); + } + else if(!strcmp(curr->m_name, "NdbBranch")) + { + update(curr, theImpl->theSubroutineList, "NdbSubroutine"); + } + else if(!strcmp(curr->m_name, "NdbSubroutine")) + { + update(curr, theImpl->theCallList, "NdbCall"); + } + else if(!strcmp(curr->m_name, "NdbCall")) + { + update(curr, theImpl->theNdbBlobIdleList, "NdbBlob"); + } + else if(!strcmp(curr->m_name, "NdbBlob")) + { + update(curr, theImpl->theScanList, "NdbReceiver"); + } + else if(!strcmp(curr->m_name, "NdbReceiver")) + { + return 0; + } + else + { + update(curr, theImpl->theConIdleList, "NdbTransaction"); + } + + return curr; +} + +#define TI(T) \ + template Ndb::Free_list_usage* \ + update(Ndb::Free_list_usage*, Ndb_free_list_t<T> &, const char * name);\ + template struct Ndb_free_list_t<T> + +TI(NdbBlob); +TI(NdbCall); +TI(NdbLabel); +TI(NdbBranch); +TI(NdbSubroutine); +TI(NdbApiSignal); +TI(NdbRecAttr); +TI(NdbOperation); +TI(NdbReceiver); +TI(NdbConnection); +TI(NdbIndexOperation); +TI(NdbIndexScanOperation); diff --git a/ndb/src/ndbapi/ObjectMap.hpp b/ndb/src/ndbapi/ObjectMap.hpp index 21407279f0b..c730d1ce6b1 100644 --- a/ndb/src/ndbapi/ObjectMap.hpp +++ b/ndb/src/ndbapi/ObjectMap.hpp @@ -30,7 +30,7 @@ class NdbObjectIdMap //: NdbLockable { public: STATIC_CONST( InvalidId = ~(Uint32)0 ); - NdbObjectIdMap(Uint32 initalSize = 128, Uint32 expandSize = 10); + NdbObjectIdMap(NdbMutex*, Uint32 initalSize = 128, Uint32 expandSize = 10); ~NdbObjectIdMap(); Uint32 map(void * object); @@ -46,14 +46,16 @@ private: void * m_obj; } * m_map; + NdbMutex * m_mutex; void expand(Uint32 newSize); }; inline -NdbObjectIdMap::NdbObjectIdMap(Uint32 sz, Uint32 eSz) { +NdbObjectIdMap::NdbObjectIdMap(NdbMutex* mutex, Uint32 sz, Uint32 eSz) { m_size = 0; m_firstFree = InvalidId; m_map = 0; + m_mutex = mutex; m_expandSize = eSz; expand(sz); #ifdef DEBUG_OBJECTMAP @@ -131,21 +133,26 @@ NdbObjectIdMap::getObject(Uint32 id){ inline void NdbObjectIdMap::expand(Uint32 incSize){ + NdbMutex_Lock(m_mutex); Uint32 newSize = m_size + incSize; - MapEntry * tmp = (MapEntry*)malloc(newSize * sizeof(MapEntry)); + MapEntry * tmp = (MapEntry*)realloc(m_map, newSize * sizeof(MapEntry)); - if (m_map) { - memcpy(tmp, m_map, m_size * sizeof(MapEntry)); - free((void*)m_map); + if (likely(tmp != 0)) + { + m_map = tmp; + + for(Uint32 i = m_size; i<newSize; i++){ + m_map[i].m_next = i + 1; + } + m_firstFree = m_size; + m_map[newSize-1].m_next = InvalidId; + m_size = newSize; } - m_map = tmp; - - for(Uint32 i = m_size; i<newSize; i++){ - m_map[i].m_next = i + 1; + else + { + ndbout_c("NdbObjectIdMap::expand unable to expand!!"); } - m_firstFree = m_size; - m_map[newSize-1].m_next = InvalidId; - m_size = newSize; + NdbMutex_Unlock(m_mutex); } #endif diff --git a/ndb/src/ndbapi/SignalSender.cpp b/ndb/src/ndbapi/SignalSender.cpp new file mode 100644 index 00000000000..a29fe68937b --- /dev/null +++ b/ndb/src/ndbapi/SignalSender.cpp @@ -0,0 +1,280 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "SignalSender.hpp" +#include <NdbSleep.h> +#include <SignalLoggerManager.hpp> +#include <signaldata/NFCompleteRep.hpp> +#include <signaldata/NodeFailRep.hpp> + +SimpleSignal::SimpleSignal(bool dealloc){ + memset(this, 0, sizeof(* this)); + deallocSections = dealloc; +} + +SimpleSignal::~SimpleSignal(){ + if(!deallocSections) + return; + if(ptr[0].p != 0) delete []ptr[0].p; + if(ptr[1].p != 0) delete []ptr[1].p; + if(ptr[2].p != 0) delete []ptr[2].p; +} + +void +SimpleSignal::set(class SignalSender& ss, + Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len){ + + header.theTrace = trace; + header.theReceiversBlockNumber = recBlock; + header.theVerId_signalNumber = gsn; + header.theLength = len; + header.theSendersBlockRef = refToBlock(ss.getOwnRef()); +} + +void +SimpleSignal::print(FILE * out){ + fprintf(out, "---- Signal ----------------\n"); + SignalLoggerManager::printSignalHeader(out, header, 0, 0, false); + SignalLoggerManager::printSignalData(out, header, theData); + for(Uint32 i = 0; i<header.m_noOfSections; i++){ + Uint32 len = ptr[i].sz; + fprintf(out, " --- Section %d size=%d ---\n", i, len); + Uint32 * signalData = ptr[i].p; + while(len >= 7){ + fprintf(out, + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + signalData[0], signalData[1], signalData[2], signalData[3], + signalData[4], signalData[5], signalData[6]); + len -= 7; + signalData += 7; + } + if(len > 0){ + fprintf(out, " H\'%.8x", signalData[0]); + for(Uint32 i = 1; i<len; i++) + fprintf(out, " H\'%.8x", signalData[i]); + fprintf(out, "\n"); + } + } +} + +SignalSender::SignalSender(TransporterFacade *facade) + : m_lock(0) +{ + m_cond = NdbCondition_Create(); + theFacade = facade; + m_blockNo = theFacade->open(this, execSignal, execNodeStatus); + assert(m_blockNo > 0); +} + +SignalSender::~SignalSender(){ + int i; + if (m_lock) + unlock(); + theFacade->close(m_blockNo,0); + // free these _after_ closing theFacade to ensure that + // we delete all signals + for (i= m_jobBuffer.size()-1; i>= 0; i--) + delete m_jobBuffer[i]; + for (i= m_usedBuffer.size()-1; i>= 0; i--) + delete m_usedBuffer[i]; + NdbCondition_Destroy(m_cond); +} + +int SignalSender::lock() +{ + if (NdbMutex_Lock(theFacade->theMutexPtr)) + return -1; + m_lock= 1; + return 0; +} + +int SignalSender::unlock() +{ + if (NdbMutex_Unlock(theFacade->theMutexPtr)) + return -1; + m_lock= 0; + return 0; +} + +Uint32 +SignalSender::getOwnRef() const { + return numberToRef(m_blockNo, theFacade->ownId()); +} + +Uint32 +SignalSender::getAliveNode() const{ + return theFacade->get_an_alive_node(); +} + +const ClusterMgr::Node & +SignalSender::getNodeInfo(Uint16 nodeId) const { + return theFacade->theClusterMgr->getNodeInfo(nodeId); +} + +Uint32 +SignalSender::getNoOfConnectedNodes() const { + return theFacade->theClusterMgr->getNoOfConnectedNodes(); +} + +SendStatus +SignalSender::sendSignal(Uint16 nodeId, const SimpleSignal * s){ + return theFacade->theTransporterRegistry->prepareSend(&s->header, + 1, // JBB + &s->theData[0], + nodeId, + &s->ptr[0]); +} + +template<class T> +SimpleSignal * +SignalSender::waitFor(Uint32 timeOutMillis, T & t) +{ + SimpleSignal * s = t.check(m_jobBuffer); + if(s != 0){ + return s; + } + + NDB_TICKS now = NdbTick_CurrentMillisecond(); + NDB_TICKS stop = now + timeOutMillis; + Uint32 wait = (timeOutMillis == 0 ? 10 : timeOutMillis); + do { + NdbCondition_WaitTimeout(m_cond, + theFacade->theMutexPtr, + wait); + + + SimpleSignal * s = t.check(m_jobBuffer); + if(s != 0){ + m_usedBuffer.push_back(s); + return s; + } + + now = NdbTick_CurrentMillisecond(); + wait = (timeOutMillis == 0 ? 10 : stop - now); + } while(stop > now || timeOutMillis == 0); + + return 0; +} + +class WaitForAny { +public: + SimpleSignal * check(Vector<SimpleSignal*> & m_jobBuffer){ + if(m_jobBuffer.size() > 0){ + SimpleSignal * s = m_jobBuffer[0]; + m_jobBuffer.erase(0); + return s; + } + return 0; + } +}; + +SimpleSignal * +SignalSender::waitFor(Uint32 timeOutMillis){ + + WaitForAny w; + return waitFor(timeOutMillis, w); +} + +class WaitForNode { +public: + Uint32 m_nodeId; + SimpleSignal * check(Vector<SimpleSignal*> & m_jobBuffer){ + Uint32 len = m_jobBuffer.size(); + for(Uint32 i = 0; i<len; i++){ + if(refToNode(m_jobBuffer[i]->header.theSendersBlockRef) == m_nodeId){ + SimpleSignal * s = m_jobBuffer[i]; + m_jobBuffer.erase(i); + return s; + } + } + return 0; + } +}; + +SimpleSignal * +SignalSender::waitFor(Uint16 nodeId, Uint32 timeOutMillis){ + + WaitForNode w; + w.m_nodeId = nodeId; + return waitFor(timeOutMillis, w); +} + +#include <NdbApiSignal.hpp> + +void +SignalSender::execSignal(void* signalSender, + NdbApiSignal* signal, + class LinearSectionPtr ptr[3]){ + SimpleSignal * s = new SimpleSignal(true); + s->header = * signal; + memcpy(&s->theData[0], signal->getDataPtr(), 4 * s->header.theLength); + for(Uint32 i = 0; i<s->header.m_noOfSections; i++){ + s->ptr[i].p = new Uint32[ptr[i].sz]; + s->ptr[i].sz = ptr[i].sz; + memcpy(s->ptr[i].p, ptr[i].p, 4 * ptr[i].sz); + } + SignalSender * ss = (SignalSender*)signalSender; + ss->m_jobBuffer.push_back(s); + NdbCondition_Signal(ss->m_cond); +} + +void +SignalSender::execNodeStatus(void* signalSender, + Uint32 nodeId, + bool alive, + bool nfCompleted){ + if (alive) { + // node connected + return; + } + + SimpleSignal * s = new SimpleSignal(true); + SignalSender * ss = (SignalSender*)signalSender; + + // node disconnected + if(nfCompleted) + { + // node shutdown complete + s->header.theVerId_signalNumber = GSN_NF_COMPLETEREP; + NFCompleteRep *rep = (NFCompleteRep *)s->getDataPtrSend(); + rep->blockNo = 0; + rep->nodeId = 0; + rep->failedNodeId = nodeId; + rep->unused = 0; + rep->from = 0; + } + else + { + // node failure + s->header.theVerId_signalNumber = GSN_NODE_FAILREP; + NodeFailRep *rep = (NodeFailRep *)s->getDataPtrSend(); + rep->failNo = 0; + rep->masterNodeId = 0; + rep->noOfNodes = 1; + NodeBitmask::clear(rep->theNodes); + NodeBitmask::set(rep->theNodes,nodeId); + } + + ss->m_jobBuffer.push_back(s); + NdbCondition_Signal(ss->m_cond); +} + +#if __SUNPRO_CC != 0x560 +template SimpleSignal* SignalSender::waitFor<WaitForNode>(unsigned, WaitForNode&); +template SimpleSignal* SignalSender::waitFor<WaitForAny>(unsigned, WaitForAny&); +#endif +template class Vector<SimpleSignal*>; + diff --git a/ndb/src/ndbapi/SignalSender.hpp b/ndb/src/ndbapi/SignalSender.hpp new file mode 100644 index 00000000000..4b991460034 --- /dev/null +++ b/ndb/src/ndbapi/SignalSender.hpp @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef SIGNAL_SENDER_HPP +#define SIGNAL_SENDER_HPP + +#include <ndb_global.h> +#include "TransporterFacade.hpp" +#include <Vector.hpp> + +struct SimpleSignal { +public: + SimpleSignal(bool dealloc = false); + ~SimpleSignal(); + + void set(class SignalSender&, + Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len); + + struct SignalHeader header; + Uint32 theData[25]; + LinearSectionPtr ptr[3]; + + int readSignalNumber() {return header.theVerId_signalNumber; } + Uint32 *getDataPtrSend() { return theData; } + const Uint32 *getDataPtr() const { return theData; } + + void print(FILE * out = stdout); +private: + bool deallocSections; +}; + +class SignalSender { +public: + SignalSender(TransporterFacade *facade); + virtual ~SignalSender(); + + int lock(); + int unlock(); + + Uint32 getOwnRef() const; + Uint32 getAliveNode() const; + const ClusterMgr::Node &getNodeInfo(Uint16 nodeId) const; + Uint32 getNoOfConnectedNodes() const; + + SendStatus sendSignal(Uint16 nodeId, const SimpleSignal *); + + SimpleSignal * waitFor(Uint32 timeOutMillis = 0); + SimpleSignal * waitFor(Uint16 nodeId, Uint32 timeOutMillis = 0); + SimpleSignal * waitFor(Uint16 nodeId, Uint16 gsn, Uint32 timeOutMillis = 0); +private: + int m_blockNo; + TransporterFacade * theFacade; + + static void execSignal(void* signalSender, + NdbApiSignal* signal, + class LinearSectionPtr ptr[3]); + + static void execNodeStatus(void* signalSender, Uint32 nodeId, + bool alive, bool nfCompleted); + + int m_lock; + struct NdbCondition * m_cond; + Vector<SimpleSignal *> m_jobBuffer; + Vector<SimpleSignal *> m_usedBuffer; + + template<class T> + SimpleSignal * waitFor(Uint32 timeOutMillis, T & t); +}; + +#endif diff --git a/ndb/src/ndbapi/TransporterFacade.cpp b/ndb/src/ndbapi/TransporterFacade.cpp index 802e0785988..77750a3c3d0 100644 --- a/ndb/src/ndbapi/TransporterFacade.cpp +++ b/ndb/src/ndbapi/TransporterFacade.cpp @@ -63,13 +63,16 @@ TransporterFacade* TransporterFacade::theFacadeInstance = NULL; *****************************************************************************/ void -reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode){ +reportError(void * callbackObj, NodeId nodeId, + TransporterError errorCode, const char *info) +{ #ifdef REPORT_TRANSPORTER - ndbout_c("REPORT_TRANSP: reportError (nodeId=%d, errorCode=%d)", - (int)nodeId, (int)errorCode); + ndbout_c("REPORT_TRANSP: reportError (nodeId=%d, errorCode=%d) %s", + (int)nodeId, (int)errorCode, info ? info : ""); #endif - if(errorCode & 0x8000) { - ndbout_c("reportError (%d, %d)\n", (int)nodeId, (int)errorCode); + if(errorCode & TE_DO_DISCONNECT) { + ndbout_c("reportError (%d, %d) %s", (int)nodeId, (int)errorCode, + info ? info : ""); ((TransporterFacade*)(callbackObj))->doDisconnect(nodeId); } } diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index 7625da609b0..34079c3e35f 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -86,7 +86,7 @@ const char *Ndb_cluster_connection::get_connectstring(char *buf, return 0; } -extern "C" pthread_handler_decl(run_ndb_cluster_connection_connect_thread, me) +pthread_handler_t run_ndb_cluster_connection_connect_thread(void *me) { g_run_connect_thread= 1; ((Ndb_cluster_connection_impl*) me)->connect_thread(); diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index 3c3893c38ae..4a9ac9affb7 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -691,5 +691,7 @@ int ndb_error_string(int err_no, char *str, unsigned int size) ndberror_classification_message(error.classification)); str[size-1]= '\0'; - return len; + if (error.classification != UE) + return len; + return -len; } diff --git a/ndb/test/include/NDBT_Test.hpp b/ndb/test/include/NDBT_Test.hpp index 1b9c2751f64..027ac356e0c 100644 --- a/ndb/test/include/NDBT_Test.hpp +++ b/ndb/test/include/NDBT_Test.hpp @@ -67,7 +67,8 @@ public: const char* getPropertyWait(const char*, const char* ); void decProperty(const char *); - + void incProperty(const char *); + // Communicate with other tests void stopTest(); bool isTestStopped(); diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am index 1d2dfb3f948..d83e9614eb5 100644 --- a/ndb/test/ndbapi/Makefile.am +++ b/ndb/test/ndbapi/Makefile.am @@ -34,7 +34,8 @@ test_event ndbapi_slow_select testReadPerf testLcp \ testPartitioning \ testBitfield \ DbCreate DbAsyncGenerator \ -test_event_multi_table +test_event_multi_table \ +testSRBank #flexTimedAsynch #testBlobs @@ -78,6 +79,7 @@ testBitfield_SOURCES = testBitfield.cpp DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp test_event_multi_table_SOURCES = test_event_multi_table.cpp +testSRBank_SOURCES = testSRBank.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel @@ -89,6 +91,7 @@ include $(top_srcdir)/ndb/config/type_ndbapitest.mk.am ##testSystemRestart_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel ##testTransactions_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel testBackup_LDADD = $(LDADD) bank/libbank.a +testSRBank_LDADD = bank/libbank.a $(LDADD) # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/ndb/test/ndbapi/bank/Bank.cpp b/ndb/test/ndbapi/bank/Bank.cpp index 40819ecc849..37224fdd055 100644 --- a/ndb/test/ndbapi/bank/Bank.cpp +++ b/ndb/test/ndbapi/bank/Bank.cpp @@ -19,12 +19,13 @@ #include <NdbSleep.h> #include <UtilTransactions.hpp> -Bank::Bank(Ndb_cluster_connection& con): +Bank::Bank(Ndb_cluster_connection& con, bool _init): m_ndb(&con, "BANK"), m_maxAccount(-1), m_initialized(false) { - + if(_init) + init(); } int Bank::init(){ @@ -34,40 +35,39 @@ int Bank::init(){ myRandom48Init(NdbTick_CurrentMillisecond()); m_ndb.init(); - while (m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - + if (m_ndb.waitUntilReady(30) != 0) + { + ndbout << "Ndb not ready" << endl; + return NDBT_FAILED; + } + if (getNumAccounts() != NDBT_OK) return NDBT_FAILED; + + m_initialized = true; return NDBT_OK; } int Bank::performTransactions(int maxSleepBetweenTrans, int yield){ - if (init() != NDBT_OK) - return NDBT_FAILED; int transactions = 0; - while(1){ - - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - - while(performTransaction() != NDBT_FAILED){ - transactions++; - - if (maxSleepBetweenTrans > 0){ - int val = myRandom48(maxSleepBetweenTrans); - NdbSleep_MilliSleep(val); - } - - if((transactions % 100) == 0) - g_info << transactions << endl; - - if (yield != 0 && transactions >= yield) - return NDBT_OK; + while(performTransaction() == NDBT_OK) + { + transactions++; + + if (maxSleepBetweenTrans > 0){ + int val = myRandom48(maxSleepBetweenTrans); + NdbSleep_MilliSleep(val); } + + if((transactions % 100) == 0) + g_info << transactions << endl; + + if (yield != 0 && transactions >= yield) + return NDBT_OK; } + return NDBT_FAILED; } @@ -92,7 +92,7 @@ int Bank::performTransaction(){ int amount = myRandom48(maxAmount); - retry_transaction: +retry_transaction: int res = performTransaction(fromAccount, toAccount, amount); if (res != 0){ switch (res){ @@ -158,8 +158,9 @@ int Bank::performTransactionImpl1(int fromAccountId, // Ok, all clear to do the transaction Uint64 transId; - if (getNextTransactionId(transId) != NDBT_OK){ - return NDBT_FAILED; + int result = NDBT_OK; + if ((result= getNextTransactionId(transId)) != NDBT_OK){ + return result; } NdbConnection* pTrans = m_ndb.startTransaction(); @@ -500,8 +501,6 @@ int Bank::performTransactionImpl1(int fromAccountId, int Bank::performMakeGLs(int yield){ int result; - if (init() != NDBT_OK) - return NDBT_FAILED; int counter, maxCounter; int yieldCounter = 0; @@ -512,9 +511,6 @@ int Bank::performMakeGLs(int yield){ counter = 0; maxCounter = 50 + myRandom48(100); - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - /** * Validate GLs and Transactions for previous days * @@ -526,6 +522,7 @@ int Bank::performMakeGLs(int yield){ return NDBT_FAILED; } g_info << "performValidateGLs failed" << endl; + return NDBT_FAILED; continue; } @@ -536,7 +533,7 @@ int Bank::performMakeGLs(int yield){ return NDBT_FAILED; } g_info << "performValidatePurged failed" << endl; - continue; + return NDBT_FAILED; } while (1){ @@ -607,14 +604,9 @@ int Bank::performMakeGLs(int yield){ int Bank::performValidateAllGLs(){ int result; - if (init() != NDBT_OK) - return NDBT_FAILED; while (1){ - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - /** * Validate GLs and Transactions for previous days * Set age so that ALL GL's are validated @@ -1930,39 +1922,29 @@ int Bank::findTransactionsToPurge(const Uint64 glTime, } - int Bank::performIncreaseTime(int maxSleepBetweenDays, int yield){ - if (init() != NDBT_OK) - return NDBT_FAILED; - +int Bank::performIncreaseTime(int maxSleepBetweenDays, int yield) +{ int yieldCounter = 0; - - while(1){ - - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - - while(1){ - - Uint64 currTime; - if (incCurrTime(currTime) != NDBT_OK) - break; - - g_info << "Current time is " << currTime << endl; - if (maxSleepBetweenDays > 0){ - int val = myRandom48(maxSleepBetweenDays); - NdbSleep_SecSleep(val); - } - - yieldCounter++; - if (yield != 0 && yieldCounter >= yield) - return NDBT_OK; - - } - } - return NDBT_FAILED; - } - - + + while(1){ + + Uint64 currTime; + if (incCurrTime(currTime) != NDBT_OK) + break; + + g_info << "Current time is " << currTime << endl; + if (maxSleepBetweenDays > 0){ + int val = myRandom48(maxSleepBetweenDays); + NdbSleep_SecSleep(val); + } + + yieldCounter++; + if (yield != 0 && yieldCounter >= yield) + return NDBT_OK; + + } + return NDBT_FAILED; +} int Bank::readSystemValue(SystemValueId sysValId, Uint64 & value){ @@ -1971,22 +1953,30 @@ int Bank::readSystemValue(SystemValueId sysValId, Uint64 & value){ NdbConnection* pTrans = m_ndb.startTransaction(); if (pTrans == NULL){ ERR(m_ndb.getNdbError()); + if(m_ndb.getNdbError().status == NdbError::TemporaryError) + return NDBT_TEMPORARY; return NDBT_FAILED; } - if (prepareReadSystemValueOp(pTrans, sysValId, value) != NDBT_OK) { + int result; + if ((result= prepareReadSystemValueOp(pTrans, sysValId, value)) != NDBT_OK) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); - return NDBT_FAILED; + return result; } check = pTrans->execute(Commit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if(pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + return NDBT_TEMPORARY; + } m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } - + m_ndb.closeTransaction(pTrans); return NDBT_OK; @@ -2092,6 +2082,8 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ NdbConnection* pTrans = m_ndb.startTransaction(); if (pTrans == NULL){ ERR(m_ndb.getNdbError()); + if (m_ndb.getNdbError().status == NdbError::TemporaryError) + DBUG_RETURN(NDBT_TEMPORARY); DBUG_RETURN(NDBT_FAILED); } @@ -2127,6 +2119,11 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ check = pTrans->execute(NoCommit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if (pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + DBUG_RETURN(NDBT_TEMPORARY); + } m_ndb.closeTransaction(pTrans); DBUG_RETURN(NDBT_FAILED); } @@ -2201,16 +2198,21 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ check = pTrans->execute(Commit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if (pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + DBUG_RETURN(NDBT_TEMPORARY); + } m_ndb.closeTransaction(pTrans); DBUG_RETURN(NDBT_FAILED); } // Check that value updated equals the value we read after the update if (valueNewRec->u_64_value() != value){ - + printf("value actual=%lld\n", valueNewRec->u_64_value()); printf("value expected=%lld actual=%lld\n", value, valueNewRec->u_64_value()); - + DBUG_PRINT("info", ("value expected=%ld actual=%ld", value, valueNewRec->u_64_value())); g_err << "getNextTransactionId: value was not updated" << endl; m_ndb.closeTransaction(pTrans); @@ -2218,7 +2220,7 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ } m_ndb.closeTransaction(pTrans); - + DBUG_RETURN(0); } @@ -2235,6 +2237,8 @@ int Bank::increaseSystemValue2(SystemValueId sysValId, Uint64 &value){ NdbConnection* pTrans = m_ndb.startTransaction(); if (pTrans == NULL){ ERR(m_ndb.getNdbError()); + if(m_ndb.getNdbError().status == NdbError::TemporaryError) + return NDBT_TEMPORARY; return NDBT_FAILED; } @@ -2277,6 +2281,11 @@ int Bank::increaseSystemValue2(SystemValueId sysValId, Uint64 &value){ check = pTrans->execute(Commit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if(pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + return NDBT_TEMPORARY; + } m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } @@ -2301,16 +2310,11 @@ int Bank::prepareGetCurrTimeOp(NdbConnection *pTrans, Uint64 &time){ int Bank::performSumAccounts(int maxSleepBetweenSums, int yield){ - if (init() != NDBT_OK) - return NDBT_FAILED; int yieldCounter = 0; while (1){ - while (m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - Uint32 sumAccounts = 0; Uint32 numAccounts = 0; if (getSumAccounts(sumAccounts, numAccounts) != NDBT_OK){ diff --git a/ndb/test/ndbapi/bank/Bank.hpp b/ndb/test/ndbapi/bank/Bank.hpp index d9dd7b25944..b80f02dae97 100644 --- a/ndb/test/ndbapi/bank/Bank.hpp +++ b/ndb/test/ndbapi/bank/Bank.hpp @@ -27,7 +27,7 @@ class Bank { public: - Bank(Ndb_cluster_connection&); + Bank(Ndb_cluster_connection&, bool init = true); int createAndLoadBank(bool overWrite, int num_accounts=10); int dropBank(); diff --git a/ndb/test/ndbapi/testBackup.cpp b/ndb/test/ndbapi/testBackup.cpp index 1ab348e735f..da3c52cf4d2 100644 --- a/ndb/test/ndbapi/testBackup.cpp +++ b/ndb/test/ndbapi/testBackup.cpp @@ -229,10 +229,13 @@ int runVerifyOne(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int count = 0; - ndbout << *(const NDBT_Table*)ctx->getTab() << endl; - - UtilTransactions utilTrans(*ctx->getTab()); - HugoTransactions hugoTrans(*ctx->getTab()); + const NdbDictionary::Table* tab = + GETNDB(step)->getDictionary()->getTable(ctx->getTab()->getName()); + if(tab == 0) + return NDBT_FAILED; + + UtilTransactions utilTrans(* tab); + HugoTransactions hugoTrans(* tab); do{ diff --git a/ndb/test/ndbapi/testOperations.cpp b/ndb/test/ndbapi/testOperations.cpp index 726f35b01fb..505b1620900 100644 --- a/ndb/test/ndbapi/testOperations.cpp +++ b/ndb/test/ndbapi/testOperations.cpp @@ -659,6 +659,9 @@ main(int argc, const char** argv){ for(Uint32 i = 0; i < 12; i++) { + if(i == 6 || i == 8 || i == 10) + continue; + BaseString name("bug_9749"); name.appfmt("_%d", i); NDBT_TestCaseImpl1 *pt = new NDBT_TestCaseImpl1(&ts, diff --git a/ndb/test/ndbapi/testSRBank.cpp b/ndb/test/ndbapi/testSRBank.cpp new file mode 100644 index 00000000000..6d57724f4c6 --- /dev/null +++ b/ndb/test/ndbapi/testSRBank.cpp @@ -0,0 +1,246 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NDBT.hpp> +#include <NDBT_Test.hpp> +#include <HugoTransactions.hpp> +#include <UtilTransactions.hpp> +#include <NdbBackup.hpp> + +#include "bank/Bank.hpp" + +int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){ + Bank bank(ctx->m_cluster_connection); + int overWriteExisting = true; + if (bank.createAndLoadBank(overWriteExisting, 10) != NDBT_OK) + return NDBT_FAILED; + return NDBT_OK; +} + +/** + * + * SR 0 - normal + * SR 1 - shutdown in progress + * SR 2 - restart in progress + */ +int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){ + int wait = 5; // Max seconds between each "day" + int yield = 1; // Loops before bank returns + + ctx->incProperty("ThreadCount"); + while (!ctx->isTestStopped()) + { + Bank bank(ctx->m_cluster_connection); + while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1) + if(bank.performIncreaseTime(wait, yield) == NDBT_FAILED) + break; + + ndbout_c("runBankTimer is stopped"); + ctx->incProperty("ThreadStopped"); + if(ctx->getPropertyWait("SR", (Uint32)0)) + break; + } + return NDBT_OK; +} + +int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){ + int wait = 0; // Max ms between each transaction + int yield = 1; // Loops before bank returns + + ctx->incProperty("ThreadCount"); + while (!ctx->isTestStopped()) + { + Bank bank(ctx->m_cluster_connection); + while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1) + if(bank.performTransactions(0, 1) == NDBT_FAILED) + break; + + ndbout_c("runBankTransactions is stopped"); + ctx->incProperty("ThreadStopped"); + if(ctx->getPropertyWait("SR", (Uint32)0)) + break; + } + return NDBT_OK; +} + +int runBankGL(NDBT_Context* ctx, NDBT_Step* step){ + int yield = 1; // Loops before bank returns + int result = NDBT_OK; + + ctx->incProperty("ThreadCount"); + while (ctx->isTestStopped() == false) + { + Bank bank(ctx->m_cluster_connection); + while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1) + if (bank.performMakeGLs(yield) != NDBT_OK) + { + if(ctx->getProperty("SR") != 0) + break; + ndbout << "bank.performMakeGLs FAILED" << endl; + return NDBT_FAILED; + } + + ndbout_c("runBankGL is stopped"); + ctx->incProperty("ThreadStopped"); + if(ctx->getPropertyWait("SR", (Uint32)0)) + break; + } + return NDBT_OK; +} + +int runBankSum(NDBT_Context* ctx, NDBT_Step* step){ + Bank bank(ctx->m_cluster_connection); + int wait = 2000; // Max ms between each sum of accounts + int yield = 1; // Loops before bank returns + int result = NDBT_OK; + + while (ctx->isTestStopped() == false) { + if (bank.performSumAccounts(wait, yield) != NDBT_OK){ + ndbout << "bank.performSumAccounts FAILED" << endl; + result = NDBT_FAILED; + } + } + return result ; +} + +#define CHECK(b) if (!(b)) { \ + g_err << "ERR: "<< step->getName() \ + << " failed on line " << __LINE__ << endl; \ + result = NDBT_FAILED; \ + continue; } + +int runSR(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + int runtime = ctx->getNumLoops(); + int sleeptime = ctx->getNumRecords(); + NdbRestarter restarter; + bool abort = true; + int timeout = 180; + + Uint32 now; + const Uint32 stop = time(0)+ runtime; + while(!ctx->isTestStopped() && ((now= time(0)) < stop) && result == NDBT_OK) + { + ndbout << " -- Sleep " << sleeptime << "s " << endl; + NdbSleep_SecSleep(sleeptime); + ndbout << " -- Shutting down " << endl; + ctx->setProperty("SR", 1); + CHECK(restarter.restartAll(false, true, abort) == 0); + ctx->setProperty("SR", 2); + CHECK(restarter.waitClusterNoStart(timeout) == 0); + + Uint32 cnt = ctx->getProperty("ThreadCount"); + Uint32 curr= ctx->getProperty("ThreadStopped"); + while(curr != cnt) + { + ndbout_c("%d %d", curr, cnt); + NdbSleep_MilliSleep(100); + curr= ctx->getProperty("ThreadStopped"); + } + + ctx->setProperty("ThreadStopped", (Uint32)0); + CHECK(restarter.startAll() == 0); + CHECK(restarter.waitClusterStarted(timeout) == 0); + + ndbout << " -- Validating starts " << endl; + { + int wait = 0; + int yield = 1; + Bank bank(ctx->m_cluster_connection); + if (bank.performSumAccounts(wait, yield) != 0) + { + ndbout << "bank.performSumAccounts FAILED" << endl; + return NDBT_FAILED; + } + + if (bank.performValidateAllGLs() != 0) + { + ndbout << "bank.performValidateAllGLs FAILED" << endl; + return NDBT_FAILED; + } + } + + ndbout << " -- Validating complete " << endl; + ctx->setProperty("SR", (Uint32)0); + ctx->broadcast(); + } + ctx->stopTest(); + return NDBT_OK; +} + +int runDropBank(NDBT_Context* ctx, NDBT_Step* step){ + Bank bank(ctx->m_cluster_connection); + if (bank.dropBank() != NDBT_OK) + return NDBT_FAILED; + return NDBT_OK; +} + + +NDBT_TESTSUITE(testSRBank); +TESTCASE("Graceful", + " Test that a consistent bank is restored after graceful shutdown\n" + "1. Create bank\n" + "2. Start bank and let it run\n" + "3. Restart ndb and verify consistency\n" + "4. Drop bank\n") +{ + INITIALIZER(runCreateBank); + STEP(runBankTimer); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankGL); + STEP(runSR); +} +TESTCASE("Abort", + " Test that a consistent bank is restored after graceful shutdown\n" + "1. Create bank\n" + "2. Start bank and let it run\n" + "3. Restart ndb and verify consistency\n" + "4. Drop bank\n") +{ + INITIALIZER(runCreateBank); + STEP(runBankTimer); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankGL); + STEP(runSR); + FINALIZER(runDropBank); +} +NDBT_TESTSUITE_END(testSRBank); + +int main(int argc, const char** argv){ + ndb_init(); + return testSRBank.execute(argc, argv); +} + + diff --git a/ndb/test/sql/test_create_drop.pl b/ndb/test/sql/test_create_drop.pl new file mode 100644 index 00000000000..7f62898b3d1 --- /dev/null +++ b/ndb/test/sql/test_create_drop.pl @@ -0,0 +1,179 @@ +use strict; +use IO::Socket; +use DBI; + +# mgm info +my $mgmhost = "localhost"; +my $mgmport = 38101; + +# location of ndb_x_fs +my $datadir = "c2"; +my @schemafiles = <$datadir/ndb_*_fs/D[12]/DBDICT/P0.SchemaLog>; +@schemafiles or die "no schemafiles in $datadir"; + +my $dsn; +$dsn = "dbi:mysql:test:localhost;port=38100"; + +# this works better for me +my $cnf = $ENV{MYSQL_HOME} . "/var/my.cnf"; +$dsn = "dbi:mysql:database=test;host=localhost;mysql_read_default_file=$cnf"; + +my $dbh; +$dbh = DBI->connect($dsn, 'root', undef, { RaiseError => 0, PrintError => 0 }); +$dbh or die $DBI::errstr; + +# mgm commands + +my $mgm = undef; + +sub mgmconnect { + $mgm = IO::Socket::INET->new( + Proto => "tcp", + PeerHost => $mgmhost, + PeerPort => $mgmport); + $mgm or die "connect to mgm failed: $!"; + $mgm->autoflush(1); +}; + +mgmconnect(); +warn "connected to mgm $mgmhost $mgmport\n"; + +my $nodeinfo = {}; + +sub getnodeinfo { + $nodeinfo = {}; + $mgm->print("get status\n"); + $mgm->print("\n"); + while (defined($_ = $mgm->getline)) { + /^node\s+status/ && last; + } + while (defined($_ = $mgm->getline)) { + /^\s*$/ && last; + /^node\.(\d+)\.(\w+):\s*(\S+)/ && ($nodeinfo->{$1}{$2} = $3); + } +} + +getnodeinfo(); + +my @dbnode = (); +for my $n (keys %$nodeinfo) { + my $p = $nodeinfo->{$n}; + ($p->{type} eq 'NDB') && push(@dbnode, $n); +} +@dbnode = sort { $a <=> $b } @dbnode; +@dbnode or die "mgm error, found no db nodes"; +warn "db nodes: @dbnode\n"; + +sub restartnode { + my($n, $initialstart) = @_; + warn "restart node $n initialstart=$initialstart\n"; + $mgm->print("restart node\n"); + $mgm->print("node: $n\n"); + $mgm->print("initialstart: $initialstart\n"); + $mgm->print("\n"); + while (1) { + sleep 5; + getnodeinfo(); + my $status = $nodeinfo->{$n}{status}; + my $sp = $nodeinfo->{$n}{startphase}; + warn "node $n status: $status sp: $sp\n"; + last if $status eq 'STARTED'; + } +} + +sub restartall { + warn "restart all\n"; + $mgm->print("restart all\n"); + $mgm->print("\n"); + while (1) { + sleep 5; + getnodeinfo(); + my $ok = 1; + for my $n (@dbnode) { + my $status = $nodeinfo->{$n}{status}; + my $sp = $nodeinfo->{$n}{startphase}; + warn "node $n status: $status sp: $sp\n"; + $ok = 0 if $status ne 'STARTED'; + } + last if $ok; + } +} + +# the sql stuff + +my $maxtab = 300; +my @tab = (); + +sub create { + my($n) = @_; + my $sql = "create table t$n (a int primary key, b varchar(20), key (b)) engine=ndb"; + warn "create t$n\n"; + $dbh->do($sql) or die "$sql\n$DBI::errstr"; +} + +sub drop { + my($n) = @_; + my $sql = "drop table t$n"; + warn "drop t$n\n"; + $dbh->do($sql) or die "$sql\n$DBI::errstr"; +} + +sub dropall { + for my $n (0..($maxtab-1)) { + my $sql = "drop table if exists t$n"; + $dbh->do($sql) or die "$sql\n$DBI::errstr"; + } +} + +sub createdrop { + my $n = int(rand($maxtab)); + if (! $tab[$n]) { + create($n); + $tab[$n] = 1; + } else { + drop($n); + $tab[$n] = 0; + } +} + +sub checkschemafiles { + system("printSchemaFile -ce @schemafiles"); + $? == 0 or die "schemafiles check failed"; +} + +sub randomrestart { + my($k) = @_; + my $s = int(rand(500)); + if ($s < 2) { + my $i = $k % scalar(@dbnode); + my $n = $dbnode[$i]; + my $initialstart = ($s < 1 ? 0 : 1); + restartnode($n, $initialstart); + return 1; + } + if ($s < 3) { + restartall(); + return 1; + } + return 0; +} + +# deterministic +srand(1); + +warn "drop any old tables\n"; +dropall(); + +my $loop = 1000000; +for my $k (0..($loop-1)) { + warn "$k\n"; + createdrop(); + checkschemafiles(); + if (randomrestart($k)) { + checkschemafiles(); + } +} + +$dbh->disconnect or die $DBI::errstr; + +# vim: set sw=2: diff --git a/mysql-test/ndb/ndb_range_bounds.pl b/ndb/test/sql/test_range_bounds.pl index abe1ea28298..abe1ea28298 100644 --- a/mysql-test/ndb/ndb_range_bounds.pl +++ b/ndb/test/sql/test_range_bounds.pl diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 7fd92db533e..8fecf56531f 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -148,6 +148,15 @@ NDBT_Context::decProperty(const char * name){ NdbCondition_Broadcast(propertyCondPtr); NdbMutex_Unlock(propertyMutexPtr); } +void +NDBT_Context::incProperty(const char * name){ + NdbMutex_Lock(propertyMutexPtr); + Uint32 val = 0; + props.get(name, &val); + props.put(name, (val + 1), true); + NdbCondition_Broadcast(propertyCondPtr); + NdbMutex_Unlock(propertyMutexPtr); +} void NDBT_Context::setProperty(const char* _name, const char* _val){ NdbMutex_Lock(propertyMutexPtr); diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index fe101b9c80b..9f65fe6b3bc 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -50,14 +50,17 @@ NdbBackup::start(unsigned int & _backup_id){ 2, // wait until completed &_backup_id, &reply) == -1) { - g_err << "Could not start backup " << endl; - g_err << "Error: " << reply.message << endl; + g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl; + g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl; + g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl; return -1; } if(reply.return_code != 0){ g_err << "PLEASE CHECK CODE NdbBackup.cpp line=" << __LINE__ << endl; - g_err << "Error: " << reply.message << endl; + g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl; + g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl; + g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl; return reply.return_code; } return 0; diff --git a/ndb/tools/ndb_config.cpp b/ndb/tools/ndb_config.cpp index d188aec1337..27ab6a182bb 100644 --- a/ndb/tools/ndb_config.cpp +++ b/ndb/tools/ndb_config.cpp @@ -23,6 +23,8 @@ #include <my_getopt.h> #include <mysql_version.h> +#include <netdb.h> + #include <NdbOut.hpp> #include <mgmapi.h> #include <mgmapi_configuration.hpp> @@ -31,7 +33,7 @@ static int g_verbose = 0; static int try_reconnect = 3; -static int g_nodes = 1; +static int g_nodes, g_connections, g_section; static const char * g_connectstring = 0; static const char * g_query = 0; @@ -40,8 +42,11 @@ static const char * g_type = 0; static const char * g_host = 0; static const char * g_field_delimiter=","; static const char * g_row_delimiter=" "; +static const char * g_config_file = 0; +static int g_mycnf = 0; int g_print_full_config, opt_ndb_shm; +my_bool opt_core; typedef ndb_mgm_configuration_iterator Iter; @@ -65,13 +70,19 @@ static struct my_option my_long_options[] = "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", (gptr*) &g_connectstring, (gptr*) &g_connectstring, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "ndb-shm", 256, "Print nodes", + (gptr*) &opt_ndb_shm, (gptr*) &opt_ndb_shm, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { "nodes", 256, "Print nodes", (gptr*) &g_nodes, (gptr*) &g_nodes, - 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + { "connections", 256, "Print connections", + (gptr*) &g_connections, (gptr*) &g_connections, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { "query", 'q', "Query option(s)", (gptr*) &g_query, (gptr*) &g_query, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - { "host", 257, "Host", + { "host", 256, "Host", (gptr*) &g_host, (gptr*) &g_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "type", 258, "Type of node/connection", @@ -89,6 +100,12 @@ static struct my_option my_long_options[] = { "rows", 'r', "Row separator", (gptr*) &g_row_delimiter, (gptr*) &g_row_delimiter, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "config-file", 256, "Path to config.ini", + (gptr*) &g_config_file, (gptr*) &g_config_file, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "mycnf", 256, "Read config from my.cnf", + (gptr*) &g_mycnf, (gptr*) &g_mycnf, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -123,6 +140,11 @@ struct Match { int m_key; BaseString m_value; + virtual int eval(const Iter&); +}; + +struct HostMatch : public Match +{ virtual int eval(NdbMgmHandle, const Iter&); }; @@ -131,18 +153,26 @@ struct Apply Apply() {} Apply(int val) { m_key = val;} int m_key; - virtual int apply(NdbMgmHandle, const Iter&); + virtual int apply(const Iter&); }; struct NodeTypeApply : public Apply { - virtual int apply(NdbMgmHandle, const Iter&); + virtual int apply(const Iter&); +}; + +struct ConnectionTypeApply : public Apply +{ + virtual int apply(const Iter&); }; static int parse_query(Vector<Apply*>&, int &argc, char**& argv); static int parse_where(Vector<Match*>&, int &argc, char**& argv); -static int eval(NdbMgmHandle, const Iter&, const Vector<Match*>&); -static int apply(NdbMgmHandle, const Iter&, const Vector<Apply*>&); +static int eval(const Iter&, const Vector<Match*>&); +static int apply(const Iter&, const Vector<Apply*>&); +static ndb_mgm_configuration* fetch_configuration(); +static ndb_mgm_configuration* load_configuration(); + int main(int argc, char** argv){ NDB_INIT(argv[0]); @@ -153,51 +183,27 @@ main(int argc, char** argv){ ndb_std_get_one_option))) return -1; - NdbMgmHandle mgm = ndb_mgm_create_handle(); - if(mgm == NULL) { - fprintf(stderr, "Cannot create handle to management server.\n"); - exit(-1); - } - - ndb_mgm_set_error_stream(mgm, stderr); - - if (ndb_mgm_set_connectstring(mgm, g_connectstring)) + if (g_nodes && g_connections) { - fprintf(stderr, "* %5d: %s\n", - ndb_mgm_get_latest_error(mgm), - ndb_mgm_get_latest_error_msg(mgm)); - fprintf(stderr, - "* %s", ndb_mgm_get_latest_error_desc(mgm)); - exit(-1); + fprintf(stderr, + "Only one option of --nodes and --connections allowed\n"); + return -1; } - if(ndb_mgm_connect(mgm, try_reconnect-1, 5, 1)) - { - fprintf(stderr, "Connect failed"); - fprintf(stderr, " code: %d, msg: %s\n", - ndb_mgm_get_latest_error(mgm), - ndb_mgm_get_latest_error_msg(mgm)); - exit(-1); - } - else if(g_verbose) - { - fprintf(stderr, "Connected to %s:%d\n", - ndb_mgm_get_connected_host(mgm), - ndb_mgm_get_connected_port(mgm)); - } - - ndb_mgm_configuration * conf = ndb_mgm_get_configuration(mgm, 0); - if(conf == 0) - { - fprintf(stderr, "Could not get configuration"); - fprintf(stderr, "code: %d, msg: %s\n", - ndb_mgm_get_latest_error(mgm), - ndb_mgm_get_latest_error_msg(mgm)); - exit(-1); - } - else if(g_verbose) + g_section = CFG_SECTION_NODE; //default + if (g_connections) + g_section = CFG_SECTION_CONNECTION; + + ndb_mgm_configuration * conf = 0; + + if (g_config_file || g_mycnf) + conf = load_configuration(); + else + conf = fetch_configuration(); + + if (conf == 0) { - fprintf(stderr, "Fetched configuration\n"); + return -1; } Vector<Apply*> select_list; @@ -218,17 +224,17 @@ main(int argc, char** argv){ exit(0); } - Iter iter(* conf, CFG_SECTION_NODE); + Iter iter(* conf, g_section); bool prev= false; iter.first(); for(iter.first(); iter.valid(); iter.next()) { - if(eval(mgm, iter, where_clause)) + if(eval(iter, where_clause)) { if(prev) printf("%s", g_row_delimiter); prev= true; - apply(mgm, iter, select_list); + apply(iter, select_list); } } printf("\n"); @@ -247,13 +253,32 @@ parse_query(Vector<Apply*>& select, int &argc, char**& argv) for(unsigned i = 0; i<list.size(); i++) { const char * str= list[i].c_str(); - if(strcasecmp(str, "id") == 0 || strcasecmp(str, "nodeid") == 0) - select.push_back(new Apply(CFG_NODE_ID)); - else if(strncasecmp(str, "host", 4) == 0) - select.push_back(new Apply(CFG_NODE_HOST)); - else if(strcasecmp(str, "type") == 0) - select.push_back(new NodeTypeApply()); - else if(g_nodes) + if(g_section == CFG_SECTION_NODE) + { + if(strcasecmp(str, "id") == 0 || strcasecmp(str, "nodeid") == 0) + { + select.push_back(new Apply(CFG_NODE_ID)); + continue; + } + else if(strncasecmp(str, "host", 4) == 0) + { + select.push_back(new Apply(CFG_NODE_HOST)); + continue; + } + else if(strcasecmp(str, "type") == 0) + { + select.push_back(new NodeTypeApply()); + continue; + } + } + else if (g_section == CFG_SECTION_CONNECTION) + { + if(strcasecmp(str, "type") == 0) + { + select.push_back(new ConnectionTypeApply()); + continue; + } + } { bool found = false; for(int p = 0; p<ConfigInfo::m_NoOfParams; p++) @@ -261,9 +286,15 @@ parse_query(Vector<Apply*>& select, int &argc, char**& argv) if(0)ndbout_c("%s %s", ConfigInfo::m_ParamInfo[p]._section, ConfigInfo::m_ParamInfo[p]._fname); - if(strcmp(ConfigInfo::m_ParamInfo[p]._section, "DB") == 0 || - strcmp(ConfigInfo::m_ParamInfo[p]._section, "API") == 0 || - strcmp(ConfigInfo::m_ParamInfo[p]._section, "MGM") == 0) + if(g_section == CFG_SECTION_CONNECTION && + (strcmp(ConfigInfo::m_ParamInfo[p]._section, "TCP") == 0 || + strcmp(ConfigInfo::m_ParamInfo[p]._section, "SCI") == 0 || + strcmp(ConfigInfo::m_ParamInfo[p]._section, "SHM") == 0) + || + g_section == CFG_SECTION_NODE && + (strcmp(ConfigInfo::m_ParamInfo[p]._section, "DB") == 0 || + strcmp(ConfigInfo::m_ParamInfo[p]._section, "API") == 0 || + strcmp(ConfigInfo::m_ParamInfo[p]._section, "MGM") == 0)) { if(strcasecmp(ConfigInfo::m_ParamInfo[p]._fname, str) == 0) { @@ -279,11 +310,6 @@ parse_query(Vector<Apply*>& select, int &argc, char**& argv) return 1; } } - else - { - fprintf(stderr, "Unknown query option: %s\n", str); - return 1; - } } } return 0; @@ -296,9 +322,10 @@ parse_where(Vector<Match*>& where, int &argc, char**& argv) Match m; if(g_host) { - m.m_key = CFG_NODE_HOST; - m.m_value.assfmt("%s", g_host); - where.push_back(new Match(m)); + HostMatch *m = new HostMatch; + m->m_key = CFG_NODE_HOST; + m->m_value.assfmt("%s", g_host); + where.push_back(m); } if(g_type) @@ -322,11 +349,11 @@ template class Vector<Match*>; static int -eval(NdbMgmHandle mgm, const Iter& iter, const Vector<Match*>& where) +eval(const Iter& iter, const Vector<Match*>& where) { for(unsigned i = 0; i<where.size(); i++) { - if(where[i]->eval(mgm, iter) == 0) + if(where[i]->eval(iter) == 0) return 0; } @@ -335,11 +362,11 @@ eval(NdbMgmHandle mgm, const Iter& iter, const Vector<Match*>& where) static int -apply(NdbMgmHandle mgm, const Iter& iter, const Vector<Apply*>& list) +apply(const Iter& iter, const Vector<Apply*>& list) { for(unsigned i = 0; i<list.size(); i++) { - list[i]->apply(mgm, iter); + list[i]->apply(iter); if(i + 1 != list.size()) printf("%s", g_field_delimiter); } @@ -347,19 +374,19 @@ apply(NdbMgmHandle mgm, const Iter& iter, const Vector<Apply*>& list) } int -Match::eval(NdbMgmHandle h, const Iter& iter) +Match::eval(const Iter& iter) { Uint32 val32; Uint64 val64; const char* valc; if (iter.get(m_key, &val32) == 0) { - if(atoi(m_value.c_str()) != val32) + if(atoi(m_value.c_str()) != (int)val32) return 0; } else if(iter.get(m_key, &val64) == 0) { - if(strtoll(m_value.c_str(), (char **)NULL, 10) != val64) + if(strtoll(m_value.c_str(), (char **)NULL, 10) != (long long)val64) return 0; } else if(iter.get(m_key, &valc) == 0) @@ -375,7 +402,41 @@ Match::eval(NdbMgmHandle h, const Iter& iter) } int -Apply::apply(NdbMgmHandle h, const Iter& iter) +HostMatch::eval(NdbMgmHandle h, const Iter& iter) +{ + const char* valc; + + if(iter.get(m_key, &valc) == 0) + { + struct hostent *h1, *h2; + + h1 = gethostbyname(m_value.c_str()); + if (h1 == NULL) { + return 0; + } + + h2 = gethostbyname(valc); + if (h2 == NULL) { + return 0; + } + + if (h1->h_addrtype != h2->h_addrtype) { + return 0; + } + + if (h1->h_length != h2->h_length) + { + return 0; + } + + return 0 == memcmp(h1->h_addr, h2->h_addr, h1->h_length); + } + + return 0; +} + +int +Apply::apply(const Iter& iter) { Uint32 val32; Uint64 val64; @@ -396,7 +457,7 @@ Apply::apply(NdbMgmHandle h, const Iter& iter) } int -NodeTypeApply::apply(NdbMgmHandle h, const Iter& iter) +NodeTypeApply::apply(const Iter& iter) { Uint32 val32; if (iter.get(CFG_TYPE_OF_SECTION, &val32) == 0) @@ -405,3 +466,111 @@ NodeTypeApply::apply(NdbMgmHandle h, const Iter& iter) } return 0; } + +int +ConnectionTypeApply::apply(const Iter& iter) +{ + Uint32 val32; + if (iter.get(CFG_TYPE_OF_SECTION, &val32) == 0) + { + switch (val32) + { + case CONNECTION_TYPE_TCP: + printf("tcp"); + break; + case CONNECTION_TYPE_SCI: + printf("sci"); + break; + case CONNECTION_TYPE_SHM: + printf("shm"); + break; + default: + printf("<unknown>"); + break; + } + } + return 0; +} + +ndb_mgm_configuration* +fetch_configuration() +{ + ndb_mgm_configuration* conf = 0; + NdbMgmHandle mgm = ndb_mgm_create_handle(); + if(mgm == NULL) { + fprintf(stderr, "Cannot create handle to management server.\n"); + return 0; + } + + ndb_mgm_set_error_stream(mgm, stderr); + + if (ndb_mgm_set_connectstring(mgm, g_connectstring)) + { + fprintf(stderr, "* %5d: %s\n", + ndb_mgm_get_latest_error(mgm), + ndb_mgm_get_latest_error_msg(mgm)); + fprintf(stderr, + "* %s", ndb_mgm_get_latest_error_desc(mgm)); + goto noconnect; + } + + if(ndb_mgm_connect(mgm, try_reconnect-1, 5, 1)) + { + fprintf(stderr, "Connect failed"); + fprintf(stderr, " code: %d, msg: %s\n", + ndb_mgm_get_latest_error(mgm), + ndb_mgm_get_latest_error_msg(mgm)); + goto noconnect; + } + else if(g_verbose) + { + fprintf(stderr, "Connected to %s:%d\n", + ndb_mgm_get_connected_host(mgm), + ndb_mgm_get_connected_port(mgm)); + } + + conf = ndb_mgm_get_configuration(mgm, 0); + if(conf == 0) + { + fprintf(stderr, "Could not get configuration"); + fprintf(stderr, "code: %d, msg: %s\n", + ndb_mgm_get_latest_error(mgm), + ndb_mgm_get_latest_error_msg(mgm)); + } + else if(g_verbose) + { + fprintf(stderr, "Fetched configuration\n"); + } + + ndb_mgm_disconnect(mgm); +noconnect: + ndb_mgm_destroy_handle(&mgm); + + return conf; +} + +#include <Config.hpp> + +ndb_mgm_configuration* +load_configuration() +{ + InitConfigFileParser parser(stderr); + if (g_config_file) + { + if (g_verbose) + fprintf(stderr, "Using config.ini : %s", g_config_file); + + Config* conf = parser.parseConfig(g_config_file); + if (conf) + return conf->m_configValues; + } + + if (g_verbose) + fprintf(stderr, "Using my.cnf"); + + Config* conf = parser.parse_mycnf(); + if (conf) + return conf->m_configValues; + + return 0; +} diff --git a/ndb/tools/ndb_size.pl b/ndb/tools/ndb_size.pl new file mode 100644 index 00000000000..64a20423636 --- /dev/null +++ b/ndb/tools/ndb_size.pl @@ -0,0 +1,263 @@ +#!/usr/bin/perl -w + +use strict; + +use DBI; +use POSIX; +use HTML::Template; + +# MySQL Cluster size estimator +# ---------------------------- +# +# (C)2005 MySQL AB +# +# +# The purpose of this tool is to work out storage requirements +# from an existing MySQL database. +# +# This involves connecting to a mysql server and throwing a bunch +# of queries at it. +# +# We currently estimate sizes for: 4.1, 5.0 and 5.1 to various amounts +# of accurracy. +# +# There is no warranty. +# +# BUGS +# ---- +# - enum/set is 0 byte storage! Woah - efficient! +# - some float stores come out weird (when there's a comma e.g. 'float(4,1)') +# - no disk data values +# - computes the storage requirements of views (and probably MERGE) +# - ignores character sets. + +my $template = HTML::Template->new(filename => 'ndb_size.tmpl', + die_on_bad_params => 0); + +my $dbh; + +{ + my $database= $ARGV[0]; + my $hostname= $ARGV[1]; + my $port= $ARGV[2]; + my $user= $ARGV[3]; + my $password= $ARGV[4]; + my $dsn = "DBI:mysql:database=$database;host=$hostname;port=$port"; + $dbh= DBI->connect($dsn, $user, $password); + $template->param(db => $database); + $template->param(dsn => $dsn); +} + +my @releases = ({rel=>'4.1'},{rel=>'5.0'},{rel=>'5.1'}); +$template->param(releases => \@releases); + +my $tables = $dbh->selectall_arrayref("show tables"); + +my @table_size; + +sub align { + my($to,@unaligned) = @_; + my @aligned; + foreach my $x (@unaligned) { + push @aligned, $to * POSIX::floor(($x+$to-1)/$to); + } + return @aligned; +} + +foreach(@{$tables}) +{ + my $table= @{$_}[0]; + my @columns; + my $info= $dbh->selectall_hashref("describe ".$dbh->quote($table),"Field"); + my @count = $dbh->selectrow_array("select count(*) from " + .$dbh->quote($table)); + my %columnsize; # used for index calculations + + # We now work out the DataMemory usage + + # sizes for 4.1, 5.0, 5.1 + my @totalsize= (0,0,0); + + foreach(keys %$info) + { + my @realsize = (0,0,0); + my $type; + my $size; + my $name= $_; + + if($$info{$_}{Type} =~ /^(.*?)\((\d+)\)/) + { + $type= $1; + $size= $2; + } + else + { + $type= $$info{$_}{Type}; + } + + if($type =~ /tinyint/) + {@realsize=(1,1,1)} + elsif($type =~ /smallint/) + {@realsize=(2,2,2)} + elsif($type =~ /mediumint/) + {@realsize=(3,3,3)} + elsif($type =~ /bigint/) + {@realsize=(8,8,8)} + elsif($type =~ /int/) + {@realsize=(4,4,4)} + elsif($type =~ /float/) + { + if($size<=24) + {@realsize=(4,4,4)} + else + {@realsize=(8,8,8)} + } + elsif($type =~ /double/ || $type =~ /real/) + {@realsize=(8,8,8)} + elsif($type =~ /bit/) + { + my $a=($size+7)/8; + @realsize = ($a,$a,$a); + } + elsif($type =~ /datetime/) + {@realsize=(8,8,8)} + elsif($type =~ /timestamp/) + {@realsize=(4,4,4)} + elsif($type =~ /date/ || $type =~ /time/) + {@realsize=(3,3,3)} + elsif($type =~ /year/) + {@realsize=(1,1,1)} + elsif($type =~ /varchar/ || $type =~ /varbinary/) + { + my $fixed= 1+$size; + my @dynamic=$dbh->selectrow_array("select avg(length(" + .$dbh->quote($name) + .")) from ".$dbh->quote($table)); + $dynamic[0]=0 if !$dynamic[0]; + @realsize= ($fixed,$fixed,ceil($dynamic[0])); + } + elsif($type =~ /binary/ || $type =~ /char/) + {@realsize=($size,$size,$size)} + elsif($type =~ /text/ || $type =~ /blob/) + {@realsize=(256,256,1)} # FIXME check if 5.1 is correct + + @realsize= align(4,@realsize); + + $totalsize[$_]+=$realsize[$_] foreach 0..$#totalsize; + + my @realout; + push @realout,{val=>$_} foreach @realsize; + + push @columns, { + name=>$name, + type=>$type, + size=>$size, + key=>$$info{$_}{Key}, + datamemory=>\@realout, + }; + + $columnsize{$name}= \@realsize; # used for index calculations + } + + # And now... the IndexMemory usage. + # + # Firstly, we assemble some information about the indexes. + # We use SHOW INDEX instead of using INFORMATION_SCHEMA so + # we can still connect to pre-5.0 mysqlds. + my %indexes; + { + my $sth= $dbh->prepare("show index from "$dbh->quote($table)); + $sth->execute; + while(my $i = $sth->fetchrow_hashref) + { + $indexes{${%$i}{Key_name}}= { + type=>${%$i}{Index_type}, + unique=>!${%$i}{Non_unique}, + comment=>${%$i}{Comment}, + } if !defined($indexes{${%$i}{Key_name}}); + + $indexes{${%$i}{Key_name}}{columns}[${%$i}{Seq_in_index}-1]= + ${%$i}{Column_name}; + } + } + + if(!defined($indexes{PRIMARY})) { + $indexes{PRIMARY}= { + type=>'BTREE', + unique=>1, + comment=>'Hidden pkey created by NDB', + columns=>['HIDDEN_NDB_PKEY'], + }; + push @columns, { + name=>'HIDDEN_NDB_PKEY', + type=>'bigint', + size=>8, + key=>'PRI', + datamemory=>[{val=>8},{val=>8},{val=>8}], + }; + $columnsize{'HIDDEN_NDB_PKEY'}= [8,8,8]; + } + + my @IndexDataMemory= ({val=>0},{val=>0},{val=>0}); + my @RowIndexMemory= ({val=>0},{val=>0},{val=>0}); + + my @indexes; + foreach my $index (keys %indexes) { + my $im41= 25; + $im41+=$columnsize{$_}[0] foreach @{$indexes{$index}{columns}}; + my @im = ({val=>$im41},{val=>25},{val=>25}); + my @dm = ({val=>10},{val=>10},{val=>10}); + push @indexes, { + name=>$index, + type=>$indexes{$index}{type}, + columns=>join(',',@{$indexes{$index}{columns}}), + indexmemory=>\@im, + datamemory=>\@dm, + }; + $IndexDataMemory[$_]{val}+=$dm[$_]{val} foreach 0..2; + $RowIndexMemory[$_]{val}+=$im[$_]{val} foreach 0..2; + } + + # total size + 16 bytes overhead + my @TotalDataMemory; + $TotalDataMemory[$_]{val}=$IndexDataMemory[$_]{val}+$totalsize[$_]+16 foreach 0..2; + + my @RowDataMemory; + push @RowDataMemory,{val=>$_} foreach @totalsize; + + my @RowPerPage; + push @RowPerPage,{val=>(floor((32768-128)/$TotalDataMemory[$_]{val}))} foreach 0..$#TotalDataMemory; + + my @RowPerIndexPage; + push @RowPerIndexPage,{val=>(floor(8192/$RowIndexMemory[$_]{val}))} foreach 0..$#TotalDataMemory; + + my @DataMemory; + push @DataMemory,{val=>ceil(($count[0]/($RowPerPage[$_]{val})))*32} foreach 0..$#RowPerPage; + + my @IndexMemory; + push @IndexMemory,{val=>ceil(($count[0]/($RowPerIndexPage[$_]{val})))*8} foreach 0..$#RowPerPage; + + my $count= $count[0]; + my @counts; + $counts[$_]{val}= $count foreach 0..$#releases; + + push @table_size, { + table=>$table, + indexes=>\@indexes, + columns=>\@columns, + count=>\@counts, + RowDataMemory=>\@RowDataMemory, + releases=>\@releases, + IndexDataMemory=>\@IndexDataMemory, + TotalDataMemory=>\@TotalDataMemory, + RowPerPage=>\@RowPerPage, + DataMemory=>\@DataMemory, + RowIndexMemory=>\@RowIndexMemory, + RowPerIndexPage=>\@RowPerIndexPage, + IndexMemory=>\@IndexMemory, + + }; +} + +$template->param(tables => \@table_size); +print $template->output; diff --git a/ndb/tools/ndb_size.tmpl b/ndb/tools/ndb_size.tmpl new file mode 100644 index 00000000000..d83d5d2c6af --- /dev/null +++ b/ndb/tools/ndb_size.tmpl @@ -0,0 +1,175 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/> + <meta name="keywords" content="MySQL Cluster" /> + <title>MySQL Cluster size estimate for <TMPL_VAR NAME="db" ESCAPE="HTML"></title> +<style type="text/css"> +table { border-collapse: collapse } +td,th { border: 1px solid black } +</style> + </head> +<body> +<h1>MySQL Cluster analysis for <TMPL_VAR NAME="db" escape="html"></h1> +<p>This is an automated analysis of the <TMPL_VAR NAME="DSN" escape="html"> database for migration into <a href="http://www.mysql.com/">MySQL</a> Cluster. No warranty is made to the accuracy of the information.</p> + +<p>This information should be valid for MySQL 4.1</p> + +<ul> +<TMPL_LOOP NAME="tables"> +<li><TMPL_VAR NAME="table"></li> +</TMPL_LOOP> +</ul> + +<hr/> + +<TMPL_LOOP NAME="tables"> +<h2><TMPL_VAR NAME="table"></h2> +<table> + <tr> + <th>Column</th> + <th>Type</th> + <th>Size</th> + <th>Key</th> + <TMPL_LOOP NAME=releases> + <th><TMPL_VAR NAME=rel> NDB Size</th> + </TMPL_LOOP> + </tr> + <TMPL_LOOP NAME="columns"> + <tr> + <td><TMPL_VAR NAME=name></td> + <td><TMPL_VAR NAME=type></td> + <td><TMPL_VAR NAME=size></td> + <td><TMPL_VAR NAME=key></td> + <TMPL_LOOP NAME=datamemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> + </tr> + </TMPL_LOOP> +</table> + +<p> </p> + +<h3>Indexes</h3> + +<p>We assume that indexes are ORDERED (not created USING HASH). If order is not required, 10 bytes of data memory can be saved per row if the index is created USING HASH</p> +<table> +<tr> + <th>Index</th> + <th>Type</th> + <th>Columns</th> + <TMPL_LOOP NAME=releases> + <th><TMPL_VAR NAME=rel> IdxMem</th> + </TMPL_LOOP> + <TMPL_LOOP NAME=releases> + <th><TMPL_VAR NAME=rel> DatMem</th> + </TMPL_LOOP> +</tr> +<TMPL_LOOP NAME="indexes"> + <tr> + <td><TMPL_VAR NAME=name></td> + <td><TMPL_VAR NAME=type></td> + <td><TMPL_VAR NAME=columns></td> + <TMPL_LOOP NAME=indexmemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> + <TMPL_LOOP NAME=datamemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> + </tr> +</TMPL_LOOP> +</table> + +<h3>DataMemory Usage</h3> +<table> +<tr> + <th> </th> + <TMPL_LOOP NAME=releases> + <th><TMPL_VAR NAME=rel></th> + </TMPL_LOOP> +</tr> +<tr> + <th>Row Overhead</th> + <TMPL_LOOP NAME=releases> + <td>16</td> + </TMPL_LOOP> +</tr> +<tr> + <th>Column DataMemory/Row</th> + <TMPL_LOOP NAME=RowDataMemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Index DataMemory/Row</th> + <TMPL_LOOP NAME=IndexDataMemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Total DataMemory/Row</th> + <TMPL_LOOP NAME=TotalDataMemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Rows per 32kb page</th> + <TMPL_LOOP NAME=RowPerPage> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Current number of rows</th> + <TMPL_LOOP NAME=count> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Total DataMemory (kb)</th> + <TMPL_LOOP NAME=DataMemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +</table> + +<h3>IndexMemory Usage</h3> +<table> +<tr> + <th> </th> + <TMPL_LOOP NAME=releases> + <th><TMPL_VAR NAME=rel></th> + </TMPL_LOOP> +</tr> +<tr> + <th>IndexMemory/Row</th> + <TMPL_LOOP NAME=RowIndexMemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Rows per 8kb page</th> + <TMPL_LOOP NAME=RowPerIndexPage> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Current number of rows</th> + <TMPL_LOOP NAME=count> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +<tr> + <th>Total IndexMemory (kb)</th> + <TMPL_LOOP NAME=IndexMemory> + <td><TMPL_VAR NAME=val></td> + </TMPL_LOOP> +</tr> +</table> + +<hr/> +</TMPL_LOOP> + +<p>This is the output of ndb_size.pl.</p> +</body> +</html> + diff --git a/ndb/tools/restore/Restore.cpp b/ndb/tools/restore/Restore.cpp index 60fbf7f8ceb..6ac06f8a6f8 100644 --- a/ndb/tools/restore/Restore.cpp +++ b/ndb/tools/restore/Restore.cpp @@ -869,7 +869,7 @@ operator<<(NdbOut& ndbout, const AttributeS& attr){ return ndbout; } - NdbRecAttr tmprec; + NdbRecAttr tmprec(0); tmprec.setup(desc.m_column, (char *)data.void_value); ndbout << tmprec; diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index 9dd8c4bf92d..552246a4f9e 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -14,9 +14,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <NDBT_ReturnCodes.h> #include "consumer_restore.hpp" #include <NdbSleep.h> +extern my_bool opt_core; + extern FilteredNdbOut err; extern FilteredNdbOut info; extern FilteredNdbOut debug; @@ -35,7 +38,7 @@ BackupRestore::init() m_cluster_connection = new Ndb_cluster_connection(g_connect_string); if(m_cluster_connection->connect(12, 5, 1) != 0) { - return -1; + return false; } m_ndb = new Ndb(m_cluster_connection); @@ -472,7 +475,11 @@ bool BackupRestore::errorHandler(restore_callback_t *cb) void BackupRestore::exitHandler() { release(); - exit(-1); + NDBT_ProgramExit(NDBT_FAILED); + if (opt_core) + abort(); + else + exit(NDBT_FAILED); } @@ -506,7 +513,7 @@ BackupRestore::logEntry(const LogEntry & tup) { // Deep shit, TODO: handle the error err << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const NdbDictionary::Table * table = get_table(tup.m_table->m_dictTable); @@ -514,7 +521,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (op == NULL) { err << "Cannot get operation: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if int check = 0; @@ -532,13 +539,13 @@ BackupRestore::logEntry(const LogEntry & tup) default: err << "Log entry has wrong operation type." << " Exiting..."; - exit(-1); + exitHandler(); } if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if Bitmask<4096> keys; @@ -567,7 +574,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if } @@ -596,7 +603,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (!ok) { err << "execute failed: " << errobj << endl; - exit(-1); + exitHandler(); } } @@ -643,7 +650,7 @@ BackupRestore::tuple(const TupleS & tup) { // Deep shit, TODO: handle the error ndbout << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const TableS * table = tup.getTable(); @@ -652,7 +659,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "Cannot get operation: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if // TODO: check return value and handle error @@ -660,7 +667,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "writeTuple call failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if for (int i = 0; i < tup.getNoOfAttributes(); i++) @@ -694,7 +701,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "execute failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } m_ndb->closeTransaction(trans); if (ret == 0) diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp index 62fccfa3082..af7c751fb67 100644 --- a/ndb/tools/restore/restore_main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -20,6 +20,7 @@ #include <ndb_limits.h> #include <NdbTCP.h> #include <NdbOut.hpp> +#include <NDBT_ReturnCodes.h> #include "consumer_restore.hpp" #include "consumer_printer.hpp" @@ -118,14 +119,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (ga_nodeId == 0) { printf("Error in --nodeid,-n setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; case 'b': if (ga_backupId == 0) { printf("Error in --backupid,-b setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; } @@ -138,7 +139,7 @@ readArguments(int *pargc, char*** pargv) load_defaults("my",load_default_groups,pargc,pargv); if (handle_options(pargc, pargv, my_long_options, get_one_option)) { - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } BackupPrinter* printer = new BackupPrinter(); @@ -229,6 +230,14 @@ free_data_callback() } const char * g_connect_string = 0; +static void exitHandler(int code) +{ + NDBT_ProgramExit(code); + if (opt_core) + abort(); + else + exit(code); +} int main(int argc, char** argv) @@ -237,7 +246,7 @@ main(int argc, char** argv) if (!readArguments(&argc, &argv)) { - return -1; + exitHandler(NDBT_FAILED); } g_connect_string = opt_connect_str; @@ -249,7 +258,7 @@ main(int argc, char** argv) if (!metaData.readHeader()) { ndbout << "Failed to read " << metaData.getFilename() << endl << endl; - return -1; + exitHandler(NDBT_FAILED); } const BackupFormat::FileHeader & tmp = metaData.getFileHeader(); @@ -267,20 +276,20 @@ main(int argc, char** argv) if (res == 0) { ndbout_c("Restore: Failed to load content"); - return -1; + exitHandler(NDBT_FAILED); } if (metaData.getNoOfTables() == 0) { ndbout_c("Restore: The backup contains no tables "); - return -1; + exitHandler(NDBT_FAILED); } if (!metaData.validateFooter()) { ndbout_c("Restore: Failed to validate footer."); - return -1; + exitHandler(NDBT_FAILED); } Uint32 i; @@ -289,7 +298,7 @@ main(int argc, char** argv) if (!g_consumers[i]->init()) { clearConsumers(); - return -11; + exitHandler(NDBT_FAILED); } } @@ -304,7 +313,7 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } @@ -313,7 +322,7 @@ main(int argc, char** argv) if (!g_consumers[i]->endOfTables()) { ndbout_c("Restore: Failed while closing tables"); - return -11; + exitHandler(NDBT_FAILED); } if (ga_restore || ga_print) @@ -326,7 +335,7 @@ main(int argc, char** argv) if (!dataIter.readHeader()) { ndbout << "Failed to read header of data file. Exiting..." ; - return -11; + exitHandler(NDBT_FAILED); } @@ -344,12 +353,12 @@ main(int argc, char** argv) { ndbout_c("Restore: An error occured while restoring data. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } if (!dataIter.validateFragmentFooter()) { ndbout_c("Restore: Error validating fragment footer. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } } // while (dataIter.readFragmentHeader(res)) @@ -357,7 +366,7 @@ main(int argc, char** argv) { err << "Restore: An error occured while restoring data. Exiting... " << "res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } @@ -373,7 +382,7 @@ main(int argc, char** argv) if (!logIter.readHeader()) { err << "Failed to read header of data file. Exiting..." << endl; - return -1; + exitHandler(NDBT_FAILED); } const LogEntry * logEntry = 0; @@ -387,7 +396,7 @@ main(int argc, char** argv) { err << "Restore: An restoring the data log. Exiting... res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } logIter.validateFooter(); //not implemented for (i= 0; i < g_consumers.size(); i++) @@ -406,14 +415,14 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to finalize restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } } } clearConsumers(); - return 0; + return NDBT_ProgramExit(NDBT_OK); } // main template class Vector<BackupConsumer*>; diff --git a/netware/BUILD/mwenv b/netware/BUILD/mwenv index 7f89a8faf7f..fa52568fcd6 100755 --- a/netware/BUILD/mwenv +++ b/netware/BUILD/mwenv @@ -19,9 +19,9 @@ export AR='mwldnlm' export AR_FLAGS='-type library -o' export AS='mwasmnlm' export CC='mwccnlm -gccincludes' -export CFLAGS='-enum int -O3 -align 8 -proc 686 -relax_pointers -dialect c' +export CFLAGS='-enum int -align 8 -proc 686 -relax_pointers -dialect c' export CXX='mwccnlm -gccincludes' -export CXXFLAGS='-enum int -O3 -align 8 -proc 686 -relax_pointers -dialect c++ -bool on -wchar_t on -D_WCHAR_T' +export CXXFLAGS='-enum int -align 8 -proc 686 -relax_pointers -dialect c++ -bool on -wchar_t on -D_WCHAR_T' export LD='mwldnlm' export LDFLAGS='-entry _LibCPrelude -exit _LibCPostlude -map -flags pseudopreemption' export RANLIB=: diff --git a/netware/mysql.def b/netware/mysql.def index b79c94b1bb1..16acc7babe1 100644 --- a/netware/mysql.def +++ b/netware/mysql.def @@ -6,6 +6,7 @@ SCREENNAME "MySQL Monitor[scrollable]" COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Monitor" VERSION 4, 0 +STACKSIZE 32768 MULTIPLE XDCDATA ../netware/mysql.xdc #DEBUG diff --git a/netware/mysql_test_run.c b/netware/mysql_test_run.c index 7ca242178ff..92ed89b4770 100644 --- a/netware/mysql_test_run.c +++ b/netware/mysql_test_run.c @@ -173,7 +173,7 @@ void report_stats() log_msg("\nFailed %u/%u test(s), %.02f%% successful.\n", total_fail, total_test, percent); log_msg("\nThe .out and .err files in %s may give you some\n", result_dir); - log_msg("hint of what when wrong.\n"); + log_msg("hint of what went wrong.\n"); log_msg("\nIf you want to report this error, please first read the documentation\n"); log_msg("at: http://www.mysql.com/doc/en/MySQL_test_suite.html\n"); } diff --git a/netware/pack_isam.def b/netware/pack_isam.def index b93cfdffbeb..9ea72a4f2e7 100644 --- a/netware/pack_isam.def +++ b/netware/pack_isam.def @@ -2,8 +2,10 @@ # Pack ISAM #------------------------------------------------------------------------------ MODULE libc.nlm +SCREENNAME "MySQL ISAM Table Pack Tool" COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL ISAM Table Pack Tool" +SCREENNAME "MySQL ISAM Table Pack Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc #DEBUG diff --git a/os2/MySQL-Source.icc b/os2/MySQL-Source.icc index de0ac75ec9c..342cb6c96b9 100644 --- a/os2/MySQL-Source.icc +++ b/os2/MySQL-Source.icc @@ -12,7 +12,7 @@ group client_global_pch = 'm_ctype.h', 'mysqld_error.h', 'my_list.h', 'my_sys.h', 'my_net.h', 'myisam.h', 'myisampack.h', '.\myisam\myisamdef.h', - '.\regex\regex.h' + '.\regex\my_regex.h' group server_global_pch = 'os2.h', @@ -38,7 +38,7 @@ group server_global_pch = 'my_tree.h', '..\mysys\my_static.h', 'netdb.h', 'thr_alarm.h', 'heap.h', '..\myisam\fulltext.h', '..\myisam\ftdefs.h', 'myisammrg.h', - '.\regex\regex.h' + '.\regex\my_regex.h' group server_pch = 'ha_heap.h', 'ha_myisammrg.h', 'opt_ft.h', diff --git a/regex/Makefile.am b/regex/Makefile.am index 3b161287d36..7e8478e8123 100644 --- a/regex/Makefile.am +++ b/regex/Makefile.am @@ -18,7 +18,7 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include noinst_LIBRARIES = libregex.a LDADD= libregex.a $(top_builddir)/strings/libmystrings.a -noinst_HEADERS = cclass.h cname.h regex2.h utils.h engine.c regex.h +noinst_HEADERS = cclass.h cname.h regex2.h utils.h engine.c my_regex.h libregex_a_SOURCES = regerror.c regcomp.c regexec.c regfree.c reginit.c noinst_PROGRAMS = re re_SOURCES = split.c debug.c main.c diff --git a/regex/debug.c b/regex/debug.c index bdd3e00d5a7..271b09bb27a 100644 --- a/regex/debug.c +++ b/regex/debug.c @@ -2,7 +2,8 @@ #include <m_ctype.h> #include <m_string.h> #include <sys/types.h> -#include <regex.h> + +#include "my_regex.h" #include "utils.h" #include "regex2.h" #include "debug.ih" @@ -15,7 +16,7 @@ */ void regprint(r, d) -regex_t *r; +my_regex_t *r; FILE *d; { register struct re_guts *g = r->re_g; diff --git a/regex/debug.ih b/regex/debug.ih index 0d91e170437..1e1fb11177c 100644 --- a/regex/debug.ih +++ b/regex/debug.ih @@ -4,7 +4,7 @@ extern "C" { #endif /* === debug.c === */ -void regprint(regex_t *r, FILE *d); +void regprint(my_regex_t *r, FILE *d); static void s_print(CHARSET_INFO *charset, register struct re_guts *g, FILE *d); static char *regchar(CHARSET_INFO *charset, int ch,char *buf); diff --git a/regex/engine.c b/regex/engine.c index c4c4efe7e2f..1968ca61a96 100644 --- a/regex/engine.c +++ b/regex/engine.c @@ -32,7 +32,7 @@ struct match { struct re_guts *g; int eflags; - regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ + my_regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ char *offp; /* offsets work from here */ char *beginp; /* start of string -- virtual NUL precedes */ char *endp; /* end of string -- virtual NUL here */ @@ -68,7 +68,7 @@ CHARSET_INFO *charset; register struct re_guts *g; char *str; size_t nmatch; -regmatch_t pmatch[]; +my_regmatch_t pmatch[]; int eflags; { register char *endp; @@ -148,8 +148,8 @@ int eflags; /* oh my, he wants the subexpressions... */ if (m->pmatch == NULL) - m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * - sizeof(regmatch_t)); + m->pmatch = (my_regmatch_t *)malloc((m->g->nsub + 1) * + sizeof(my_regmatch_t)); if (m->pmatch == NULL) { if (m->lastpos != NULL) free((char *)m->lastpos); diff --git a/regex/engine.ih b/regex/engine.ih index 7cfcb39fb2d..a9e98abef00 100644 --- a/regex/engine.ih +++ b/regex/engine.ih @@ -4,7 +4,7 @@ extern "C" { #endif /* === engine.c === */ -static int matcher(CHARSET_INFO *charset,register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags); +static int matcher(CHARSET_INFO *charset,register struct re_guts *g, char *string, size_t nmatch, my_regmatch_t pmatch[], int eflags); static char *dissect(CHARSET_INFO *charset,register struct match *m, char *start, char *stop, sopno startst, sopno stopst); static char *backref(CHARSET_INFO *charset, register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev); static char *fast(CHARSET_INFO *charset, register struct match *m, char *start, char *stop, sopno startst, sopno stopst); diff --git a/regex/main.c b/regex/main.c index 8fe16d74eee..fa97ca89047 100644 --- a/regex/main.c +++ b/regex/main.c @@ -1,9 +1,9 @@ #include <my_global.h> #include <m_string.h> #include <sys/types.h> -#include <regex.h> #include <assert.h> +#include "my_regex.h" #include "main.ih" char *progname; @@ -27,9 +27,9 @@ int main(argc, argv) int argc; char *argv[]; { - regex_t re; + my_regex_t re; # define NS 10 - regmatch_t subs[NS]; + my_regmatch_t subs[NS]; char erbuf[100]; int err; size_t len; @@ -74,9 +74,9 @@ char *argv[]; exit(status); } - err = regcomp(&re, argv[optind++], copts, &my_charset_latin1); + err = my_regcomp(&re, argv[optind++], copts, &my_charset_latin1); if (err) { - len = regerror(err, &re, erbuf, sizeof(erbuf)); + len = my_regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "error %s, %d/%d `%s'\n", eprint(err), (int) len, (int) sizeof(erbuf), erbuf); exit(status); @@ -84,7 +84,7 @@ char *argv[]; regprint(&re, stdout); if (optind >= argc) { - regfree(&re); + my_regfree(&re); exit(status); } @@ -92,9 +92,9 @@ char *argv[]; subs[0].rm_so = startoff; subs[0].rm_eo = strlen(argv[optind]) - endoff; } - err = regexec(&re, argv[optind], (size_t)NS, subs, eopts); + err = my_regexec(&re, argv[optind], (size_t)NS, subs, eopts); if (err) { - len = regerror(err, &re, erbuf, sizeof(erbuf)); + len = my_regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "error %s, %d/%d `%s'\n", eprint(err), (int) len, (int) sizeof(erbuf), erbuf); exit(status); @@ -136,7 +136,7 @@ FILE *in; const char *badpat = "invalid regular expression"; # define SHORT 10 const char *bpname = "REG_BADPAT"; - regex_t re; + my_regex_t re; while (fgets(inbuf, sizeof(inbuf), in) != NULL) { line++; @@ -163,27 +163,27 @@ FILE *in; options('c', f[1]) &~ REG_EXTENDED); } - ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf)); + ne = my_regerror(REG_BADPAT, (my_regex_t *)NULL, erbuf, sizeof(erbuf)); if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) { fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n", erbuf, badpat); status = 1; } - ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT); + ne = my_regerror(REG_BADPAT, (my_regex_t *)NULL, erbuf, (size_t)SHORT); if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' || ne != strlen(badpat)+1) { fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n", erbuf, SHORT-1, badpat); status = 1; } - ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf)); + ne = my_regerror(REG_ITOA|REG_BADPAT, (my_regex_t *)NULL, erbuf, sizeof(erbuf)); if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) { fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n", erbuf, bpname); status = 1; } re.re_endp = bpname; - ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf)); + ne = my_regerror(REG_ATOI, &re, erbuf, sizeof(erbuf)); if (atoi(erbuf) != (int)REG_BADPAT) { fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n", erbuf, (long)REG_BADPAT); @@ -208,9 +208,9 @@ char *f3; char *f4; int opts; /* may not match f1 */ { - regex_t re; + my_regex_t re; # define NSUBS 10 - regmatch_t subs[NSUBS]; + my_regmatch_t subs[NSUBS]; # define NSHOULD 15 char *should[NSHOULD]; int nshould; @@ -226,10 +226,10 @@ int opts; /* may not match f1 */ strcpy(f0copy, f0); re.re_endp = (opts®_PEND) ? f0copy + strlen(f0copy) : NULL; fixstr(f0copy); - err = regcomp(&re, f0copy, opts, &my_charset_latin1); + err = my_regcomp(&re, f0copy, opts, &my_charset_latin1); if (err != 0 && (!opt('C', f1) || err != efind(f2))) { /* unexpected error or wrong error */ - len = regerror(err, &re, erbuf, sizeof(erbuf)); + len = my_regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n", line, type, eprint(err), len, (int) sizeof(erbuf), erbuf); @@ -243,7 +243,7 @@ int opts; /* may not match f1 */ } if (err != 0) { - regfree(&re); + my_regfree(&re); return; } @@ -256,11 +256,11 @@ int opts; /* may not match f1 */ subs[0].rm_so = strchr(f2, '(') - f2 + 1; subs[0].rm_eo = strchr(f2, ')') - f2; } - err = regexec(&re, f2copy, NSUBS, subs, options('e', f1)); + err = my_regexec(&re, f2copy, NSUBS, subs, options('e', f1)); if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) { /* unexpected error or wrong error */ - len = regerror(err, &re, erbuf, sizeof(erbuf)); + len = my_regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n", line, type, eprint(err), len, (int) sizeof(erbuf), erbuf); @@ -282,7 +282,7 @@ int opts; /* may not match f1 */ } if (err != 0 || f4 == NULL) { - regfree(&re); + my_regfree(&re); return; } @@ -303,7 +303,7 @@ int opts; /* may not match f1 */ } } - regfree(&re); + my_regfree(&re); } /* @@ -404,7 +404,7 @@ register char *p; char * /* NULL or complaint */ check(str, sub, should) char *str; -regmatch_t sub; +my_regmatch_t sub; char *should; { register int len; @@ -485,7 +485,7 @@ int err; static char epbuf[100]; size_t len; - len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf)); + len = my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf)); assert(len <= sizeof(epbuf)); return(epbuf); } @@ -499,11 +499,11 @@ efind(name) char *name; { static char efbuf[100]; - regex_t re; + my_regex_t re; sprintf(efbuf, "REG_%s", name); assert(strlen(efbuf) < sizeof(efbuf)); re.re_endp = efbuf; - (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf)); + (void) my_regerror(REG_ATOI, &re, efbuf, sizeof(efbuf)); return(atoi(efbuf)); } diff --git a/regex/main.ih b/regex/main.ih index 4b16e676ad3..f0104cc18c0 100644 --- a/regex/main.ih +++ b/regex/main.ih @@ -9,7 +9,7 @@ void rx_try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts); int options(int type, char *s); int opt(int c, char *s); void fixstr(register char *p); -char *check(char *str, regmatch_t sub, char *should); +char *check(char *str, my_regmatch_t sub, char *should); static char *eprint(int err); static int efind(char *name); diff --git a/regex/regex.h b/regex/my_regex.h index e0fb0c77dc9..0d1cedf5430 100644 --- a/regex/regex.h +++ b/regex/my_regex.h @@ -20,15 +20,15 @@ typedef struct { const char *re_endp; /* end pointer for REG_PEND */ struct re_guts *re_g; /* none of your business :-) */ CHARSET_INFO *charset; /* For ctype things */ -} regex_t; +} my_regex_t; typedef struct { regoff_t rm_so; /* start of match */ regoff_t rm_eo; /* end of match */ -} regmatch_t; +} my_regmatch_t; /* === regcomp.c === */ -extern int regcomp(regex_t *, const char *, int, CHARSET_INFO *charset); +extern int my_regcomp(my_regex_t *, const char *, int, CHARSET_INFO *charset); #define REG_BASIC 0000 #define REG_EXTENDED 0001 #define REG_ICASE 0002 @@ -58,11 +58,11 @@ extern int regcomp(regex_t *, const char *, int, CHARSET_INFO *charset); #define REG_INVARG 16 #define REG_ATOI 255 /* convert name to number (!) */ #define REG_ITOA 0400 /* convert number to name (!) */ -extern size_t regerror(int, const regex_t *, char *, size_t); +extern size_t my_regerror(int, const my_regex_t *, char *, size_t); /* === regexec.c === */ -extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); +extern int my_regexec(const my_regex_t *, const char *, size_t, my_regmatch_t [], int); #define REG_NOTBOL 00001 #define REG_NOTEOL 00002 #define REG_STARTEND 00004 @@ -72,12 +72,12 @@ extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); /* === regfree.c === */ -extern void regfree(regex_t *); +extern void my_regfree(my_regex_t *); /* === reginit.c === */ -extern void regex_init(CHARSET_INFO *cs); /* Should be called for multithread progs */ -extern void regex_end(void); /* If one wants a clean end */ +extern void my_regex_init(CHARSET_INFO *cs); /* Should be called for multithread progs */ +extern void my_regex_end(void); /* If one wants a clean end */ #ifdef __cplusplus } diff --git a/regex/regcomp.c b/regex/regcomp.c index 998b39379aa..9cba56a97dd 100644 --- a/regex/regcomp.c +++ b/regex/regcomp.c @@ -1,11 +1,11 @@ #include <my_global.h> #include <m_string.h> #include <m_ctype.h> -#include <regex.h> #ifdef __WIN__ #include <limits.h> #endif +#include "my_regex.h" #include "utils.h" #include "regex2.h" @@ -100,8 +100,8 @@ static int never = 0; /* for use in asserts; shuts lint up */ = #define REG_DUMP 0200 */ int /* 0 success, otherwise REG_something */ -regcomp(preg, pattern, cflags, charset) -regex_t *preg; +my_regcomp(preg, pattern, cflags, charset) +my_regex_t *preg; const char *pattern; int cflags; CHARSET_INFO *charset; @@ -117,7 +117,7 @@ CHARSET_INFO *charset; # define GOODFLAGS(f) ((f)&~REG_DUMP) #endif - regex_init(charset); /* Init cclass if neaded */ + my_regex_init(charset); /* Init cclass if neaded */ preg->charset=charset; cflags = GOODFLAGS(cflags); if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) @@ -199,7 +199,7 @@ CHARSET_INFO *charset; /* win or lose, we're done */ if (p->error != 0) /* lose */ - regfree(preg); + my_regfree(preg); return(p->error); } diff --git a/regex/regerror.c b/regex/regerror.c index 9caa5b95a4c..489f2e35abb 100644 --- a/regex/regerror.c +++ b/regex/regerror.c @@ -1,8 +1,8 @@ #include <my_global.h> #include <m_string.h> #include <m_ctype.h> -#include <regex.h> +#include "my_regex.h" #include "utils.h" #include "regerror.ih" @@ -56,7 +56,7 @@ static struct rerr { */ /* ARGSUSED */ size_t -regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +my_regerror(int errcode, const my_regex_t *preg, char *errbuf, size_t errbuf_size) { register struct rerr *r; register size_t len; @@ -101,7 +101,7 @@ regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) */ static char * regatoi(preg, localbuf) -const regex_t *preg; +const my_regex_t *preg; char *localbuf; { register struct rerr *r; diff --git a/regex/regerror.ih b/regex/regerror.ih index 2cb668c24f0..a4d048022f8 100644 --- a/regex/regerror.ih +++ b/regex/regerror.ih @@ -4,7 +4,7 @@ extern "C" { #endif /* === regerror.c === */ -static char *regatoi(const regex_t *preg, char *localbuf); +static char *regatoi(const my_regex_t *preg, char *localbuf); #ifdef __cplusplus } diff --git a/regex/regexec.c b/regex/regexec.c index 723289bd0ad..b7ad83ba883 100644 --- a/regex/regexec.c +++ b/regex/regexec.c @@ -8,11 +8,10 @@ #include <my_global.h> #include <m_string.h> #include <m_ctype.h> -#include <regex.h> #ifdef __WIN__ #include <limits.h> #endif - +#include "my_regex.h" #include "utils.h" #include "regex2.h" @@ -110,11 +109,11 @@ static int nope = 0; /* for use in asserts; shuts lint up */ * have been prototyped. */ int /* 0 success, REG_NOMATCH failure */ -regexec(preg, str, nmatch, pmatch, eflags) -const regex_t *preg; +my_regexec(preg, str, nmatch, pmatch, eflags) +const my_regex_t *preg; const char *str; size_t nmatch; -regmatch_t pmatch[]; +my_regmatch_t pmatch[]; int eflags; { register struct re_guts *g = preg->re_g; diff --git a/regex/regfree.c b/regex/regfree.c index 6ab50735075..f764fcdf84e 100644 --- a/regex/regfree.c +++ b/regex/regfree.c @@ -2,7 +2,7 @@ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> -#include <regex.h> +#include "my_regex.h" #include "utils.h" #include "regex2.h" @@ -12,8 +12,8 @@ = extern void regfree(regex_t *); */ void -regfree(preg) -regex_t *preg; +my_regfree(preg) +my_regex_t *preg; { register struct re_guts *g; diff --git a/regex/reginit.c b/regex/reginit.c index 74ad3dc6de4..f0b53e64be3 100644 --- a/regex/reginit.c +++ b/regex/reginit.c @@ -7,7 +7,7 @@ static bool regex_inited=0; -void regex_init(CHARSET_INFO *cs) +void my_regex_init(CHARSET_INFO *cs) { char buff[CCLASS_LAST][256]; int count[CCLASS_LAST]; @@ -67,7 +67,7 @@ void regex_init(CHARSET_INFO *cs) return; } -void regex_end() +void my_regex_end() { if (regex_inited) { diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 474ebedda62..2f6dd8c52e5 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -127,6 +127,7 @@ SUFFIXES = .sh -e 's!@''innodb_system_libs''@!@innodb_system_libs@!' \ -e 's!@''openssl_libs''@!@openssl_libs@!' \ -e 's!@''VERSION''@!@VERSION@!' \ + -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \ -e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \ -e 's!@''COMPILATION_COMMENT''@!@COMPILATION_COMMENT@!' \ -e 's!@''MACHINE_TYPE''@!@MACHINE_TYPE@!' \ diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index fbdbd998138..5767728fe4f 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -1,56 +1,78 @@ #!/bin/sh -# The default path should be /usr/local -# Get some info from configure -# chmod +x ./scripts/setsomevars +# This is a script to create a TAR or ZIP binary distribution out of a +# built source tree. The output file will be put at the top level of +# the source tree, as "mysql-<vsn>....{tar.gz,zip}" +# +# The temporary directory path given to "--tmp=<path>" has to be +# absolute and with no spaces. machine=@MACHINE_TYPE@ system=@SYSTEM_TYPE@ version=@VERSION@ -export machine system version -SOURCE=`pwd` +SOURCE=`pwd` CP="cp -p" MV="mv" STRIP=1 DEBUG=0 SILENT=0 -MACHINE= +MACHINE="" +PLATFORM="" TMP=/tmp SUFFIX="" -NDBCLUSTER= - -parse_arguments() { - for arg do - case "$arg" in - --debug) DEBUG=1;; - --tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;; - --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; - --no-strip) STRIP=0 ;; - --machine=*) MACHINE=`echo "$arg" | sed -e "s;--machine=;;"` ;; - --silent) SILENT=1 ;; - --with-ndbcluster) NDBCLUSTER=1 ;; - *) - echo "Unknown argument '$arg'" - exit 1 - ;; - esac - done -} +NDBCLUSTER="" + +for arg do + case "$arg" in + --debug) DEBUG=1;; + --tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;; + --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; + --no-strip) STRIP=0 ;; + --machine=*) MACHINE=`echo "$arg" | sed -e "s;--machine=;;"` ;; + --platform=*) PLATFORM=`echo "$arg" | sed -e "s;--platform=;;"` ;; + --silent) SILENT=1 ;; + --with-ndbcluster) NDBCLUSTER=1 ;; + *) + echo "Unknown argument '$arg'" + exit 1 + ;; + esac +done -parse_arguments "$@" +# Remove vendor from $system +system=`echo $system | sed -e 's/[a-z]*-\(.*\)/\1/g'` +# Map OS names to "our" OS names (eg. darwin6.8 -> osx10.2) +system=`echo $system | sed -e 's/darwin6.*/osx10.2/g'` +system=`echo $system | sed -e 's/darwin7.*/osx10.3/g'` +system=`echo $system | sed -e 's/darwin8.*/osx10.4/g'` +system=`echo $system | sed -e 's/\(aix4.3\).*/\1/g'` +system=`echo $system | sed -e 's/\(aix5.1\).*/\1/g'` +system=`echo $system | sed -e 's/\(aix5.2\).*/\1/g'` +system=`echo $system | sed -e 's/\(aix5.3\).*/\1/g'` +system=`echo $system | sed -e 's/osf5.1b/tru64/g'` +system=`echo $system | sed -e 's/linux-gnu/linux/g'` +system=`echo $system | sed -e 's/solaris2.\([0-9]*\)/solaris\1/g'` +system=`echo $system | sed -e 's/sco3.2v\(.*\)/openserver\1/g'` +if [ x"$MACHINE" != x"" ] ; then + machine=$MACHINE +fi -#make +if [ x"$PLATFORM" != x"" ] ; then + platform="$PLATFORM" +else + platform="$system-$machine" +fi -# This should really be integrated with automake and not duplicate the +# FIXME This should really be integrated with automake and not duplicate the # installation list. BASE=$TMP/my_dist$SUFFIX if [ -d $BASE ] ; then - rm -r -f $BASE + rm -rf $BASE fi BS="" @@ -79,25 +101,29 @@ if [ $BASE_SYSTEM != "netware" ] ; then chmod o-rwx $BASE/data $BASE/data/* fi -for i in ChangeLog \ - Docs/mysql.info -do - if [ -f $i ] - then - $CP $i $BASE/docs - fi -done +# Copy files if they exists, warn for those that don't +copyfileto() +{ + destdir=$1 + shift + for i + do + if [ -f $i ] ; then + $CP $i $destdir + elif [ -d $i ] ; then + echo "Warning: Will not copy directory \"$i\"" + else + echo "Warning: Listed file not found \"$i\"" + fi + done +} -for i in COPYING COPYING.LIB README Docs/INSTALL-BINARY \ +copyfileto $BASE/docs ChangeLog Docs/mysql.info + +copyfileto $BASE COPYING COPYING.LIB README Docs/INSTALL-BINARY \ EXCEPTIONS-CLIENT MySQLEULA.txt LICENSE.doc README.NW -do - if [ -f $i ] - then - $CP $i $BASE - fi -done -# Non platform-specific bin files: +# Non platform-specific bin dir files: BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \ extra/resolveip$BS extra/my_print_defaults$BS \ extra/resolve_stack_dump$BS extra/mysql_waitpid$BS \ @@ -114,7 +140,7 @@ BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \ libmysqld/examples/mysqltest_embedded$BS \ "; -# Platform-specific bin files: +# Platform-specific bin dir files: if [ $BASE_SYSTEM = "netware" ] ; then BIN_FILES="$BIN_FILES \ netware/mysqld_safe$BS netware/mysql_install_db$BS \ @@ -137,45 +163,28 @@ else "; fi -for i in $BIN_FILES -do - if [ -f $i ] - then - $CP $i $BASE/bin - fi -done +copyfileto $BASE/bin $BIN_FILES if [ x$STRIP = x1 ] ; then strip $BASE/bin/* fi # Copy not binary files -for i in sql/mysqld.sym.gz -do - if [ -f $i ] - then - $CP $i $BASE/bin - fi -done +copyfileto $BASE/bin sql/mysqld.sym.gz if [ $BASE_SYSTEM = "netware" ] ; then - $CP -r netware/*.pl $BASE/scripts + $CP netware/*.pl $BASE/scripts $CP scripts/mysqlhotcopy $BASE/scripts/mysqlhotcopy.pl fi -for i in \ +copyfileto $BASE/lib \ libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* \ libmysql/libmysqlclient.* libmysql_r/.libs/libmysqlclient_r.a \ libmysql_r/.libs/libmysqlclient_r.so* libmysql_r/libmysqlclient_r.* \ mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a \ libmysqld/.libs/libmysqld.a libmysqld/.libs/libmysqld.so* \ - libmysqld/libmysqld.a netware/libmysql.imp -do - if [ -f $i ] - then - $CP $i $BASE/lib - fi -done + libmysqld/libmysqld.a netware/libmysql.imp \ + zlib/.libs/libz.a # convert the .a to .lib for NetWare if [ $BASE_SYSTEM = "netware" ] ; then @@ -186,7 +195,8 @@ if [ $BASE_SYSTEM = "netware" ] ; then done fi -$CP config.h include/* $BASE/include +copyfileto $BASE/include config.h include/* + rm -f $BASE/include/Makefile* $BASE/include/*.in $BASE/include/config-win.h if [ $BASE_SYSTEM != "netware" ] ; then rm -f $BASE/include/config-netware.h @@ -201,51 +211,60 @@ if [ $BASE_SYSTEM != "netware" ] ; then fi fi -$CP support-files/* $BASE/support-files -$CP scripts/*.sql $BASE/share +copyfileto $BASE/support-files support-files/* + +copyfileto $BASE/share scripts/*.sql $CP -r sql/share/* $MYSQL_SHARE rm -f $MYSQL_SHARE/Makefile* $MYSQL_SHARE/*/*.OLD -for i in mysql-test/mysql-test-run mysql-test/install_test_db \ +copyfileto $BASE/mysql-test \ + mysql-test/mysql-test-run mysql-test/install_test_db \ mysql-test/mysql-test-run.pl mysql-test/README \ mysql-test/valgrind.supp \ netware/mysql_test_run.nlm netware/install_test_db.ncf -do - if [ -f $i ] - then - $CP $i $BASE/mysql-test - fi -done $CP mysql-test/lib/*.pl $BASE/mysql-test/lib $CP mysql-test/lib/*.sql $BASE/mysql-test/lib +$CP mysql-test/t/*.def $BASE/mysql-test/t $CP mysql-test/include/*.inc $BASE/mysql-test/include $CP mysql-test/t/*.def $BASE/mysql-test/t $CP mysql-test/std_data/*.dat mysql-test/std_data/*.frm \ mysql-test/std_data/*.pem mysql-test/std_data/Moscow_leap \ mysql-test/std_data/des_key_file mysql-test/std_data/*.*001 \ + mysql-test/std_data/*.cnf \ $BASE/mysql-test/std_data -$CP mysql-test/t/*.test mysql-test/t/*.disabled mysql-test/t/*.opt \ +$CP mysql-test/t/*.test mysql-test/t/*.imtest \ + mysql-test/t/*.disabled mysql-test/t/*.opt \ mysql-test/t/*.slave-mi mysql-test/t/*.sh mysql-test/t/*.sql $BASE/mysql-test/t $CP mysql-test/r/*.result mysql-test/r/*.require \ $BASE/mysql-test/r if [ $BASE_SYSTEM != "netware" ] ; then chmod a+x $BASE/bin/* - $CP scripts/* $BASE/bin - $BASE/bin/replace \@localstatedir\@ ./data \@bindir\@ ./bin \@scriptdir\@ ./bin \@libexecdir\@ ./bin \@sbindir\@ ./bin \@prefix\@ . \@HOSTNAME\@ @HOSTNAME@ \@pkgdatadir\@ ./support-files < $SOURCE/scripts/mysql_install_db.sh > $BASE/scripts/mysql_install_db - $BASE/bin/replace \@prefix\@ /usr/local/mysql \@bindir\@ ./bin \@sbindir\@ ./bin \@libexecdir\@ ./bin \@MYSQLD_USER\@ @MYSQLD_USER@ \@localstatedir\@ /usr/local/mysql/data \@HOSTNAME\@ @HOSTNAME@ < $SOURCE/support-files/mysql.server.sh > $BASE/support-files/mysql.server + copyfileto $BASE/bin scripts/* + $BASE/bin/replace \@localstatedir\@ ./data \@bindir\@ ./bin \@scriptdir\@ \ + ./bin \@libexecdir\@ ./bin \@sbindir\@ ./bin \@prefix\@ . \@HOSTNAME\@ \ + @HOSTNAME@ \@pkgdatadir\@ ./support-files \ + < scripts/mysql_install_db.sh > $BASE/scripts/mysql_install_db + $BASE/bin/replace \@prefix\@ /usr/local/mysql \@bindir\@ ./bin \ + \@sbindir\@ ./bin \@libexecdir\@ ./bin \ + \@MYSQLD_USER\@ @MYSQLD_USER@ \@localstatedir\@ /usr/local/mysql/data \ + \@HOSTNAME\@ @HOSTNAME@ \ + < support-files/mysql.server.sh > $BASE/support-files/mysql.server $BASE/bin/replace /my/gnu/bin/hostname /bin/hostname -- $BASE/bin/mysqld_safe mv $BASE/support-files/binary-configure $BASE/configure - chmod a+x $BASE/bin/* $BASE/scripts/* $BASE/support-files/mysql-* $BASE/support-files/mysql.server $BASE/configure + chmod a+x $BASE/bin/* $BASE/scripts/* $BASE/support-files/mysql-* \ + $BASE/support-files/mysql.server $BASE/configure $CP -r sql-bench/* $BASE/sql-bench rm -f $BASE/sql-bench/*.sh $BASE/sql-bench/Makefile* $BASE/lib/*.la rm -f $BASE/bin/*.sql fi -rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh $BASE/bin/mysql_install_db $BASE/bin/make_binary_distribution $BASE/bin/setsomevars $BASE/support-files/Makefile* $BASE/support-files/*.sh - +rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh \ + $BASE/bin/mysql_install_db $BASE/bin/make_binary_distribution \ + $BASE/bin/setsomevars $BASE/support-files/Makefile* \ + $BASE/support-files/*.sh # # Copy system dependent files @@ -253,8 +272,11 @@ rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh $BASE/bin/mysql_install_ if [ $BASE_SYSTEM = "netware" ] ; then echo "CREATE DATABASE mysql;" > $BASE/bin/init_db.sql echo "CREATE DATABASE test;" >> $BASE/bin/init_db.sql - sh ./scripts/mysql_create_system_tables.sh real >> $BASE/bin/init_db.sql - sh ./scripts/mysql_create_system_tables.sh test > $BASE/bin/test_db.sql + sh ./scripts/mysql_create_system_tables.sh real "" "%" 0 \ + >> $BASE/bin/init_db.sql + sh ./scripts/mysql_create_system_tables.sh test "" "%" 0 \ + > $BASE/bin/test_db.sql + ./scripts/fill_help_tables < ./Docs/manual.texi >> ./netware/init_db.sql fi # @@ -279,9 +301,9 @@ if [ $BASE_SYSTEM != "netware" ] ; then fi # Clean up if we did this from a bk tree -if [ -d $BASE/sql-bench/SCCS ] ; then - find $BASE/share -name SCCS -print | xargs rm -r -f - find $BASE/sql-bench -name SCCS -print | xargs rm -r -f +if [ -d $BASE/sql-bench/SCCS ] ; then + find $BASE/share -name SCCS -print | xargs rm -rf + find $BASE/sql-bench -name SCCS -print | xargs rm -rf fi # NDB Cluster @@ -296,52 +318,27 @@ if [ x$NDBCLUSTER = x1 ]; then rm -rf $BASE/ndb-stage fi -# Remove vendor from $system -system=`echo $system | sed -e 's/[a-z]*-\(.*\)/\1/g'` - -# Map OS names to "our" OS names (eg. darwin6.8 -> osx10.2) -system=`echo $system | sed -e 's/darwin6.*/osx10.2/g'` -system=`echo $system | sed -e 's/darwin7.*/osx10.3/g'` -system=`echo $system | sed -e 's/darwin8.*/osx10.4/g'` -system=`echo $system | sed -e 's/\(aix4.3\).*/\1/g'` -system=`echo $system | sed -e 's/\(aix5.1\).*/\1/g'` -system=`echo $system | sed -e 's/\(aix5.2\).*/\1/g'` -system=`echo $system | sed -e 's/\(aix5.3\).*/\1/g'` -system=`echo $system | sed -e 's/osf5.1b/tru64/g'` -system=`echo $system | sed -e 's/linux-gnu/linux/g'` -system=`echo $system | sed -e 's/solaris2.\([0-9]*\)/solaris\1/g'` -system=`echo $system | sed -e 's/sco3.2v\(.*\)/openserver\1/g'` - -# Use the override --machine if present -if [ -n "$MACHINE" ] ; then - machine=$MACHINE -fi - # Change the distribution to a long descriptive name -NEW_NAME=mysql@MYSQL_SERVER_SUFFIX@-$version-$system-$machine$SUFFIX +NEW_NAME=mysql@MYSQL_SERVER_SUFFIX@-$version-$platform$SUFFIX # Print the platform name for build logs -echo "PLATFORM NAME: $system-$machine" +echo "PLATFORM NAME: $platform" BASE2=$TMP/$NEW_NAME -rm -r -f $BASE2 +rm -rf $BASE2 mv $BASE $BASE2 BASE=$BASE2 # # If we are compiling with gcc, copy libgcc.a to the distribution as libmygcc.a # -if test "@GXX@" = "yes" -then - cd $BASE/lib +if [ x"@GXX@" = x"yes" ] ; then gcclib=`@CC@ --print-libgcc-file` - if test $? -ne 0 - then + if [ $? -ne 0 ] ; then print "Warning: Couldn't find libgcc.a!" else - $CP $gcclib libmygcc.a + $CP $gcclib $BASE/lib/libmygcc.a fi - cd $SOURCE fi #if we are debugging, do not do tar/gz @@ -352,7 +349,9 @@ fi # This is needed to prefere gnu tar instead of tar because tar can't # always handle long filenames -PATH_DIRS=`echo $PATH | sed -e 's/^:/. /' -e 's/:$/ ./' -e 's/::/ . /g' -e 's/:/ /g' ` +PATH_DIRS=`echo $PATH | \ + sed -e 's/^:/. /' -e 's/:$/ ./' -e 's/::/ . /g' -e 's/:/ /g' ` + which_1 () { for cmd @@ -361,8 +360,7 @@ which_1 () do for file in $d/$cmd do - if test -x $file -a ! -d $file - then + if [ -x $file -a ! -d $file ] ; then echo $file exit 0 fi @@ -377,38 +375,35 @@ if [ $BASE_SYSTEM != "netware" ] ; then # # Create the result tar file # - + tar=`which_1 gnutar gtar` - if test "$?" = "1" -o "$tar" = "" - then + if [ "$?" = "1" -o x"$tar" = x"" ] ; then tar=tar fi - + echo "Using $tar to create archive" - cd $TMP - + OPT=cvf if [ x$SILENT = x1 ] ; then OPT=cf fi - - $tar $OPT $SOURCE/$NEW_NAME.tar $NEW_NAME - cd $SOURCE - echo "Compressing archive" + + echo "Creating and compressing archive" rm -f $NEW_NAME.tar.gz - gzip -9 $NEW_NAME.tar + (cd $TMP ; $tar $OPT - $NEW_NAME) | gzip -9 > $NEW_NAME.tar.gz echo "$NEW_NAME.tar.gz created" + else # # Create a zip file for NetWare users # - cd $TMP - if test -e "$SOURCE/$NEW_NAME.zip"; then rm $SOURCE/$NEW_NAME.zip; fi - zip -r $SOURCE/$NEW_NAME.zip $NEW_NAME + rm -f $NEW_NAME.zip + (cd $TMP; zip -r "$SOURCE/$NEW_NAME.zip" $NEW_NAME) echo "$NEW_NAME.zip created" fi + echo "Removing temporary directory" -rm -r -f $BASE +rm -rf $BASE diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh index 0d2a8cdd5d7..ea3ca66db6e 100644 --- a/scripts/make_win_src_distribution.sh +++ b/scripts/make_win_src_distribution.sh @@ -266,7 +266,7 @@ make -C $SOURCE/ndb windoze # Input directories to be copied recursively # -for i in bdb innobase ndb extra/yassl +for i in bdb innobase ndb extra/yassl server-tools do copy_dir_dirs $i done @@ -289,7 +289,7 @@ cd $SOURCE for i in COPYING ChangeLog README EXCEPTIONS-CLIENT\ INSTALL-SOURCE INSTALL-WIN \ INSTALL-WIN-SOURCE \ - Docs/INSTALL-BINARY + Docs/INSTALL-BINARY Docs/manual.chm do print_debug "Copying file '$i'" if [ -f $i ] diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index 16e50c044ca..5b35c0190a5 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -101,13 +101,16 @@ libs_r="$ldflags -L$pkglibdir -lmysqlclient_r @ZLIB_DEPS@ @LIBS@ @openssl_libs@" libs_r=`echo "$libs_r" | sed -e 's; \+; ;g' | sed -e 's;^ *;;' | sed -e 's; *\$;;'` cflags="-I$pkgincludedir @CFLAGS@ " #note: end space! include="-I$pkgincludedir" -embedded_libs="$ldflags -L$pkglibdir -lmysqld @LIBS@ @WRAPLIBS@ @innodb_system_libs@ $client_libs" +embedded_libs="$ldflags -L$pkglibdir -lmysqld @ZLIB_DEPS@ @LIBS@ @WRAPLIBS@ @innodb_system_libs@" embedded_libs=`echo "$embedded_libs" | sed -e 's; \+; ;g' | sed -e 's;^ *;;' | sed -e 's; *\$;;'` # Remove some options that a client doesn't have to care about +# FIXME until we have a --cxxflags, we need to remove -Xa +# and -xstrconst to make --cflags usable for Sun Forte C++ for remove in DDBUG_OFF DSAFEMALLOC USAFEMALLOC DSAFE_MUTEX \ DPEDANTIC_SAFEMALLOC DUNIV_MUST_NOT_INLINE DFORCE_INIT_OF_VARS \ - DEXTRA_DEBUG DHAVE_purify 'O[0-9]' 'W[-A-Za-z]*' + DEXTRA_DEBUG DHAVE_purify 'O[0-9]' 'W[-A-Za-z]*' \ + Xa xstrconst do # The first option we might strip will always have a space before it because # we set -I$pkgincludedir as the first option @@ -120,13 +123,13 @@ usage () { Usage: $0 [OPTIONS] Options: --cflags [$cflags] - --include [$include] + --include [$include] --libs [$libs] --libs_r [$libs_r] --socket [$socket] --port [$port] --version [$version] - --libmysqld-libs [$embedded_libs] + --libmysqld-libs [$embedded_libs] EOF exit 1 } @@ -136,13 +139,13 @@ if test $# -le 0; then usage; fi while test $# -gt 0; do case $1 in --cflags) echo "$cflags" ;; - --include) echo "$include" ;; + --include) echo "$include" ;; --libs) echo "$libs" ;; --libs_r) echo "$libs_r" ;; --socket) echo "$socket" ;; --port) echo "$port" ;; --version) echo "$version" ;; - --embedded-libs | --embedded | --libmysqld-libs) echo "$embedded_libs" ;; + --embedded-libs | --embedded | --libmysqld-libs) echo "$embedded_libs" ;; *) usage ;; esac diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index 383f8b80dc8..54f0ef230ad 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -123,7 +123,7 @@ then c_u="$c_u CREATE TABLE user (" c_u="$c_u Host char(60) binary DEFAULT '' NOT NULL," c_u="$c_u User char(16) binary DEFAULT '' NOT NULL," - c_u="$c_u Password char(41) binary DEFAULT '' NOT NULL," + c_u="$c_u Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL," c_u="$c_u Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_u="$c_u Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_u="$c_u Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh index d080b68b268..073964d4bde 100644 --- a/scripts/mysql_fix_privilege_tables.sh +++ b/scripts/mysql_fix_privilege_tables.sh @@ -97,9 +97,11 @@ fi # Find where 'mysql' command is located +dirname=`dirname "$0"` + if test -z "$bindir" then - for i in @bindir@ $basedir/bin client + for i in @bindir@ $basedir/bin "$dirname/../client" do if test -f $i/mysql then @@ -109,6 +111,13 @@ then done fi +if test -z "$bindir" +then + echo "Could not find MySQL command-line client (mysql)." + echo "Please use --basedir to specify the directory where MySQL is installed." + exit 1 +fi + cmd="$bindir/mysql --no-defaults --force --user=$user --host=$host" if test ! -z "$password" ; then cmd="$cmd --password=$password" @@ -128,7 +137,7 @@ fi # Find where first mysql_fix_privilege_tables.sql is located for i in $basedir/support-files $basedir/share $basedir/share/mysql \ - $basedir/scripts $pkgdatadir . ./scripts + $basedir/scripts $pkgdatadir . "$dirname" do if test -f $i/$file then diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 45f3b8533b5..d1b0c35266e 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -156,9 +156,9 @@ alter table columns_priv comment='Column privileges'; ALTER TABLE user MODIFY Host char(60) NOT NULL default '', MODIFY User char(16) NOT NULL default '', - MODIFY Password char(41) NOT NULL default '', ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin; ALTER TABLE user + MODIFY Password char(41) character set latin1 collate latin1_bin NOT NULL default '', MODIFY Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, MODIFY Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, MODIFY Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index 642772bca44..b2b85018d7a 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -4,7 +4,7 @@ use Getopt::Long; use POSIX qw(strftime); $|=1; -$VER="2.14"; +$VER="2.15"; $opt_config_file = undef(); $opt_example = 0; @@ -326,7 +326,6 @@ sub start_mysqlds() } else { - $options[$j]=~ s/;/\\;/g; $options[$j]= quote_opt_arg($options[$j]); $tmp.= " $options[$j]"; } @@ -412,7 +411,12 @@ sub get_mysqladmin_options $mysqladmin_found= 0 if (!length($mysqladmin)); $com = "$mysqladmin"; $tmp = " -u $opt_user"; - $tmp.= defined($opt_password) ? " -p$opt_password" : ""; + if (defined($opt_password)) { + my $pw= $opt_password; + # Protect single quotes in password + $pw =~ s/'/'"'"'/g; + $tmp.= " -p'$pw'"; + } $tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : ""; for ($j = 0; defined($options[$j]); $j++) { diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp index e040a5da8c2..b7ea8e7eb81 100644 --- a/server-tools/instance-manager/IMService.cpp +++ b/server-tools/instance-manager/IMService.cpp @@ -1,12 +1,16 @@ #include <windows.h> +#include <signal.h> #include "log.h" #include "options.h" #include "IMService.h" +#include "manager.h" IMService::IMService(void) { serviceName= "MySqlManager"; displayName= "MySQL Manager"; + username= NULL; + password= NULL; } IMService::~IMService(void) @@ -16,18 +20,25 @@ IMService::~IMService(void) void IMService::Stop() { ReportStatus(SERVICE_STOP_PENDING); + // stop the IM work + raise(SIGTERM); } -void IMService::Run() +void IMService::Run(DWORD argc, LPTSTR *argv) { // report to the SCM that we're about to start ReportStatus((DWORD)SERVICE_START_PENDING); + Options o; + o.load(argc, argv); + // init goes here ReportStatus((DWORD)SERVICE_RUNNING); // wait for main loop to terminate + manager(o); + o.cleanup(); } void IMService::Log(const char *msg) diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h index 60c202fc561..cad38bebdaf 100644 --- a/server-tools/instance-manager/IMService.h +++ b/server-tools/instance-manager/IMService.h @@ -10,5 +10,5 @@ public: protected: void Log(const char *msg); void Stop(); - void Run(); + void Run(DWORD argc, LPTSTR *argv); }; diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp index fb7e00e0d9b..192045b7a4c 100644 --- a/server-tools/instance-manager/WindowsService.cpp +++ b/server-tools/instance-manager/WindowsService.cpp @@ -8,7 +8,8 @@ WindowsService::WindowsService(void) : statusCheckpoint(0), serviceName(NULL), inited(false), - dwAcceptedControls(SERVICE_ACCEPT_STOP) + dwAcceptedControls(SERVICE_ACCEPT_STOP), + debugging(false) { gService= this; status.dwServiceType= SERVICE_WIN32_OWN_PROCESS; @@ -148,7 +149,7 @@ void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv) { statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler); if (statusHandle && ReportStatus(SERVICE_START_PENDING)) - Run(); + Run(argc, argv); ReportStatus(SERVICE_STOPPED); } diff --git a/server-tools/instance-manager/WindowsService.h b/server-tools/instance-manager/WindowsService.h index 612eeda21e9..1a034ce1351 100644 --- a/server-tools/instance-manager/WindowsService.h +++ b/server-tools/instance-manager/WindowsService.h @@ -30,7 +30,7 @@ public: static void WINAPI ControlHandler(DWORD CtrlType); protected: - virtual void Run()= 0; + virtual void Run(DWORD argc, LPTSTR *argv)= 0; virtual void Stop() {} virtual void Shutdown() {} virtual void Pause() {} diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc index 26df401c3c5..8039ab24481 100644 --- a/server-tools/instance-manager/buffer.cc +++ b/server-tools/instance-manager/buffer.cc @@ -14,13 +14,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif #include "buffer.h" #include <m_string.h> +const uint Buffer::BUFFER_INITIAL_SIZE= 4096; +const uint Buffer::MAX_BUFFER_SIZE= 16777216; /* Puts the given string to the buffer. diff --git a/server-tools/instance-manager/buffer.h b/server-tools/instance-manager/buffer.h index e63d725f508..afc71320ecb 100644 --- a/server-tools/instance-manager/buffer.h +++ b/server-tools/instance-manager/buffer.h @@ -19,7 +19,7 @@ #include <my_global.h> #include <my_sys.h> -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) #pragma interface #endif @@ -33,9 +33,9 @@ class Buffer { private: - enum { BUFFER_INITIAL_SIZE= 4096 }; + static const uint BUFFER_INITIAL_SIZE; /* maximum buffer size is 16Mb */ - enum { MAX_BUFFER_SIZE= 16777216 }; + static const uint MAX_BUFFER_SIZE; size_t buffer_size; /* Error flag. Triggered if we get an error of some kind */ int error; diff --git a/server-tools/instance-manager/command.cc b/server-tools/instance-manager/command.cc index 73dd49ef8b8..f76366d5661 100644 --- a/server-tools/instance-manager/command.cc +++ b/server-tools/instance-manager/command.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h index 8ae4e33b92f..b84cc6a8e9e 100644 --- a/server-tools/instance-manager/command.h +++ b/server-tools/instance-manager/command.h @@ -16,12 +16,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#include <my_global.h> + +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) #pragma interface #endif -#include <my_global.h> - /* Class responsible for allocation of im commands. */ class Instance_map; diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc index 1cf888eab45..b4dd1b469f1 100644 --- a/server-tools/instance-manager/commands.cc +++ b/server-tools/instance-manager/commands.cc @@ -695,9 +695,9 @@ Set_option::Set_option(Instance_map *instance_map_arg, int Set_option::correct_file(int skip) { - int error; - const static int mysys_to_im_error[]= { 0, ER_OUT_OF_RESOURCES, + static const int mysys_to_im_error[]= { 0, ER_OUT_OF_RESOURCES, ER_ACCESS_OPTION_FILE }; + int error; error= modify_defaults_file(Options::config_file, option, option_value, instance_name, skip); diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc index 17f4204185a..291b685ef1b 100644 --- a/server-tools/instance-manager/guardian.cc +++ b/server-tools/instance-manager/guardian.cc @@ -15,7 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif @@ -33,18 +33,13 @@ -C_MODE_START - -pthread_handler_decl(guardian, arg) +pthread_handler_t guardian(void *arg) { Guardian_thread *guardian_thread= (Guardian_thread *) arg; guardian_thread->run(); return 0; } -C_MODE_END - - Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg, Instance_map *instance_map_arg, uint monitoring_interval_arg) : diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h index 758c4a3f3bc..16b4c373c91 100644 --- a/server-tools/instance-manager/guardian.h +++ b/server-tools/instance-manager/guardian.h @@ -22,7 +22,7 @@ #include <my_sys.h> #include <my_list.h> -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) #pragma interface #endif @@ -31,11 +31,7 @@ class Instance_map; class Thread_registry; struct GUARD_NODE; -C_MODE_START - -pthread_handler_decl(guardian, arg); - -C_MODE_END +pthread_handler_t guardian(void *arg); struct Guardian_thread_args { diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index 0a373429d01..0756f0b4d9f 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -14,13 +14,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif -#ifdef __WIN__ -#include <process.h> -#endif #include "instance.h" #include "mysql_manager_error.h" @@ -40,14 +37,12 @@ static void start_and_monitor_instance(Instance_options *old_instance_options, Instance_map *instance_map); -#ifndef _WIN_ +#ifndef __WIN__ typedef pid_t My_process_info; #else typedef PROCESS_INFORMATION My_process_info; #endif -C_MODE_START - /* Proxy thread is a simple way to avoid all pitfalls of the threads implementation in the OS (e.g. LinuxThreads). With such a thread we @@ -55,7 +50,7 @@ C_MODE_START to do it in a portable way. */ -pthread_handler_decl(proxy, arg) +pthread_handler_t proxy(void *arg) { Instance *instance= (Instance *) arg; start_and_monitor_instance(&instance->options, @@ -63,9 +58,6 @@ pthread_handler_decl(proxy, arg) return 0; } -C_MODE_END - - /* Wait for an instance @@ -146,15 +138,25 @@ static int wait_process(My_process_info *pi) static int start_process(Instance_options *instance_options, My_process_info *pi) { +#ifndef __QNX__ *pi= fork(); +#else + /* + On QNX one cannot use fork() in multithreaded environment and we + should use spawn() or one of it's siblings instead. + Here we use spawnv(), which is a combination of fork() and execv() + in one call. It returns the pid of newly created process (>0) or -1 + */ + *pi= spawnv(P_NOWAIT, instance_options->mysqld_path, instance_options->argv); +#endif switch (*pi) { - case 0: + case 0: /* never happens on QNX */ execv(instance_options->mysqld_path, instance_options->argv); /* exec never returns */ exit(1); - case 1: - log_info("cannot fork() to start instance %s", + case -1: + log_info("cannot create a new process to start instance %s", instance_options->instance_name); return 1; } @@ -171,25 +173,24 @@ static int start_process(Instance_options *instance_options, ZeroMemory(pi, sizeof(PROCESS_INFORMATION)); int cmdlen= 0; - for (int i= 1; instance_options->argv[i] != 0; i++) - cmdlen+= strlen(instance_options->argv[i]) + 1; - cmdlen++; /* we have to add a single space for CreateProcess (see docs) */ + for (int i= 0; instance_options->argv[i] != 0; i++) + cmdlen+= strlen(instance_options->argv[i]) + 3; + cmdlen++; /* make room for the null */ - char *cmdline= NULL; - if (cmdlen > 0) + char *cmdline= new char[cmdlen]; + if (cmdline == NULL) + return 1; + + for (int i= 0; instance_options->argv[i] != 0; i++) { - cmdline= new char[cmdlen]; - cmdline[0]= 0; - for (int i= 1; instance_options->argv[i] != 0; i++) - { - strcat(cmdline, " "); - strcat(cmdline, instance_options->argv[i]); - } + strcat(cmdline, "\""); + strcat(cmdline, instance_options->argv[i]); + strcat(cmdline, "\" "); } /* Start the child process */ BOOL result= - CreateProcess(instance_options->mysqld_path, /* File to execute */ + CreateProcess(NULL, /* Put it all in cmdline */ cmdline, /* Command line */ NULL, /* Process handle not inheritable */ NULL, /* Thread handle not inheritable */ @@ -478,7 +479,7 @@ int Instance::stop() status= pthread_cond_timedwait(&COND_instance_stopped, &LOCK_instance, &timeout); - if (status == ETIMEDOUT) + if (status == ETIMEDOUT || status == ETIME) break; } diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h index 003cbca8cef..adb66991685 100644 --- a/server-tools/instance-manager/instance.h +++ b/server-tools/instance-manager/instance.h @@ -19,7 +19,7 @@ #include <my_global.h> #include "instance_options.h" -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) #pragma interface #endif diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc index b3a207ae79f..611eda457f2 100644 --- a/server-tools/instance-manager/instance_map.cc +++ b/server-tools/instance-manager/instance_map.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h index 47037e0d433..51971db4c2f 100644 --- a/server-tools/instance-manager/instance_map.h +++ b/server-tools/instance-manager/instance_map.h @@ -24,7 +24,7 @@ #include <my_sys.h> #include <hash.h> -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) #pragma interface #endif diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index 124195aad37..25609f489af 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif @@ -46,8 +46,16 @@ static inline int create_mysqld_command(Buffer *buf, if (buf->get_size()) /* malloc succeeded */ { +#ifdef __WIN__ + buf->append(position, "\"", 1); + position++; +#endif buf->append(position, mysqld_path_str, mysqld_path_len); position+= mysqld_path_len; +#ifdef __WIN__ + buf->append(position, "\"", 1); + position++; +#endif /* here the '\0' character is copied from the option string */ buf->append(position, option, option_len); @@ -461,7 +469,7 @@ int Instance_options::add_option(const char* option) case SAVE_WHOLE: *(selected_options->value)= tmp; return 0; - defaut: + default: break; } } diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h index dc62d277a43..dae1c2695d1 100644 --- a/server-tools/instance-manager/instance_options.h +++ b/server-tools/instance-manager/instance_options.h @@ -21,7 +21,7 @@ #include "parse.h" #include "portability.h" -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) #pragma interface #endif diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc index 790770be09e..08c28dc9f7d 100644 --- a/server-tools/instance-manager/listener.cc +++ b/server-tools/instance-manager/listener.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif @@ -121,6 +121,9 @@ void Listener_thread::run() n= max(n, sockets[i]); n++; + timeval tv; + tv.tv_sec= 0; + tv.tv_usec= 100000; while (!thread_registry.is_shutdown()) { fd_set read_fds_arg= read_fds; @@ -130,13 +133,13 @@ void Listener_thread::run() signal during shutdown. This results in failing assert (Thread_registry::~Thread_registry). Valgrind 2.2 works fine. */ - int rc= select(n, &read_fds_arg, 0, 0, 0); + int rc= select(n, &read_fds_arg, 0, 0, &tv); - - if (rc == -1 && errno != EINTR) + if (rc == 0 || rc == -1) { - log_error("Listener_thread::run(): select() failed, %s", - strerror(errno)); + if (rc == -1 && errno != EINTR) + log_error("Listener_thread::run(): select() failed, %s", + strerror(errno)); continue; } @@ -369,10 +372,7 @@ void Listener_thread::handle_new_mysql_connection(Vio *vio) } -C_MODE_START - - -pthread_handler_decl(listener, arg) +pthread_handler_t listener(void *arg) { Listener_thread_args *args= (Listener_thread_args *) arg; Listener_thread listener(*args); @@ -384,6 +384,3 @@ pthread_handler_decl(listener, arg) return 0; } - -C_MODE_END - diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h index 67a090c3aa2..28ccbf91731 100644 --- a/server-tools/instance-manager/listener.h +++ b/server-tools/instance-manager/listener.h @@ -16,19 +16,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ -#pragma interface -#endif - #include <my_global.h> #include <my_pthread.h> +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) +#pragma interface +#endif -C_MODE_START - -pthread_handler_decl(listener, arg); -C_MODE_END +pthread_handler_t listener(void *arg); class Thread_registry; struct Options; diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc index a42a25eadf3..cc16ee6562f 100644 --- a/server-tools/instance-manager/manager.cc +++ b/server-tools/instance-manager/manager.cc @@ -231,6 +231,10 @@ void manager(const Options &options) } #ifndef __WIN__ +#ifdef IGNORE_SIGHUP_SIGQUIT + if ( SIGHUP == signo ) + continue; +#endif if (THR_SERVER_ALARM == signo) process_alarm(signo); else diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc index dfa12f6f6e2..bf39c843f0a 100644 --- a/server-tools/instance-manager/mysql_connection.cc +++ b/server-tools/instance-manager/mysql_connection.cc @@ -14,8 +14,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ -#pragma interface +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) +#pragma implementation #endif #include "mysql_connection.h" @@ -364,9 +364,7 @@ int Mysql_connection_thread::dispatch_command(enum enum_server_command command, } -C_MODE_START - -pthread_handler_decl(mysql_connection, arg) +pthread_handler_t mysql_connection(void *arg) { Mysql_connection_thread_args *args= (Mysql_connection_thread_args *) arg; Mysql_connection_thread mysql_connection_thread(*args); @@ -381,9 +379,6 @@ pthread_handler_decl(mysql_connection, arg) return 0; } -C_MODE_END - - /* vim: fdm=marker */ diff --git a/server-tools/instance-manager/mysql_connection.h b/server-tools/instance-manager/mysql_connection.h index e0109ce234f..3496cc05815 100644 --- a/server-tools/instance-manager/mysql_connection.h +++ b/server-tools/instance-manager/mysql_connection.h @@ -16,20 +16,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ -#pragma interface -#endif - #include <my_global.h> #include <my_pthread.h> +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) +#pragma interface +#endif -C_MODE_START - -pthread_handler_decl(mysql_connection, arg); - -C_MODE_END - +pthread_handler_t mysql_connection(void *arg); class Thread_registry; class User_map; diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index a1420a639cb..3d2907f4776 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -102,10 +102,12 @@ int main(int argc, char *argv[]) angel(options); } #else -#ifdef NDEBUG - return_value= HandleServiceOptions(options); - goto err; /* this is not always an error but we reuse the label */ -#endif + if (!options.stand_alone) + { + if (HandleServiceOptions(options)) + goto err; + } + else #endif manager(options); diff --git a/server-tools/instance-manager/mysqlmanager.vcproj b/server-tools/instance-manager/mysqlmanager.vcproj index 2ab9a4878c1..ef8b2dd017e 100644 --- a/server-tools/instance-manager/mysqlmanager.vcproj +++ b/server-tools/instance-manager/mysqlmanager.vcproj @@ -12,14 +12,14 @@ <Configurations> <Configuration Name="Debug|Win32" - OutputDirectory="Debug" + OutputDirectory="../../client_debug" IntermediateDirectory="Debug" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories="..\include" + AdditionalIncludeDirectories="..\..\include,../../extra/yassl/include" PreprocessorDefinitions="MYSQL_INSTANCE_MANAGER;MYSQL_SERVER;_DEBUG;SAFEMALLOC;SAFE_MUTEX;_WINDOWS;CONSOLE" MinimalRebuild="TRUE" ExceptionHandling="FALSE" @@ -63,13 +63,13 @@ </Configuration> <Configuration Name="Release|Win32" - OutputDirectory="Release" + OutputDirectory="../../client_release" IntermediateDirectory="Release" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" - AdditionalIncludeDirectories="..\include" + AdditionalIncludeDirectories="..\..\include,../../extra/yassl/include" PreprocessorDefinitions="MYSQL_INSTANCE_MANAGER;MYSQL_SERVER;_WINDOWS;CONSOLE" ExceptionHandling="FALSE" RuntimeLibrary="0" @@ -119,94 +119,172 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> <File - RelativePath=".\buffer.cc"> + RelativePath=".\buffer.cpp"> </File> <File - RelativePath="..\sql\client.c"> + RelativePath="..\..\sql\client.c"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> </File> <File - RelativePath=".\command.cc"> + RelativePath=".\command.cpp"> </File> <File - RelativePath=".\commands.cc"> + RelativePath=".\commands.cpp"> </File> <File - RelativePath=".\factory.cc"> + RelativePath="..\..\libmysql\get_password.c"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> </File> <File - RelativePath="..\libmysql\get_password.c"> - </File> - <File - RelativePath=".\guardian.cc"> + RelativePath=".\guardian.cpp"> </File> <File RelativePath=".\IMService.cpp"> </File> <File - RelativePath=".\instance.cc"> - </File> - <File - RelativePath=".\instance_map.cc"> + RelativePath=".\instance.cpp"> </File> <File - RelativePath=".\instance_options.cc"> + RelativePath=".\instance_map.cpp"> </File> <File - RelativePath=".\listener.cc"> + RelativePath=".\instance_options.cpp"> </File> <File - RelativePath=".\log.cc"> + RelativePath=".\listener.cpp"> </File> <File - RelativePath=".\manager.cc"> + RelativePath=".\log.cpp"> </File> <File - RelativePath=".\messages.cc"> + RelativePath=".\manager.cpp"> </File> <File - RelativePath="..\sql\mini_client_errors.c"> + RelativePath=".\messages.cpp"> </File> <File - RelativePath=".\mysql_connection.cc"> + RelativePath="..\..\sql\mini_client_errors.c"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> </File> <File - RelativePath=".\mysqlmanager.cc"> + RelativePath=".\mysql_connection.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> </File> <File - RelativePath="..\sql\net_serv.cpp"> + RelativePath=".\mysqlmanager.cpp"> </File> <File - RelativePath=".\options.cc"> + RelativePath="..\..\sql\net_serv.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> </File> <File - RelativePath="..\sql\pack.c"> + RelativePath=".\options.cpp"> </File> <File - RelativePath=".\parse.cc"> + RelativePath="..\..\sql\pack.c"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> </File> <File - RelativePath=".\parse_output.cc"> + RelativePath=".\parse.cpp"> </File> <File - RelativePath="..\sql\password.c"> + RelativePath=".\parse_output.cpp"> </File> <File - RelativePath=".\priv.cc"> + RelativePath="..\..\sql\password.c"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> </File> <File - RelativePath=".\protocol.cc"> + RelativePath=".\priv.cpp"> </File> <File - RelativePath=".\service_funcs.cpp"> + RelativePath=".\protocol.cpp"> </File> <File - RelativePath="..\sql\sql_state.c"> + RelativePath="..\..\sql\sql_state.c"> </File> <File - RelativePath=".\thread_registry.cc"> + RelativePath=".\thread_registry.cpp"> </File> <File - RelativePath=".\user_map.cc"> + RelativePath=".\user_map.cpp"> </File> <File RelativePath=".\WindowsService.cpp"> diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index 334b67e5d37..b16fcabae01 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif @@ -33,6 +33,7 @@ #ifdef __WIN__ char Options::install_as_service; char Options::remove_service; +char Options::stand_alone; char windows_config_file[FN_REFLEN]; char default_password_file_name[FN_REFLEN]; char default_log_file_name[FN_REFLEN]; @@ -72,6 +73,7 @@ enum options { #else OPT_INSTALL_SERVICE, OPT_REMOVE_SERVICE, + OPT_STAND_ALONE, #endif OPT_MONITORING_INTERVAL, OPT_PORT, @@ -106,7 +108,7 @@ static struct my_option my_long_options[] = (gptr *) &Options::port_number, (gptr *) &Options::port_number, 0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 }, - { "password-file", OPT_PASSWORD_FILE, "Look for Instane Manager users" + { "password-file", OPT_PASSWORD_FILE, "Look for Instance Manager users" " and passwords here.", (gptr *) &Options::password_file_name, (gptr *) &Options::password_file_name, @@ -131,6 +133,9 @@ static struct my_option my_long_options[] = { "remove", OPT_REMOVE_SERVICE, "Remove system service.", (gptr *)&Options::remove_service, (gptr*) &Options::remove_service, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, + { "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.", + (gptr *)&Options::stand_alone, (gptr*) &Options::stand_alone, + 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, #else { "run-as-service", OPT_RUN_AS_SERVICE, "Daemonize and start angel process.", (gptr *) &Options::run_as_service, diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h index 5cc14e7ee7f..6d719c69629 100644 --- a/server-tools/instance-manager/options.h +++ b/server-tools/instance-manager/options.h @@ -16,21 +16,22 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ -#pragma interface -#endif - /* Options - all possible options for the instance manager grouped in one struct. */ #include <my_global.h> +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) +#pragma interface +#endif + struct Options { #ifdef __WIN__ static char install_as_service; static char remove_service; + static char stand_alone; #else static char run_as_service; /* handle_options doesn't support bool */ static const char *user; @@ -52,7 +53,7 @@ struct Options int load(int argc, char **argv); void cleanup(); #ifdef __WIN__ - int setup_windows_defaults(const char *progname); + int setup_windows_defaults(); #endif }; diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc index 4ec9a71bfd2..b5af3cb83a7 100644 --- a/server-tools/instance-manager/parse_output.cc +++ b/server-tools/instance-manager/parse_output.cc @@ -107,7 +107,6 @@ int parse_output_and_get_value(const char *command, const char *word, } } -pclose: /* we are not interested in the termination status */ pclose(output); diff --git a/server-tools/instance-manager/portability.h b/server-tools/instance-manager/portability.h index c2b4e8b7467..2bdeff71a72 100644 --- a/server-tools/instance-manager/portability.h +++ b/server-tools/instance-manager/portability.h @@ -1,6 +1,10 @@ #ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H #define INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H +#if defined(_SCO_DS) && !defined(SHUT_RDWR) +#define SHUT_RDWR 2 +#endif + #ifdef __WIN__ #define vsnprintf _vsnprintf diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc index cd1be805b6b..73e07f993ae 100644 --- a/server-tools/instance-manager/protocol.cc +++ b/server-tools/instance-manager/protocol.cc @@ -23,6 +23,7 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ +static const char ERROR_PACKET_CODE= (char) 255; int net_send_ok(struct st_net *net, unsigned long connection_id, @@ -74,7 +75,6 @@ int net_send_error(struct st_net *net, uint sql_errno) MYSQL_ERRMSG_SIZE]; // message char *pos= buff; - enum { ERROR_PACKET_CODE= 255 }; *pos++= ERROR_PACKET_CODE; int2store(pos, sql_errno); pos+= 2; @@ -95,7 +95,6 @@ int net_send_error_323(struct st_net *net, uint sql_errno) MYSQL_ERRMSG_SIZE]; // message char *pos= buff; - enum { ERROR_PACKET_CODE= 255 }; *pos++= ERROR_PACKET_CODE; int2store(pos, sql_errno); pos+= 2; @@ -148,14 +147,14 @@ int store_to_protocol_packet(Buffer *buf, const char *string, uint *position) int send_eof(struct st_net *net) { - char buff[1 + /* eof packet code */ - 2 + /* warning count */ - 2]; /* server status */ + uchar buff[1 + /* eof packet code */ + 2 + /* warning count */ + 2]; /* server status */ buff[0]=254; int2store(buff+1, 0); int2store(buff+3, 0); - return my_net_write(net, buff, sizeof buff); + return my_net_write(net, (char*) buff, sizeof buff); } int send_fields(struct st_net *net, LIST *fields) @@ -195,7 +194,7 @@ int send_fields(struct st_net *net, LIST *fields) int2store(send_buff.buffer + position, 1); /* charsetnr */ int4store(send_buff.buffer + position + 2, field->length); /* field length */ - send_buff.buffer[position+6]= FIELD_TYPE_STRING; /* type */ + send_buff.buffer[position+6]= (char) FIELD_TYPE_STRING; /* type */ int2store(send_buff.buffer + position + 7, 0); /* flags */ send_buff.buffer[position + 9]= (char) 0; /* decimals */ send_buff.buffer[position + 10]= 0; diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc index a7384c0fa13..0091d713a91 100644 --- a/server-tools/instance-manager/thread_registry.cc +++ b/server-tools/instance-manager/thread_registry.cc @@ -1,4 +1,4 @@ -/* cOPYRIght (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) #pragma implementation #endif @@ -38,6 +38,14 @@ static void handle_signal(int __attribute__((unused)) sig_no) #endif /* + Thread_info initializer methods +*/ + +Thread_info::Thread_info() {} +Thread_info::Thread_info(pthread_t thread_id_arg) : + thread_id(thread_id_arg) {} + +/* TODO: think about moving signal information (now it's shutdown_in_progress) to Thread_info. It will reduce contention and allow signal deliverence to a particular thread, not to the whole worker crew @@ -145,6 +153,7 @@ int Thread_registry::cond_timedwait(Thread_info *info, pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *wait_time) { + int rc; pthread_mutex_lock(&LOCK_thread_registry); if (shutdown_in_progress) { @@ -154,7 +163,8 @@ int Thread_registry::cond_timedwait(Thread_info *info, pthread_cond_t *cond, info->current_cond= cond; pthread_mutex_unlock(&LOCK_thread_registry); /* sic: race condition here, cond can be signaled in deliver_shutdown */ - int rc= pthread_cond_timedwait(cond, mutex, wait_time); + if ((rc= pthread_cond_timedwait(cond, mutex, wait_time)) == ETIME) + rc= ETIMEDOUT; // For easier usage pthread_mutex_lock(&LOCK_thread_registry); info->current_cond= 0; pthread_mutex_unlock(&LOCK_thread_registry); @@ -172,6 +182,7 @@ void Thread_registry::deliver_shutdown() { Thread_info *info; struct timespec shutdown_time; + int error; set_timespec(shutdown_time, 1); pthread_mutex_lock(&LOCK_thread_registry); @@ -204,11 +215,13 @@ void Thread_registry::deliver_shutdown() released - the only case when the predicate is false is when no other threads exist. */ - while (pthread_cond_timedwait(&COND_thread_registry_is_empty, - &LOCK_thread_registry, - &shutdown_time) != ETIMEDOUT && + while (((error= pthread_cond_timedwait(&COND_thread_registry_is_empty, + &LOCK_thread_registry, + &shutdown_time)) != ETIMEDOUT && + error != ETIME) && head.next != &head) ; + /* If previous signals did not reach some threads, they must be sleeping in pthread_cond_wait or in a blocking syscall. Wake them up: diff --git a/server-tools/instance-manager/thread_registry.h b/server-tools/instance-manager/thread_registry.h index 28899810f23..6dc320a8533 100644 --- a/server-tools/instance-manager/thread_registry.h +++ b/server-tools/instance-manager/thread_registry.h @@ -50,13 +50,12 @@ in manner, similar to ``quit'' signals. */ -#ifdef __GNUC__ -#pragma interface -#endif - #include <my_global.h> #include <my_pthread.h> +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) +#pragma interface +#endif /* Thread_info - repository entry for each worker thread @@ -67,13 +66,14 @@ class Thread_info { +public: + Thread_info(); + Thread_info(pthread_t thread_id_arg); + friend class Thread_registry; +private: pthread_cond_t *current_cond; Thread_info *prev, *next; pthread_t thread_id; - Thread_info() {} - friend class Thread_registry; -public: - Thread_info(pthread_t thread_id_arg) : thread_id(thread_id_arg) {} }; diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc index d13eb681d05..9cb15307131 100644 --- a/server-tools/instance-manager/user_map.cc +++ b/server-tools/instance-manager/user_map.cc @@ -14,8 +14,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ -#pragma interface +#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) +#pragma implementation #endif #include "user_map.h" @@ -66,7 +66,8 @@ int User::init(const char *line) */ if (password[strlen(password)-2] == '\r') line_ending_len= 2; - if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + line_ending_len) + if (strlen(password) != (uint) (SCRAMBLED_PASSWORD_CHAR_LENGTH + + line_ending_len)) goto err; memcpy(user, name_begin, user_length); diff --git a/server-tools/instance-manager/user_map.h b/server-tools/instance-manager/user_map.h index 4c86edd93d9..4134017dd9b 100644 --- a/server-tools/instance-manager/user_map.h +++ b/server-tools/instance-manager/user_map.h @@ -16,15 +16,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef __GNUC__ -#pragma interface -#endif #include <my_global.h> #include <my_sys.h> #include <hash.h> +#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) +#pragma interface +#endif + /* User_map -- all users and passwords */ diff --git a/sql-common/client.c b/sql-common/client.c index 993978f132f..08ad906e2b6 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -599,7 +599,7 @@ net_safe_read(MYSQL *mysql) DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", vio_description(net->vio),len)); #ifdef MYSQL_SERVER - if (vio_errno(net->vio) == SOCKET_EINTR) + if (vio_was_interrupted(net->vio)) return (packet_error); #endif /*MYSQL_SERVER*/ end_server(mysql); @@ -2203,8 +2203,9 @@ my_bool mysql_reconnect(MYSQL *mysql) DBUG_RETURN(1); } mysql_init(&tmp_mysql); - tmp_mysql.options=mysql->options; - tmp_mysql.rpl_pivot = mysql->rpl_pivot; + tmp_mysql.options= mysql->options; + tmp_mysql.rpl_pivot= mysql->rpl_pivot; + if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, mysql->db, mysql->port, mysql->unix_socket, mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) @@ -2216,6 +2217,8 @@ my_bool mysql_reconnect(MYSQL *mysql) } if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname)) { + DBUG_PRINT("error", ("mysql_set_character_set() failed")); + bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options)); mysql_close(&tmp_mysql); mysql->net.last_errno= tmp_mysql.net.last_errno; strmov(mysql->net.last_error, tmp_mysql.net.last_error); @@ -2223,6 +2226,7 @@ my_bool mysql_reconnect(MYSQL *mysql) DBUG_RETURN(1); } + DBUG_PRINT("info", ("reconnect succeded")); tmp_mysql.reconnect= 1; tmp_mysql.free_me= mysql->free_me; @@ -2286,6 +2290,8 @@ mysql_select_db(MYSQL *mysql, const char *db) static void mysql_close_free_options(MYSQL *mysql) { + DBUG_ENTER("mysql_close_free_options"); + my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR)); @@ -2314,6 +2320,7 @@ static void mysql_close_free_options(MYSQL *mysql) my_free(mysql->options.shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif /* HAVE_SMEM */ bzero((char*) &mysql->options,sizeof(mysql->options)); + DBUG_VOID_RETURN; } @@ -2760,6 +2767,9 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg) case MYSQL_REPORT_DATA_TRUNCATION: mysql->options.report_data_truncation= test(*(my_bool *) arg); break; + case MYSQL_OPT_RECONNECT: + mysql->reconnect= *(my_bool *) arg; + break; default: DBUG_RETURN(1); } diff --git a/sql/Makefile.am b/sql/Makefile.am index 4824a75d6fa..cd1de0ce3c9 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -61,8 +61,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ tztime.h my_decimal.h\ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ parse_file.h sql_view.h sql_trigger.h \ - sql_array.h \ - examples/ha_example.h examples/ha_archive.h \ + sql_array.h sql_cursor.h \ + examples/ha_example.h ha_archive.h \ examples/ha_tina.h ha_blackhole.h \ ha_federated.h mysqld_SOURCES = sql_lex.cc sql_handler.cc \ @@ -94,11 +94,11 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ client.c sql_client.cc mini_client_errors.c pack.c\ stacktrace.c repl_failsafe.h repl_failsafe.cc \ sql_olap.cc sql_view.cc \ - gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \ + gstream.cc spatial.cc sql_help.cc sql_cursor.cc \ tztime.cc my_time.c my_decimal.cc\ sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \ sp_cache.cc parse_file.cc sql_trigger.cc \ - examples/ha_example.cc examples/ha_archive.cc \ + examples/ha_example.cc ha_archive.cc \ examples/ha_tina.cc ha_blackhole.cc \ ha_federated.cc diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index dfc2fa7a260..d340b9289ec 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -73,8 +73,12 @@ #include "ha_example.h" -static handlerton example_hton= { - "CSV", +handlerton example_hton= { + "EXAMPLE", + SHOW_OPTION_YES, + "Example storage engine", + DB_TYPE_EXAMPLE_DB, + NULL, /* We do need to write one! */ 0, /* slot */ 0, /* savepoint size. */ NULL, /* close_connection */ @@ -90,7 +94,7 @@ static handlerton example_hton= { NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS + HTON_CAN_RECREATE }; /* Variables for example share methods */ diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 74ff3457cd2..541e91f4b46 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -54,8 +54,12 @@ pthread_mutex_t tina_mutex; static HASH tina_open_tables; static int tina_init= 0; -static handlerton tina_hton= { +handlerton tina_hton= { "CSV", + SHOW_OPTION_YES, + "CSV storage engine", + DB_TYPE_CSV_DB, + NULL, /* One needs to be written! */ 0, /* slot */ 0, /* savepoint size. */ NULL, /* close_connection */ @@ -71,7 +75,7 @@ static handlerton tina_hton= { NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS + HTON_CAN_RECREATE }; /***************************************************************************** @@ -234,6 +238,16 @@ static int free_share(TINA_SHARE *share) DBUG_RETURN(result_code); } +bool tina_end() +{ + if (tina_init) + { + hash_free(&tina_open_tables); + VOID(pthread_mutex_destroy(&tina_mutex)); + } + tina_init= 0; + return FALSE; +} /* Finds the end of a line. @@ -651,7 +665,8 @@ int ha_tina::rnd_init(bool scan) records= 0; chain_ptr= chain; #ifdef HAVE_MADVISE - (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); + if (scan) + (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); #endif DBUG_RETURN(0); @@ -847,21 +862,6 @@ THR_LOCK_DATA **ha_tina::store_lock(THD *thd, } /* - Range optimizer calls this. - I need to update the information on this. -*/ -ha_rows ha_tina::records_in_range(int inx, - const byte *start_key,uint start_key_len, - enum ha_rkey_function start_search_flag, - const byte *end_key,uint end_key_len, - enum ha_rkey_function end_search_flag) -{ - DBUG_ENTER("ha_tina::records_in_range "); - DBUG_RETURN(records); // Good guess -} - - -/* Create a table. You do not want to leave the table open after a call to this (the database will call ::open() if it needs to). */ diff --git a/sql/examples/ha_tina.h b/sql/examples/ha_tina.h index 5679d77a4dc..84854e868fa 100644 --- a/sql/examples/ha_tina.h +++ b/sql/examples/ha_tina.h @@ -78,7 +78,6 @@ public: */ virtual double scan_time() { return (double) (records+deleted) / 20.0+10; } /* The next method will never be called */ - virtual double read_time(ha_rows rows) { DBUG_ASSERT(0); return((double) rows / 20.0+1); } virtual bool fast_key_read() { return 1;} /* TODO: return actual upper bound of number of records in the table. @@ -110,12 +109,6 @@ public: int reset(void); int external_lock(THD *thd, int lock_type); int delete_all_rows(void); - ha_rows records_in_range(int inx, const byte *start_key,uint start_key_len, - enum ha_rkey_function start_search_flag, - const byte *end_key,uint end_key_len, - enum ha_rkey_function end_search_flag); -// int delete_table(const char *from); -// int rename_table(const char * from, const char * to); int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, @@ -126,3 +119,6 @@ public: int find_current_row(byte *buf); int chain_append(); }; + +bool tina_end(); + diff --git a/sql/field.cc b/sql/field.cc index 224b6c279f3..b4ba89f613c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1199,7 +1199,7 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) This is used for printing bit_fields as numbers while debugging */ -String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_flag) +String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val) { CHARSET_INFO *cs= &my_charset_bin; uint length= 21; @@ -1208,7 +1208,7 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_flag) return 0; length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(), length, - unsigned_flag ? 10 : -10, + unsigned_val ? 10 : -10, value); val_buffer->length(length); return val_buffer; @@ -1360,7 +1360,7 @@ int Field_num::store_decimal(const my_decimal *val) { int err= 0; longlong i= convert_decimal2longlong(val, unsigned_flag, &err); - return test(err | store(i)); + return test(err | store(i, unsigned_flag)); } @@ -2122,36 +2122,37 @@ int Field_decimal::store(double nr) } -int Field_decimal::store(longlong nr) +int Field_decimal::store(longlong nr, bool unsigned_val) { - if (unsigned_flag && nr < 0) + char buff[22]; + uint length, int_part; + char fyllchar, *to; + + if (nr < 0 && unsigned_flag && !unsigned_val) { overflow(1); return 1; } - char buff[22]; - uint length=(uint) (longlong10_to_str(nr,buff,-10)-buff); - uint int_part=field_length- (dec ? dec+1 : 0); + length= (uint) (longlong10_to_str(nr,buff,unsigned_val ? 10 : -10) - buff); + int_part= field_length- (dec ? dec+1 : 0); if (length > int_part) { - overflow(test(nr < 0L)); /* purecov: inspected */ + overflow(!unsigned_val && nr < 0L); /* purecov: inspected */ return 1; } - else + + fyllchar = zerofill ? (char) '0' : (char) ' '; + to= ptr; + for (uint i=int_part-length ; i-- > 0 ;) + *to++ = fyllchar; + memcpy(to,buff,length); + if (dec) { - char fyllchar = zerofill ? (char) '0' : (char) ' '; - char *to=ptr; - for (uint i=int_part-length ; i-- > 0 ;) - *to++ = fyllchar; - memcpy(to,buff,length); - if (dec) - { - to[length]='.'; - bfill(to+length+1,dec,'0'); - } - return 0; + to[length]='.'; + bfill(to+length+1,dec,'0'); } + return 0; } @@ -2482,13 +2483,13 @@ int Field_new_decimal::store(double nr) } -int Field_new_decimal::store(longlong nr) +int Field_new_decimal::store(longlong nr, bool unsigned_val) { my_decimal decimal_value; int err; if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, - nr, FALSE, &decimal_value))) + nr, unsigned_val, &decimal_value))) { if (check_overflow(err)) set_value_on_overflow(&decimal_value, decimal_value.sign()); @@ -2663,18 +2664,20 @@ int Field_tiny::store(double nr) return error; } -int Field_tiny::store(longlong nr) + +int Field_tiny::store(longlong nr, bool unsigned_val) { int error= 0; + if (unsigned_flag) { - if (nr < 0L) + if (nr < 0 && !unsigned_val) { - *ptr=0; + *ptr= 0; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } - else if (nr > 255L) + else if ((ulonglong) nr > (ulonglong) 255) { *ptr= (char) 255; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); @@ -2685,13 +2688,15 @@ int Field_tiny::store(longlong nr) } else { - if (nr < -128L) + if (nr < 0 && unsigned_val) + nr= 256; // Generate overflow + if (nr < -128) { *ptr= (char) -128; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } - else if (nr > 127L) + else if (nr > 127) { *ptr=127; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); @@ -2711,6 +2716,7 @@ double Field_tiny::val_real(void) return (double) tmp; } + longlong Field_tiny::val_int(void) { int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] : @@ -2718,6 +2724,7 @@ longlong Field_tiny::val_int(void) return (longlong) tmp; } + String *Field_tiny::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -2877,19 +2884,21 @@ int Field_short::store(double nr) return error; } -int Field_short::store(longlong nr) + +int Field_short::store(longlong nr, bool unsigned_val) { int error= 0; int16 res; + if (unsigned_flag) { - if (nr < 0L) + if (nr < 0L && !unsigned_val) { res=0; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } - else if (nr > (longlong) UINT_MAX16) + else if ((ulonglong) nr > (ulonglong) UINT_MAX16) { res=(int16) UINT_MAX16; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); @@ -2900,13 +2909,16 @@ int Field_short::store(longlong nr) } else { + if (nr < 0 && unsigned_val) + nr= UINT_MAX16+1; // Generate overflow + if (nr < INT_MIN16) { res=INT_MIN16; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } - else if (nr > INT_MAX16) + else if (nr > (longlong) INT_MAX16) { res=INT_MAX16; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); @@ -3134,20 +3146,22 @@ int Field_medium::store(double nr) return error; } -int Field_medium::store(longlong nr) + +int Field_medium::store(longlong nr, bool unsigned_val) { int error= 0; + if (unsigned_flag) { - if (nr < 0L) + if (nr < 0 && !unsigned_val) { int3store(ptr,0); set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } - else if (nr >= (longlong) (long) (1L << 24)) + else if ((ulonglong) nr >= (ulonglong) (long) (1L << 24)) { - long tmp=(long) (1L << 24)-1L;; + long tmp= (long) (1L << 24)-1L; int3store(ptr,tmp); set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; @@ -3157,9 +3171,12 @@ int Field_medium::store(longlong nr) } else { + if (nr < 0 && unsigned_val) + nr= (ulonglong) (long) (1L << 24); // Generate overflow + if (nr < (longlong) INT_MIN24) { - long tmp=(long) INT_MIN24; + long tmp= (long) INT_MIN24; int3store(ptr,tmp); set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; @@ -3397,7 +3414,7 @@ int Field_long::store(double nr) } -int Field_long::store(longlong nr) +int Field_long::store(longlong nr, bool unsigned_val) { int error= 0; int32 res; @@ -3405,12 +3422,12 @@ int Field_long::store(longlong nr) if (unsigned_flag) { - if (nr < 0) + if (nr < 0 && !unsigned_val) { res=0; error= 1; } - else if (nr >= (LL(1) << 32)) + else if ((ulonglong) nr >= (LL(1) << 32)) { res=(int32) (uint32) ~0L; error= 1; @@ -3420,7 +3437,9 @@ int Field_long::store(longlong nr) } else { - if (nr < (longlong) INT_MIN32) + if (nr < 0 && unsigned_val) + nr= ((longlong) INT_MAX32) + 1; // Generate overflow + if (nr < (longlong) INT_MIN32) { res=(int32) INT_MIN32; error= 1; @@ -3657,8 +3676,24 @@ int Field_longlong::store(double nr) } -int Field_longlong::store(longlong nr) +int Field_longlong::store(longlong nr, bool unsigned_val) { + int error= 0; + + if (nr < 0) // Only possible error + { + /* + if field is unsigned and value is signed (< 0) or + if field is signed and value is unsigned we have an overflow + */ + if (unsigned_flag != unsigned_val) + { + nr= unsigned_flag ? (ulonglong) 0 : (ulonglong) LONGLONG_MAX; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + error= 1; + } + } + #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) { @@ -3667,7 +3702,7 @@ int Field_longlong::store(longlong nr) else #endif longlongstore(ptr,nr); - return 0; + return error; } @@ -3886,11 +3921,12 @@ int Field_float::store(double nr) } -int Field_float::store(longlong nr) +int Field_float::store(longlong nr, bool unsigned_val) { - return store((double)nr); + return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr); } + double Field_float::val_real(void) { float j; @@ -4166,11 +4202,12 @@ int Field_double::store(double nr) } -int Field_double::store(longlong nr) +int Field_double::store(longlong nr, bool unsigned_val) { - return store((double)nr); + return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr); } + int Field_real::store_decimal(const my_decimal *dm) { double dbl; @@ -4529,12 +4566,12 @@ int Field_timestamp::store(double nr) nr= 0; // Avoid overflow on buff error= 1; } - error|= Field_timestamp::store((longlong) rint(nr)); + error|= Field_timestamp::store((longlong) rint(nr), FALSE); return error; } -int Field_timestamp::store(longlong nr) +int Field_timestamp::store(longlong nr, bool unsigned_val) { TIME l_time; my_time_t timestamp= 0; @@ -4829,7 +4866,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) if (ltime.neg) tmp= -tmp; - error |= Field_time::store((longlong) tmp); + error |= Field_time::store((longlong) tmp, FALSE); return error; } @@ -4881,21 +4918,21 @@ int Field_time::store(double nr) } -int Field_time::store(longlong nr) +int Field_time::store(longlong nr, bool unsigned_val) { long tmp; int error= 0; - if (nr > (longlong) 8385959L) + if (nr < (longlong) -8385959L && !unsigned_val) { - tmp=8385959L; + tmp= -8385959L; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); error= 1; } - else if (nr < (longlong) -8385959L) + else if (nr > (longlong) 8385959 || nr < 0 && unsigned_val) { - tmp= -8385959L; + tmp=8385959L; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); @@ -5076,18 +5113,18 @@ int Field_year::store(double nr) { if (nr < 0.0 || nr >= 2155.0) { - (void) Field_year::store((longlong) -1); + (void) Field_year::store((longlong) -1, FALSE); return 1; } - else - return Field_year::store((longlong) nr); + return Field_year::store((longlong) nr, FALSE); } -int Field_year::store(longlong nr) + +int Field_year::store(longlong nr, bool unsigned_val) { if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { - *ptr=0; + *ptr= 0; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } @@ -5102,17 +5139,20 @@ int Field_year::store(longlong nr) return 0; } + bool Field_year::send_binary(Protocol *protocol) { ulonglong tmp= Field_year::val_int(); return protocol->store_short(tmp); } + double Field_year::val_real(void) { return (double) Field_year::val_int(); } + longlong Field_year::val_int(void) { int tmp= (int) ((uchar*) ptr)[0]; @@ -5123,6 +5163,7 @@ longlong Field_year::val_int(void) return (longlong) tmp; } + String *Field_year::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -5133,6 +5174,7 @@ String *Field_year::val_str(String *val_buffer, return val_buffer; } + void Field_year::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); @@ -5203,7 +5245,7 @@ int Field_date::store(double nr) } -int Field_date::store(longlong nr) +int Field_date::store(longlong nr, bool unsigned_val) { TIME not_used; int error; @@ -5262,6 +5304,7 @@ double Field_date::val_real(void) return (double) (uint32) j; } + longlong Field_date::val_int(void) { int32 j; @@ -5274,6 +5317,7 @@ longlong Field_date::val_int(void) return (longlong) (uint32) j; } + String *Field_date::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -5382,11 +5426,11 @@ int Field_newdate::store(double nr) WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE); return 1; } - return Field_newdate::store((longlong) rint(nr)); + return Field_newdate::store((longlong) rint(nr), FALSE); } -int Field_newdate::store(longlong nr) +int Field_newdate::store(longlong nr, bool unsigned_val) { TIME l_time; longlong tmp; @@ -5576,12 +5620,12 @@ int Field_datetime::store(double nr) nr= 0.0; error= 1; } - error|= Field_datetime::store((longlong) rint(nr)); + error|= Field_datetime::store((longlong) rint(nr), FALSE); return error; } -int Field_datetime::store(longlong nr) +int Field_datetime::store(longlong nr, bool unsigned_val) { TIME not_used; int error; @@ -5837,7 +5881,8 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) memcpy(ptr,from,copy_length); if (copy_length < field_length) // Append spaces if shorter field_charset->cset->fill(field_charset,ptr+copy_length, - field_length-copy_length,' '); + field_length-copy_length, + field_charset->pad_char); if ((copy_length < length) && table->in_use->count_cuted_fields) { // Check if we loosed some info @@ -5905,12 +5950,13 @@ int Field_str::store(double nr) } -int Field_string::store(longlong nr) +int Field_string::store(longlong nr, bool unsigned_val) { char buff[64]; int l; CHARSET_INFO *cs=charset(); - l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr); + l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff), + unsigned_val ? 10 : -10, nr); return Field_string::store(buff,(uint)l,cs); } @@ -6234,14 +6280,16 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) } -int Field_varstring::store(longlong nr) +int Field_varstring::store(longlong nr, bool unsigned_val) { char buff[64]; uint length; length= (uint) (field_charset->cset->longlong10_to_str)(field_charset, buff, sizeof(buff), - -10,nr); + (unsigned_val ? 10: + -10), + nr); return Field_varstring::store(buff, length, field_charset); } @@ -6354,6 +6402,17 @@ int Field_varstring::key_cmp(const byte *a,const byte *b) void Field_varstring::sort_string(char *to,uint length) { uint tot_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); + + if (field_charset == &my_charset_bin) + { + /* Store length last in high-byte order to sort longer strings first */ + if (length_bytes == 1) + to[length-1]= tot_length; + else + mi_int2store(to+length-2, tot_length); + length-= length_bytes; + } + tot_length= my_strnxfrm(field_charset, (uchar*) to, length, (uchar*) ptr + length_bytes, @@ -6859,13 +6918,17 @@ int Field_blob::store(double nr) } -int Field_blob::store(longlong nr) +int Field_blob::store(longlong nr, bool unsigned_val) { CHARSET_INFO *cs=charset(); - value.set(nr, cs); + if (unsigned_val) + value.set((ulonglong) nr, cs); + else + value.set(nr, cs); return Field_blob::store(value.ptr(), (uint) value.length(), cs); } + double Field_blob::val_real(void) { int not_used; @@ -7041,6 +7104,13 @@ int Field_blob::key_cmp(const byte *a,const byte *b) } +uint32 Field_blob::sort_length() const +{ + return (uint32) (current_thd->variables.max_sort_length + + (field_charset == &my_charset_bin ? 0 : packlength)); +} + + void Field_blob::sort_string(char *to,uint length) { char *blob; @@ -7050,6 +7120,31 @@ void Field_blob::sort_string(char *to,uint length) bzero(to,length); else { + if (field_charset == &my_charset_bin) + { + char *pos; + + /* + Store length of blob last in blob to shorter blobs before longer blobs + */ + length-= packlength; + pos= to+length; + + switch (packlength) { + case 1: + *pos= (char) blob_length; + break; + case 2: + mi_int2store(pos, blob_length); + break; + case 3: + mi_int3store(pos, blob_length); + break; + case 4: + mi_int4store(pos, blob_length); + break; + } + } memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); blob_length=my_strnxfrm(field_charset, @@ -7330,7 +7425,7 @@ int Field_geom::store(double nr) } -int Field_geom::store(longlong nr) +int Field_geom::store(longlong nr, bool unsigned_val) { my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); @@ -7483,14 +7578,14 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) int Field_enum::store(double nr) { - return Field_enum::store((longlong) nr); + return Field_enum::store((longlong) nr, FALSE); } -int Field_enum::store(longlong nr) +int Field_enum::store(longlong nr, bool unsigned_val) { int error= 0; - if ((uint) nr > typelib->count || nr == 0) + if ((ulonglong) nr > typelib->count || nr == 0) { set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); nr=0; @@ -7661,7 +7756,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) } -int Field_set::store(longlong nr) +int Field_set::store(longlong nr, bool unsigned_val) { int error= 0; if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) - @@ -7881,11 +7976,11 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) int Field_bit::store(double nr) { - return store((longlong) nr); + return store((longlong) nr, FALSE); } -int Field_bit::store(longlong nr) +int Field_bit::store(longlong nr, bool unsigned_val) { char buf[8]; @@ -8466,8 +8561,8 @@ create_field::create_field(Field *old_field,Field *orig_field) else interval=0; def=0; + if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && - !old_field->is_real_null() && old_field->ptr && orig_field && (sql_type != FIELD_TYPE_TIMESTAMP || /* set def only if */ old_field->table->timestamp_field != old_field || /* timestamp field */ diff --git a/sql/field.h b/sql/field.h index 2b67ed3f599..a9f47ecc4a9 100644 --- a/sql/field.h +++ b/sql/field.h @@ -97,7 +97,7 @@ public: /* Store functions returns 1 on overflow and -1 on fatal error */ virtual int store(const char *to,uint length,CHARSET_INFO *cs)=0; virtual int store(double nr)=0; - virtual int store(longlong nr)=0; + virtual int store(longlong nr, bool unsigned_val)=0; virtual int store_decimal(const my_decimal *d)=0; virtual int store_time(TIME *ltime, timestamp_type t_type); virtual double val_real(void)=0; @@ -132,6 +132,7 @@ public: virtual bool eq_def(Field *field); virtual uint32 pack_length() const { return (uint32) field_length; } virtual uint32 pack_length_in_rec() const { return pack_length(); } + virtual uint32 sort_length() const { return pack_length(); } virtual void reset(void) { bzero(ptr,pack_length()); } virtual void reset_fields() {} virtual void set_default() @@ -357,7 +358,7 @@ public: Item_result result_type () const { return STRING_RESULT; } uint decimals() const { return NOT_FIXED_DEC; } int store(double nr); - int store(longlong nr)=0; + int store(longlong nr, bool unsigned_val)=0; int store_decimal(const my_decimal *); int store(const char *to,uint length,CHARSET_INFO *cs)=0; uint size_of() const { return sizeof(*this); } @@ -422,7 +423,7 @@ public: void reset(void); int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -464,7 +465,7 @@ public: void set_value_on_overflow(my_decimal *decimal_value, bool sign); int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); int store_decimal(const my_decimal *); double val_real(void); longlong val_int(void); @@ -497,7 +498,7 @@ public: { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=0; } double val_real(void); longlong val_int(void); @@ -533,7 +534,7 @@ public: { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=ptr[1]=0; } double val_real(void); longlong val_int(void); @@ -564,7 +565,7 @@ public: { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; } double val_real(void); longlong val_int(void); @@ -600,7 +601,7 @@ public: { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); @@ -638,7 +639,7 @@ public: { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; } double val_real(void); longlong val_int(void); @@ -674,7 +675,7 @@ public: enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { bzero(ptr,sizeof(float)); } double val_real(void); longlong val_int(void); @@ -708,7 +709,7 @@ public: enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { bzero(ptr,sizeof(double)); } double val_real(void); longlong val_int(void); @@ -737,7 +738,7 @@ public: int store(const char *to, uint length, CHARSET_INFO *cs) { null[0]=1; return 0; } int store(double nr) { null[0]=1; return 0; } - int store(longlong nr) { null[0]=1; return 0; } + int store(longlong nr, bool unsigned_val) { null[0]=1; return 0; } int store_decimal(const my_decimal *d) { null[0]=1; return 0; } void reset(void) {} double val_real(void) { return 0.0;} @@ -766,7 +767,7 @@ public: enum Item_result cmp_type () const { return INT_RESULT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); @@ -818,7 +819,7 @@ public: enum_field_types type() const { return FIELD_TYPE_YEAR;} int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -845,7 +846,7 @@ public: enum Item_result cmp_type () const { return INT_RESULT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); @@ -873,7 +874,7 @@ public: enum Item_result cmp_type () const { return INT_RESULT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); int store_time(TIME *ltime, timestamp_type type); void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; } double val_real(void); @@ -909,7 +910,7 @@ public: int store_time(TIME *ltime, timestamp_type type); int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; } double val_real(void); longlong val_int(void); @@ -946,7 +947,7 @@ public: uint decimals() const { return DATETIME_DEC; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); int store_time(TIME *ltime, timestamp_type type); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; } double val_real(void); @@ -990,7 +991,7 @@ public: bool zero_pack() const { return 0; } void reset(void) { charset()->cset->fill(charset(),ptr,field_length,' '); } int store(const char *to,uint length,CHARSET_INFO *charset); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ double val_real(void); longlong val_int(void); @@ -1048,8 +1049,13 @@ public: void reset(void) { bzero(ptr,field_length+length_bytes); } uint32 pack_length() const { return (uint32) field_length+length_bytes; } uint32 key_length() const { return (uint32) field_length; } + uint32 sort_length() const + { + return (uint32) field_length + (field_charset == &my_charset_bin ? + length_bytes : 0); + } int store(const char *to,uint length,CHARSET_INFO *charset); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ double val_real(void); longlong val_int(void); @@ -1106,7 +1112,7 @@ public: { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -1120,6 +1126,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return (uint32) (packlength+table->s->blob_ptr_size); } + uint32 sort_length() const; inline uint32 max_data_length() const { return (uint32) (((ulonglong) 1 << (packlength*8)) -1); @@ -1201,7 +1208,7 @@ public: void sql_type(String &str) const; int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); int store_decimal(const my_decimal *); void get_key_image(char *buff,uint length,imagetype type); uint size_of() const { return sizeof(*this); } @@ -1232,7 +1239,7 @@ public: enum ha_base_keytype key_type() const; int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); void reset() { bzero(ptr,packlength); } double val_real(void); longlong val_int(void); @@ -1268,8 +1275,8 @@ public: flags=(flags & ~ENUM_FLAG) | SET_FLAG; } int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr) { return Field_set::store((longlong) nr); } - int store(longlong nr); + int store(double nr) { return Field_set::store((longlong) nr, FALSE); } + int store(longlong nr, bool unsigned_val); virtual bool zero_pack() const { return 1; } String *val_str(String*,String *); void sql_type(String &str) const; @@ -1296,7 +1303,7 @@ public: void reset(void) { bzero(ptr, field_length); } int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); - int store(longlong nr); + int store(longlong nr, bool unsigned_val); int store_decimal(const my_decimal *); double val_real(void); longlong val_int(void); @@ -1342,7 +1349,8 @@ public: uint size_of() const { return sizeof(*this); } int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr) { return Field_bit::store(nr); } - int store(longlong nr) { return Field_bit::store(nr); } + int store(longlong nr, bool unsigned_val) + { return Field_bit::store(nr, unsigned_val); } void sql_type(String &str) const; }; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 40f3ff85c58..bbe2dbe5e9f 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -311,8 +311,9 @@ static void do_field_string(Copy_field *copy) static void do_field_int(Copy_field *copy) { - longlong value=copy->from_field->val_int(); - copy->to_field->store(value); + longlong value= copy->from_field->val_int(); + copy->to_field->store(value, + test(copy->from_field->flags & UNSIGNED_FLAG)); } static void do_field_real(Copy_field *copy) @@ -689,5 +690,5 @@ void field_conv(Field *to,Field *from) to->store_decimal(from->val_decimal(&buff)); } else - to->store(from->val_int()); + to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG)); } diff --git a/sql/filesort.cc b/sql/filesort.cc index 75da43afed5..42d25dbbaee 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -50,7 +50,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer, IO_CACHE *outfile); static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count, FILESORT_INFO *table_sort); -static uint sortlength(SORT_FIELD *sortorder, uint s_length, +static uint suffix_length(ulong string_length); +static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset); static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength); @@ -123,7 +124,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, sort_keys= (uchar **) NULL; error= 1; bzero((char*) ¶m,sizeof(param)); - param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset); + param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset); param.ref_length= table->file->ref_length; param.addon_field= 0; param.addon_length= 0; @@ -466,7 +467,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, my_store_ptr(ref_pos,ref_length,record); // Position to row record+= sort_form->s->db_record_offset; } - else + else if (!error) file->position(sort_form->record[0]); } if (error && error != HA_ERR_RECORD_DELETED) @@ -585,6 +586,28 @@ err: } /* write_keys */ +/* + Store length as suffix in high-byte-first order +*/ + +static inline void store_length(uchar *to, uint length, uint pack_length) +{ + switch (pack_length) { + case 1: + *to= (uchar) length; + break; + case 2: + mi_int2store(to, length); + break; + case 3: + mi_int3store(to, length); + default: + mi_int4store(to, length); + break; + } +} + + /* makes a sort-key from record */ static void make_sortkey(register SORTPARAM *param, @@ -623,9 +646,11 @@ static void make_sortkey(register SORTPARAM *param, maybe_null= item->maybe_null; switch (sort_field->result_type) { case STRING_RESULT: - { + { CHARSET_INFO *cs=item->collation.collation; char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' '); + int diff; + uint sort_field_length; if (maybe_null) *to++=1; @@ -644,24 +669,32 @@ static void make_sortkey(register SORTPARAM *param, } break; } - length=res->length(); - int diff=(int) (sort_field->length-length); + length= res->length(); + sort_field_length= sort_field->length - sort_field->suffix_length; + diff=(int) (sort_field_length - length); if (diff < 0) { diff=0; /* purecov: inspected */ - length=sort_field->length; + length= sort_field_length; } + if (sort_field->suffix_length) + { + /* Store length last in result_string */ + store_length(to + sort_field_length, length, + sort_field->suffix_length); + } if (sort_field->need_strxnfrm) { char *from=(char*) res->ptr(); + uint tmp_length; if ((unsigned char *)from == to) { set_if_smaller(length,sort_field->length); memcpy(param->tmp_buffer,from,length); from=param->tmp_buffer; } - uint tmp_length=my_strnxfrm(cs,to,sort_field->length, - (unsigned char *) from, length); + tmp_length= my_strnxfrm(cs,to,sort_field->length, + (unsigned char *) from, length); DBUG_ASSERT(tmp_length == sort_field->length); } else @@ -670,7 +703,7 @@ static void make_sortkey(register SORTPARAM *param, cs->cset->fill(cs, (char *)to+length,diff,fill_char); } break; - } + } case INT_RESULT: { longlong value= item->val_int_result(); @@ -1170,11 +1203,25 @@ static int merge_index(SORTPARAM *param, uchar *sort_buffer, } /* merge_index */ +static uint suffix_length(ulong string_length) +{ + if (string_length < 256) + return 1; + if (string_length < 256L*256L) + return 2; + if (string_length < 256L*256L*256L) + return 3; + return 4; // Can't sort longer than 4G +} + + + /* Calculate length of sort key SYNOPSIS sortlength() + thd Thread handler sortorder Order of items to sort uint s_length Number of items to sort multi_byte_charset (out) @@ -1190,10 +1237,10 @@ static int merge_index(SORTPARAM *param, uchar *sort_buffer, */ static uint -sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) +sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, + bool *multi_byte_charset) { reg2 uint length; - THD *thd= current_thd; CHARSET_INFO *cs; *multi_byte_charset= 0; @@ -1201,19 +1248,17 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) for (; s_length-- ; sortorder++) { sortorder->need_strxnfrm= 0; + sortorder->suffix_length= 0; if (sortorder->field) { - if (sortorder->field->type() == FIELD_TYPE_BLOB) - sortorder->length= thd->variables.max_sort_length; - else + cs= sortorder->field->sort_charset(); + sortorder->length= sortorder->field->sort_length(); + + if (use_strnxfrm((cs=sortorder->field->sort_charset()))) { - sortorder->length=sortorder->field->pack_length(); - if (use_strnxfrm((cs=sortorder->field->sort_charset()))) - { - sortorder->need_strxnfrm= 1; - *multi_byte_charset= 1; - sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length); - } + sortorder->need_strxnfrm= 1; + *multi_byte_charset= 1; + sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length); } if (sortorder->field->maybe_null()) length++; // Place for NULL marker @@ -1229,6 +1274,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) sortorder->need_strxnfrm= 1; *multi_byte_charset= 1; } + else if (cs == &my_charset_bin) + { + /* Store length last to be able to sort blob/varbinary */ + sortorder->suffix_length= suffix_length(sortorder->length); + sortorder->length+= sortorder->suffix_length; + } break; case INT_RESULT: #if SIZEOF_LONG_LONG > 4 diff --git a/sql/examples/ha_archive.cc b/sql/ha_archive.cc index 7b9f6e23548..b4bcf162ff0 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/ha_archive.cc @@ -18,7 +18,7 @@ #pragma implementation // gcc: Class implementation #endif -#include "../mysql_priv.h" +#include "mysql_priv.h" #ifdef HAVE_ARCHIVE_DB #include "ha_archive.h" @@ -116,7 +116,7 @@ */ /* If the archive storage engine has been inited */ -static bool archive_inited= 0; +static bool archive_inited= FALSE; /* Variables for archive share methods */ pthread_mutex_t archive_mutex; static HASH archive_open_tables; @@ -136,8 +136,12 @@ static HASH archive_open_tables; #define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption /* dummy handlerton - only to have something to return from archive_db_init */ -static handlerton archive_hton = { - "archive", +handlerton archive_hton = { + "ARCHIVE", + SHOW_OPTION_YES, + "Archive storage engine", + DB_TYPE_ARCHIVE_DB, + archive_db_init, 0, /* slot */ 0, /* savepoint size. */ NULL, /* close_connection */ @@ -176,18 +180,28 @@ static byte* archive_get_key(ARCHIVE_SHARE *share,uint *length, void RETURN - &archive_hton OK - 0 Error + FALSE OK + TRUE Error */ -handlerton *archive_db_init() +bool archive_db_init() { - archive_inited= 1; - VOID(pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST)); + DBUG_ENTER("archive_db_init"); + if (pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST)) + goto error; if (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0, (hash_get_key) archive_get_key, 0, 0)) - return 0; - return &archive_hton; + { + VOID(pthread_mutex_destroy(&archive_mutex)); + } + else + { + archive_inited= TRUE; + DBUG_RETURN(FALSE); + } +error: + have_archive_db= SHOW_OPTION_DISABLED; // If we couldn't use handler + DBUG_RETURN(TRUE); } /* @@ -544,7 +558,7 @@ int ha_archive::create(const char *name, TABLE *table_arg, error= my_errno; goto error; } - if ((archive= gzdopen(create_file, "ab")) == NULL) + if ((archive= gzdopen(create_file, "wb")) == NULL) { error= errno; goto error2; @@ -1039,4 +1053,81 @@ int ha_archive::delete_all_rows() DBUG_ENTER("ha_archive::delete_all_rows"); DBUG_RETURN(0); } + +/* + We just return state if asked. +*/ +bool ha_archive::is_crashed() const +{ + return share->crashed; +} + +/* + Simple scan of the tables to make sure everything is ok. +*/ + +int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) +{ + int rc= 0; + byte *buf; + const char *old_proc_info=thd->proc_info; + ha_rows count= share->rows_recorded; + DBUG_ENTER("ha_archive::check"); + + thd->proc_info= "Checking table"; + /* Flush any waiting data */ + gzflush(share->archive_write, Z_SYNC_FLUSH); + + /* + First we create a buffer that we can use for reading rows, and can pass + to get_row(). + */ + if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME)))) + rc= HA_ERR_OUT_OF_MEM; + + /* + Now we will rewind the archive file so that we are positioned at the + start of the file. + */ + if (!rc) + read_data_header(archive); + + if (!rc) + while (!(rc= get_row(archive, buf))) + count--; + + my_free((char*)buf, MYF(0)); + + thd->proc_info= old_proc_info; + + if ((rc && rc != HA_ERR_END_OF_FILE) || count) + { + share->crashed= FALSE; + DBUG_RETURN(HA_ADMIN_CORRUPT); + } + else + { + DBUG_RETURN(HA_ADMIN_OK); + } +} + +/* + Check and repair the table if needed. +*/ +bool ha_archive::check_and_repair(THD *thd) +{ + HA_CHECK_OPT check_opt; + DBUG_ENTER("ha_archive::check_and_repair"); + + check_opt.init(); + + if (check(thd, &check_opt) == HA_ADMIN_CORRUPT) + { + DBUG_RETURN(repair(thd, &check_opt)); + } + else + { + DBUG_RETURN(HA_ADMIN_OK); + } +} #endif /* HAVE_ARCHIVE_DB */ diff --git a/sql/examples/ha_archive.h b/sql/ha_archive.h index e2d8aa49add..6ba6d95685e 100644 --- a/sql/examples/ha_archive.h +++ b/sql/ha_archive.h @@ -103,8 +103,11 @@ public: } THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); + bool is_crashed() const; + int check(THD* thd, HA_CHECK_OPT* check_opt); + bool check_and_repair(THD *thd); }; -handlerton *archive_db_init(void); +bool archive_db_init(void); bool archive_db_end(void); diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index b8a779c08cf..7cbb4e90452 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -107,8 +107,12 @@ static int berkeley_close_connection(THD *thd); static int berkeley_commit(THD *thd, bool all); static int berkeley_rollback(THD *thd, bool all); -static handlerton berkeley_hton = { +handlerton berkeley_hton = { "BerkeleyDB", + SHOW_OPTION_YES, + "Supports transactions and page-level locking", + DB_TYPE_BERKELEY_DB, + berkeley_init, 0, /* slot */ 0, /* savepoint size */ berkeley_close_connection, @@ -135,10 +139,13 @@ typedef struct st_berkeley_trx_data { /* General functions */ -handlerton *berkeley_init(void) +bool berkeley_init(void) { DBUG_ENTER("berkeley_init"); + if (have_berkeley_db != SHOW_OPTION_YES) + goto error; + if (!berkeley_tmpdir) berkeley_tmpdir=mysql_tmpdir; if (!berkeley_home) @@ -164,7 +171,7 @@ handlerton *berkeley_init(void) berkeley_log_file_size= max(berkeley_log_file_size, 10*1024*1024L); if (db_env_create(&db_env,0)) - DBUG_RETURN(0); + goto error; db_env->set_errcall(db_env,berkeley_print_error); db_env->set_errpfx(db_env,"bdb"); db_env->set_noticecall(db_env, berkeley_noticecall); @@ -194,13 +201,16 @@ handlerton *berkeley_init(void) { db_env->close(db_env,0); db_env=0; - DBUG_RETURN(0); + goto error; } (void) hash_init(&bdb_open_tables,system_charset_info,32,0,0, (hash_get_key) bdb_get_key,0,0); pthread_mutex_init(&bdb_mutex,MY_MUTEX_INIT_FAST); - DBUG_RETURN(&berkeley_hton); + DBUG_RETURN(FALSE); +error: + have_berkeley_db= SHOW_OPTION_DISABLED; // If we couldn't use handler + DBUG_RETURN(TRUE); } @@ -1894,7 +1904,7 @@ int ha_berkeley::external_lock(THD *thd, int lock_type) Under LOCK TABLES, each used tables will force a call to start_stmt. */ -int ha_berkeley::start_stmt(THD *thd) +int ha_berkeley::start_stmt(THD *thd, thr_lock_type lock_type) { int error=0; DBUG_ENTER("ha_berkeley::start_stmt"); diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index 282641e3f25..59f11bfd74a 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -124,7 +124,7 @@ class ha_berkeley: public handler int extra(enum ha_extra_function operation); int reset(void); int external_lock(THD *thd, int lock_type); - int start_stmt(THD *thd); + int start_stmt(THD *thd, thr_lock_type lock_type); void position(byte *record); int analyze(THD* thd,HA_CHECK_OPT* check_opt); int optimize(THD* thd, HA_CHECK_OPT* check_opt); @@ -161,7 +161,7 @@ extern char *berkeley_home, *berkeley_tmpdir, *berkeley_logdir; extern long berkeley_lock_scan_time; extern TYPELIB berkeley_lock_typelib; -handlerton *berkeley_init(void); +bool berkeley_init(void); bool berkeley_end(void); bool berkeley_flush_logs(void); int berkeley_show_logs(Protocol *protocol); diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index a287d6e446b..2505919af39 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -26,8 +26,12 @@ /* Blackhole storage engine handlerton */ -static handlerton blackhole_hton= { +handlerton blackhole_hton= { "BLACKHOLE", + SHOW_OPTION_YES, + "/dev/null storage engine (anything you write to it disappears)", + DB_TYPE_BLACKHOLE_DB, + NULL, 0, /* slot */ 0, /* savepoint size. */ NULL, /* close_connection */ @@ -43,7 +47,7 @@ static handlerton blackhole_hton= { NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS + HTON_CAN_RECREATE }; /***************************************************************************** diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 639f09d10ca..d6d6b5980f6 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -363,6 +363,33 @@ pthread_mutex_t federated_mutex; // This is the mutex we use to static int federated_init= FALSE; // Variable for checking the // init state of hash +/* Federated storage engine handlerton */ + +handlerton federated_hton= { + "FEDERATED", + SHOW_OPTION_YES, + "Federated MySQL storage engine", + DB_TYPE_FEDERATED_DB, + federated_db_init, + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_ALTER_NOT_SUPPORTED +}; + + /* Function we use in the creation of our hash to get key. */ static byte *federated_get_key(FEDERATED_SHARE *share, uint *length, @@ -386,10 +413,22 @@ static byte *federated_get_key(FEDERATED_SHARE *share, uint *length, bool federated_db_init() { - federated_init= 1; - VOID(pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST)); - return (hash_init(&federated_open_tables, system_charset_info, 32, 0, 0, - (hash_get_key) federated_get_key, 0, 0)); + DBUG_ENTER("federated_db_init"); + if (pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST)) + goto error; + if (hash_init(&federated_open_tables, system_charset_info, 32, 0, 0, + (hash_get_key) federated_get_key, 0, 0)) + { + VOID(pthread_mutex_destroy(&federated_mutex)); + } + else + { + federated_init= TRUE; + DBUG_RETURN(FALSE); + } +error: + have_federated_db= SHOW_OPTION_DISABLED; // If we couldn't use handler + DBUG_RETURN(TRUE); } @@ -441,6 +480,7 @@ static int check_foreign_data_source( String query(query_buffer, sizeof(query_buffer), &my_charset_bin); MYSQL *mysql; DBUG_ENTER("ha_federated::check_foreign_data_source"); + /* Zero the length, otherwise the string will have misc chars */ query.length(0); @@ -473,13 +513,15 @@ static int check_foreign_data_source( else { /* - Since we do not support transactions at this version, we can let the client - API silently reconnect. For future versions, we will need more logic to deal - with transactions + Since we do not support transactions at this version, we can let the + client API silently reconnect. For future versions, we will need more + logic to deal with transactions */ mysql->reconnect= 1; /* - Note: I am not using INORMATION_SCHEMA because this needs to work with < 5.0 + Note: I am not using INORMATION_SCHEMA because this needs to work with + versions prior to 5.0 + if we can connect, then make sure the table exists the query will be: SELECT * FROM `tablename` WHERE 1=0 @@ -497,7 +539,8 @@ static int check_foreign_data_source( query.append(FEDERATED_WHERE); query.append(FEDERATED_FALSE); - DBUG_PRINT("info", ("check_foreign_data_source query %s", query.c_ptr_quick())); + DBUG_PRINT("info", ("check_foreign_data_source query %s", + query.c_ptr_quick())); if (mysql_real_query(mysql, query.ptr(), query.length())) { error_code= table_create_flag ? @@ -517,8 +560,29 @@ error: } +static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num) +{ + char buf[FEDERATED_QUERY_BUFFER_SIZE]; + int buf_len; + DBUG_ENTER("ha_federated parse_url_error"); + + if (share->scheme) + { + DBUG_PRINT("info", + ("error: parse_url. Returning error code %d \ + freeing share->scheme %lx", error_num, share->scheme)); + my_free((gptr) share->scheme, MYF(0)); + share->scheme= 0; + } + buf_len= min(table->s->connect_string.length, + FEDERATED_QUERY_BUFFER_SIZE-1); + strmake(buf, table->s->connect_string.str, buf_len); + my_error(error_num, MYF(0), buf); + DBUG_RETURN(error_num); +} + /* - Parse connection info from table->s->comment + Parse connection info from table->s->connect_string SYNOPSIS parse_url() @@ -563,145 +627,112 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, DBUG_ENTER("ha_federated::parse_url"); share->port= 0; - share->scheme= my_strdup(table->s->comment, MYF(0)); + share->socket= 0; + DBUG_PRINT("info", ("Length %d \n", table->s->connect_string.length)); + DBUG_PRINT("info", ("String %.*s \n", table->s->connect_string.length, + table->s->connect_string.str)); + share->scheme= my_strdup_with_length((const byte*)table->s-> + connect_string.str, + table->s->connect_string.length, + MYF(0)); + + // Add a null for later termination of table name + share->scheme[table->s->connect_string.length]= 0; DBUG_PRINT("info",("parse_url alloced share->scheme %lx", share->scheme)); /* remove addition of null terminator and store length for each string in share */ - if ((share->username= strstr(share->scheme, "://"))) - { - share->scheme[share->username - share->scheme]= '\0'; - - if (strcmp(share->scheme, "mysql") != 0) - goto error; + if (!(share->username= strstr(share->scheme, "://"))) + goto error; + share->scheme[share->username - share->scheme]= '\0'; - share->username+= 3; + if (strcmp(share->scheme, "mysql") != 0) + goto error; - if ((share->hostname= strchr(share->username, '@'))) - { - share->username[share->hostname - share->username]= '\0'; - share->hostname++; + share->username+= 3; - if ((share->password= strchr(share->username, ':'))) - { - share->username[share->password - share->username]= '\0'; - share->password++; - share->username= share->username; - /* make sure there isn't an extra / or @ */ - if ((strchr(share->password, '/') || strchr(share->hostname, '@'))) - goto error; - /* - Found that if the string is: - user:@hostname:port/database/table - Then password is a null string, so set to NULL - */ - if ((share->password[0] == '\0')) - share->password= NULL; - } - else - share->username= share->username; + if (!(share->hostname= strchr(share->username, '@'))) + goto error; + + share->username[share->hostname - share->username]= '\0'; + share->hostname++; - /* make sure there isn't an extra / or @ */ - if ((strchr(share->username, '/')) || (strchr(share->hostname, '@'))) - goto error; + if ((share->password= strchr(share->username, ':'))) + { + share->username[share->password - share->username]= '\0'; + share->password++; + share->username= share->username; + /* make sure there isn't an extra / or @ */ + if ((strchr(share->password, '/') || strchr(share->hostname, '@'))) + goto error; + /* + Found that if the string is: + user:@hostname:port/database/table + Then password is a null string, so set to NULL + */ + if ((share->password[0] == '\0')) + share->password= NULL; + } + else + share->username= share->username; - if ((share->database= strchr(share->hostname, '/'))) - { - share->hostname[share->database - share->hostname]= '\0'; - share->database++; + /* make sure there isn't an extra / or @ */ + if ((strchr(share->username, '/')) || (strchr(share->hostname, '@'))) + goto error; - if ((share->sport= strchr(share->hostname, ':'))) - { - share->hostname[share->sport - share->hostname]= '\0'; - share->sport++; - if (share->sport[0] == '\0') - share->sport= NULL; - else - share->port= atoi(share->sport); - } + if (!(share->database= strchr(share->hostname, '/'))) + goto error; + share->hostname[share->database - share->hostname]= '\0'; + share->database++; - if ((share->table_name= strchr(share->database, '/'))) - { - share->database[share->table_name - share->database]= '\0'; - share->table_name++; - } - else - goto error; + if ((share->sport= strchr(share->hostname, ':'))) + { + share->hostname[share->sport - share->hostname]= '\0'; + share->sport++; + if (share->sport[0] == '\0') + share->sport= NULL; + else + share->port= atoi(share->sport); + } - share->table_name_length= strlen(share->table_name); - } - else - goto error; - /* make sure there's not an extra / */ - if ((strchr(share->table_name, '/'))) - goto error; + if (!(share->table_name= strchr(share->database, '/'))) + goto error; + share->database[share->table_name - share->database]= '\0'; + share->table_name++; - if (share->hostname[0] == '\0') - share->hostname= NULL; + share->table_name_length= strlen(share->table_name); + + /* make sure there's not an extra / */ + if ((strchr(share->table_name, '/'))) + goto error; - if (!share->port) - { - if (strcmp(share->hostname, my_localhost) == 0) - share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0)); - else - share->port= MYSQL_PORT; - } + if (share->hostname[0] == '\0') + share->hostname= NULL; - DBUG_PRINT("info", - ("scheme %s username %s password %s \ - hostname %s port %d database %s tablename %s\n", - share->scheme, share->username, share->password, - share->hostname, share->port, share->database, - share->table_name)); - } + if (!share->port) + { + if (strcmp(share->hostname, my_localhost) == 0) + share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0)); else - goto error; + share->port= MYSQL_PORT; } - else - goto error; + + DBUG_PRINT("info", + ("scheme %s username %s password %s \ + hostname %s port %d database %s tablename %s\n", + share->scheme, share->username, share->password, + share->hostname, share->port, share->database, + share->table_name)); DBUG_RETURN(0); error: - if (share->scheme) - { - DBUG_PRINT("info", - ("error: parse_url. Returning error code %d \ - freeing share->scheme %lx", error_num, share->scheme)); - my_free((gptr) share->scheme, MYF(0)); - share->scheme= 0; - } - my_error(error_num, MYF(0), table->s->comment); - DBUG_RETURN(error_num); - + DBUG_RETURN(parse_url_error(share, table, error_num)); } -/* Federated storage engine handlerton */ - -static handlerton federated_hton= { - "FEDERATED", - 0, /* slot */ - 0, /* savepoint size. */ - NULL, /* close_connection */ - NULL, /* savepoint */ - NULL, /* rollback to savepoint */ - NULL, /* release savepoint */ - NULL, /* commit */ - NULL, /* rollback */ - NULL, /* prepare */ - NULL, /* recover */ - NULL, /* commit_by_xid */ - NULL, /* rollback_by_xid */ - NULL, /* create_cursor_read_view */ - NULL, /* set_cursor_read_view */ - NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS -}; - - /***************************************************************************** ** FEDERATED tables *****************************************************************************/ @@ -734,15 +765,11 @@ ha_federated::ha_federated(TABLE *table_arg) uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row) { - uint num_fields; ulong *lengths; Field **field; - DBUG_ENTER("ha_federated::convert_row_to_internal_format"); - num_fields= mysql_num_fields(stored_result); lengths= mysql_fetch_lengths(stored_result); - memset(record, 0, table->s->null_bytes); for (field= table->field; *field; field++) @@ -794,13 +821,8 @@ static bool emit_key_part_element(String *to, KEY_PART_INFO *part, *buf++= '0'; *buf++= 'x'; - for (; len; ptr++,len--) - { - uint tmp= (uint)(uchar) *ptr; - *buf++= _dig_vec_upper[tmp >> 4]; - *buf++= _dig_vec_upper[tmp & 15]; - } - if (to->append(buff, (uint)(buf - buff))) + buf= octet2hex(buf, (char*) ptr, len); + if (to->append((char*) buff, (uint)(buf - buff))) DBUG_RETURN(1); } else if (part->key_part_flag & HA_BLOB_PART) @@ -1097,8 +1119,8 @@ bool ha_federated::create_where_from_key(String *to, char tmpbuff[FEDERATED_QUERY_BUFFER_SIZE]; String tmp(tmpbuff, sizeof(tmpbuff), system_charset_info); const key_range *ranges[2]= { start_key, end_key }; - DBUG_ENTER("ha_federated::create_where_from_key"); + tmp.length(0); if (start_key == NULL && end_key == NULL) DBUG_RETURN(1); @@ -1106,12 +1128,9 @@ bool ha_federated::create_where_from_key(String *to, for (int i= 0; i <= 1; i++) { bool needs_quotes; - uint loop_counter= 0; KEY_PART_INFO *key_part; if (ranges[i] == NULL) continue; - const byte *key= ranges[i]->key; - uint key_length= ranges[i]->length; if (both_not_null) { @@ -1150,6 +1169,7 @@ bool ha_federated::create_where_from_key(String *to, switch(ranges[i]->flag) { case(HA_READ_KEY_EXACT): + DBUG_PRINT("info", ("federated HA_READ_KEY_EXACT %d", i)); if (store_length >= length || !needs_quotes || key_part->type == HA_KEYTYPE_BIT || @@ -1184,6 +1204,7 @@ bool ha_federated::create_where_from_key(String *to, } break; case(HA_READ_AFTER_KEY): + DBUG_PRINT("info", ("federated HA_READ_AFTER_KEY %d", i)); if (store_length >= length) /* end key */ { if (emit_key_part_name(&tmp, key_part)) @@ -1208,6 +1229,7 @@ bool ha_federated::create_where_from_key(String *to, break; } case(HA_READ_KEY_OR_NEXT): + DBUG_PRINT("info", ("federated HA_READ_KEY_OR_NEXT %d", i)); if (emit_key_part_name(&tmp, key_part) || tmp.append(FEDERATED_GE) || emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr, @@ -1215,6 +1237,7 @@ bool ha_federated::create_where_from_key(String *to, DBUG_RETURN(1); break; case(HA_READ_BEFORE_KEY): + DBUG_PRINT("info", ("federated HA_READ_BEFORE_KEY %d", i)); if (store_length >= length) { if (emit_key_part_name(&tmp, key_part) || @@ -1225,6 +1248,7 @@ bool ha_federated::create_where_from_key(String *to, break; } case(HA_READ_KEY_OR_PREV): + DBUG_PRINT("info", ("federated HA_READ_KEY_OR_PREV %d", i)); if (emit_key_part_name(&tmp, key_part) || tmp.append(FEDERATED_LE) || emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr, @@ -1307,13 +1331,12 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) query.append(FEDERATED_FROM); query.append(FEDERATED_BTICK); - if (!(share= (FEDERATED_SHARE *) my_multi_malloc(MYF(MY_WME), &share, sizeof(*share), &tmp_table_name, tmp_table_name_length+ 1, &select_query, - query.length()+strlen(table->s->comment)+1, + query.length()+table->s->connect_string.length+1, NullS))) { pthread_mutex_unlock(&federated_mutex); @@ -1362,17 +1385,13 @@ error: static int free_share(FEDERATED_SHARE *share) { DBUG_ENTER("free_share"); - pthread_mutex_lock(&federated_mutex); + pthread_mutex_lock(&federated_mutex); if (!--share->use_count) { - if (share->scheme) - { - my_free((gptr) share->scheme, MYF(0)); - share->scheme= 0; - } - hash_delete(&federated_open_tables, (byte*) share); + my_free((gptr) share->scheme, MYF(MY_ALLOW_ZERO_PTR)); + share->scheme= 0; thr_lock_delete(&share->lock); VOID(pthread_mutex_destroy(&share->mutex)); my_free((gptr) share, MYF(0)); @@ -1426,7 +1445,6 @@ const char **ha_federated::bas_ext() const int ha_federated::open(const char *name, int mode, uint test_if_locked) { - int rc; DBUG_ENTER("ha_federated::open"); if (!(share= get_share(name, table))) @@ -1443,13 +1461,7 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) share->port, share->socket, 0)) { - int error_code; - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - error_code= ER_CONNECT_TO_FOREIGN_DATA_SOURCE; - my_sprintf(error_buffer, (error_buffer, ": %d : %s", - mysql_errno(mysql), mysql_error(mysql))); - my_error(error_code, MYF(0), error_buffer); - DBUG_RETURN(error_code); + DBUG_RETURN(stash_remote_error()); } /* Since we do not support transactions at this version, we can let the client @@ -1565,7 +1577,6 @@ int ha_federated::write_row(byte *buf) values_string.length(0); insert_string.length(0); insert_field_value_string.length(0); - DBUG_ENTER("ha_federated::write_row"); DBUG_PRINT("info", ("table charset name %s csname %s", @@ -1681,13 +1692,7 @@ int ha_federated::write_row(byte *buf) if (mysql_real_query(mysql, insert_string.ptr(), insert_string.length())) { - int error_code; - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; - my_sprintf(error_buffer, (error_buffer, ": %d : %s", - mysql_errno(mysql), mysql_error(mysql))); - my_error(error_code, MYF(0), error_buffer); - DBUG_RETURN(error_code); + DBUG_RETURN(stash_remote_error()); } DBUG_RETURN(0); @@ -1698,7 +1703,6 @@ int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt) { char query_buffer[STRING_BUFFER_USUAL_SIZE]; String query(query_buffer, sizeof(query_buffer), &my_charset_bin); - DBUG_ENTER("ha_federated::optimize"); query.length(0); @@ -1711,8 +1715,7 @@ int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt) if (mysql_real_query(mysql, query.ptr(), query.length())) { - my_error(-1, MYF(0), mysql_error(mysql)); - DBUG_RETURN(-1); + DBUG_RETURN(stash_remote_error()); } DBUG_RETURN(0); @@ -1723,7 +1726,6 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt) { char query_buffer[STRING_BUFFER_USUAL_SIZE]; String query(query_buffer, sizeof(query_buffer), &my_charset_bin); - DBUG_ENTER("ha_federated::repair"); query.length(0); @@ -1742,8 +1744,7 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt) if (mysql_real_query(mysql, query.ptr(), query.length())) { - my_error(-1, MYF(0), mysql_error(mysql)); - DBUG_RETURN(-1); + DBUG_RETURN(stash_remote_error()); } DBUG_RETURN(0); @@ -1770,20 +1771,21 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt) int ha_federated::update_row(const byte *old_data, byte *new_data) { /* - This used to control how the query was built. If there was a primary key, - the query would be built such that there was a where clause with only - that column as the condition. This is flawed, because if we have a multi-part - primary key, it would only use the first part! We don't need to do this anyway, - because read_range_first will retrieve the correct record, which is what is used - to build the WHERE clause. We can however use this to append a LIMIT to the end - if there is NOT a primary key. Why do this? Because we only are updating one - record, and LIMIT enforces this. + This used to control how the query was built. If there was a + primary key, the query would be built such that there was a where + clause with only that column as the condition. This is flawed, + because if we have a multi-part primary key, it would only use the + first part! We don't need to do this anyway, because + read_range_first will retrieve the correct record, which is what + is used to build the WHERE clause. We can however use this to + append a LIMIT to the end if there is NOT a primary key. Why do + this? Because we only are updating one record, and LIMIT enforces + this. */ bool has_a_primary_key= (table->s->primary_key == 0 ? TRUE : FALSE); /* buffers for following strings */ - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char old_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; char new_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; char update_buffer[FEDERATED_QUERY_BUFFER_SIZE]; @@ -1805,7 +1807,6 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) String where_string(where_buffer, sizeof(where_buffer), &my_charset_bin); - DBUG_ENTER("ha_federated::update_row"); /* set string lengths to 0 to avoid misc chars in string @@ -1853,10 +1854,8 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) where_string.append(FEDERATED_ISNULL); else { - uint o_len; (*field)->val_str(&old_field_value, (char*) (old_data + (*field)->offset())); - o_len= (*field)->pack_length(); (*field)->quote_data(&old_field_value); where_string.append(old_field_value); } @@ -1886,12 +1885,7 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) if (mysql_real_query(mysql, update_string.ptr(), update_string.length())) { - int error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - my_sprintf(error_buffer, (error_buffer, ": %d : %s", - mysql_errno(mysql), mysql_error(mysql))); - my_error(error_code, MYF(0), error_buffer); - DBUG_RETURN(error_code); + DBUG_RETURN(stash_remote_error()); } DBUG_RETURN(0); } @@ -1918,11 +1912,9 @@ int ha_federated::delete_row(const byte *buf) String delete_string(delete_buffer, sizeof(delete_buffer), &my_charset_bin); String data_string(data_buffer, sizeof(data_buffer), &my_charset_bin); - delete_string.length(0); - data_string.length(0); - DBUG_ENTER("ha_federated::delete_row"); + delete_string.length(0); delete_string.append(FEDERATED_DELETE); delete_string.append(FEDERATED_FROM); delete_string.append(FEDERATED_BTICK); @@ -1932,9 +1924,11 @@ int ha_federated::delete_row(const byte *buf) for (Field **field= table->field; *field; field++) { - delete_string.append((*field)->field_name); + Field *cur_field= *field; + data_string.length(0); + delete_string.append(cur_field->field_name); - if ((*field)->is_null()) + if (cur_field->is_null()) { delete_string.append(FEDERATED_IS); data_string.append(FEDERATED_NULL); @@ -1942,26 +1936,21 @@ int ha_federated::delete_row(const byte *buf) else { delete_string.append(FEDERATED_EQ); - (*field)->val_str(&data_string); - (*field)->quote_data(&data_string); + cur_field->val_str(&data_string); + cur_field->quote_data(&data_string); } delete_string.append(data_string); - data_string.length(0); - - if (*(field + 1)) - delete_string.append(FEDERATED_AND); + delete_string.append(FEDERATED_AND); } + delete_string.length(delete_string.length()-5); // Remove trailing AND delete_string.append(FEDERATED_LIMIT1); DBUG_PRINT("info", ("Delete sql: %s", delete_string.c_ptr_quick())); if (mysql_real_query(mysql, delete_string.ptr(), delete_string.length())) { - int error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - my_error(error_code, MYF(0), error_buffer); - DBUG_RETURN(error_code); + DBUG_RETURN(stash_remote_error()); } deleted+= mysql->affected_rows; DBUG_PRINT("info", @@ -2004,8 +1993,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, int retval; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char index_value[STRING_BUFFER_USUAL_SIZE]; - char key_value[STRING_BUFFER_USUAL_SIZE]; - char test_value[STRING_BUFFER_USUAL_SIZE]; char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; String index_string(index_value, sizeof(index_value), @@ -2014,12 +2001,10 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, sizeof(sql_query_buffer), &my_charset_bin); key_range range; + DBUG_ENTER("ha_federated::index_read_idx"); index_string.length(0); sql_query.length(0); - - DBUG_ENTER("ha_federated::index_read_idx"); - statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); @@ -2086,7 +2071,6 @@ error: /* Initialized at each key walk (called multiple times unlike rnd_init()) */ int ha_federated::index_init(uint keynr) { - int error; DBUG_ENTER("ha_federated::index_init"); DBUG_PRINT("info", ("table: '%s' key: %d", table->s->table_name, keynr)); @@ -2109,8 +2093,8 @@ int ha_federated::read_range_first(const key_range *start_key, String sql_query(sql_query_buffer, sizeof(sql_query_buffer), &my_charset_bin); - DBUG_ENTER("ha_federated::read_range_first"); + if (start_key == NULL && end_key == NULL) DBUG_RETURN(0); @@ -2193,10 +2177,6 @@ int ha_federated::index_next(byte *buf) int ha_federated::rnd_init(bool scan) { - int num_fields, rows; - int retval; - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - DBUG_ENTER("ha_federated::rnd_init"); /* The use of the 'scan' flag is incredibly important for this handler @@ -2256,13 +2236,7 @@ int ha_federated::rnd_init(bool scan) DBUG_RETURN(0); error: - retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE; - my_sprintf(error_buffer, (error_buffer, ": %d : %s", - mysql_errno(mysql), mysql_error(mysql))); - my_error(retval, MYF(0), error_buffer); - DBUG_PRINT("info", - ("return error code %d", retval)); - DBUG_RETURN(retval); + DBUG_RETURN(stash_remote_error()); } int ha_federated::rnd_end() @@ -2435,7 +2409,6 @@ void ha_federated::info(uint flag) MYSQL_RES *result= 0; MYSQL_ROW row; String status_query_string(status_buf, sizeof(status_buf), &my_charset_bin); - DBUG_ENTER("ha_federated::info"); error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; @@ -2493,7 +2466,6 @@ void ha_federated::info(uint flag) } if (flag & HA_STATUS_CONST) { - TABLE_SHARE *share= table->s; block_size= 4096; } } @@ -2527,10 +2499,10 @@ error: int ha_federated::delete_all_rows() { - DBUG_ENTER("ha_federated::delete_all_rows"); - char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; String query(query_buffer, sizeof(query_buffer), &my_charset_bin); + DBUG_ENTER("ha_federated::delete_all_rows"); + query.length(0); query.set_charset(system_charset_info); @@ -2542,16 +2514,12 @@ int ha_federated::delete_all_rows() /* TRUNCATE won't return anything in mysql_affected_rows */ - deleted+= records; if (mysql_real_query(mysql, query.ptr(), query.length())) { - int error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; - char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - my_sprintf(error_buffer, (error_buffer, ": %d : %s", - mysql_errno(mysql), mysql_error(mysql))); - my_error(error_code, MYF(0), error_buffer); - DBUG_RETURN(error_code); + DBUG_RETURN(stash_remote_error()); } + deleted+= records; + records= 0; DBUG_RETURN(0); } @@ -2630,33 +2598,45 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd, int ha_federated::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info) { - int retval= 0; - /* - only a temporary share, to test the url - */ - FEDERATED_SHARE tmp_share; + int retval; + FEDERATED_SHARE tmp_share; // Only a temporary share, to test the url DBUG_ENTER("ha_federated::create"); - if ((retval= parse_url(&tmp_share, table_arg, 1))) - goto error; - - if ((retval= check_foreign_data_source(&tmp_share, 1))) - goto error; + if (!(retval= parse_url(&tmp_share, table_arg, 1))) + retval= check_foreign_data_source(&tmp_share, 1); - if (tmp_share.scheme) - { - my_free((gptr) tmp_share.scheme, MYF(0)); - tmp_share.scheme= 0; - } + my_free((gptr) tmp_share.scheme, MYF(MY_ALLOW_ZERO_PTR)); DBUG_RETURN(retval); -error: - if (tmp_share.scheme) +} + + +int ha_federated::stash_remote_error() +{ + DBUG_ENTER("ha_federated::stash_remote_error()"); + remote_error_number= mysql_errno(mysql); + my_snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE, + mysql_error(mysql)); + DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM); +} + + +bool ha_federated::get_error_message(int error, String* buf) +{ + DBUG_ENTER("ha_federated::get_error_message"); + DBUG_PRINT("enter", ("error: %d", error)); + if (error == HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM) { - my_free((gptr) tmp_share.scheme, MYF(0)); - tmp_share.scheme= 0; - } - DBUG_RETURN(retval); + buf->append("Error on remote system: "); + buf->qs_append(remote_error_number); + buf->append(": "); + buf->append(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE); + remote_error_number= 0; + remote_error_buf[0]= '\0'; + } + DBUG_PRINT("exit", ("message: %s", buf->ptr())); + DBUG_RETURN(FALSE); } + #endif /* HAVE_FEDERATED_DB */ diff --git a/sql/ha_federated.h b/sql/ha_federated.h index 58b78ab0dde..b25071dda16 100644 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -27,6 +27,14 @@ #include <mysql.h> +/* + handler::print_error has a case statement for error numbers. + This value is (10000) is far out of range and will envoke the + default: case. + (Current error range is 120-159 from include/my_base.h) +*/ +#define HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM 10000 + #define FEDERATED_QUERY_BUFFER_SIZE STRING_BUFFER_USUAL_SIZE * 5 #define FEDERATED_RECORDS_IN_RANGE 2 @@ -149,6 +157,8 @@ class ha_federated: public handler uint ref_length; uint fetch_num; // stores the fetch num MYSQL_ROW_OFFSET current_position; // Current position used by ::position() + int remote_error_number; + char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE]; private: /* @@ -160,6 +170,7 @@ private: const key_range *start_key, const key_range *end_key, bool records_in_range); + int stash_remote_error(); public: ha_federated(TABLE *table_arg); @@ -282,9 +293,11 @@ public: HA_CREATE_INFO *create_info); //required ha_rows records_in_range(uint inx, key_range *start_key, key_range *end_key); + uint8 table_cache_type() { return HA_CACHE_TBL_NOCACHE; } THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); //required + virtual bool get_error_message(int error, String *buf); }; bool federated_db_init(void); diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 94ee3f8e656..98cc96db707 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -23,8 +23,12 @@ #include <myisampack.h> #include "ha_heap.h" -static handlerton heap_hton= { +handlerton heap_hton= { "MEMORY", + SHOW_OPTION_YES, + "Hash based, stored in memory, useful for temporary tables", + DB_TYPE_HEAP, + NULL, 0, /* slot */ 0, /* savepoint size. */ NULL, /* close_connection */ @@ -40,7 +44,7 @@ static handlerton heap_hton= { NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS + HTON_CAN_RECREATE }; /***************************************************************************** diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 404ac95b81a..a7957ee3cbf 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -206,8 +206,12 @@ static int innobase_rollback_to_savepoint(THD* thd, void *savepoint); static int innobase_savepoint(THD* thd, void *savepoint); static int innobase_release_savepoint(THD* thd, void *savepoint); -static handlerton innobase_hton = { +handlerton innobase_hton = { "InnoDB", + SHOW_OPTION_YES, + "Supports transactions, row-level locking, and foreign keys", + DB_TYPE_INNODB, + innobase_init, 0, /* slot */ sizeof(trx_named_savept_t), /* savepoint size. TODO: use it */ innobase_close_connection, @@ -463,13 +467,9 @@ convert_error_code_to_mysql( } else if (error == (int) DB_LOCK_WAIT_TIMEOUT) { - /* Since we rolled back the whole transaction, we must - tell it also to MySQL so that MySQL knows to empty the - cached binlog for this transaction */ - - if (thd) { - ha_rollback(thd); - } + /* Starting from 5.0.13, we let MySQL just roll back the + latest SQL statement in a lock wait timeout. Previously, we + rolled back the whole transaction. */ return(HA_ERR_LOCK_WAIT_TIMEOUT); @@ -567,25 +567,29 @@ innobase_mysql_print_thd( use the default max length */ { const THD* thd; + const Security_context *sctx; const char* s; thd = (const THD*) input_thd; + /* We probably want to have original user as part of debug output. */ + sctx = &thd->main_security_ctx; + fprintf(f, "MySQL thread id %lu, query id %lu", thd->thread_id, (ulong) thd->query_id); - if (thd->host) { + if (sctx->host) { putc(' ', f); - fputs(thd->host, f); + fputs(sctx->host, f); } - if (thd->ip) { + if (sctx->ip) { putc(' ', f); - fputs(thd->ip, f); + fputs(sctx->ip, f); } - if (thd->user) { + if (sctx->user) { putc(' ', f); - fputs(thd->user, f); + fputs(sctx->user, f); } if ((s = thd->proc_info)) { @@ -1188,10 +1192,10 @@ ha_innobase::init_table_handle_for_HANDLER(void) /************************************************************************* Opens an InnoDB database. */ -handlerton* +bool innobase_init(void) /*===============*/ - /* out: TRUE if error */ + /* out: &innobase_hton, or NULL on error */ { static char current_dir[3]; /* Set if using current lib */ int err; @@ -1200,6 +1204,9 @@ innobase_init(void) DBUG_ENTER("innobase_init"); + if (have_innodb != SHOW_OPTION_YES) + goto error; + ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); os_innodb_umask = (ulint)my_umask; @@ -1252,7 +1259,7 @@ innobase_init(void) copy of it: */ internal_innobase_data_file_path = my_strdup(innobase_data_file_path, - MYF(MY_WME)); + MYF(MY_FAE)); ret = (bool) srv_parse_data_file_paths_and_sizes( internal_innobase_data_file_path, @@ -1267,7 +1274,7 @@ innobase_init(void) "InnoDB: syntax error in innodb_data_file_path"); my_free(internal_innobase_data_file_path, MYF(MY_ALLOW_ZERO_PTR)); - DBUG_RETURN(0); + goto error; } /* -------------- Log files ---------------------------*/ @@ -1298,7 +1305,7 @@ innobase_init(void) my_free(internal_innobase_data_file_path, MYF(MY_ALLOW_ZERO_PTR)); - DBUG_RETURN(0); + goto error; } /* --------------------------------------------------*/ @@ -1386,7 +1393,7 @@ innobase_init(void) if (err != DB_SUCCESS) { my_free(internal_innobase_data_file_path, MYF(MY_ALLOW_ZERO_PTR)); - DBUG_RETURN(0); + goto error; } (void) hash_init(&innobase_open_tables,system_charset_info, 32, 0, 0, @@ -1413,7 +1420,10 @@ innobase_init(void) glob_mi.pos = trx_sys_mysql_master_log_pos; } */ - DBUG_RETURN(&innobase_hton); + DBUG_RETURN(FALSE); +error: + have_innodb= SHOW_OPTION_DISABLED; // If we couldn't use handler + DBUG_RETURN(TRUE); } /*********************************************************************** @@ -2116,7 +2126,7 @@ innobase_rollback_to_savepoint( /* TODO: use provided savepoint data area to store savepoint data */ - longlong2str((ulonglong)savepoint, name, 36); + longlong2str((ulint)savepoint, name, 36); error = (int) trx_rollback_to_savepoint_for_mysql(trx, name, &mysql_binlog_cache_pos); @@ -2145,7 +2155,7 @@ innobase_release_savepoint( /* TODO: use provided savepoint data area to store savepoint data */ - longlong2str((ulonglong)savepoint, name, 36); + longlong2str((ulint)savepoint, name, 36); error = (int) trx_release_savepoint_for_mysql(trx, name); @@ -2186,7 +2196,7 @@ innobase_savepoint( /* TODO: use provided savepoint data area to store savepoint data */ char name[64]; - longlong2str((ulonglong)savepoint,name,36); + longlong2str((ulint)savepoint,name,36); error = (int) trx_savepoint_for_mysql(trx, name, (ib_longlong)0); @@ -2386,7 +2396,7 @@ ha_innobase::open( "how you can resolve the problem.\n", norm_name); free_share(share); - my_free((char*) upd_buff, MYF(0)); + my_free((gptr) upd_buff, MYF(0)); my_errno = ENOENT; DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); @@ -2404,7 +2414,7 @@ ha_innobase::open( "how you can resolve the problem.\n", norm_name); free_share(share); - my_free((char*) upd_buff, MYF(0)); + my_free((gptr) upd_buff, MYF(0)); my_errno = ENOENT; dict_table_decrement_handle_count(ib_table); @@ -2492,13 +2502,13 @@ Closes a handle to an InnoDB table. */ int ha_innobase::close(void) /*====================*/ - /* out: error number */ + /* out: 0 */ { DBUG_ENTER("ha_innobase::close"); row_prebuilt_free((row_prebuilt_t*) innobase_prebuilt); - my_free((char*) upd_buff, MYF(0)); + my_free((gptr) upd_buff, MYF(0)); free_share(share); /* Tell InnoDB server that there might be work for @@ -2862,6 +2872,9 @@ ha_innobase::store_key_val_for_row( ulint lenlen; ulint len; byte* data; + ulint key_len; + CHARSET_INFO* cs; + int error=0; if (is_null) { buff += key_part->length + 2; @@ -2880,8 +2893,20 @@ ha_innobase::store_key_val_for_row( /* In a column prefix index, we may need to truncate the stored value: */ - if (len > key_part->length) { - len = key_part->length; + cs = key_part->field->charset(); + + if (cs->mbmaxlen > 1 && key_part->length > 0) { + key_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) data, + (const char *) data + key_part->length, + key_part->length / cs->mbmaxlen, + &error); + } else { + key_len = key_part->length; + } + + if (len > key_len) { + len = key_len; } /* The length in a key value is always stored in 2 @@ -2905,6 +2930,11 @@ ha_innobase::store_key_val_for_row( || mysql_type == FIELD_TYPE_BLOB || mysql_type == FIELD_TYPE_LONG_BLOB) { + CHARSET_INFO* cs; + ulint key_len; + ulint len; + int error=0; + ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); if (is_null) { @@ -2925,8 +2955,21 @@ ha_innobase::store_key_val_for_row( indexes, and we may need to truncate the data to be stored in the key value: */ - if (blob_len > key_part->length) { - blob_len = key_part->length; + cs = key_part->field->charset(); + + if (cs->mbmaxlen > 1 && key_part->length > 0) { + key_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) blob_data, + (const char *) blob_data + + key_part->length, + key_part->length / cs->mbmaxlen, + &error); + } else { + key_len = key_part->length; + } + + if (blob_len > key_len) { + blob_len = key_len; } /* MySQL reserves 2 bytes for the length and the @@ -2948,15 +2991,40 @@ ha_innobase::store_key_val_for_row( value we store may be also in a column prefix index. */ + CHARSET_INFO* cs; + ulint len; + const mysql_byte* src_start; + int error=0; + if (is_null) { buff += key_part->length; continue; } - memcpy(buff, record + key_part->offset, - key_part->length); - buff += key_part->length; + cs = key_part->field->charset(); + src_start = record + key_part->offset; + + if (key_part->length > 0 && cs->mbmaxlen > 1) { + len = (ulint) cs->cset->well_formed_len(cs, + src_start, + src_start + key_part->length, + key_part->length / cs->mbmaxlen, + &error); + } else { + len = key_part->length; + } + + memcpy(buff, src_start, len); + buff+=len; + + /* Pad the unused space with spaces */ + + if (len < key_part->length) { + len = key_part->length - len; + memset(buff, ' ', len); + buff+=len; + } } } @@ -4492,7 +4560,8 @@ create_index( ulint is_unsigned; ulint i; ulint j; - + ulint* field_lengths; + DBUG_ENTER("create_index"); key = form->key_info + key_num; @@ -4514,6 +4583,10 @@ create_index( index = dict_mem_index_create((char*) table_name, key->name, 0, ind_type, n_fields); + + field_lengths = (ulint*) my_malloc(sizeof(ulint) * n_fields, + MYF(MY_FAE)); + for (i = 0; i < n_fields; i++) { key_part = key->key_part + i; @@ -4568,6 +4641,8 @@ create_index( prefix_len = 0; } + field_lengths[i] = key_part->length; + /* We assume all fields should be sorted in ascending order, hence the '0': */ @@ -4576,10 +4651,12 @@ create_index( 0, prefix_len); } - error = row_create_index_for_mysql(index, trx); + error = row_create_index_for_mysql(index, trx, field_lengths); error = convert_error_code_to_mysql(error, NULL); + my_free((gptr) field_lengths, MYF(0)); + DBUG_RETURN(error); } @@ -4602,7 +4679,7 @@ create_clustered_index_when_no_primary( index = dict_mem_index_create((char*) table_name, (char*) "GEN_CLUST_INDEX", 0, DICT_CLUSTERED, 0); - error = row_create_index_for_mysql(index, trx); + error = row_create_index_for_mysql(index, trx, NULL); error = convert_error_code_to_mysql(error, NULL); @@ -4691,13 +4768,7 @@ ha_innobase::create( form->s->row_type != ROW_TYPE_REDUNDANT); if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } /* Look for a primary key */ @@ -4721,13 +4792,7 @@ ha_innobase::create( error = create_clustered_index_when_no_primary(trx, norm_name); if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } @@ -4736,13 +4801,7 @@ ha_innobase::create( first */ if ((error = create_index(trx, form, norm_name, (uint) primary_key_no))) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } @@ -4751,14 +4810,7 @@ ha_innobase::create( if (i != (uint) primary_key_no) { if ((error = create_index(trx, form, norm_name, i))) { - - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } } @@ -4771,21 +4823,18 @@ ha_innobase::create( current_thd->query_length, current_thd->charset())) { error = HA_ERR_OUT_OF_MEM; - } else { - error = row_table_add_foreign_constraints(trx, - q.str, norm_name); - - error = convert_error_code_to_mysql(error, NULL); + + goto cleanup; } - if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); + error = row_table_add_foreign_constraints(trx, + q.str, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE); - trx_free_for_mysql(trx); + error = convert_error_code_to_mysql(error, NULL); - DBUG_RETURN(error); + if (error) { + goto cleanup; } } @@ -4825,6 +4874,15 @@ ha_innobase::create( trx_free_for_mysql(trx); DBUG_RETURN(0); + +cleanup: + innobase_commit_low(trx); + + row_mysql_unlock_data_dictionary(trx); + + trx_free_for_mysql(trx); + + DBUG_RETURN(error); } /********************************************************************* @@ -5157,7 +5215,7 @@ ha_innobase::records_in_range( mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc( table->s->reclength + table->s->max_key_length + 100, - MYF(MY_WME)); + MYF(MY_FAE)); ulint buff2_len = table->s->reclength + table->s->max_key_length + 100; dtuple_t* range_start; @@ -5216,7 +5274,7 @@ ha_innobase::records_in_range( dtuple_free_for_mysql(heap1); dtuple_free_for_mysql(heap2); - my_free((char*) key_val_buff2, MYF(0)); + my_free((gptr) key_val_buff2, MYF(0)); prebuilt->trx->op_info = (char*)""; @@ -5537,6 +5595,33 @@ ha_innobase::info( trx_get_error_info(prebuilt->trx)); } + if (flag & HA_STATUS_AUTO && table->found_next_number_field) { + longlong auto_inc; + int ret; + + /* The following function call can the first time fail in + a lock wait timeout error because it reserves the auto-inc + lock on the table. If it fails, then someone is already initing + the auto-inc counter, and the second call is guaranteed to + succeed. */ + + ret = innobase_read_and_init_auto_inc(&auto_inc); + + if (ret != 0) { + ret = innobase_read_and_init_auto_inc(&auto_inc); + + if (ret != 0) { + ut_print_timestamp(stderr); + sql_print_error("Cannot get table %s auto-inc" + "counter value in ::info\n", + ib_table->name); + auto_inc = 0; + } + } + + auto_increment_value = auto_inc; + } + prebuilt->trx->op_info = (char*)""; DBUG_VOID_RETURN; @@ -5743,7 +5828,8 @@ ha_innobase::get_foreign_key_create_info(void) fclose(file); } else { /* unable to create temporary file */ - str = my_malloc(1, MYF(MY_ZEROFILL)); + str = my_strdup( +"/* Error: cannot display foreign key constraints */", MYF(0)); } return(str); @@ -5983,7 +6069,8 @@ int ha_innobase::start_stmt( /*====================*/ /* out: 0 or error code */ - THD* thd) /* in: handle to the user thread */ + THD* thd, /* in: handle to the user thread */ + thr_lock_type lock_type) { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; trx_t* trx; @@ -6024,7 +6111,7 @@ ha_innobase::start_stmt( } else { if (trx->isolation_level != TRX_ISO_SERIALIZABLE && thd->lex->sql_command == SQLCOM_SELECT - && thd->lex->lock_option == TL_READ) { + && lock_type == TL_READ) { /* For other than temporary tables, we obtain no lock for consistent read (plain SELECT). */ @@ -6057,6 +6144,8 @@ ha_innobase::start_stmt( } } + trx->detailed_error[0] = '\0'; + /* Set the MySQL flag to mark that there is an active transaction */ if (trx->active_trans == 0) { @@ -6130,6 +6219,8 @@ ha_innobase::external_lock( if (lock_type != F_UNLCK) { /* MySQL is setting a new table lock */ + trx->detailed_error[0] = '\0'; + /* Set the MySQL flag to mark that there is an active transaction */ if (trx->active_trans == 0) { @@ -6667,6 +6758,11 @@ ha_innobase::store_lock( prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = LOCK_NONE; + } else if (thd->lex->sql_command == SQLCOM_CHECKSUM) { + /* Use consistent read for checksum table */ + + prebuilt->select_lock_type = LOCK_NONE; + prebuilt->stored_select_lock_type = LOCK_NONE; } else { prebuilt->select_lock_type = LOCK_S; prebuilt->stored_select_lock_type = LOCK_S; @@ -6845,8 +6941,13 @@ ha_innobase::innobase_read_and_init_auto_inc( goto func_exit; } } else { - /* Initialize to max(col) + 1 */ - auto_inc = (longlong) table->next_number_field-> + /* Initialize to max(col) + 1; we use + 'found_next_number_field' below because MySQL in SHOW TABLE + STATUS does not seem to set 'next_number_field'. The comment + in table.h says that 'next_number_field' is set when it is + 'active'. */ + + auto_inc = (longlong) table->found_next_number_field-> val_int_offset(table->s->rec_buff_length) + 1; } @@ -6861,9 +6962,11 @@ func_exit: func_exit_early: /* Since MySQL does not seem to call autocommit after SHOW TABLE - STATUS (even if we would register the trx here), we must commit our + STATUS (even if we would register the trx here), we commit our transaction here if it was started here. This is to eliminate a - dangling transaction. */ + dangling transaction. If the user had AUTOCOMMIT=0, then SHOW + TABLE STATUS does leave a dangling transaction if the user does not + himself call COMMIT. */ if (trx_was_not_started) { @@ -6926,6 +7029,18 @@ ha_innobase::reset_auto_increment(ulonglong value) DBUG_RETURN(0); } +/* See comment in handler.cc */ +bool +ha_innobase::get_error_message(int error, String *buf) +{ + trx_t* trx = check_trx_exists(current_thd); + + buf->copy(trx->detailed_error, strlen(trx->detailed_error), + system_charset_info); + + return FALSE; +} + /*********************************************************************** Compares two 'refs'. A 'ref' is the (internal) primary key value of the row. If there is no explicitly declared non-null unique key or a primary key, then @@ -6985,8 +7100,7 @@ ha_innobase::cmp_ref( (const char*)ref1, len1, (const char*)ref2, len2); } else { - result = field->cmp((const char*)ref1, - (const char*)ref2); + result = field->key_cmp(ref1, ref2); } if (result) { diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 672e48d9817..78cd0f927e9 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -150,7 +150,7 @@ class ha_innobase: public handler int extra(enum ha_extra_function operation); int external_lock(THD *thd, int lock_type); int transactional_table_lock(THD *thd, int lock_type); - int start_stmt(THD *thd); + int start_stmt(THD *thd, thr_lock_type lock_type); void position(byte *record); ha_rows records_in_range(uint inx, key_range *min_key, key_range @@ -174,6 +174,8 @@ class ha_innobase: public handler void init_table_handle_for_HANDLER(); ulonglong get_auto_increment(); int reset_auto_increment(ulonglong value); + + virtual bool get_error_message(int error, String *buf); uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; } /* @@ -239,7 +241,7 @@ extern ulong srv_commit_concurrency; extern TYPELIB innobase_lock_typelib; -handlerton *innobase_init(void); +bool innobase_init(void); bool innobase_end(void); bool innobase_flush_logs(void); uint innobase_get_free_space(void); @@ -344,4 +346,4 @@ restored to a transaction read view. */ void innobase_set_cursor_view( /*=====================*/ - void* curview); /* in: Consistent read view to be closed */ + void* curview); /* in: Consistent read view to be set */ diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 8f3970d69e6..70137ff2b16 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -39,6 +39,12 @@ const char *myisam_recover_names[] = TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", myisam_recover_names, NULL}; +const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal", + NullS}; +TYPELIB myisam_stats_method_typelib= { + array_elements(myisam_stats_method_names) - 1, "", + myisam_stats_method_names, NULL}; + /***************************************************************************** ** MyISAM tables @@ -46,8 +52,12 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", /* MyISAM handlerton */ -static handlerton myisam_hton= { +handlerton myisam_hton= { "MyISAM", + SHOW_OPTION_YES, + "Default engine as of MySQL 3.23 with great performance", + DB_TYPE_MYISAM, + NULL, 0, /* slot */ 0, /* savepoint size. */ NULL, /* close_connection */ @@ -67,7 +77,7 @@ static handlerton myisam_hton= { MyISAM doesn't support transactions and doesn't have transaction-dependent context: cursors can survive a commit. */ - HTON_NO_FLAGS + HTON_CAN_RECREATE }; // collect errors printed by mi_check routines @@ -324,6 +334,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) param.db_name= table->s->db; param.table_name= table->alias; param.testflag = check_opt->flags | T_CHECK | T_SILENT; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; if (!(table->db_stat & HA_READ_ONLY)) param.testflag|= T_STATISTICS; @@ -413,6 +424,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt) param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS | T_DONT_CHECK_CHECKSUM); param.using_global_keycache = 1; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; if (!(share->state.changed & STATE_NOT_ANALYZED)) return HA_ADMIN_ALREADY_DONE; @@ -967,6 +979,7 @@ int ha_myisam::enable_indexes(uint mode) T_CREATE_MISSING_KEYS); param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; param.tmpdir=&mysql_tmpdir_list; if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair) { @@ -1694,6 +1707,6 @@ int ha_myisam::ft_read(byte * buf) uint ha_myisam::checksum() const { - return (uint)file->s->state.checksum; + return (uint)file->state->checksum; } diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index f92717e11eb..5911d6c0fbc 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -34,8 +34,12 @@ /* MyISAM MERGE handlerton */ -static handlerton myisammrg_hton= { - "MRG_MyISAM", +handlerton myisammrg_hton= { + "MRG_MYISAM", + SHOW_OPTION_YES, + "Collection of identical MyISAM tables", + DB_TYPE_MRG_MYISAM, + NULL, 0, /* slot */ 0, /* savepoint size. */ NULL, /* close_connection */ @@ -51,7 +55,7 @@ static handlerton myisammrg_hton= { NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS + HTON_CAN_RECREATE }; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 5353daf95e6..a0efcd2c4f9 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -49,8 +49,12 @@ static int ndbcluster_close_connection(THD *thd); static int ndbcluster_commit(THD *thd, bool all); static int ndbcluster_rollback(THD *thd, bool all); -static handlerton ndbcluster_hton = { +handlerton ndbcluster_hton = { "ndbcluster", + SHOW_OPTION_YES, + "Clustered, fault-tolerant, memory-based tables", + DB_TYPE_NDBCLUSTER, + ndbcluster_init, 0, /* slot */ 0, /* savepoint size */ ndbcluster_close_connection, @@ -117,7 +121,7 @@ static int ndb_get_table_statistics(Ndb*, const char *, static pthread_t ndb_util_thread; pthread_mutex_t LOCK_ndb_util_thread; pthread_cond_t COND_ndb_util_thread; -extern "C" pthread_handler_decl(ndb_util_thread_func, arg); +pthread_handler_t ndb_util_thread_func(void *arg); ulong ndb_cache_check_time; /* @@ -1209,12 +1213,13 @@ inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part, DBUG_ENTER("ha_ndbcluster::index_flags"); DBUG_PRINT("info", ("idx_no: %d", idx_no)); DBUG_ASSERT(get_index_type_from_table(idx_no) < index_flags_size); - DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)]); + DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)] | + HA_KEY_SCAN_NOT_ROR); } static void shrink_varchar(Field* field, const byte* & ptr, char* buf) { - if (field->type() == MYSQL_TYPE_VARCHAR) { + if (field->type() == MYSQL_TYPE_VARCHAR && ptr != NULL) { Field_varstring* f= (Field_varstring*)field; if (f->length_bytes == 1) { uint pack_len= field->pack_length(); @@ -2332,7 +2337,8 @@ void ha_ndbcluster::unpack_record(byte* buf) DBUG_PRINT("info", ("bit field H'%.8X", (*value).rec->u_32_value())); ((Field_bit *) *field)->store((longlong) - (*value).rec->u_32_value()); + (*value).rec->u_32_value(), + FALSE); } else { @@ -2340,7 +2346,8 @@ void ha_ndbcluster::unpack_record(byte* buf) *(Uint32 *)(*value).rec->aRef(), *((Uint32 *)(*value).rec->aRef()+1))); ((Field_bit *) *field)->store((longlong) - (*value).rec->u_64_value()); } + (*value).rec->u_64_value(), TRUE); + } } } else @@ -3217,7 +3224,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) if (!thd_ndb->lock_count++) { PRINT_OPTION_FLAGS(thd); - if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK))) + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { // Autocommit transaction DBUG_ASSERT(!thd_ndb->stmt); @@ -3391,31 +3398,24 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) } /* - When using LOCK TABLE's external_lock is only called when the actual - TABLE LOCK is done. - Under LOCK TABLES, each used tables will force a call to start_stmt. - Ndb doesn't currently support table locks, and will do ordinary - startTransaction for each transaction/statement. + Start a transaction for running a statement if one is not + already running in a transaction. This will be the case in + a BEGIN; COMMIT; block + When using LOCK TABLE's external_lock will start a transaction + since ndb does not currently does not support table locking */ -int ha_ndbcluster::start_stmt(THD *thd) +int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) { int error=0; DBUG_ENTER("start_stmt"); PRINT_OPTION_FLAGS(thd); Thd_ndb *thd_ndb= get_thd_ndb(thd); - NdbTransaction *trans= thd_ndb->stmt; + NdbTransaction *trans= (thd_ndb->stmt)?thd_ndb->stmt:thd_ndb->all; if (!trans){ Ndb *ndb= thd_ndb->ndb; DBUG_PRINT("trans",("Starting transaction stmt")); - -#if 0 - NdbTransaction *tablock_trans= thd_ndb->all; - DBUG_PRINT("info", ("tablock_trans: %x", (UintPtr)tablock_trans)); - DBUG_ASSERT(tablock_trans); -// trans= ndb->hupp(tablock_trans); -#endif trans= ndb->startTransaction(); if (trans == NULL) ERR_RETURN(ndb->getNdbError()); @@ -4180,7 +4180,12 @@ ulonglong ha_ndbcluster::get_auto_increment() --retries && ndb->getNdbError().status == NdbError::TemporaryError); if (auto_value == NDB_FAILED_AUTO_INCREMENT) - ERR_RETURN(ndb->getNdbError()); + { + const NdbError err= ndb->getNdbError(); + sql_print_error("Error %lu in ::get_auto_increment(): %s", + (ulong) err.code, err.message); + DBUG_RETURN(~(ulonglong) 0); + } DBUG_RETURN((longlong)auto_value); } @@ -4732,11 +4737,14 @@ static int connect_callback() return 0; } -handlerton * -ndbcluster_init() +bool ndbcluster_init() { int res; DBUG_ENTER("ndbcluster_init"); + + if (have_ndbcluster != SHOW_OPTION_YES) + goto ndbcluster_init_error; + // Set connectstring if specified if (opt_ndbcluster_connectstring != 0) DBUG_PRINT("connectstring", ("%s", opt_ndbcluster_connectstring)); @@ -4817,16 +4825,17 @@ ndbcluster_init() } ndbcluster_inited= 1; - DBUG_RETURN(&ndbcluster_hton); + DBUG_RETURN(FALSE); - ndbcluster_init_error: +ndbcluster_init_error: if (g_ndb) delete g_ndb; g_ndb= NULL; if (g_ndb_cluster_connection) delete g_ndb_cluster_connection; g_ndb_cluster_connection= NULL; - DBUG_RETURN(NULL); + have_ndbcluster= SHOW_OPTION_DISABLED; // If we couldn't use handler + DBUG_RETURN(TRUE); } @@ -5915,12 +5924,10 @@ ha_ndbcluster::update_table_comment( // Utility thread main loop -extern "C" pthread_handler_decl(ndb_util_thread_func, - arg __attribute__((unused))) +pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) { THD *thd; /* needs to be first for thread_stack */ Ndb* ndb; - int error= 0; struct timespec abstime; my_thread_init(); @@ -5949,9 +5956,9 @@ extern "C" pthread_handler_decl(ndb_util_thread_func, { pthread_mutex_lock(&LOCK_ndb_util_thread); - error= pthread_cond_timedwait(&COND_ndb_util_thread, - &LOCK_ndb_util_thread, - &abstime); + pthread_cond_timedwait(&COND_ndb_util_thread, + &LOCK_ndb_util_thread, + &abstime); pthread_mutex_unlock(&LOCK_ndb_util_thread); DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %d", @@ -6618,13 +6625,24 @@ void ndb_serialize_cond(const Item *item, void *arg) case Item_func::BETWEEN: { DBUG_PRINT("info", ("BETWEEN, rewriting using AND")); + Item_func_between *between_func= (Item_func_between *) func_item; Ndb_rewrite_context *rewrite_context= new Ndb_rewrite_context(func_item); rewrite_context->next= context->rewrite_stack; context->rewrite_stack= rewrite_context; + if (between_func->negated) + { + DBUG_PRINT("info", ("NOT_FUNC")); + curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1); + prev_cond= curr_cond; + curr_cond= context->cond_ptr= new Ndb_cond(); + curr_cond->prev= prev_cond; + prev_cond->next= curr_cond; + } DBUG_PRINT("info", ("COND_AND_FUNC")); - curr_cond->ndb_item= new Ndb_item(Item_func::COND_AND_FUNC, - func_item->argument_count() - 1); + curr_cond->ndb_item= + new Ndb_item(Item_func::COND_AND_FUNC, + func_item->argument_count() - 1); context->expect_only(Item::FIELD_ITEM); context->expect(Item::INT_ITEM); context->expect(Item::STRING_ITEM); @@ -6635,10 +6653,20 @@ void ndb_serialize_cond(const Item *item, void *arg) case Item_func::IN_FUNC: { DBUG_PRINT("info", ("IN_FUNC, rewriting using OR")); + Item_func_in *in_func= (Item_func_in *) func_item; Ndb_rewrite_context *rewrite_context= new Ndb_rewrite_context(func_item); rewrite_context->next= context->rewrite_stack; context->rewrite_stack= rewrite_context; + if (in_func->negated) + { + DBUG_PRINT("info", ("NOT_FUNC")); + curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1); + prev_cond= curr_cond; + curr_cond= context->cond_ptr= new Ndb_cond(); + curr_cond->prev= prev_cond; + prev_cond->next= curr_cond; + } DBUG_PRINT("info", ("COND_OR_FUNC")); curr_cond->ndb_item= new Ndb_item(Item_func::COND_OR_FUNC, func_item->argument_count() - 1); @@ -6960,6 +6988,7 @@ void ndb_serialize_cond(const Item *item, void *arg) DBUG_PRINT("info", ("End of condition group")); prev_cond= curr_cond; curr_cond= context->cond_ptr= new Ndb_cond(); + curr_cond->prev= prev_cond; prev_cond->next= curr_cond; curr_cond->ndb_item= new Ndb_item(NDB_END_COND); // Pop rewrite stack @@ -7368,4 +7397,49 @@ ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack, DBUG_RETURN(0); } +int +ndbcluster_show_status(THD* thd) +{ + Protocol *protocol= thd->protocol; + + DBUG_ENTER("ndbcluster_show_status"); + + if (have_ndbcluster != SHOW_OPTION_YES) + { + my_message(ER_NOT_SUPPORTED_YET, + "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is defined", + MYF(0)); + DBUG_RETURN(TRUE); + } + + List<Item> field_list; + field_list.push_back(new Item_empty_string("free_list", 255)); + field_list.push_back(new Item_return_int("created", 10,MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("free", 10,MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("sizeof", 10,MYSQL_TYPE_LONG)); + + if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + DBUG_RETURN(TRUE); + + if (get_thd_ndb(thd) && get_thd_ndb(thd)->ndb) + { + Ndb* ndb= (get_thd_ndb(thd))->ndb; + Ndb::Free_list_usage tmp; tmp.m_name= 0; + while (ndb->get_free_list_usage(&tmp)) + { + protocol->prepare_for_resend(); + + protocol->store(tmp.m_name, &my_charset_bin); + protocol->store((uint)tmp.m_created); + protocol->store((uint)tmp.m_free); + protocol->store((uint)tmp.m_sizeof); + if (protocol->write()) + DBUG_RETURN(TRUE); + } + } + send_eof(thd); + + DBUG_RETURN(FALSE); +} + #endif /* HAVE_NDBCLUSTER_DB */ diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 034bb9292e8..466d7b7044b 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -501,7 +501,7 @@ class ha_ndbcluster: public handler int extra(enum ha_extra_function operation); int extra_opt(enum ha_extra_function operation, ulong cache_size); int external_lock(THD *thd, int lock_type); - int start_stmt(THD *thd); + int start_stmt(THD *thd, thr_lock_type lock_type); const char * table_type() const; const char ** bas_ext() const; ulong table_flags(void) const; @@ -716,7 +716,7 @@ private: extern struct show_var_st ndb_status_variables[]; -handlerton *ndbcluster_init(void); +bool ndbcluster_init(void); bool ndbcluster_end(void); int ndbcluster_discover(THD* thd, const char* dbname, const char* name, @@ -728,3 +728,5 @@ int ndbcluster_table_exists_in_engine(THD* thd, int ndbcluster_drop_database(const char* path); void ndbcluster_print_error(int error, const NdbOperation *error_op); + +int ndbcluster_show_status(THD*); diff --git a/sql/handler.cc b/sql/handler.cc index cf1fbfec465..81e94af5dc7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -25,39 +25,107 @@ #include "ha_heap.h" #include "ha_myisam.h" #include "ha_myisammrg.h" + + +/* + We have dummy hanldertons in case the handler has not been compiled + in. This will be removed in 5.1. +*/ #ifdef HAVE_BERKELEY_DB #include "ha_berkeley.h" +extern handlerton berkeley_hton; +#else +handlerton berkeley_hton = { "BerkeleyDB", SHOW_OPTION_NO, + "Supports transactions and page-level locking", DB_TYPE_BERKELEY_DB, NULL, + 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, HTON_NO_FLAGS }; #endif #ifdef HAVE_BLACKHOLE_DB #include "ha_blackhole.h" +extern handlerton blackhole_hton; +#else +handlerton blackhole_hton = { "BLACKHOLE", SHOW_OPTION_NO, + "/dev/null storage engine (anything you write to it disappears)", + DB_TYPE_BLACKHOLE_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + HTON_NO_FLAGS }; #endif #ifdef HAVE_EXAMPLE_DB #include "examples/ha_example.h" +extern handlerton example_hton; +#else +handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO, + "Example storage engine", + DB_TYPE_EXAMPLE_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + HTON_NO_FLAGS }; #endif #ifdef HAVE_ARCHIVE_DB -#include "examples/ha_archive.h" +#include "ha_archive.h" +extern handlerton archive_hton; +#else +handlerton archive_hton = { "ARCHIVE", SHOW_OPTION_NO, + "Archive storage engine", DB_TYPE_ARCHIVE_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + HTON_NO_FLAGS }; #endif #ifdef HAVE_CSV_DB #include "examples/ha_tina.h" +extern handlerton tina_hton; +#else +handlerton tina_hton = { "CSV", SHOW_OPTION_NO, "CSV storage engine", + DB_TYPE_CSV_DB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + HTON_NO_FLAGS }; #endif #ifdef HAVE_INNOBASE_DB #include "ha_innodb.h" +extern handlerton innobase_hton; +#else +handlerton innobase_hton = { "InnoDB", SHOW_OPTION_NO, + "Supports transactions, row-level locking, and foreign keys", + DB_TYPE_INNODB, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + HTON_NO_FLAGS }; #endif #ifdef HAVE_NDBCLUSTER_DB #include "ha_ndbcluster.h" +extern handlerton ndbcluster_hton; +#else +handlerton ndbcluster_hton = { "ndbcluster", SHOW_OPTION_NO, + "Clustered, fault-tolerant, memory-based tables", + DB_TYPE_NDBCLUSTER, NULL, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + HTON_NO_FLAGS }; #endif #ifdef HAVE_FEDERATED_DB #include "ha_federated.h" +extern handlerton federated_hton; +#else +handlerton federated_hton = { "FEDERATED", SHOW_OPTION_NO, + "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB, NULL, 0, 0, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + HTON_NO_FLAGS }; #endif #include <myisampack.h> #include <errno.h> - /* static functions defined in this file */ +extern handlerton myisam_hton; +extern handlerton myisammrg_hton; +extern handlerton heap_hton; +extern handlerton binlog_hton; + +/* + Obsolete +*/ +handlerton isam_hton = { "ISAM", SHOW_OPTION_NO, "Obsolete storage engine", + DB_TYPE_ISAM, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; -static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; -/* list of all available storage engines (of their handlertons) */ -handlerton *handlertons[MAX_HA]={0}; +/* static functions defined in this file */ + +static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; /* number of entries in handlertons[] */ ulong total_ha; @@ -66,46 +134,35 @@ ulong total_ha_2pc; /* size of savepoint storage area (see ha_init) */ ulong savepoint_alloc_size; -struct show_table_type_st sys_table_types[]= -{ - {"MyISAM", &have_yes, - "Default engine as of MySQL 3.23 with great performance", DB_TYPE_MYISAM}, - {"MEMORY", &have_yes, - "Hash based, stored in memory, useful for temporary tables", DB_TYPE_HEAP}, - {"HEAP", &have_yes, - "Alias for MEMORY", DB_TYPE_HEAP}, - {"MERGE", &have_yes, - "Collection of identical MyISAM tables", DB_TYPE_MRG_MYISAM}, - {"MRG_MYISAM",&have_yes, - "Alias for MERGE", DB_TYPE_MRG_MYISAM}, - {"ISAM", &have_isam, - "Obsolete storage engine, now replaced by MyISAM", DB_TYPE_ISAM}, - {"MRG_ISAM", &have_isam, - "Obsolete storage engine, now replaced by MERGE", DB_TYPE_MRG_ISAM}, - {"InnoDB", &have_innodb, - "Supports transactions, row-level locking, and foreign keys", DB_TYPE_INNODB}, - {"INNOBASE", &have_innodb, - "Alias for INNODB", DB_TYPE_INNODB}, - {"BDB", &have_berkeley_db, - "Supports transactions and page-level locking", DB_TYPE_BERKELEY_DB}, - {"BERKELEYDB",&have_berkeley_db, - "Alias for BDB", DB_TYPE_BERKELEY_DB}, - {"NDBCLUSTER", &have_ndbcluster, - "Clustered, fault-tolerant, memory-based tables", DB_TYPE_NDBCLUSTER}, - {"NDB", &have_ndbcluster, - "Alias for NDBCLUSTER", DB_TYPE_NDBCLUSTER}, - {"EXAMPLE",&have_example_db, - "Example storage engine", DB_TYPE_EXAMPLE_DB}, - {"ARCHIVE",&have_archive_db, - "Archive storage engine", DB_TYPE_ARCHIVE_DB}, - {"CSV",&have_csv_db, - "CSV storage engine", DB_TYPE_CSV_DB}, - {"FEDERATED",&have_federated_db, - "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB}, - {"BLACKHOLE",&have_blackhole_db, - "/dev/null storage engine (anything you write to it disappears)", - DB_TYPE_BLACKHOLE_DB}, - {NullS, NULL, NullS, DB_TYPE_UNKNOWN} +/* + This array is used for processing compiled in engines. +*/ +handlerton *sys_table_types[]= +{ + &myisam_hton, + &heap_hton, + &innobase_hton, + &berkeley_hton, + &blackhole_hton, + &example_hton, + &archive_hton, + &tina_hton, + &ndbcluster_hton, + &federated_hton, + &myisammrg_hton, + &binlog_hton, + &isam_hton, + NULL +}; + +struct show_table_alias_st sys_table_aliases[]= +{ + {"INNOBASE", "InnoDB"}, + {"NDB", "NDBCLUSTER"}, + {"BDB", "BERKELEYDB"}, + {"HEAP", "MEMORY"}, + {"MERGE", "MRG_MYISAM"}, + {NullS, NullS} }; const char *ha_row_type[] = { @@ -124,46 +181,81 @@ uint known_extensions_id= 0; enum db_type ha_resolve_by_name(const char *name, uint namelen) { THD *thd= current_thd; - if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) { + show_table_alias_st *table_alias; + handlerton **types; + + if (thd && !my_strnncoll(&my_charset_latin1, + (const uchar *)name, namelen, + (const uchar *)"DEFAULT", 7)) return (enum db_type) thd->variables.table_type; + +retest: + for (types= sys_table_types; *types; types++) + { + if (!my_strnncoll(&my_charset_latin1, + (const uchar *)name, namelen, + (const uchar *)(*types)->name, strlen((*types)->name))) + return (enum db_type) (*types)->db_type; } - show_table_type_st *types; - for (types= sys_table_types; types->type; types++) + /* + We check for the historical aliases. + */ + for (table_alias= sys_table_aliases; table_alias->type; table_alias++) { - if (!my_strcasecmp(&my_charset_latin1, name, types->type)) - return (enum db_type) types->db_type; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *)name, namelen, + (const uchar *)table_alias->alias, + strlen(table_alias->alias))) + { + name= table_alias->type; + namelen= strlen(name); + goto retest; + } } + return DB_TYPE_UNKNOWN; } + const char *ha_get_storage_engine(enum db_type db_type) { - show_table_type_st *types; - for (types= sys_table_types; types->type; types++) + handlerton **types; + for (types= sys_table_types; *types; types++) { - if (db_type == types->db_type) - return types->type; + if (db_type == (*types)->db_type) + return (*types)->name; } + return "*NONE*"; +} + - return "none"; +bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag) +{ + handlerton **types; + for (types= sys_table_types; *types; types++) + { + if (db_type == (*types)->db_type) + return test((*types)->flags & flag); + } + return FALSE; // No matching engine } my_bool ha_storage_engine_is_enabled(enum db_type database_type) { - show_table_type_st *types; - for (types= sys_table_types; types->type; types++) + handlerton **types; + for (types= sys_table_types; *types; types++) { - if ((database_type == types->db_type) && - (*types->value == SHOW_OPTION_YES)) + if ((database_type == (*types)->db_type) && + ((*types)->state == SHOW_OPTION_YES)) return TRUE; } return FALSE; } - /* Use other database handler if databasehandler is not incompiled */ +/* Use other database handler if databasehandler is not compiled in */ enum db_type ha_checktype(THD *thd, enum db_type database_type, bool no_substitute, bool report_error) @@ -310,8 +402,8 @@ static int ha_init_errors(void) SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION)); SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK)); SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN)); - SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW)); - SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED)); + SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW_2)); + SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED_2)); SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name"); SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size"); SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'"); @@ -360,81 +452,24 @@ static inline void ha_was_inited_ok(handlerton **ht) int ha_init() { int error= 0; - handlerton **ht= handlertons; + handlerton **types; + show_table_alias_st *table_alias; total_ha= savepoint_alloc_size= 0; if (ha_init_errors()) return 1; - if (opt_bin_log) - { - if (!(*ht= binlog_init())) // Always succeed - { - mysql_bin_log.close(LOG_CLOSE_INDEX); // Never used - opt_bin_log= 0; // Never used - error= 1; // Never used - } - else - ha_was_inited_ok(ht++); - } -#ifdef HAVE_BERKELEY_DB - if (have_berkeley_db == SHOW_OPTION_YES) - { - if (!(*ht= berkeley_init())) - { - have_berkeley_db= SHOW_OPTION_DISABLED; // If we couldn't use handler - error= 1; - } - else - ha_was_inited_ok(ht++); - } -#endif -#ifdef HAVE_INNOBASE_DB - if (have_innodb == SHOW_OPTION_YES) - { - if (!(*ht= innobase_init())) - { - have_innodb= SHOW_OPTION_DISABLED; // If we couldn't use handler - error= 1; - } - else - ha_was_inited_ok(ht++); - } -#endif -#ifdef HAVE_NDBCLUSTER_DB - if (have_ndbcluster == SHOW_OPTION_YES) - { - if (!(*ht= ndbcluster_init())) - { - have_ndbcluster= SHOW_OPTION_DISABLED; - error= 1; - } - else - ha_was_inited_ok(ht++); - } -#endif -#ifdef HAVE_FEDERATED_DB - if (have_federated_db == SHOW_OPTION_YES) - { - if (federated_db_init()) - { - have_federated_db= SHOW_OPTION_DISABLED; - error= 1; - } - } -#endif -#ifdef HAVE_ARCHIVE_DB - if (have_archive_db == SHOW_OPTION_YES) + /* + We now initialize everything here. + */ + for (types= sys_table_types; *types; types++) { - if (!(*ht= archive_db_init())) - { - have_archive_db= SHOW_OPTION_DISABLED; - error= 1; - } + if (!(*types)->init || !(*types)->init()) + ha_was_inited_ok(types); else - ha_was_inited_ok(ht++); + (*types)->state= SHOW_OPTION_DISABLED; } -#endif + DBUG_ASSERT(total_ha < MAX_HA); /* Check if there is a transaction-capable storage engine besides the @@ -482,6 +517,10 @@ int ha_panic(enum ha_panic_function flag) if (have_archive_db == SHOW_OPTION_YES) error|= archive_db_end(); #endif +#ifdef HAVE_CSV_DB + if (have_csv_db == SHOW_OPTION_YES) + error|= tina_end(); +#endif if (ha_finish_errors()) error= 1; return error; @@ -502,9 +541,10 @@ void ha_drop_database(char* path) /* don't bother to rollback here, it's done already */ void ha_close_connection(THD* thd) { - for (uint i=0; i < total_ha; i++) - if (thd->ha_data[i]) - (*handlertons[i]->close_connection)(thd); + handlerton **types; + for (types= sys_table_types; *types; types++) + if (thd->ha_data[(*types)->slot]) + (*types)->close_connection(thd); } /* ======================================================================== @@ -570,12 +610,20 @@ int ha_prepare(THD *thd) { int err; statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status); - if ((err= (*(*ht)->prepare)(thd, all))) + if ((*ht)->prepare) { - my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); - ha_rollback_trans(thd, all); - error=1; - break; + if ((err= (*(*ht)->prepare)(thd, all))) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); + ha_rollback_trans(thd, all); + error=1; + break; + } + } + else + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), (*ht)->name); } } } @@ -805,18 +853,25 @@ int ha_autocommit_or_rollback(THD *thd, int error) DBUG_RETURN(error); } + int ha_commit_or_rollback_by_xid(XID *xid, bool commit) { - handlerton **ht= handlertons, **end_ht=ht+total_ha; + handlerton **types; int res= 1; - for ( ; ht < end_ht ; ht++) - if ((*ht)->recover) - res= res && - (*(commit ? (*ht)->commit_by_xid : (*ht)->rollback_by_xid))(xid); + for (types= sys_table_types; *types; types++) + { + if ((*types)->state == SHOW_OPTION_YES && (*types)->recover) + { + if ((*(commit ? (*types)->commit_by_xid : + (*types)->rollback_by_xid))(xid)); + res= 0; + } + } return res; } + #ifndef DBUG_OFF /* this does not need to be multi-byte safe or anything */ static char* xid_to_str(char *buf, XID *xid) @@ -892,7 +947,7 @@ static char* xid_to_str(char *buf, XID *xid) int ha_recover(HASH *commit_list) { int len, got, found_foreign_xids=0, found_my_xids=0; - handlerton **ht= handlertons, **end_ht=ht+total_ha; + handlerton **types; XID *list=0; bool dry_run=(commit_list==0 && tc_heuristic_recover==0); DBUG_ENTER("ha_recover"); @@ -928,14 +983,14 @@ int ha_recover(HASH *commit_list) DBUG_RETURN(1); } - for ( ; ht < end_ht ; ht++) + for (types= sys_table_types; *types; types++) { - if (!(*ht)->recover) + if ((*types)->state != SHOW_OPTION_YES || !(*types)->recover) continue; - while ((got=(*(*ht)->recover)(list, len)) > 0 ) + while ((got=(*(*types)->recover)(list, len)) > 0 ) { sql_print_information("Found %d prepared transaction(s) in %s", - got, (*ht)->name); + got, (*types)->name); for (int i=0; i < got; i ++) { my_xid x=list[i].get_my_xid(); @@ -963,7 +1018,7 @@ int ha_recover(HASH *commit_list) char buf[XIDDATASIZE*4+6]; // see xid_to_str sql_print_information("commit xid %s", xid_to_str(buf, list+i)); #endif - (*(*ht)->commit_by_xid)(list+i); + (*(*types)->commit_by_xid)(list+i); } else { @@ -971,7 +1026,7 @@ int ha_recover(HASH *commit_list) char buf[XIDDATASIZE*4+6]; // see xid_to_str sql_print_information("rollback xid %s", xid_to_str(buf, list+i)); #endif - (*(*ht)->rollback_by_xid)(list+i); + (*(*types)->rollback_by_xid)(list+i); } } if (got < len) @@ -1331,11 +1386,9 @@ int handler::ha_open(const char *name, int mode, int test_if_locked) table->db_stat|=HA_READ_ONLY; (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL - if (!alloc_root_inited(&table->mem_root)) // If temporary table - ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2); - else - ref=(byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2); - if (!ref) + DBUG_ASSERT(alloc_root_inited(&table->mem_root)); + + if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2))) { close(); error=HA_ERR_OUT_OF_MEM; @@ -1510,7 +1563,7 @@ bool handler::update_auto_increment() /* Mark that we should clear next_insert_id before next stmt */ thd->clear_next_insert_id= 1; - if (!table->next_number_field->store((longlong) nr)) + if (!table->next_number_field->store((longlong) nr, TRUE)) thd->insert_id((ulonglong) nr); else thd->insert_id(table->next_number_field->val_int()); @@ -1695,11 +1748,19 @@ void handler::print_error(int error, myf errflag) textno=ER_CANNOT_ADD_FOREIGN; break; case HA_ERR_ROW_IS_REFERENCED: - textno=ER_ROW_IS_REFERENCED; - break; + { + String str; + get_error_message(error, &str); + my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe()); + DBUG_VOID_RETURN; + } case HA_ERR_NO_REFERENCED_ROW: - textno=ER_NO_REFERENCED_ROW; - break; + { + String str; + get_error_message(error, &str); + my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe()); + DBUG_VOID_RETURN; + } case HA_ERR_TABLE_DEF_CHANGED: textno=ER_TABLE_DEF_CHANGED; break; @@ -2410,7 +2471,7 @@ TYPELIB *ha_known_exts(void) { if (!known_extensions.type_names || mysys_usage_id != known_extensions_id) { - show_table_type_st *types; + handlerton **types; List<char> found_exts; List_iterator_fast<char> it(found_exts); const char **ext, *old_ext; @@ -2418,11 +2479,11 @@ TYPELIB *ha_known_exts(void) known_extensions_id= mysys_usage_id; found_exts.push_back((char*) triggers_file_ext); found_exts.push_back((char*) trigname_file_ext); - for (types= sys_table_types; types->type; types++) + for (types= sys_table_types; *types; types++) { - if (*types->value == SHOW_OPTION_YES) + if ((*types)->state == SHOW_OPTION_YES) { - handler *file= get_new_handler(0,(enum db_type) types->db_type); + handler *file= get_new_handler(0,(enum db_type) (*types)->db_type); for (ext= file->bas_ext(); *ext; ext++) { while ((old_ext= it++)) diff --git a/sql/handler.h b/sql/handler.h index 811791a498b..af80f021e75 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -98,6 +98,13 @@ #define HA_ONLY_WHOLE_INDEX 16 /* Can't use part key searches */ #define HA_KEYREAD_ONLY 64 /* Support HA_EXTRA_KEYREAD */ +/* + Index scan will not return records in rowid order. Not guaranteed to be + set for unordered (e.g. HASH) indexes. +*/ +#define HA_KEY_SCAN_NOT_ROR 128 + + /* operations for disable/enable indexes */ #define HA_KEY_SWITCH_NONUNIQ 0 #define HA_KEY_SWITCH_ALL 1 @@ -177,13 +184,6 @@ enum db_type DB_TYPE_DEFAULT // Must be last }; -struct show_table_type_st { - const char *type; - SHOW_COMP_OPTION *value; - const char *comment; - enum db_type db_type; -}; - enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED, ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT }; @@ -209,6 +209,7 @@ enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, #define HA_CREATE_USED_ROW_FORMAT (1L << 15) #define HA_CREATE_USED_COMMENT (1L << 16) #define HA_CREATE_USED_PASSWORD (1L << 17) +#define HA_CREATE_USED_CONNECTION (1L << 18) typedef ulonglong my_xid; // this line is the same as in log_event.h #define MYSQL_XID_PREFIX "MySQLXid" @@ -227,7 +228,7 @@ struct xid_t { char data[XIDDATASIZE]; // not \0-terminated ! bool eq(struct xid_t *xid) - { return !memcmp(this, xid, length()); } + { return eq(xid->gtrid_length, xid->bqual_length, xid->data); } bool eq(long g, long b, const char *d) { return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); } void set(struct xid_t *xid) @@ -275,6 +276,14 @@ struct xid_t { return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+ gtrid_length+bqual_length; } + byte *key() + { + return (byte *)>rid_length; + } + uint key_length() + { + return sizeof(gtrid_length)+sizeof(bqual_length)+gtrid_length+bqual_length; + } }; typedef struct xid_t XID; @@ -303,6 +312,27 @@ typedef struct storage engine name as it should be printed to a user */ const char *name; + + /* + Historical marker for if the engine is available of not + */ + SHOW_COMP_OPTION state; + + /* + A comment used by SHOW to describe an engine. + */ + const char *comment; + + /* + Historical number used for frm file to determine the correct storage engine. + This is going away and new engines will just use "name" for this. + */ + enum db_type db_type; + /* + Method that initizlizes a storage engine + */ + bool (*init)(); + /* each storage engine has it's own memory area (actually a pointer) in the thd, for storing per-connection information. @@ -362,9 +392,16 @@ typedef struct uint32 flags; /* global handler flags */ } handlerton; +struct show_table_alias_st { + const char *alias; + const char *type; +}; + /* Possible flags of a handlerton */ -#define HTON_NO_FLAGS 0 -#define HTON_CLOSE_CURSORS_AT_COMMIT 1 +#define HTON_NO_FLAGS 0 +#define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0) +#define HTON_ALTER_NOT_SUPPORTED (1 << 1) +#define HTON_CAN_RECREATE (1 << 2) typedef struct st_thd_trans { @@ -382,6 +419,7 @@ enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED, typedef struct st_ha_create_information { CHARSET_INFO *table_charset, *default_table_charset; + LEX_STRING connect_string; const char *comment,*password; const char *data_file_name, *index_file_name; const char *alias; @@ -398,6 +436,7 @@ typedef struct st_ha_create_information uint options; /* OR of HA_CREATE_ options */ uint raid_type,raid_chunks; uint merge_insert_method; + uint extra_size; /* length of extra data segment */ bool table_existed; /* 1 in create if table existed */ bool frm_only; /* 1 if no ha_create_table() */ bool varchar; /* 1 if table has a VARCHAR */ @@ -639,7 +678,7 @@ public: virtual int reset() { return extra(HA_EXTRA_RESET); } virtual int external_lock(THD *thd, int lock_type) { return 0; } virtual void unlock_row() {} - virtual int start_stmt(THD *thd) {return 0;} + virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;} /* This is called to delete all rows in a table If the handler don't support this, then this function will @@ -820,10 +859,10 @@ public: /* Some extern variables used with handlers */ -extern struct show_table_type_st sys_table_types[]; +extern handlerton *sys_table_types[]; extern const char *ha_row_type[]; extern TYPELIB tx_isolation_typelib; -extern handlerton *handlertons[MAX_HA]; +extern TYPELIB myisam_stats_method_typelib; extern ulong total_ha, total_ha_2pc; /* Wrapper functions */ @@ -832,18 +871,13 @@ extern ulong total_ha, total_ha_2pc; #define ha_commit(thd) (ha_commit_trans((thd), TRUE)) #define ha_rollback(thd) (ha_rollback_trans((thd), TRUE)) -#define ha_supports_generate(T) (T != DB_TYPE_INNODB && \ - T != DB_TYPE_BERKELEY_DB && \ - T != DB_TYPE_ARCHIVE_DB && \ - T != DB_TYPE_FEDERATED_DB && \ - T != DB_TYPE_NDBCLUSTER) - /* lookups */ enum db_type ha_resolve_by_name(const char *name, uint namelen); const char *ha_get_storage_engine(enum db_type db_type); handler *get_new_handler(TABLE *table, enum db_type db_type); enum db_type ha_checktype(THD *thd, enum db_type database_type, bool no_substitute, bool report_error); +bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag); /* basic stuff */ int ha_init(void); diff --git a/sql/item.cc b/sql/item.cc index 1bbef46c0c9..b2aca750475 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -696,6 +696,32 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) } +Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs) +{ + if (const_item()) + { + Item_string *conv; + uint cnv_errors; + char buf[MAX_FIELD_WIDTH]; + String tmp(buf, sizeof(buf), &my_charset_bin); + String cstr, *ostr= val_str(&tmp); + /* + As safe_charset_converter is not executed for + a parameter bound to NULL, ostr should never be 0. + */ + cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &cnv_errors); + if (cnv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(), + cstr.charset(), + collation.derivation))) + return NULL; + conv->str_value.copy(); + conv->str_value.mark_as_const(); + return conv; + } + return NULL; +} + + Item *Item_static_string_func::safe_charset_converter(CHARSET_INFO *tocs) { Item_string *conv; @@ -817,9 +843,33 @@ String *Item_splocal::val_str(String *sp) { DBUG_ASSERT(fixed); Item *it= this_item(); - String *ret= it->val_str(sp); + String *res= it->val_str(sp); + null_value= it->null_value; - return ret; + if (!res) + return NULL; + + /* + This way we mark returned value of val_str as const, + so that various functions (e.g. CONCAT) won't try to + modify the value of the Item. Analogous mechanism is + implemented for Item_param. + Without this trick Item_splocal could be changed as a + side-effect of expression computation. Here is an example + of what happens without it: suppose x is varchar local + variable in a SP with initial value 'ab' Then + select concat(x,'c'); + would change x's value to 'abc', as Item_func_concat::val_str() + would use x's internal buffer to compute the result. + This is intended behaviour of Item_func_concat. Comments to + Item_param class contain some more details on the topic. + */ + + if (res != &str_value) + str_value.set(res->ptr(), res->length(), res->charset()); + else + res->mark_as_const(); + return &str_value; } @@ -836,17 +886,13 @@ my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value) bool Item_splocal::is_null() { Item *it= this_item(); - bool ret= it->is_null(); - null_value= it->null_value; - return ret; + return it->is_null(); } Item * Item_splocal::this_item() { - THD *thd= current_thd; - return thd->spcont->get_item(m_offset); } @@ -860,28 +906,27 @@ Item_splocal::this_item_addr(THD *thd, Item **addr) Item * Item_splocal::this_const_item() const { - THD *thd= current_thd; - return thd->spcont->get_item(m_offset); } Item::Type Item_splocal::type() const { - THD *thd= current_thd; - - if (thd->spcont) + if (thd && thd->spcont) return thd->spcont->get_item(m_offset)->type(); return NULL_ITEM; // Anything but SUBSELECT_ITEM } -bool Item_splocal::fix_fields(THD *, Item **) +bool Item_splocal::fix_fields(THD *thd_arg, Item **ref) { - Item *it= this_item(); + Item *it; + thd= thd_arg; // Must be set before this_item() + it= this_item(); DBUG_ASSERT(it->fixed); max_length= it->max_length; decimals= it->decimals; + unsigned_flag= it->unsigned_flag; fixed= 1; return FALSE; } @@ -905,6 +950,7 @@ void Item_splocal::print(String *str) /***************************************************************************** Item_name_const methods *****************************************************************************/ + double Item_name_const::val_real() { DBUG_ASSERT(fixed); @@ -943,9 +989,7 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value) bool Item_name_const::is_null() { - bool ret= value_item->is_null(); - null_value= value_item->null_value; - return ret; + return value_item->is_null(); } Item::Type Item_name_const::type() const @@ -954,7 +998,7 @@ Item::Type Item_name_const::type() const } -bool Item_name_const::fix_fields(THD *thd, Item **) +bool Item_name_const::fix_fields(THD *thd, Item **ref) { char buf[128]; String *item_name; @@ -1022,9 +1066,9 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, /* Will split complicated items and ignore simple ones */ split_sum_func(thd, ref_pointer_array, fields); } - else if ((type() == SUM_FUNC_ITEM || - (used_tables() & ~PARAM_TABLE_BIT)) && - type() != REF_ITEM) + else if ((type() == SUM_FUNC_ITEM || (used_tables() & ~PARAM_TABLE_BIT)) && + (type() != REF_ITEM || + ((Item_ref*)this)->ref_type() == Item_ref::VIEW_REF)) { /* Replace item with a reference so that we can easily calculate @@ -1033,15 +1077,17 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, The test above is to ensure we don't do a reference for things that are constants (PARAM_TABLE_BIT is in effect a constant) or already referenced (for example an item in HAVING) + Exception is Item_direct_view_ref which we need to convert to + Item_ref to allow fields from view being stored in tmp table. */ uint el= fields.elements; - Item *new_item; - ref_pointer_array[el]= this; + Item *new_item, *real_itm= real_item(); + + ref_pointer_array[el]= real_itm; if (!(new_item= new Item_ref(&thd->lex->current_select->context, ref_pointer_array + el, 0, name))) return; // fatal_error is set - fields.push_front(this); - ref_pointer_array[el]= this; + fields.push_front(real_itm); thd->change_item_tree(ref, new_item); } } @@ -1296,7 +1342,7 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, In case we're in statement prepare, create conversion item in its memory: it will be reused on each execute. */ - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); for (arg= args, last= args + nargs; arg < last; arg++) { @@ -1331,7 +1377,7 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, been created in prepare. In this case register the change for rollback. */ - if (arena) + if (arena && arena->is_conventional()) *arg= conv; else thd->change_item_tree(arg, conv); @@ -1342,7 +1388,7 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, conv->fix_fields(thd, arg); } if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); return res; } @@ -1385,7 +1431,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, structure can go away and pop up again between subsequent executions of a prepared statement). */ - if (thd->current_arena->is_stmt_prepare_or_first_sp_execute()) + if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) { if (db_name) orig_db_name= thd->strdup(db_name); @@ -1509,11 +1555,15 @@ void Item_ident::print(String *str) } if (db_name && db_name[0] && !alias_name_used) { - append_identifier(thd, str, d_name, (uint) strlen(d_name)); - str->append('.'); - append_identifier(thd, str, t_name, (uint) strlen(t_name)); + if (!(cached_table && cached_table->belong_to_view && + cached_table->belong_to_view->compact_view_format)) + { + append_identifier(thd, str, d_name, (uint)strlen(d_name)); + str->append('.'); + } + append_identifier(thd, str, t_name, (uint)strlen(t_name)); str->append('.'); - append_identifier(thd, str, field_name, (uint) strlen(field_name)); + append_identifier(thd, str, field_name, (uint)strlen(field_name)); } else { @@ -1659,7 +1709,7 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const return 0; Item_field *item_field= (Item_field*) item; - if (item_field->field) + if (item_field->field && field) return item_field->field == field; /* We may come here when we are trying to find a function in a GROUP BY @@ -1673,10 +1723,10 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const */ return (!my_strcasecmp(system_charset_info, item_field->name, field_name) && - (!item_field->table_name || + (!item_field->table_name || !table_name || (!my_strcasecmp(table_alias_charset, item_field->table_name, table_name) && - (!item_field->db_name || + (!item_field->db_name || !db_name || (item_field->db_name && !strcmp(item_field->db_name, db_name)))))); } @@ -1776,6 +1826,7 @@ Item_decimal::Item_decimal(const char *str_arg, uint length, name= (char*) str_arg; decimals= (uint8) decimal_value.frac; fixed= 1; + unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1785,6 +1836,7 @@ Item_decimal::Item_decimal(longlong val, bool unsig) int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; + unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1795,6 +1847,7 @@ Item_decimal::Item_decimal(double val, int precision, int scale) double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; + unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1807,6 +1860,7 @@ Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg, name= (char*) str; decimals= (uint8) decimal_par; max_length= length; + unsigned_flag= !decimal_value.sign(); fixed= 1; } @@ -1816,8 +1870,9 @@ Item_decimal::Item_decimal(my_decimal *value_par) my_decimal2decimal(value_par, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; + unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, - decimals, !decimal_value.sign()); + decimals, unsigned_flag); } @@ -1827,8 +1882,9 @@ Item_decimal::Item_decimal(const char *bin, int precision, int scale) &decimal_value, precision, scale); decimals= (uint8) decimal_value.frac; fixed= 1; + unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(precision, decimals, - !decimal_value.sign()); + unsigned_flag); } @@ -2322,7 +2378,7 @@ int Item_param::save_in_field(Field *field, bool no_conversions) switch (state) { case INT_VALUE: - return field->store(value.integer); + return field->store(value.integer, unsigned_flag); case REAL_VALUE: return field->store(value.real); case DECIMAL_VALUE: @@ -2748,7 +2804,7 @@ int Item_copy_string::save_in_field(Field *field, bool no_conversions) */ /* ARGSUSED */ -bool Item::fix_fields(THD *thd, Item ** ref) +bool Item::fix_fields(THD *thd, Item **ref) { // We do not check fields which are fixed during construction @@ -2938,7 +2994,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) const char *field_name; ORDER *found_group= NULL; int found_match_degree= 0; - Item_field *cur_field; + Item_ident *cur_field; int cur_match_degree= 0; if (find_item->type() == Item::FIELD_ITEM || @@ -2955,9 +3011,9 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next) { - if ((*(cur_group->item))->type() == Item::FIELD_ITEM) + if ((*(cur_group->item))->real_item()->type() == Item::FIELD_ITEM) { - cur_field= (Item_field*) *cur_group->item; + cur_field= (Item_ident*) *cur_group->item; cur_match_degree= 0; DBUG_ASSERT(cur_field->field_name != 0); @@ -3183,6 +3239,22 @@ bool Item_field::fix_fields(THD *thd, Item **reference) TRUE)) == not_found_field) { + + /* Look up in current select's item_list to find aliased fields */ + if (thd->lex->current_select->is_item_list_lookup) + { + uint counter; + bool not_used; + Item** res= find_item_in_list(this, thd->lex->current_select->item_list, + &counter, REPORT_EXCEPT_NOT_FOUND, + ¬_used); + if (res != not_found_item && (*res)->type() == Item::FIELD_ITEM) + { + set_field((*((Item_field**)res))->field); + return 0; + } + } + /* If there are outer contexts (outer selects, but current select is not derived table or view) try to resolve this reference in the @@ -3415,8 +3487,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference) VIEW_ANY_ACL))) { my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - "ANY", thd->priv_user, thd->host_or_ip, - field_name, tab); + "ANY", thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, field_name, tab); goto error; } } @@ -3876,7 +3948,7 @@ int Item::save_in_field(Field *field, bool no_conversions) if (null_value) return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); - error=field->store(nr); + error=field->store(nr, unsigned_flag); } return error; } @@ -3892,12 +3964,10 @@ int Item_string::save_in_field(Field *field, bool no_conversions) return field->store(result->ptr(),result->length(),collation.collation); } + int Item_uint::save_in_field(Field *field, bool no_conversions) { - /* - TODO: To be fixed when wen have a - field->store(longlong, unsigned_flag) method - */ + /* Item_int::save_in_field handles both signed and unsigned. */ return Item_int::save_in_field(field, no_conversions); } @@ -3908,7 +3978,7 @@ int Item_int::save_in_field(Field *field, bool no_conversions) if (null_value) return set_field_to_null(field); field->set_notnull(); - return field->store(nr); + return field->store(nr, unsigned_flag); } @@ -4115,7 +4185,7 @@ int Item_hex_string::save_in_field(Field *field, bool no_conversions) else { longlong nr=val_int(); - error=field->store(nr); + error=field->store(nr, TRUE); // Assume hex numbers are unsigned } return error; } @@ -4600,7 +4670,7 @@ void Item_ref::cleanup() void Item_ref::print(String *str) { - if (ref && *ref) + if (ref) (*ref)->print(str); else Item_ident::print(str); @@ -4732,8 +4802,7 @@ String *Item_ref::val_str(String* tmp) bool Item_ref::is_null() { DBUG_ASSERT(fixed); - (void) (*ref)->val_int_result(); - return (*ref)->null_value; + return (*ref)->is_null(); } @@ -4787,7 +4856,7 @@ void Item_ref::make_field(Send_field *field) void Item_ref_null_helper::print(String *str) { str->append("<ref_null_helper>(", 18); - if (ref && *ref) + if (ref) (*ref)->print(str); else str->append('?'); @@ -4980,10 +5049,7 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (context->error_processor == &view_error_processor) { - TABLE_LIST *view= (cached_table->belong_to_view ? - cached_table->belong_to_view : - cached_table); - // TODO: make correct error message + TABLE_LIST *view= cached_table->top_table(); push_warning_printf(field_arg->table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NO_DEFAULT_FOR_VIEW_FIELD, @@ -5204,6 +5270,25 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) (Item*) new Item_int(name, result, length)); break; } + case ROW_RESULT: + { + Item_row *item_row= (Item_row*) item; + Item_row *comp_item_row= (Item_row*) comp_item; + uint col; + new_item= 0; + /* + If item and comp_item are both Item_rows and have same number of cols + then process items in Item_row one by one. + We can't ignore NULL values here as this item may be used with <=>, in + which case NULL's are significant. + */ + DBUG_ASSERT(item->result_type() == comp_item->result_type()); + DBUG_ASSERT(item_row->cols() == comp_item_row->cols()); + col= item_row->cols(); + while (col-- > 0) + resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col)); + break; + } case REAL_RESULT: { // It must REAL_RESULT double result= item->val_real(); @@ -5224,7 +5309,6 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) (Item*) new Item_decimal(name, result, length, decimals)); break; } - case ROW_RESULT: default: DBUG_ASSERT(0); } @@ -5657,6 +5741,8 @@ enum_field_types Item_type_holder::get_real_type(Item *item) bool Item_type_holder::join_types(THD *thd, Item *item) { + uint max_length_orig= max_length; + uint decimals_orig= decimals; DBUG_ENTER("Item_type_holder::join_types"); DBUG_PRINT("info:", ("was type %d len %d, dec %d name %s", fld_type, max_length, decimals, @@ -5683,7 +5769,10 @@ bool Item_type_holder::join_types(THD *thd, Item *item) } else max_length= max(max_length, display_length(item)); - if (Field::result_merge_type(fld_type) == STRING_RESULT) + + switch (Field::result_merge_type(fld_type)) + { + case STRING_RESULT: { const char *old_cs, *old_derivation; old_cs= collation.collation->name; @@ -5697,7 +5786,23 @@ bool Item_type_holder::join_types(THD *thd, Item *item) "UNION"); DBUG_RETURN(TRUE); } + break; } + case REAL_RESULT: + { + if (decimals != NOT_FIXED_DEC) + { + int delta1= max_length_orig - decimals_orig; + int delta2= item->max_length - item->decimals; + max_length= min(max(delta1, delta2) + decimals, + (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7); + } + else + max_length= (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7; + break; + } + default:; + }; maybe_null|= item->maybe_null; get_full_info(item); diff --git a/sql/item.h b/sql/item.h index b934e1f9f3f..3e52cbe5fd7 100644 --- a/sql/item.h +++ b/sql/item.h @@ -164,6 +164,7 @@ struct Hybrid_type_traits virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const; virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; static const Hybrid_type_traits *instance(); + Hybrid_type_traits() {}; }; @@ -185,6 +186,7 @@ struct Hybrid_type_traits_decimal: public Hybrid_type_traits { return &val->dec_buf[val->used_dec_buf_no]; } virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; static const Hybrid_type_traits_decimal *instance(); + Hybrid_type_traits_decimal() {}; }; @@ -215,6 +217,7 @@ struct Hybrid_type_traits_integer: public Hybrid_type_traits virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const { buf->set(val->integer, &my_charset_bin); return buf;} static const Hybrid_type_traits_integer *instance(); + Hybrid_type_traits_integer() {}; }; @@ -715,8 +718,10 @@ public: class Item_splocal : public Item { uint m_offset; + public: LEX_STRING m_name; + THD *thd; /* Position of this reference to SP variable in the statement (the @@ -728,10 +733,10 @@ public: Value of 0 means that this object doesn't corresponding to reference to SP variable in query text. */ - int pos_in_query; + uint pos_in_query; - Item_splocal(LEX_STRING name, uint offset, int pos_in_q=0) - : m_offset(offset), m_name(name), pos_in_query(pos_in_q) + Item_splocal(LEX_STRING name, uint offset, uint pos_in_q=0) + : m_offset(offset), m_name(name), thd(0), pos_in_query(pos_in_q) { maybe_null= TRUE; } @@ -1189,6 +1194,7 @@ public: constant, assert otherwise. This method is called only if basic_const_item returned TRUE. */ + Item *safe_charset_converter(CHARSET_INFO *tocs); Item *new_item(); /* Implement by-value equality evaluation if parameter value @@ -1326,6 +1332,14 @@ public: longlong val_int() { DBUG_ASSERT(fixed == 1); + if (value <= (double) LONGLONG_MIN) + { + return LONGLONG_MIN; + } + else if (value >= (double) (ulonglong) LONGLONG_MAX) + { + return LONGLONG_MAX; + } return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } String *val_str(String*); @@ -1494,6 +1508,7 @@ public: my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); enum Item_result result_type () const { return STRING_RESULT; } + enum Item_result cast_to_int_type() const { return INT_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} @@ -1537,6 +1552,7 @@ class Item_ref :public Item_ident protected: void set_properties(); public: + enum Ref_Type { REF, DIRECT_REF, VIEW_REF }; Field *result_field; /* Save result here */ Item **ref; Item_ref(Name_resolution_context *context_arg, @@ -1609,7 +1625,7 @@ public: } Item *real_item() { - return (*ref)->real_item(); + return ref ? (*ref)->real_item() : this; } bool walk(Item_processor processor, byte *arg) { return (*ref)->walk(processor, arg); } @@ -1617,6 +1633,7 @@ public: void cleanup(); Item_field *filed_for_view_update() { return (*ref)->filed_for_view_update(); } + virtual Ref_Type ref_type() { return REF; } }; @@ -1641,6 +1658,7 @@ public: bool val_bool(); bool is_null(); bool get_date(TIME *ltime,uint fuzzydate); + virtual Ref_Type ref_type() { return DIRECT_REF; } }; /* @@ -1660,6 +1678,7 @@ public: bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; + virtual Ref_Type ref_type() { return VIEW_REF; } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9443a2949d8..761d15c8a3e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -671,7 +671,7 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref) If it is preparation PS only then we do not know values of parameters => cant't get there values and do not need that values. */ - if (!thd->current_arena->is_stmt_prepare()) + if (!thd->stmt_arena->is_stmt_prepare()) cache->store(args[0]); if (cache->cols() == 1) { @@ -988,6 +988,53 @@ longlong Item_func_interval::val_int() } +/* + Perform context analysis of a BETWEEN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_between as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2)) + T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + + RETURN + 0 ok + 1 got error +*/ + +bool Item_func_between::fix_fields(THD *thd, Item **ref) +{ + if (Item_func_opt_neg::fix_fields(thd, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */ + if (pred_level && !negated) + return 0; + + /* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */ + not_null_tables_cache= (args[0]->not_null_tables() | + (args[1]->not_null_tables() & + args[2]->not_null_tables())); + + return 0; +} + + void Item_func_between::fix_length_and_dec() { max_length= 1; @@ -1040,8 +1087,9 @@ longlong Item_func_between::val_int() a=args[1]->val_str(&value1); b=args[2]->val_str(&value2); if (!args[1]->null_value && !args[2]->null_value) - return (sortcmp(value,a,cmp_collation.collation) >= 0 && - sortcmp(value,b,cmp_collation.collation) <= 0) ? 1 : 0; + return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 && + sortcmp(value,b,cmp_collation.collation) <= 0) != + negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -1063,7 +1111,7 @@ longlong Item_func_between::val_int() a=args[1]->val_int(); b=args[2]->val_int(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -1084,8 +1132,8 @@ longlong Item_func_between::val_int() a_dec= args[1]->val_decimal(&a_buf); b_dec= args[2]->val_decimal(&b_buf); if (!args[1]->null_value && !args[2]->null_value) - return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0); - + return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 && + my_decimal_cmp(dec, b_dec) <= 0) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -1101,7 +1149,7 @@ longlong Item_func_between::val_int() a= args[1]->val_real(); b= args[2]->val_real(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -1113,7 +1161,7 @@ longlong Item_func_between::val_int() null_value= value >= a; } } - return 0; + return (longlong) (!null_value && negated); } @@ -1121,6 +1169,8 @@ void Item_func_between::print(String *str) { str->append('('); args[0]->print(str); + if (negated) + str->append(" not", 4); str->append(" between ", 9); args[1]->print(str); str->append(" and ", 5); @@ -1244,6 +1294,49 @@ Item_func_ifnull::str_op(String *str) } +/* + Perform context analysis of an IF item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_if as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(IF(e,e1,e2) = T1(IF(e,e1,e2)) + T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2)) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_if::fix_fields(THD *thd, Item **ref) +{ + DBUG_ASSERT(fixed == 0); + args[0]->top_level_item(); + + if (Item_func::fix_fields(thd, ref)) + return 1; + + not_null_tables_cache= (args[1]->not_null_tables() & + args[2]->not_null_tables()); + + return 0; +} + + void Item_func_if::fix_length_and_dec() { @@ -2184,6 +2277,56 @@ bool Item_func_in::nulls_in_row() } +/* + Perform context analysis of an IN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_in as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei))) + T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_in::fix_fields(THD *thd, Item **ref) +{ + Item **arg, **arg_end; + + if (Item_func_opt_neg::fix_fields(thd, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),union(T1(ei))) */ + if (pred_level && negated) + return 0; + + /* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */ + not_null_tables_cache= ~(table_map) 0; + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++) + not_null_tables_cache&= (*arg)->not_null_tables(); + not_null_tables_cache|= (*args)->not_null_tables(); + return 0; +} + + static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) { return cs->coll->strnncollsp(cs, @@ -2270,6 +2413,8 @@ void Item_func_in::print(String *str) { str->append('('); args[0]->print(str); + if (negated) + str->append(" not", 4); str->append(" in (", 5); print_args(str, 1); str->append("))", 2); @@ -2283,7 +2428,7 @@ longlong Item_func_in::val_int() { int tmp=array->find(args[0]); null_value=args[0]->null_value || (!tmp && have_null); - return tmp; + return (longlong) (!null_value && tmp != negated); } in_item->store_value(args[0]); if ((null_value=args[0]->null_value)) @@ -2292,11 +2437,11 @@ longlong Item_func_in::val_int() for (uint i=1 ; i < arg_count ; i++) { if (!in_item->cmp(args[i]) && !args[i]->null_value) - return 1; // Would maybe be nice with i ? + return (longlong) (!negated); have_null|= args[i]->null_value; } null_value= have_null; - return 0; + return (longlong) (!null_value && negated); } @@ -2811,7 +2956,52 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&tmp_value1); - escape= escape_str ? *(escape_str->ptr()) : '\\'; + if (escape_str) + { + if (escape_used_in_parsing && ( + (((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) && + escape_str->numchars() != 1) || + escape_str->numchars() > 1))) + { + my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE"); + return TRUE; + } + + if (use_mb(cmp.cmp_collation.collation)) + { + CHARSET_INFO *cs= escape_str->charset(); + my_wc_t wc; + int rc= cs->cset->mb_wc(cs, &wc, + (const uchar*) escape_str->ptr(), + (const uchar*) escape_str->ptr() + + escape_str->length()); + escape= (int) (rc > 0 ? wc : '\\'); + } + else + { + /* + In the case of 8bit character set, we pass native + code instead of Unicode code as "escape" argument. + Convert to "cs" if charset of escape differs. + */ + CHARSET_INFO *cs= cmp.cmp_collation.collation; + uint32 unused; + if (escape_str->needs_conversion(escape_str->length(), + escape_str->charset(), cs, &unused)) + { + char ch; + uint errors; + uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(), + escape_str->length(), + escape_str->charset(), &errors); + escape= cnvlen ? ch : '\\'; + } + else + escape= *(escape_str->ptr()); + } + } + else + escape= '\\'; /* We could also do boyer-more for non-const items, but as we would have to @@ -2892,14 +3082,14 @@ Item_func_regex::fix_fields(THD *thd, Item **ref) return FALSE; } int error; - if ((error= regcomp(&preg,res->c_ptr(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation))) + if ((error= my_regcomp(&preg,res->c_ptr(), + ((cmp_collation.collation->state & + (MY_CS_BINSORT | MY_CS_CSSORT)) ? + REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE), + cmp_collation.collation))) { - (void) regerror(error,&preg,buff,sizeof(buff)); + (void) my_regerror(error,&preg,buff,sizeof(buff)); my_error(ER_REGEXP_ERROR, MYF(0), buff); return TRUE; } @@ -2941,15 +3131,15 @@ longlong Item_func_regex::val_int() prev_regexp.copy(*res2); if (regex_compiled) { - regfree(&preg); + my_regfree(&preg); regex_compiled=0; } - if (regcomp(&preg,res2->c_ptr_safe(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation)) + if (my_regcomp(&preg,res2->c_ptr_safe(), + ((cmp_collation.collation->state & + (MY_CS_BINSORT | MY_CS_CSSORT)) ? + REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE), + cmp_collation.collation)) { null_value=1; return 0; @@ -2958,7 +3148,7 @@ longlong Item_func_regex::val_int() } } null_value=0; - return regexec(&preg,res->c_ptr(),0,(regmatch_t*) 0,0) ? 0 : 1; + return my_regexec(&preg,res->c_ptr(),0,(my_regmatch_t*) 0,0) ? 0 : 1; } @@ -2968,7 +3158,7 @@ void Item_func_regex::cleanup() Item_bool_func::cleanup(); if (regex_compiled) { - regfree(&preg); + my_regfree(&preg); regex_compiled=0; } DBUG_VOID_RETURN; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1915dbaabf6..bfd32223d4c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -401,17 +401,49 @@ public: }; -class Item_func_between :public Item_int_func +/* + The class Item_func_opt_neg is defined to factor out the functionality + common for the classes Item_func_between and Item_func_in. The objects + of these classes can express predicates or there negations. + The alternative approach would be to create pairs Item_func_between, + Item_func_notbetween and Item_func_in, Item_func_notin. + +*/ + +class Item_func_opt_neg :public Item_int_func +{ +public: + bool negated; /* <=> the item represents NOT <func> */ + bool pred_level; /* <=> [NOT] <func> is used on a predicate level */ +public: + Item_func_opt_neg(Item *a, Item *b, Item *c) + :Item_int_func(a, b, c), negated(0), pred_level(0) {} + Item_func_opt_neg(List<Item> &list) + :Item_int_func(list), negated(0), pred_level(0) {} +public: + inline void negate() { negated= !negated; } + inline void top_level_item() { pred_level= 1; } + Item *neg_transformer(THD *thd) + { + negated= !negated; + return this; + } +}; + + +class Item_func_between :public Item_func_opt_neg { DTCollation cmp_collation; public: Item_result cmp_type; String value0,value1,value2; - Item_func_between(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} + Item_func_between(Item *a, Item *b, Item *c) + :Item_func_opt_neg(a, b, c) {} longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_KEY; } enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } + bool fix_fields(THD *, Item **); void fix_length_and_dec(); void print(String *str); bool is_bool_func() { return 1; } @@ -505,16 +537,10 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd, Item **ref) - { - DBUG_ASSERT(fixed == 0); - args[0]->top_level_item(); - return Item_func::fix_fields(thd, ref); - } + bool fix_fields(THD *, Item **); void fix_length_and_dec(); uint decimal_precision() const; const char *func_name() const { return "if"; } - table_map not_null_tables() const { return 0; } }; @@ -819,7 +845,7 @@ public: } }; -class Item_func_in :public Item_int_func +class Item_func_in :public Item_func_opt_neg { Item_result cmp_type; in_vector *array; @@ -828,11 +854,12 @@ class Item_func_in :public Item_int_func DTCollation cmp_collation; public: Item_func_in(List<Item> &list) - :Item_int_func(list), array(0), in_item(0), have_null(0) + :Item_func_opt_neg(list), array(0), in_item(0), have_null(0) { allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); + bool fix_fields(THD *, Item **); void fix_length_and_dec(); uint decimal_precision() const { return 1; } void cleanup() @@ -853,12 +880,6 @@ class Item_func_in :public Item_int_func bool nulls_in_row(); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } - /* - IN() protect from NULL only first argument, if construction like - "expression IN ()" will be allowed, we will need to check number of - argument here, because "NOT(NULL IN ())" is TRUE. - */ - table_map not_null_tables() const { return args[0]->not_null_tables(); } }; /* Functions used by where clause */ @@ -889,7 +910,7 @@ public: else { args[0]->update_used_tables(); - if (!(used_tables_cache=args[0]->used_tables())) + if ((const_item_cache= !(used_tables_cache= args[0]->used_tables()))) { /* Remember if the value is always NULL or never NULL */ cached_value= (longlong) args[0]->is_null(); @@ -964,13 +985,16 @@ class Item_func_like :public Item_bool_func2 enum { alphabet_size = 256 }; Item *escape_item; + + bool escape_used_in_parsing; public: - char escape; + int escape; - Item_func_like(Item *a,Item *b, Item *escape_arg) + Item_func_like(Item *a,Item *b, Item *escape_arg, bool escape_used) :Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0), - bmGs(0), bmBc(0), escape_item(escape_arg) {} + bmGs(0), bmBc(0), escape_item(escape_arg), + escape_used_in_parsing(escape_used) {} longlong val_int(); enum Functype functype() const { return LIKE_FUNC; } optimize_type select_optimize() const; @@ -981,11 +1005,11 @@ public: #ifdef USE_REGEX -#include <regex.h> +#include "my_regex.h" class Item_func_regex :public Item_bool_func { - regex_t preg; + my_regex_t preg; bool regex_compiled; bool regex_is_const; String prev_regexp; diff --git a/sql/item_create.cc b/sql/item_create.cc index 82a82873ad9..342ef245a76 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -109,7 +109,7 @@ Item *create_func_dayofmonth(Item* a) Item *create_func_dayofweek(Item* a) { - return new Item_func_weekday(new Item_func_to_days(a),1); + return new Item_func_weekday(a, 1); } Item *create_func_dayofyear(Item* a) @@ -119,7 +119,7 @@ Item *create_func_dayofyear(Item* a) Item *create_func_dayname(Item* a) { - return new Item_func_dayname(new Item_func_to_days(a)); + return new Item_func_dayname(a); } Item *create_func_degrees(Item *a) @@ -443,7 +443,7 @@ Item *create_func_version(void) Item *create_func_weekday(Item* a) { - return new Item_func_weekday(new Item_func_to_days(a),0); + return new Item_func_weekday(a, 0); } Item *create_func_year(Item* a) diff --git a/sql/item_func.cc b/sql/item_func.cc index 8125264ab15..35ed9b615f2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -32,6 +32,11 @@ #include "sp_rcontext.h" #include "sp.h" +#ifdef NO_EMBEDDED_ACCESS_CHECKS +#define sp_restore_security_context(A,B) while (0) {} +#endif + + bool check_reserved_words(LEX_STRING *name) { if (!my_strcasecmp(system_charset_info, name->str, "GLOBAL") || @@ -765,7 +770,7 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) } case REAL_RESULT: { - double result= (double)int_op(); + double result= (double)real_op(); double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value); break; } @@ -1874,8 +1879,13 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) used_tables_cache|= RAND_TABLE_BIT; if (arg_count) { // Only use argument once in query + if (!args[0]->const_during_execution()) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND"); + return TRUE; + } /* - Allocate rand structure once: we must use thd->current_arena + Allocate rand structure once: we must use thd->stmt_arena to create rand in proper mem_root if it's a prepared statement or stored procedure. @@ -1883,7 +1893,7 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) as it will be replicated in the query as such. */ if (!rand && !(rand= (struct rand_struct*) - thd->current_arena->alloc(sizeof(*rand)))) + thd->stmt_arena->alloc(sizeof(*rand)))) return TRUE; /* PARAM_ITEM is returned if we're in statement prepare and consequently @@ -2010,7 +2020,6 @@ String *Item_func_min_max::val_str(String *str) { String *res; LINT_INIT(res); - null_value= 0; for (uint i=0; i < arg_count ; i++) { if (i == 0) @@ -2025,14 +2034,11 @@ String *Item_func_min_max::val_str(String *str) if ((cmp_sign < 0 ? cmp : -cmp) < 0) res=res2; } - else - res= 0; } if ((null_value= args[i]->null_value)) - break; + return 0; } - if (res) // If !NULL - res->set_charset(collation.collation); + res->set_charset(collation.collation); return res; } case ROW_RESULT: @@ -2049,7 +2055,6 @@ double Item_func_min_max::val_real() { DBUG_ASSERT(fixed == 1); double value=0.0; - null_value= 0; for (uint i=0; i < arg_count ; i++) { if (i == 0) @@ -2071,7 +2076,6 @@ longlong Item_func_min_max::val_int() { DBUG_ASSERT(fixed == 1); longlong value=0; - null_value= 0; for (uint i=0; i < arg_count ; i++) { if (i == 0) @@ -2092,21 +2096,21 @@ longlong Item_func_min_max::val_int() my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) { DBUG_ASSERT(fixed == 1); - my_decimal tmp_buf, *tmp, *res= NULL; - null_value= 0; + my_decimal tmp_buf, *tmp, *res; + LINT_INIT(res); + for (uint i=0; i < arg_count ; i++) { if (i == 0) res= args[i]->val_decimal(dec); else { - tmp= args[i]->val_decimal(&tmp_buf); - if (args[i]->null_value) - res= 0; - else if ((my_decimal_cmp(tmp, res) * cmp_sign) < 0) + tmp= args[i]->val_decimal(&tmp_buf); // Zero if NULL + if (tmp && (my_decimal_cmp(tmp, res) * cmp_sign) < 0) { if (tmp == &tmp_buf) { + /* Move value out of tmp_buf as this will be reused on next loop */ my_decimal2decimal(tmp, dec); res= dec; } @@ -2115,7 +2119,10 @@ my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) } } if ((null_value= args[i]->null_value)) + { + res= 0; break; + } } return res; } @@ -2344,7 +2351,7 @@ void Item_func_find_in_set::fix_length_and_dec() } } } - agg_arg_collations_for_comparison(cmp_collation, args, 2); + agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV); } static const char separator=','; @@ -3026,9 +3033,13 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) thd->mysys_var->current_cond= &ull->cond; set_timespec(abstime,lock_timeout); - while (!thd->killed && - pthread_cond_timedwait(&ull->cond, &LOCK_user_locks, - &abstime) != ETIMEDOUT && ull->locked) ; + while (ull->locked && !thd->killed) + { + int error= pthread_cond_timedwait(&ull->cond, &LOCK_user_locks, &abstime); + if (error == ETIMEDOUT || error == ETIME) + break; + } + if (ull->locked) { if (!--ull->count) @@ -3072,7 +3083,7 @@ longlong Item_func_get_lock::val_int() struct timespec abstime; THD *thd=current_thd; User_level_lock *ull; - int error=0; + int error; /* In slave thread no need to get locks, everything is serialized. Anyway @@ -3128,22 +3139,29 @@ longlong Item_func_get_lock::val_int() thd->mysys_var->current_cond= &ull->cond; set_timespec(abstime,timeout); - while (!thd->killed && - (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime)) - != ETIMEDOUT && error != EINVAL && ull->locked) ; - if (thd->killed) - error=EINTR; // Return NULL + error= 0; + while (ull->locked && !thd->killed) + { + error= pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime); + if (error == ETIMEDOUT || error == ETIME) + break; + error= 0; + } + if (ull->locked) { if (!--ull->count) + { + DBUG_ASSERT(0); delete ull; // Should never happen - if (error != ETIMEDOUT) + } + if (!error) // Killed (thd->killed != 0) { error=1; null_value=1; // Return NULL } } - else + else // We got the lock { ull->locked=1; ull->thread=thd->real_id; @@ -3265,6 +3283,7 @@ void Item_func_benchmark::print(String *str) str->append(')'); } + /* This function is just used to create tests with time gaps */ longlong Item_func_sleep::val_int() @@ -3285,10 +3304,14 @@ longlong Item_func_sleep::val_int() thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &cond; - while (!thd->killed && - (error= pthread_cond_timedwait(&cond, &LOCK_user_locks, - &abstime)) != ETIMEDOUT && - error != EINVAL) ; + error= 0; + while (!thd->killed) + { + error= pthread_cond_timedwait(&cond, &LOCK_user_locks, &abstime); + if (error == ETIMEDOUT || error == ETIME) + break; + error= 0; + } pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; @@ -3298,7 +3321,7 @@ longlong Item_func_sleep::val_int() pthread_mutex_unlock(&LOCK_user_locks); pthread_cond_destroy(&cond); - return (error == ETIMEDOUT) ? 0 : 1; + return test(!error); // Return 1 killed } @@ -3834,21 +3857,21 @@ longlong Item_func_get_user_var::val_int() stores this variable and its value in thd->user_var_events, so that it can be written to the binlog (will be written just before the query is written, see log.cc). - + RETURN - 0 OK + 0 OK 1 Failed to put appropriate record into binary log - + */ -int get_var_with_binlog(THD *thd, LEX_STRING &name, - user_var_entry **out_entry) +int get_var_with_binlog(THD *thd, enum_sql_command sql_command, + LEX_STRING &name, user_var_entry **out_entry) { BINLOG_USER_VAR_EVENT *user_var_event; user_var_entry *var_entry; var_entry= get_variable(&thd->user_vars, name, 0); - - if (!(opt_bin_log && is_update_query(thd->lex->sql_command))) + + if (!(opt_bin_log && is_update_query(sql_command))) { *out_entry= var_entry; return 0; @@ -3879,7 +3902,8 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, if (!(var_entry= get_variable(&thd->user_vars, name, 0))) goto err; } - else if (var_entry->used_query_id == thd->query_id) + else if (var_entry->used_query_id == thd->query_id || + mysql_bin_log.is_query_in_union(thd, var_entry->used_query_id)) { /* If this variable was already stored in user_var_events by this query @@ -3896,10 +3920,16 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, appears: > set @a:=1; > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1); - We have to write to binlog value @a= 1; + We have to write to binlog value @a= 1. + + We allocate the user_var_event on user_var_events_alloc pool, not on + the this-statement-execution pool because in SPs user_var_event objects + may need to be valid after current [SP] statement execution pool is + destroyed. */ - size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length; - if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size))) + size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length; + if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) + alloc_root(thd->user_var_events_alloc, size))) goto err; user_var_event->value= (char*) user_var_event + @@ -3941,7 +3971,7 @@ void Item_func_get_user_var::fix_length_and_dec() decimals=NOT_FIXED_DEC; max_length=MAX_BLOB_WIDTH; - error= get_var_with_binlog(thd, name, &var_entry); + error= get_var_with_binlog(thd, thd->lex->sql_command, name, &var_entry); if (var_entry) { @@ -4473,7 +4503,6 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, LEX_STRING component) { sys_var *var; - char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos; LEX_STRING *base_name, *component_name; if (component.str == 0 && @@ -4699,27 +4728,11 @@ Item_func_sp::execute(Item **itp) THD *thd= current_thd; int res= -1; Sub_statement_state statement_state; + Security_context *save_ctx; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - st_sp_security_context save_ctx; -#endif - - if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) - { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx)) goto error; - } -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_routine_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - goto error; - sp_change_security_context(thd, m_sp, &save_ctx); - if (save_ctx.changed && - check_routine_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - goto error_check_ctx; -#endif /* Disable the binlogging if this is not a SELECT statement. If this is a SELECT, leave binlogging on, so execute_function() code writes the @@ -4728,7 +4741,7 @@ Item_func_sp::execute(Item **itp) thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION); res= m_sp->execute_function(thd, args, arg_count, itp); thd->restore_sub_statement_state(&statement_state); - + if (res && mysql_bin_log.is_open() && (m_sp->m_chistics->daccess == SP_CONTAINS_SQL || m_sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA)) @@ -4736,11 +4749,7 @@ Item_func_sp::execute(Item **itp) ER_FAILED_ROUTINE_BREAK_BINLOG, ER(ER_FAILED_ROUTINE_BREAK_BINLOG)); -#ifndef NO_EMBEDDED_ACCESS_CHECKS -error_check_ctx: - sp_restore_security_context(thd, m_sp, &save_ctx); -#endif - + sp_restore_security_context(thd, save_ctx); error: DBUG_RETURN(res); } @@ -4845,3 +4854,88 @@ Item_func_sp::tmp_table_field(TABLE *t_arg) DBUG_RETURN(res); } + + +/* + Find the function and chack access rigths to the function + + SYNOPSIS + find_and_check_access() + thd thread handler + want_access requested access + save backup of security context + + RETURN + FALSE Access granted + TRUE Requested access can't be granted or function doesn't exists + In this case security context is not changed and *save = 0 + + NOTES + Checks if requested access to function can be granted to user. + If function isn't found yet, it searches function first. + If function can't be found or user don't have requested access + error is raised. + If security context sp_ctx is provided and access can be granted then + switch back to previous context isn't performed. + In case of access error or if context is not provided then + find_and_check_access() switches back to previous security context. +*/ + +bool +Item_func_sp::find_and_check_access(THD *thd, ulong want_access, + Security_context **save) +{ + bool res= TRUE; + + *save= 0; // Safety if error + if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) + { + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + goto error; + } + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (check_routine_access(thd, want_access, + m_sp->m_db.str, m_sp->m_name.str, 0, FALSE)) + goto error; + + sp_change_security_context(thd, m_sp, save); + /* + If we changed context to run as another user, we need to check the + access right for the new context again as someone may have deleted + this person the right to use the procedure + + TODO: + Cache if the definer has the right to use the object on the first + usage and only reset the cache if someone does a GRANT statement + that 'may' affect this. + */ + if (*save && + check_routine_access(thd, want_access, + m_sp->m_db.str, m_sp->m_name.str, 0, FALSE)) + { + sp_restore_security_context(thd, *save); + *save= 0; // Safety + goto error; + } +#endif + res= FALSE; // no error + +error: + return res; +} + +bool +Item_func_sp::fix_fields(THD *thd, Item **ref) +{ + bool res; + DBUG_ASSERT(fixed == 0); + res= Item_func::fix_fields(thd, ref); + if (!res) + { + Security_context *save_ctx; + if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx))) + sp_restore_security_context(thd, save_ctx); + } + return res; +} diff --git a/sql/item_func.h b/sql/item_func.h index 019abb0c072..223144a5d51 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -55,7 +55,7 @@ public: NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, - EXTRACT_FUNC, CHAR_TYPECAST_FUNC }; + EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } @@ -1286,9 +1286,6 @@ public: { ft_handler->please->close_search(ft_handler); ft_handler=0; - if (join_key) - table->file->ft_handler=0; - table->fulltext_searched=0; } concat= 0; DBUG_VOID_RETURN; @@ -1365,6 +1362,7 @@ public: class sp_head; class sp_name; +struct st_sp_security_context; class Item_func_sp :public Item_func { @@ -1434,7 +1432,11 @@ public: { context= (Name_resolution_context *)cntx; return FALSE; } void fix_length_and_dec(); + bool find_and_check_access(THD * thd, ulong want_access, + Security_context **backup); + virtual enum Functype functype() const { return FUNC_SP; } + bool fix_fields(THD *thd, Item **ref); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4fd33c06095..1e8fe2e695f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -473,7 +473,8 @@ String *Item_func_des_decrypt::val_str(String *str) { uint key_number=(uint) (*res)[0] & 127; // Check if automatic key and that we have privilege to uncompress using it - if (!(current_thd->master_access & SUPER_ACL) || key_number > 9) + if (!(current_thd->security_ctx->master_access & SUPER_ACL) || + key_number > 9) goto error; VOID(pthread_mutex_lock(&LOCK_des_key_file)); @@ -1503,7 +1504,13 @@ String *Item_func_encrypt::val_str(String *str) salt_ptr= salt_str->c_ptr(); } pthread_mutex_lock(&LOCK_crypt); - char *tmp=crypt(res->c_ptr(),salt_ptr); + char *tmp= crypt(res->c_ptr(),salt_ptr); + if (!tmp) + { + pthread_mutex_unlock(&LOCK_crypt); + null_value= 1; + return 0; + } str->set(tmp,(uint) strlen(tmp),res->charset()); str->copy(); pthread_mutex_unlock(&LOCK_crypt); @@ -1601,13 +1608,13 @@ String *Item_func_user::val_str(String *str) if (is_current) { - user= thd->priv_user; - host= thd->priv_host; + user= thd->security_ctx->priv_user; + host= thd->security_ctx->priv_host; } else { - user= thd->user; - host= thd->host_or_ip; + user= thd->main_security_ctx.user; + host= thd->main_security_ctx.host_or_ip; } // For system threads (e.g. replication SQL thread) user may be empty @@ -1732,6 +1739,8 @@ String *Item_func_format::val_str(String *str) { my_decimal dec_val, rnd_dec, *res; res= args[0]->val_decimal(&dec_val); + if ((null_value=args[0]->null_value)) + return 0; /* purecov: inspected */ my_decimal_round(E_DEC_FATAL_ERROR, res, decimals, false, &rnd_dec); my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str); str_length= str->length(); @@ -1961,25 +1970,47 @@ String *Item_func_char::val_str(String *str) int32 num=(int32) args[i]->val_int(); if (!args[i]->null_value) { -#ifdef USE_MB - if (use_mb(collation.collation)) - { - if (num&0xFF000000L) { - str->append((char)(num>>24)); - goto b2; - } else if (num&0xFF0000L) { -b2: str->append((char)(num>>16)); - goto b1; - } else if (num&0xFF00L) { -b1: str->append((char)(num>>8)); - } + if (num&0xFF000000L) { + str->append((char)(num>>24)); + goto b2; + } else if (num&0xFF0000L) { + b2: str->append((char)(num>>16)); + goto b1; + } else if (num&0xFF00L) { + b1: str->append((char)(num>>8)); } -#endif - str->append((char)num); + str->append((char) num); } } str->set_charset(collation.collation); str->realloc(str->length()); // Add end 0 (for Purify) + + /* Check whether we got a well-formed string */ + CHARSET_INFO *cs= collation.collation; + int well_formed_error; + uint wlen= cs->cset->well_formed_len(cs, + str->ptr(), str->ptr() + str->length(), + str->length(), &well_formed_error); + if (wlen < str->length()) + { + THD *thd= current_thd; + char hexbuf[7]; + enum MYSQL_ERROR::enum_warning_level level; + uint diff= str->length() - wlen; + set_if_smaller(diff, 3); + octet2hex(hexbuf, str->ptr() + wlen, diff); + if (thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)) + { + level= MYSQL_ERROR::WARN_LEVEL_ERROR; + null_value= 1; + str= 0; + } + else + level= MYSQL_ERROR::WARN_LEVEL_WARN; + push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING, + ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf); + } return str; } @@ -2406,6 +2437,7 @@ String *Item_func_collation::val_str(String *str) String *Item_func_hex::val_str(String *str) { + String *res; DBUG_ASSERT(fixed == 1); if (args[0]->result_type() != STRING_RESULT) { @@ -2434,24 +2466,16 @@ String *Item_func_hex::val_str(String *str) } /* Convert given string to a hex string, character by character */ - String *res= args[0]->val_str(str); - const char *from, *end; - char *to; - if (!res || tmp_value.alloc(res->length()*2)) + res= args[0]->val_str(str); + if (!res || tmp_value.alloc(res->length()*2+1)) { null_value=1; return 0; } null_value=0; tmp_value.length(res->length()*2); - for (from=res->ptr(), end=from+res->length(), to= (char*) tmp_value.ptr(); - from < end ; - from++, to+=2) - { - uint tmp=(uint) (uchar) *from; - to[0]=_dig_vec_upper[tmp >> 4]; - to[1]=_dig_vec_upper[tmp & 15]; - } + + octet2hex((char*) tmp_value.ptr(), res->ptr(), res->length()); return &tmp_value; } @@ -2518,7 +2542,7 @@ String *Item_load_file::val_str(String *str) if (!(file_name= args[0]->val_str(str)) #ifndef NO_EMBEDDED_ACCESS_CHECKS - || !(current_thd->master_access & FILE_ACL) + || !(current_thd->security_ctx->master_access & FILE_ACL) #endif ) goto err; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index fa098849a43..5889821293d 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -480,12 +480,15 @@ public: class Item_func_char :public Item_str_func { public: - Item_func_char(List<Item> &list) :Item_str_func(list) {} + Item_func_char(List<Item> &list) :Item_str_func(list) + { collation.set(&my_charset_bin); } + Item_func_char(List<Item> &list, CHARSET_INFO *cs) :Item_str_func(list) + { collation.set(cs); } String *val_str(String *); void fix_length_and_dec() { - collation.set(default_charset()); - maybe_null=0; max_length=arg_count; + maybe_null=0; + max_length=arg_count * collation.collation->mbmaxlen; } const char *func_name() const { return "char"; } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a5985a6c4a9..8afc885e59b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -333,7 +333,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) return RES_OK; SELECT_LEX *select_lex= join->select_lex; - Query_arena *arena= thd->current_arena; + Query_arena *arena= thd->stmt_arena; if (!select_lex->master_unit()->first_select()->next_select() && !select_lex->table_list.elements && @@ -1287,10 +1287,10 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) */ if (!optimizer) { - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); result= (!(optimizer= new Item_in_optimizer(left_expr, this))); if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); if (result) goto err; } @@ -1306,7 +1306,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) goto err; transformed= 1; - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); /* Both transformers call fix_fields() only for Items created inside them, and all that items do not make permanent changes in current item arena @@ -1322,14 +1322,14 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) if (func != &eq_creator) { if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); my_error(ER_OPERAND_COLUMNS, MYF(0), 1); DBUG_RETURN(RES_ERROR); } res= row_value_transformer(join); } if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); err: thd->where= save_where; DBUG_RETURN(res); @@ -1413,6 +1413,12 @@ void subselect_union_engine::cleanup() } +bool subselect_union_engine::is_executed() const +{ + return unit->executed; +} + + void subselect_uniquesubquery_engine::cleanup() { DBUG_ENTER("subselect_uniquesubquery_engine::cleanup"); @@ -1468,7 +1474,7 @@ int subselect_single_select_engine::prepare() int subselect_union_engine::prepare() { - return unit->prepare(thd, result, SELECT_NO_UNLOCK, ""); + return unit->prepare(thd, result, SELECT_NO_UNLOCK); } int subselect_uniquesubquery_engine::prepare() diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 46623f76170..f1c99f74498 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -26,7 +26,6 @@ class JOIN; class select_subselect; class subselect_engine; class Item_bool_func2; -class Item_arena; /* base class for subselects */ @@ -111,6 +110,12 @@ public: return eng == 0; } /* + True if this subquery has been already evaluated. Implemented only for + single select and union subqueries only. + */ + bool is_evaluated() const; + + /* Used by max/min subquery to initialize value presence registration mechanism. Engine call this method before rexecution query. */ @@ -318,6 +323,7 @@ public: virtual void print(String *str)= 0; virtual bool change_result(Item_subselect *si, select_subselect *result)= 0; virtual bool no_tables()= 0; + virtual bool is_executed() const { return FALSE; } }; @@ -343,6 +349,7 @@ public: void print (String *str); bool change_result(Item_subselect *si, select_subselect *result); bool no_tables(); + bool is_executed() const { return executed; } }; @@ -364,6 +371,7 @@ public: void print (String *str); bool change_result(Item_subselect *si, select_subselect *result); bool no_tables(); + bool is_executed() const; }; @@ -412,3 +420,10 @@ public: int exec(); void print (String *str); }; + + +inline bool Item_subselect::is_evaluated() const +{ + return engine->is_executed(); +} + diff --git a/sql/item_sum.cc b/sql/item_sum.cc index f6544d76504..b56d99cf245 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -545,6 +545,7 @@ struct Hybrid_type_traits_fast_decimal: public val->traits->div(val, u); } static const Hybrid_type_traits_fast_decimal *instance(); + Hybrid_type_traits_fast_decimal() {}; }; static const Hybrid_type_traits_fast_decimal fast_decimal_traits_instance; @@ -1367,8 +1368,8 @@ void Item_sum_hybrid::cleanup() void Item_sum_hybrid::no_rows_in_result() { - Item_sum::no_rows_in_result(); was_values= FALSE; + clear(); } @@ -1614,7 +1615,7 @@ void Item_sum_hybrid::reset_field() else result_field->set_notnull(); } - result_field->store(nr); + result_field->store(nr, unsigned_flag); break; } case REAL_RESULT: @@ -1930,7 +1931,7 @@ Item_sum_hybrid::min_max_update_int_field() } else if (result_field->is_null(0)) result_field->set_null(); - result_field->store(old_nr); + result_field->store(old_nr, unsigned_flag); } @@ -2740,7 +2741,9 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), String *result= &item->result; Item **arg= item->args, **arg_end= item->args + item->arg_count_field; - if (result->length()) + if (item->no_appended) + item->no_appended= FALSE; + else result->append(*item->separator); tmp.length(0); @@ -2925,6 +2928,7 @@ void Item_func_group_concat::clear() result.copy(); null_value= TRUE; warning_for_row= FALSE; + no_appended= TRUE; if (tree) reset_tree(tree); /* No need to reset the table as we never call write_row */ @@ -3001,6 +3005,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) args, arg_count, MY_COLL_ALLOW_CONV)) return 1; + result.set_charset(collation.collation); result_field= 0; null_value= 1; thd->allow_sum_func= 1; diff --git a/sql/item_sum.h b/sql/item_sum.h index 32a1d8dd923..87cc248e5e4 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -23,8 +23,6 @@ #include <my_tree.h> -class Item_arena; - class Item_sum :public Item_result_field { public: @@ -883,6 +881,7 @@ class Item_func_group_concat : public Item_sum bool distinct; bool warning_for_row; bool always_null; + bool no_appended; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) @@ -914,8 +913,8 @@ public: virtual Item_result result_type () const { return STRING_RESULT; } void clear(); bool add(); - void reset_field() {} // not used - void update_field() {} // not used + void reset_field() { DBUG_ASSERT(0); } // not used + void update_field() { DBUG_ASSERT(0); } // not used bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique(); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 0d9e23ff0a1..7f94c19647e 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1030,16 +1030,17 @@ longlong Item_func_yearweek::val_int() } -/* weekday() has a automatic to_days() on item */ - longlong Item_func_weekday::val_int() { DBUG_ASSERT(fixed == 1); - ulong tmp_value=(ulong) args[0]->val_int(); - if ((null_value=(args[0]->null_value || !tmp_value))) - return 0; /* purecov: inspected */ + TIME ltime; + + if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + return 0; - return (longlong) calc_weekday(tmp_value,odbc_type)+test(odbc_type); + return (longlong) calc_weekday(calc_daynr(ltime.year, ltime.month, + ltime.day), + odbc_type) + test(odbc_type); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 4602088a5f5..8e15acbc1fc 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -257,7 +257,10 @@ public: str->set(val_int(), &my_charset_bin); return null_value ? 0 : str; } - const char *func_name() const { return "weekday"; } + const char *func_name() const + { + return (odbc_type ? "dayofweek" : "weekday"); + } enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { diff --git a/sql/lock.cc b/sql/lock.cc index 941d7baa76e..f4c4a781e45 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -93,23 +93,33 @@ static void print_lock_error(int error, const char *); flags Options: MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables. + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered + or dropped tables by itself, + mysql_lock_tables() should + notify upper level and rely + on caller doing this. + need_reopen Out parameter, TRUE if some tables were altered + or deleted and should be reopened by caller. RETURN A lock structure pointer on success. - NULL on error. + NULL on error or if some tables should be reopen. */ +/* Map the return value of thr_lock to an error from errmsg.txt */ static int thr_lock_errno_to_mysql[]= { 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK }; -MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, + uint flags, bool *need_reopen) { MYSQL_LOCK *sql_lock; TABLE *write_lock_used; int rc; - /* Map the return value of thr_lock to an error from errmsg.txt */ DBUG_ENTER("mysql_lock_tables"); + *need_reopen= FALSE; + for (;;) { if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used))) @@ -178,6 +188,11 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) thd->locked=0; retry: sql_lock=0; + if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN) + { + *need_reopen= TRUE; + break; + } if (wait_for_tables(thd)) break; // Couldn't open tables } diff --git a/sql/log.cc b/sql/log.cc index d62fa52a165..a881602d510 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -38,6 +38,7 @@ ulong sync_binlog_counter= 0; static bool test_if_number(const char *str, long *res, bool allow_wildcards); +static bool binlog_init(); static int binlog_close_connection(THD *thd); static int binlog_savepoint_set(THD *thd, void *sv); static int binlog_savepoint_rollback(THD *thd, void *sv); @@ -45,8 +46,12 @@ static int binlog_commit(THD *thd, bool all); static int binlog_rollback(THD *thd, bool all); static int binlog_prepare(THD *thd, bool all); -static handlerton binlog_hton = { +handlerton binlog_hton = { "binlog", + SHOW_OPTION_YES, + "This is a meta storage engine to represent the binlog in a transaction", + DB_TYPE_UNKNOWN, /* IGNORE for now */ + binlog_init, 0, sizeof(my_off_t), /* savepoint size = binlog offset */ binlog_close_connection, @@ -61,7 +66,7 @@ static handlerton binlog_hton = { NULL, /* rollback_by_xid */ NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ - NULL, /* close_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; @@ -71,9 +76,9 @@ static handlerton binlog_hton = { should be moved here. */ -handlerton *binlog_init() +bool binlog_init() { - return &binlog_hton; + return !opt_bin_log; } static int binlog_close_connection(THD *thd) @@ -353,7 +358,7 @@ MYSQL_LOG::MYSQL_LOG() :bytes_written(0), last_time(0), query_start(0), name(0), file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0), need_start_event(1), prepared_xids(0), description_event_for_exec(0), - description_event_for_queue(0) + description_event_for_queue(0), readers_count(0), reset_pending(false) { /* We don't want to initialize LOCK_Log here as such initialization depends on @@ -379,7 +384,9 @@ void MYSQL_LOG::cleanup() delete description_event_for_exec; (void) pthread_mutex_destroy(&LOCK_log); (void) pthread_mutex_destroy(&LOCK_index); + (void) pthread_mutex_destroy(&LOCK_readers); (void) pthread_cond_destroy(&update_cond); + (void) pthread_cond_destroy(&reset_cond); } DBUG_VOID_RETURN; } @@ -424,7 +431,9 @@ void MYSQL_LOG::init_pthread_objects() inited= 1; (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW); + (void) pthread_mutex_init(&LOCK_readers, MY_MUTEX_INIT_SLOW); (void) pthread_cond_init(&update_cond, 0); + (void) pthread_cond_init(&reset_cond, 0); } const char *MYSQL_LOG::generate_name(const char *log_name, @@ -927,6 +936,13 @@ bool MYSQL_LOG::reset_logs(THD* thd) */ pthread_mutex_lock(&LOCK_log); pthread_mutex_lock(&LOCK_index); + + /* + we need one more lock to block attempts to open a log while + we are waiting untill all log files will be closed + */ + pthread_mutex_lock(&LOCK_readers); + /* The following mutex is needed to ensure that no threads call 'delete thd' as we would then risk missing a 'rollback' from this @@ -949,6 +965,19 @@ bool MYSQL_LOG::reset_logs(THD* thd) goto err; } + reset_pending= true; + /* + send update signal just in case so that all reader threads waiting + for log update will leave wait condition + */ + signal_update(); + /* + if there are active readers wait until all of them will + release opened files + */ + if (readers_count) + pthread_cond_wait(&reset_cond, &LOCK_log); + for (;;) { my_delete(linfo.log_file_name, MYF(MY_WME)); @@ -967,7 +996,10 @@ bool MYSQL_LOG::reset_logs(THD* thd) my_free((gptr) save_name, MYF(0)); err: + reset_pending= false; + (void) pthread_mutex_unlock(&LOCK_thread_count); + pthread_mutex_unlock(&LOCK_readers); pthread_mutex_unlock(&LOCK_index); pthread_mutex_unlock(&LOCK_log); DBUG_RETURN(error); @@ -1348,7 +1380,8 @@ void MYSQL_LOG::new_file(bool need_lock) to change base names at some point. */ THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */ - Rotate_log_event r(thd,new_name+dirname_length(new_name)); + Rotate_log_event r(thd,new_name+dirname_length(new_name), + 0, LOG_EVENT_OFFSET, 0); r.write(&log_file); bytes_written += r.data_written; } @@ -1427,7 +1460,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...) DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - pthread_mutex_lock(&LOCK_log); + safe_mutex_assert_owner(&LOCK_log); do { if (my_b_append(&log_file,(byte*) buf,len)) @@ -1442,7 +1475,6 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...) new_file(0); err: - pthread_mutex_unlock(&LOCK_log); if (!error) signal_update(); DBUG_RETURN(error); @@ -1476,7 +1508,7 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, { // Normal thread if ((thd->options & OPTION_LOG_OFF) #ifndef NO_EMBEDDED_ACCESS_CHECKS - && (thd->master_access & SUPER_ACL) + && (thd->security_ctx->master_access & SUPER_ACL) #endif ) { @@ -1559,6 +1591,7 @@ void MYSQL_LOG::start_union_events(THD *thd) thd->binlog_evt_union.do_union= TRUE; thd->binlog_evt_union.unioned_events= FALSE; thd->binlog_evt_union.unioned_events_trans= FALSE; + thd->binlog_evt_union.first_query_id= thd->query_id; } void MYSQL_LOG::stop_union_events(THD *thd) @@ -1567,6 +1600,12 @@ void MYSQL_LOG::stop_union_events(THD *thd) thd->binlog_evt_union.do_union= FALSE; } +bool MYSQL_LOG::is_query_in_union(THD *thd, query_id_t query_id_param) +{ + return (thd->binlog_evt_union.do_union && + query_id_param >= thd->binlog_evt_union.first_query_id); +} + /* Write an event to the binary log */ @@ -1843,7 +1882,9 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) if (commit_event->write(&log_file)) goto err; +#ifndef DBUG_OFF DBUG_skip_commit: +#endif if (flush_and_sync()) goto err; DBUG_EXECUTE_IF("half_binlogged_transaction", abort();); @@ -1908,6 +1949,7 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, } if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT) || query_start_arg) { + Security_context *sctx= thd->security_ctx; current_time=time(NULL); if (current_time != last_time) { @@ -1928,10 +1970,12 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, tmp_errno=errno; } if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n", - thd->priv_user ? thd->priv_user : "", - thd->user ? thd->user : "", - thd->host ? thd->host : "", - thd->ip ? thd->ip : "") == (uint) -1) + sctx->priv_user ? + sctx->priv_user : "", + sctx->user ? sctx->user : "", + sctx->host ? sctx->host : "", + sctx->ip ? sctx->ip : "") == + (uint) -1) tmp_errno=errno; } if (query_start_arg) @@ -2028,6 +2072,10 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave) { const char *old_msg; DBUG_ENTER("wait_for_update"); + + if (reset_pending) + DBUG_VOID_RETURN; + old_msg= thd->enter_cond(&update_cond, &LOCK_log, is_slave ? "Has read all relay log; waiting for the slave I/O " @@ -2278,6 +2326,32 @@ void MYSQL_LOG::signal_update() DBUG_VOID_RETURN; } +void MYSQL_LOG::readers_addref() +{ + /* + There is no necessity for reference counting on *nix, since it allows to + delete opened files, however it is more clean way to wait + untill all files will be closed on *nix as well. + */ + DBUG_ENTER("MYSQL_LOG::reader_addref"); + pthread_mutex_lock(&LOCK_log); + pthread_mutex_lock(&LOCK_readers); + readers_count++; + pthread_mutex_unlock(&LOCK_readers); + pthread_mutex_unlock(&LOCK_log); + DBUG_VOID_RETURN; +} + +void MYSQL_LOG::readers_release() +{ + DBUG_ENTER("MYSQL_LOG::reader_release"); + pthread_mutex_lock(&LOCK_log); + readers_count--; + if (!readers_count) + pthread_cond_broadcast(&reset_cond); + pthread_mutex_unlock(&LOCK_log); + DBUG_VOID_RETURN; +} #ifdef __NT__ void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, @@ -2783,7 +2857,7 @@ void TC_LOG_MMAP::close() case 3: my_free((gptr)pages, MYF(0)); case 2: - my_munmap(data, (size_t)file_length); + my_munmap((byte*)data, (size_t)file_length); case 1: my_close(fd, MYF(0)); } diff --git a/sql/log_event.cc b/sql/log_event.cc index e7eb9c7bda6..2ec63febca4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -121,8 +121,9 @@ static char *pretty_print_str(char *packet, char *str, int len) static inline char* slave_load_file_stem(char*buf, uint file_id, int event_server_id) { - fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", - MY_UNPACK_FILENAME | MY_UNIX_PATH); + fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME); + to_unix_path(buf); + buf = strend(buf); buf = int10_to_str(::server_id, buf, 10); *buf++ = '-'; @@ -211,24 +212,18 @@ static inline int read_str(char **buf, char *buf_end, char **str, /* Transforms a string into "" or its expression in 0x... form. */ + char *str_to_hex(char *to, const char *from, uint len) { - char *p= to; if (len) { - p= strmov(p, "0x"); - for (uint i= 0; i < len; i++, p+= 2) - { - /* val[i] is char. Casting to uchar helps greatly if val[i] < 0 */ - uint tmp= (uint) (uchar) from[i]; - p[0]= _dig_vec_upper[tmp >> 4]; - p[1]= _dig_vec_upper[tmp & 15]; - } - *p= 0; + *to++= '0'; + *to++= 'x'; + to= octet2hex(to, from, len); } else - p= strmov(p, "\"\""); - return p; // pointer to end 0 of 'to' + to= strmov(to, "\"\""); + return to; // pointer to end 0 of 'to' } /* @@ -1165,7 +1160,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, But it's likely that we don't want to use 32 bits for 3 bits; in the future we will probably want to reclaim the 29 bits. So we need the &. */ - flags2= thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG; + flags2= (uint32) (thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG); DBUG_ASSERT(thd->variables.character_set_client->number < 256*256); DBUG_ASSERT(thd->variables.collation_connection->number < 256*256); DBUG_ASSERT(thd->variables.collation_server->number < 256*256); @@ -1554,6 +1549,16 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query clear_all_errors(thd, rli); + /* + Note: We do not need to execute reset_one_shot_variables() if this + db_ok() test fails. + Reason: The db stored in binlog events is the same for SET and for + its companion query. If the SET is ignored because of + db_ok(), the companion query will also be ignored, and if + the companion query is ignored in the db_ok() test of + ::exec_event(), then the companion SET also have so we + don't need to reset_one_shot_variables(). + */ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { thd->set_time((time_t)when); @@ -2703,6 +2708,16 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, Create_file_log_event::exec_event() and then discarding Append_block and al. Another way is do the filtering in the I/O thread (more efficient: no disk writes at all). + + + Note: We do not need to execute reset_one_shot_variables() if this + db_ok() test fails. + Reason: The db stored in binlog events is the same for SET and for + its companion query. If the SET is ignored because of + db_ok(), the companion query will also be ignored, and if + the companion query is ignored in the db_ok() test of + ::exec_event(), then the companion SET also have so we + don't need to reset_one_shot_variables(). */ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { @@ -2947,13 +2962,38 @@ void Rotate_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ #endif /* MYSQL_CLIENT */ + /* - Rotate_log_event::Rotate_log_event() + Rotate_log_event::Rotate_log_event() (2 constructors) */ + +#ifndef MYSQL_CLIENT +Rotate_log_event::Rotate_log_event(THD* thd_arg, + const char* new_log_ident_arg, + uint ident_len_arg, ulonglong pos_arg, + uint flags_arg) + :Log_event(), new_log_ident(new_log_ident_arg), + pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg : + (uint) strlen(new_log_ident_arg)), flags(flags_arg) +{ +#ifndef DBUG_OFF + char buff[22]; + DBUG_ENTER("Rotate_log_event::Rotate_log_event(THD*,...)"); + DBUG_PRINT("enter",("new_log_ident %s pos %s flags %lu", new_log_ident_arg, + llstr(pos_arg, buff), flags)); +#endif + if (flags & DUP_NAME) + new_log_ident= my_strdup_with_length((const byte*) new_log_ident_arg, + ident_len, MYF(MY_WME)); + DBUG_VOID_RETURN; +} +#endif + + Rotate_log_event::Rotate_log_event(const char* buf, uint event_len, const Format_description_log_event* description_event) - :Log_event(buf, description_event) ,new_log_ident(NULL),alloced(0) + :Log_event(buf, description_event) ,new_log_ident(0), flags(DUP_NAME) { DBUG_ENTER("Rotate_log_event::Rotate_log_event(char*,...)"); // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET @@ -2968,12 +3008,9 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len, (header_size+post_header_len)); ident_offset = post_header_len; set_if_smaller(ident_len,FN_REFLEN-1); - if (!(new_log_ident= my_strdup_with_length((byte*) buf + - ident_offset, - (uint) ident_len, - MYF(MY_WME)))) - DBUG_VOID_RETURN; - alloced = 1; + new_log_ident= my_strdup_with_length((byte*) buf + ident_offset, + (uint) ident_len, + MYF(MY_WME)); DBUG_VOID_RETURN; } diff --git a/sql/log_event.h b/sql/log_event.h index 1d8941e65ac..b0f76aa1034 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1177,9 +1177,6 @@ class Xid_log_event: public Log_event Every time a query uses the value of a user variable, a User_var_log_event is written before the Query_log_event, to set the user variable. - Every time a query uses the value of a user variable, a User_var_log_event is - written before the Query_log_event, to set the user variable. - ****************************************************************************/ class User_var_log_event: public Log_event @@ -1250,18 +1247,17 @@ public: class Rotate_log_event: public Log_event { public: + enum { + DUP_NAME= 2 // if constructor should dup the string argument + }; const char* new_log_ident; ulonglong pos; uint ident_len; - bool alloced; + uint flags; #ifndef MYSQL_CLIENT Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg, - uint ident_len_arg = 0, - ulonglong pos_arg = LOG_EVENT_OFFSET) - :Log_event(), new_log_ident(new_log_ident_arg), - pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg : - (uint) strlen(new_log_ident_arg)), alloced(0) - {} + uint ident_len_arg, + ulonglong pos_arg, uint flags); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); @@ -1274,8 +1270,8 @@ public: const Format_description_log_event* description_event); ~Rotate_log_event() { - if (alloced) - my_free((gptr) new_log_ident, MYF(0)); + if (flags & DUP_NAME) + my_free((gptr) new_log_ident, MYF(MY_ALLOW_ZERO_PTR)); } Log_event_type get_type_code() { return ROTATE_EVENT;} int get_data_size() { return ident_len + ROTATE_HEADER_LEN;} diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7e21a19bd66..e33ac05e293 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -284,7 +284,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; /* Flag set if setup_tables already done */ #define OPTION_SETUP_TABLES_DONE (1L << 30) // intern /* If not set then the thread will ignore all warnings with level notes. */ -#define OPTION_SQL_NOTES (1L << 31) // THD, user +#define OPTION_SQL_NOTES (1UL << 31) // THD, user /* Force the used temporary table to be a MyISAM table (because we will use fulltext functions when reading from it. @@ -379,6 +379,10 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); #define SHOW_LOG_STATUS_FREE "FREE" #define SHOW_LOG_STATUS_INUSE "IN USE" +struct st_table_list; +class String; +void view_store_options(THD *thd, st_table_list *table, String *buff); + /* Options to add_table_to_list() */ #define TL_OPTION_UPDATING 1 #define TL_OPTION_FORCE_INDEX 2 @@ -408,7 +412,6 @@ enum enum_parsing_place struct st_table; class THD; -class Item_arena; /* Struct to handle simple linked lists */ @@ -481,6 +484,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, #include "protocol.h" #include "sql_udf.h" class user_var_entry; +class Security_context; enum enum_var_type { OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL @@ -512,6 +516,8 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables); bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); +bool default_view_definer(Security_context *sctx, st_lex_user *definer); + enum enum_mysql_completiontype { ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7, @@ -532,6 +538,7 @@ struct Query_cache_query_flags unsigned int client_long_flag:1; unsigned int client_protocol_41:1; unsigned int more_results_exists:1; + unsigned int pkt_nr; uint character_set_client_num; uint character_set_results_num; uint collation_connection_num; @@ -546,6 +553,7 @@ struct Query_cache_query_flags #define query_cache_store_query(A, B) query_cache.store_query(A, B) #define query_cache_destroy() query_cache.destroy() #define query_cache_result_size_limit(A) query_cache.result_size_limit(A) +#define query_cache_init() query_cache.init() #define query_cache_resize(A) query_cache.resize(A) #define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A) #define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C) @@ -559,6 +567,7 @@ struct Query_cache_query_flags #define query_cache_store_query(A, B) #define query_cache_destroy() #define query_cache_result_size_limit(A) +#define query_cache_init() #define query_cache_resize(A) #define query_cache_set_min_res_unit(A) #define query_cache_invalidate3(A, B, C) @@ -590,7 +599,7 @@ bool mysql_change_db(THD *thd,const char *name,bool no_access_check); void mysql_parse(THD *thd,char *inBuf,uint length); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); bool is_update_query(enum enum_sql_command command); -bool alloc_query(THD *thd, char *packet, ulong packet_length); +bool alloc_query(THD *thd, const char *packet, uint packet_length); void mysql_init_select(LEX *lex); void mysql_reset_thd_for_next_command(THD *thd); void mysql_init_query(THD *thd, uchar *buf, uint length); @@ -601,8 +610,8 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void init_max_user_conn(void); void init_update_queries(void); void free_max_user_conn(void); -extern "C" pthread_handler_decl(handle_one_connection,arg); -extern "C" pthread_handler_decl(handle_bootstrap,arg); +pthread_handler_t handle_one_connection(void *arg); +pthread_handler_t handle_bootstrap(void *arg); void end_thread(THD *thd,bool put_in_cache); void flush_thread_cache(); bool mysql_execute_command(THD *thd); @@ -620,7 +629,7 @@ void close_connection(THD *thd, uint errcode, bool lock); bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, bool *write_to_binlog); bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv, - bool no_grant, bool no_errors); + bool no_grant, bool no_errors, bool schema_db); bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, bool no_errors); bool check_global_access(THD *thd, ulong want_access); @@ -748,7 +757,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem, bool *refresh, uint flags); -TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table); +bool reopen_name_locked_table(THD* thd, TABLE_LIST* table); TABLE *find_locked_table(THD *thd, const char *db,const char *table_name); bool reopen_table(TABLE *table,bool locked); bool reopen_tables(THD *thd,bool get_locks,bool in_refresh); @@ -847,18 +856,21 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); bool get_schema_tables_result(JOIN *join); +#define is_schema_db(X) \ + !my_strcasecmp(system_charset_info, information_schema_name.str, (X)) /* sql_prepare.cc */ -bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, - LEX_STRING *name); + +void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length); void mysql_stmt_execute(THD *thd, char *packet, uint packet_length); -void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name); -void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length); void mysql_stmt_close(THD *thd, char *packet); +void mysql_sql_stmt_prepare(THD *thd); +void mysql_sql_stmt_execute(THD *thd); +void mysql_sql_stmt_close(THD *thd); +void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length); void mysql_stmt_reset(THD *thd, char *packet); void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); void reinit_stmt_before_use(THD *thd, LEX *lex); -void init_stmt_after_parse(THD*, LEX*); /* sql_handler.cc */ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen); @@ -897,6 +909,9 @@ void add_join_on(TABLE_LIST *b,Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields); bool add_proc_to_list(THD *thd, Item *item); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); +void update_non_unique_table_error(TABLE_LIST *update, + const char *operation, + TABLE_LIST *duplicate); SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, @@ -939,7 +954,7 @@ int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags); -int lock_tables(THD *thd, TABLE_LIST *tables, uint counter); +int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); bool rm_temporary_table(enum db_type base, char *path); @@ -947,6 +962,7 @@ void free_io_cache(TABLE *entry); void intern_close_table(TABLE *entry); bool close_thread_table(THD *thd, TABLE **table_ptr); void close_temporary_tables(THD *thd); +void close_tables_for_reopen(THD *thd, TABLE_LIST *tables); TABLE_LIST *find_table_in_list(TABLE_LIST *table, uint offset_to_list, const char *db_name, @@ -1019,7 +1035,7 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info); extern ulong volatile manager_status; extern bool volatile manager_thread_in_use, mqh_used; extern pthread_t manager_thread; -extern "C" pthread_handler_decl(handle_manager, arg); +pthread_handler_t handle_manager(void *arg); /* sql_test.cc */ #ifndef DBUG_OFF @@ -1054,7 +1070,6 @@ bool fn_format_relative_to_data_home(my_string to, const char *name, const char *dir, const char *extension); File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg); -handlerton *binlog_init(); /* mysqld.cc */ extern void yyerror(const char*); @@ -1139,11 +1154,13 @@ extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; extern uint test_flags,select_errors,ha_open_options; extern uint protocol_version, mysqld_port, dropping_tables; extern uint delay_key_write_options, lower_case_table_names; -extern bool opt_endinfo, using_udf_functions, locked_in_memory; +extern bool opt_endinfo, using_udf_functions; +extern my_bool locked_in_memory; extern bool opt_using_transactions, mysqld_embedded; extern bool using_update_log, opt_large_files, server_id_supplied; extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log; extern bool opt_disable_networking, opt_skip_show_db; +extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress, grant_option; extern bool mysql_proc_table_exists; extern uint volatile thread_count, thread_running, global_read_lock; @@ -1158,7 +1175,7 @@ extern my_bool sp_automatic_privileges, opt_noacl; extern my_bool opt_old_style_user_limits, trust_routine_creators; extern uint opt_crash_binlog_innodb; extern char *shared_memory_base_name, *mysqld_unix_port; -extern bool opt_enable_shared_memory; +extern my_bool opt_enable_shared_memory; extern char *default_tz_name; extern my_bool opt_large_pages; extern uint opt_large_page_size; @@ -1224,10 +1241,12 @@ extern pthread_t signal_thread; extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ -MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags); +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, + uint flags, bool *need_reopen); /* mysql_lock_tables() flags bits */ #define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001 #define MYSQL_LOCK_IGNORE_FLUSH 0x0002 +#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004 void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); @@ -1315,6 +1334,8 @@ void change_byte(byte *,uint,char,char); void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, int use_record_cache, bool print_errors); +void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, + bool print_error, uint idx); void end_read_record(READ_RECORD *info); ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder, uint s_length, SQL_SELECT *select, @@ -1362,8 +1383,8 @@ extern int sql_cache_hit(THD *thd, char *inBuf, uint length); /* item_func.cc */ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, LEX_STRING component); -int get_var_with_binlog(THD *thd, LEX_STRING &name, - user_var_entry **out_entry); +int get_var_with_binlog(THD *thd, enum_sql_command sql_command, + LEX_STRING &name, user_var_entry **out_entry); /* log.cc */ bool flush_error_log(void); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f58dd72f6b5..e51eb481767 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -294,7 +294,7 @@ bool opt_large_files= sizeof(my_off_t) > 4; /* Used with --help for detailed option */ -static bool opt_help= 0, opt_verbose= 0; +static my_bool opt_help= 0, opt_verbose= 0; arg_cmp_func Arg_comparator::comparator_matrix[5][2] = {{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string}, @@ -338,8 +338,10 @@ static my_bool opt_sync_bdb_logs; bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +my_bool opt_character_set_client_handshake= 1; bool server_id_supplied = 0; -bool opt_endinfo,using_udf_functions, locked_in_memory; +bool opt_endinfo,using_udf_functions; +my_bool locked_in_memory; bool opt_using_transactions, using_update_log; bool volatile abort_loop; bool volatile shutdown_in_progress, grant_option; @@ -431,6 +433,7 @@ char server_version[SERVER_VERSION_LENGTH]; char *mysqld_unix_port, *opt_mysql_tmpdir; const char **errmesg; /* Error messages */ const char *myisam_recover_options_str="OFF"; +const char *myisam_stats_method_str="nulls_unequal"; /* name of reference on left espression in rewritten IN subquery */ const char *in_left_expr_name= "<left expr>"; /* name of additional condition */ @@ -570,12 +573,26 @@ Query_cache query_cache; #endif #ifdef HAVE_SMEM char *shared_memory_base_name= default_shared_memory_base_name; -bool opt_enable_shared_memory; +my_bool opt_enable_shared_memory; HANDLE smem_event_connect_request= 0; #endif #include "sslopt-vars.h" #ifdef HAVE_OPENSSL +#include <openssl/crypto.h> +#ifndef HAVE_YASSL +typedef struct CRYPTO_dynlock_value +{ + rw_lock_t lock; +} openssl_lock_t; + +static openssl_lock_t *openssl_stdlocks; +static openssl_lock_t *openssl_dynlock_create(const char *, int); +static void openssl_dynlock_destroy(openssl_lock_t *, const char *, int); +static void openssl_lock_function(int, int, const char *, int); +static void openssl_lock(int, openssl_lock_t *, const char *, int); +static unsigned long openssl_id_function(); +#endif char *des_key_file; struct st_VioSSLAcceptorFd *ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ @@ -584,25 +601,25 @@ struct st_VioSSLAcceptorFd *ssl_acceptor_fd; /* Function declarations */ static void start_signal_handler(void); -static pthread_handler_decl(signal_hand, arg); +pthread_handler_t signal_hand(void *arg); static void mysql_init_variables(void); static void get_options(int argc,char **argv); static void set_server_version(void); static int init_thread_environment(); static char *get_relative_path(const char *path); static void fix_paths(void); -extern "C" pthread_handler_decl(handle_connections_sockets,arg); -extern "C" pthread_handler_decl(kill_server_thread,arg); +pthread_handler_t handle_connections_sockets(void *arg); +pthread_handler_t kill_server_thread(void *arg); static void bootstrap(FILE *file); static void close_server_sock(); static bool read_init_file(char *file_name); #ifdef __NT__ -extern "C" pthread_handler_decl(handle_connections_namedpipes,arg); +pthread_handler_t handle_connections_namedpipes(void *arg); #endif #ifdef HAVE_SMEM -static pthread_handler_decl(handle_connections_shared_memory,arg); +pthread_handler_t handle_connections_shared_memory(void *arg); #endif -extern "C" pthread_handler_decl(handle_slave,arg); +pthread_handler_t handle_slave(void *arg); static ulong find_bit_type(const char *x, TYPELIB *bit_lib); static void clean_up(bool print_message); static void clean_up_mutexes(void); @@ -775,7 +792,9 @@ static void close_connections(void) { if (global_system_variables.log_warnings) sql_print_warning(ER(ER_FORCING_CLOSE),my_progname, - tmp->thread_id,tmp->user ? tmp->user : ""); + tmp->thread_id, + (tmp->main_security_ctx.user ? + tmp->main_security_ctx.user : "")); close_connection(tmp,0,0); } #endif @@ -909,7 +928,7 @@ static void __cdecl kill_server(int sig_ptr) RETURN_FROM_KILL_SERVER; kill_in_progress=TRUE; abort_loop=1; // This should be set - signal(sig,SIG_IGN); + my_sigset(sig,SIG_IGN); if (sig == MYSQL_KILL_SIGNAL || sig == 0) sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname); else @@ -949,7 +968,7 @@ static void __cdecl kill_server(int sig_ptr) #if defined(USE_ONE_SIGNAL_HAND) || (defined(__NETWARE__) && defined(SIGNALS_DONT_BREAK_READ)) -extern "C" pthread_handler_decl(kill_server_thread,arg __attribute__((unused))) +pthread_handler_t kill_server_thread(void *arg __attribute__((unused))) { my_thread_init(); // Initialize new thread kill_server(0); @@ -958,11 +977,6 @@ extern "C" pthread_handler_decl(kill_server_thread,arg __attribute__((unused))) } #endif -#if defined(__amiga__) -#undef sigset -#define sigset signal -#endif - extern "C" sig_handler print_signal_warning(int sig) { if (!DBUG_IN_USE) @@ -972,7 +986,7 @@ extern "C" sig_handler print_signal_warning(int sig) sig,my_thread_id()); } #ifdef DONT_REMEMBER_SIGNAL - sigset(sig,print_signal_warning); /* int. thread system calls */ + my_sigset(sig,print_signal_warning); /* int. thread system calls */ #endif #if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) if (sig == SIGALRM) @@ -1094,7 +1108,7 @@ void clean_up(bool print_message) my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR)); #endif /* HAVE_OPENSSL */ #ifdef USE_REGEX - regex_end(); + my_regex_end(); #endif if (print_message && errmesg) @@ -1165,6 +1179,11 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_user_conn); #ifdef HAVE_OPENSSL (void) pthread_mutex_destroy(&LOCK_des_key_file); +#ifndef HAVE_YASSL + for (int i= 0; i < CRYPTO_num_locks(); ++i) + (void) rwlock_destroy(&openssl_stdlocks[i].lock); + OPENSSL_free(openssl_stdlocks); +#endif #endif #ifdef HAVE_REPLICATION (void) pthread_mutex_destroy(&LOCK_rpl_status); @@ -2050,8 +2069,8 @@ static void init_signals(void) DBUG_ENTER("init_signals"); if (test_flags & TEST_SIGINT) - sigset(THR_KILL_SIGNAL,end_thread_signal); - sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! + my_sigset(THR_KILL_SIGNAL,end_thread_signal); + my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) { @@ -2085,13 +2104,8 @@ static void init_signals(void) } #endif (void) sigemptyset(&set); -#ifdef THREAD_SPECIFIC_SIGPIPE - sigset(SIGPIPE,abort_thread); - sigaddset(&set,SIGPIPE); -#else - (void) signal(SIGPIPE,SIG_IGN); // Can't know which thread + my_sigset(SIGPIPE,SIG_IGN); sigaddset(&set,SIGPIPE); -#endif sigaddset(&set,SIGINT); #ifndef IGNORE_SIGHUP_SIGQUIT sigaddset(&set,SIGQUIT); @@ -2162,7 +2176,7 @@ static void start_signal_handler(void) /* This threads handles all signals and alarms */ /* ARGSUSED */ -static void *signal_hand(void *arg __attribute__((unused))) +pthread_handler_t signal_hand(void *arg __attribute__((unused))) { sigset_t set; int sig; @@ -2318,6 +2332,8 @@ static int my_message_sql(uint error, const char *str, myf MyFlags) if (thd->spcont && thd->spcont->find_handler(error, MYSQL_ERROR::WARN_LEVEL_ERROR)) { + if (! thd->spcont->found_handler_here()) + thd->net.report_error= 1; /* Make "select" abort correctly */ DBUG_RETURN(0); } @@ -2383,7 +2399,7 @@ int uname(struct utsname *a) } -extern "C" pthread_handler_decl(handle_shutdown,arg) +pthread_handler_t handle_shutdown(void *arg) { MSG msg; my_thread_init(); @@ -2412,7 +2428,7 @@ int STDCALL handle_kill(ulong ctrl_type) #ifdef OS2 -extern "C" pthread_handler_decl(handle_shutdown,arg) +pthread_handler_t handle_shutdown(void *arg) { my_thread_init(); @@ -2601,7 +2617,7 @@ static int init_common_variables(const char *conf_file_name, int argc, set_var_init(); mysys_uses_curses=0; #ifdef USE_REGEX - regex_init(&my_charset_latin1); + my_regex_init(&my_charset_latin1); #endif if (!(default_charset_info= get_charset_by_csname(default_character_set_name, MY_CS_PRIMARY, @@ -2721,6 +2737,17 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST); #ifdef HAVE_OPENSSL (void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST); +#ifndef HAVE_YASSL + openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() * + sizeof(openssl_lock_t)); + for (int i= 0; i < CRYPTO_num_locks(); ++i) + (void) my_rwlock_init(&openssl_stdlocks[i].lock, NULL); + CRYPTO_set_dynlock_create_callback(openssl_dynlock_create); + CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy); + CRYPTO_set_dynlock_lock_callback(openssl_lock); + CRYPTO_set_locking_callback(openssl_lock_function); + CRYPTO_set_id_callback(openssl_id_function); +#endif #endif (void) my_rwlock_init(&LOCK_sys_init_connect, NULL); (void) my_rwlock_init(&LOCK_sys_init_slave, NULL); @@ -2753,6 +2780,75 @@ static int init_thread_environment() } +#if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) +static unsigned long openssl_id_function() +{ + return (unsigned long) pthread_self(); +} + + +static openssl_lock_t *openssl_dynlock_create(const char *file, int line) +{ + openssl_lock_t *lock= new openssl_lock_t; + my_rwlock_init(&lock->lock, NULL); + return lock; +} + + +static void openssl_dynlock_destroy(openssl_lock_t *lock, const char *file, + int line) +{ + rwlock_destroy(&lock->lock); + delete lock; +} + + +static void openssl_lock_function(int mode, int n, const char *file, int line) +{ + if (n < 0 || n > CRYPTO_num_locks()) + { + /* Lock number out of bounds. */ + sql_print_error("Fatal: OpenSSL interface problem (n = %d)", n); + abort(); + } + openssl_lock(mode, &openssl_stdlocks[n], file, line); +} + + +static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, + int line) +{ + int err; + char const *what; + + switch (mode) { + case CRYPTO_LOCK|CRYPTO_READ: + what = "read lock"; + err = rw_rdlock(&lock->lock); + break; + case CRYPTO_LOCK|CRYPTO_WRITE: + what = "write lock"; + err = rw_wrlock(&lock->lock); + break; + case CRYPTO_UNLOCK|CRYPTO_READ: + case CRYPTO_UNLOCK|CRYPTO_WRITE: + what = "unlock"; + err = rw_unlock(&lock->lock); + break; + default: + /* Unknown locking mode. */ + sql_print_error("Fatal: OpenSSL interface problem (mode=0x%x)", mode); + abort(); + } + if (err) + { + sql_print_error("Fatal: can't %s OpenSSL %s lock", what); + abort(); + } +} +#endif /* HAVE_OPENSSL */ + + static void init_ssl() { #ifdef HAVE_OPENSSL @@ -2780,6 +2876,7 @@ static int init_server_components() query_cache_result_size_limit(query_cache_limit); query_cache_set_min_res_unit(query_cache_min_res_unit); + query_cache_init(); query_cache_resize(query_cache_size); randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); reset_floating_point_exceptions(); @@ -3254,7 +3351,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); */ error_handler_hook= my_message_sql; start_signal_handler(); // Creates pidfile - if (acl_init((THD *)0, opt_noacl) || + if (acl_init(opt_noacl) || my_tz_init((THD *)0, default_tz_name, opt_bootstrap)) { abort_loop=1; @@ -3271,7 +3368,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); exit(1); } if (!opt_noacl) - (void) grant_init((THD *)0); + (void) grant_init(); #ifdef HAVE_DLOPEN if (!opt_noacl) @@ -3577,10 +3674,9 @@ static void bootstrap(FILE *file) THD *thd= new THD; thd->bootstrap=1; - thd->client_capabilities=0; my_net_init(&thd->net,(st_vio*) 0); thd->max_client_packet_length= thd->net.max_packet; - thd->master_access= ~(ulong)0; + thd->security_ctx->master_access= ~(ulong)0; thd->thread_id=thread_id++; thread_count++; @@ -3725,8 +3821,7 @@ inline void kill_broken_server() /* Handle new connections and spawn new process to handle them */ #ifndef EMBEDDED_LIBRARY -extern "C" pthread_handler_decl(handle_connections_sockets, - arg __attribute__((unused))) +pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) { my_socket sock,new_sock; uint error_count=0; @@ -3920,7 +4015,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets, continue; } if (sock == unix_sock) - thd->host=(char*) my_localhost; + thd->security_ctx->host=(char*) my_localhost; #ifdef __WIN__ /* Set default wait_timeout */ ulong wait_timeout= global_system_variables.net_wait_timeout * 1000; @@ -3940,7 +4035,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets, #ifdef __NT__ -extern "C" pthread_handler_decl(handle_connections_namedpipes,arg) +pthread_handler_t handle_connections_namedpipes(void *arg) { HANDLE hConnectedPipe; BOOL fConnected; @@ -4011,8 +4106,8 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg) delete thd; continue; } - /* host name is unknown */ - thd->host = my_strdup(my_localhost,MYF(0)); /* Host is unknown */ + /* Host is unknown */ + thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); create_new_thread(thd); } @@ -4026,17 +4121,16 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg) Thread of shared memory's service SYNOPSIS - pthread_handler_decl() - handle_connections_shared_memory Thread handle + handle_connections_shared_memory() arg Arguments of thread */ #ifdef HAVE_SMEM -pthread_handler_decl(handle_connections_shared_memory,arg) +pthread_handler_t handle_connections_shared_memory(void *arg) { /* file-mapping object, use for create shared memory */ HANDLE handle_connect_file_map= 0; - char *handle_connect_map= 0; // pointer on shared memory + char *handle_connect_map= 0; // pointer on shared memory HANDLE event_connect_answer= 0; ulong smem_buffer_length= shared_memory_buffer_length + 4; ulong connect_number= 1; @@ -4203,7 +4297,7 @@ pthread_handler_decl(handle_connections_shared_memory,arg) errmsg= 0; goto errorconn; } - thd->host= my_strdup(my_localhost,MYF(0)); /* Host is unknown */ + thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); /* Host is unknown */ create_new_thread(thd); connect_number++; continue; @@ -4356,6 +4450,7 @@ enum options_mysqld OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, + OPT_MYISAM_STATS_METHOD, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT, OPT_OPEN_FILES_LIMIT, @@ -4410,6 +4505,7 @@ enum options_mysqld OPT_EXPIRE_LOGS_DAYS, OPT_GROUP_CONCAT_MAX_LEN, OPT_DEFAULT_COLLATION, + OPT_CHARACTER_SET_CLIENT_HANDSHAKE, OPT_INIT_CONNECT, OPT_INIT_SLAVE, OPT_SECURE_AUTH, @@ -4511,6 +4607,11 @@ Disable with --skip-bdb (will save memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, + "Don't use client side character set value sent during handshake.", + (gptr*) &opt_character_set_client_handshake, + (gptr*) &opt_character_set_client_handshake, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"character-set-server", 'C', "Set the default character set.", (gptr*) &default_character_set_name, (gptr*) &default_character_set_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, @@ -5505,6 +5606,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.myisam_sort_buff_size, (gptr*) &max_system_variables.myisam_sort_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0}, + {"myisam_stats_method", OPT_MYISAM_STATS_METHOD, + "Specifies how MyISAM index statistics collection code should threat NULLs. " + "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).", + (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "Buffer length for TCP/IP and socket communication.", (gptr*) &global_system_variables.net_buffer_length, @@ -5580,7 +5686,8 @@ The minimum value for this variable is 4096.", "Persistent buffer for query parsing and execution", (gptr*) &global_system_variables.query_prealloc_size, (gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG, - REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 16384, ~0L, 0, 1024, 0}, + REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, QUERY_ALLOC_PREALLOC_SIZE, + ~0L, 0, 1024, 0}, {"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE, "Allocation block size for storing ranges during optimization", (gptr*) &global_system_variables.range_alloc_block_size, @@ -5813,6 +5920,7 @@ struct show_var_st status_vars[]= { {"Com_show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS}, {"Com_show_logs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_LOGS]), SHOW_LONG_STATUS}, {"Com_show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS}, + {"Com_show_ndb_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NDBCLUSTER_STATUS]), SHOW_LONG_STATUS}, {"Com_show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS}, {"Com_show_open_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_OPEN_TABLES]), SHOW_LONG_STATUS}, {"Com_show_privileges", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PRIVILEGES]), SHOW_LONG_STATUS}, @@ -5872,10 +5980,10 @@ struct show_var_st status_vars[]= { {"Key_blocks_not_flushed", (char*) &dflt_key_cache_var.global_blocks_changed, SHOW_KEY_CACHE_LONG}, {"Key_blocks_unused", (char*) &dflt_key_cache_var.blocks_unused, SHOW_KEY_CACHE_CONST_LONG}, {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used, SHOW_KEY_CACHE_CONST_LONG}, - {"Key_read_requests", (char*) &dflt_key_cache_var.global_cache_r_requests, SHOW_KEY_CACHE_LONG}, - {"Key_reads", (char*) &dflt_key_cache_var.global_cache_read, SHOW_KEY_CACHE_LONG}, - {"Key_write_requests", (char*) &dflt_key_cache_var.global_cache_w_requests, SHOW_KEY_CACHE_LONG}, - {"Key_writes", (char*) &dflt_key_cache_var.global_cache_write, SHOW_KEY_CACHE_LONG}, + {"Key_read_requests", (char*) &dflt_key_cache_var.global_cache_r_requests, SHOW_KEY_CACHE_LONGLONG}, + {"Key_reads", (char*) &dflt_key_cache_var.global_cache_read, SHOW_KEY_CACHE_LONGLONG}, + {"Key_write_requests", (char*) &dflt_key_cache_var.global_cache_w_requests, SHOW_KEY_CACHE_LONGLONG}, + {"Key_writes", (char*) &dflt_key_cache_var.global_cache_write, SHOW_KEY_CACHE_LONGLONG}, {"Last_query_cost", (char*) offsetof(STATUS_VAR, last_query_cost), SHOW_DOUBLE_STATUS}, {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, #ifdef HAVE_NDBCLUSTER_DB @@ -6088,6 +6196,7 @@ static void mysql_init_variables(void) query_id= thread_id= 1L; strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; + myisam_stats_method_str= "nulls_unequal"; my_bind_addr = htonl(INADDR_ANY); threads.empty(); thread_cache.empty(); @@ -6136,6 +6245,12 @@ static void mysql_init_variables(void) global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; + + /* + Default behavior for 4.1 and 5.0 is to treat NULL values as unequal + when collecting index statistics for MyISAM tables. + */ + global_system_variables.myisam_stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; /* Variables that depends on compile options */ #ifndef DBUG_OFF @@ -6194,7 +6309,7 @@ static void mysql_init_variables(void) #else have_openssl=SHOW_OPTION_NO; #endif -#ifdef HAVE_BROKEN_REALPATH +#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH) have_symlink=SHOW_OPTION_NO; #else have_symlink=SHOW_OPTION_YES; @@ -6745,6 +6860,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), fprintf(stderr, "Unknown option to tc-heuristic-recover: %s\n",argument); exit(1); } + } + case OPT_MYISAM_STATS_METHOD: + { + myisam_stats_method_str= argument; + int method; + if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0) + { + fprintf(stderr, "Invalid value of myisam_stats_method: %s.\n", argument); + exit(1); + } + global_system_variables.myisam_stats_method= method-1; break; } case OPT_SQL_MODE: @@ -6880,7 +7006,7 @@ static void get_options(int argc,char **argv) usage(); exit(0); } -#if defined(HAVE_BROKEN_REALPATH) +#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH) my_use_symdir=0; my_disable_symlinks=1; have_symlink=SHOW_OPTION_NO; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 9f6295f8a36..7326c0395e3 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -763,7 +763,7 @@ my_real_read(NET *net, ulong *complen) net->error= 2; /* Close socket */ net->report_error= 1; #ifdef MYSQL_SERVER - net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED : + net->last_errno= (vio_was_interrupted(net->vio) ? ER_NET_READ_INTERRUPTED : ER_NET_READ_ERROR); #endif goto end; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3fabb1667e9..ff2b14a27ee 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -750,10 +750,9 @@ int QUICK_RANGE_SELECT::init() { DBUG_ENTER("QUICK_RANGE_SELECT::init"); - if (file->inited == handler::NONE) - DBUG_RETURN(error= file->ha_index_init(index)); - error= 0; - DBUG_RETURN(0); + if (file->inited != handler::NONE) + file->ha_index_or_rnd_end(); + DBUG_RETURN(error= file->ha_index_init(index)); } @@ -1364,6 +1363,95 @@ SEL_ARG *SEL_ARG::clone_tree() /* + Find the best index to retrieve first N records in given order + + SYNOPSIS + get_index_for_order() + table Table to be accessed + order Required ordering + limit Number of records that will be retrieved + + DESCRIPTION + Find the best index that allows to retrieve first #limit records in the + given order cheaper then one would retrieve them using full table scan. + + IMPLEMENTATION + Run through all table indexes and find the shortest index that allows + records to be retrieved in given order. We look for the shortest index + as we will have fewer index pages to read with it. + + This function is used only by UPDATE/DELETE, so we take into account how + the UPDATE/DELETE code will work: + * index can only be scanned in forward direction + * HA_EXTRA_KEYREAD will not be used + Perhaps these assumptions could be relaxed + + RETURN + index number + MAX_KEY if no such index was found. +*/ + +uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit) +{ + uint idx; + uint match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1; + ORDER *ord; + + for (ord= order; ord; ord= ord->next) + if (!ord->asc) + return MAX_KEY; + + for (idx= 0; idx < table->s->keys; idx++) + { + if (!(table->keys_in_use_for_query.is_set(idx))) + continue; + KEY_PART_INFO *keyinfo= table->key_info[idx].key_part; + uint partno= 0; + + /* + The below check is sufficient considering we now have either BTREE + indexes (records are returned in order for any index prefix) or HASH + indexes (records are not returned in order for any index prefix). + */ + if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER)) + continue; + for (ord= order; ord; ord= ord->next, partno++) + { + Item *item= order->item[0]; + if (!(item->type() == Item::FIELD_ITEM && + ((Item_field*)item)->field->eq(keyinfo[partno].field))) + break; + } + + if (!ord && table->key_info[idx].key_length < match_key_len) + { + /* + Ok, the ordering is compatible and this key is shorter then + previous match (we want shorter keys as we'll have to read fewer + index pages for the same number of records) + */ + match_key= idx; + match_key_len= table->key_info[idx].key_length; + } + } + + if (match_key != MAX_KEY) + { + /* + Found an index that allows records to be retrieved in the requested + order. Now we'll check if using the index is cheaper then doing a table + scan. + */ + double full_scan_time= table->file->scan_time(); + double index_scan_time= table->file->read_time(match_key, 1, limit); + if (index_scan_time > full_scan_time) + match_key= MAX_KEY; + } + return match_key; +} + + +/* Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived objects from table read plans. */ @@ -3524,18 +3612,9 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) } Item_func *cond_func= (Item_func*) cond; - if (cond_func->functype() == Item_func::NOT_FUNC) - { - /* Optimize NOT BETWEEN and NOT IN */ - Item *arg= cond_func->arguments()[0]; - if (arg->type() != Item::FUNC_ITEM) - DBUG_RETURN(0); - cond_func= (Item_func*) arg; - if (cond_func->functype() != Item_func::BETWEEN && - cond_func->functype() != Item_func::IN_FUNC) - DBUG_RETURN(0); - inv= TRUE; - } + if (cond_func->functype() == Item_func::BETWEEN || + cond_func->functype() == Item_func::IN_FUNC) + inv= ((Item_func_opt_neg *) cond_func)->negated; else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_RETURN(0); @@ -3543,17 +3622,17 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) switch (cond_func->functype()) { case Item_func::BETWEEN: - if (cond_func->arguments()[0]->type() != Item::FIELD_ITEM) + if (cond_func->arguments()[0]->real_item()->type() != Item::FIELD_ITEM) DBUG_RETURN(0); - field_item= (Item_field*) (cond_func->arguments()[0]); + field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); value= NULL; break; case Item_func::IN_FUNC: { Item_func_in *func=(Item_func_in*) cond_func; - if (func->key_item()->type() != Item::FIELD_ITEM) + if (func->key_item()->real_item()->type() != Item::FIELD_ITEM) DBUG_RETURN(0); - field_item= (Item_field*) (func->key_item()); + field_item= (Item_field*) (func->key_item()->real_item()); value= NULL; break; } @@ -5127,6 +5206,8 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree) if (cpk_scan) param->is_ror_scan= TRUE; } + if (param->table->file->index_flags(key, 0, TRUE) & HA_KEY_SCAN_NOT_ROR) + param->is_ror_scan= FALSE; DBUG_PRINT("exit", ("Records: %lu", (ulong) records)); DBUG_RETURN(records); } @@ -7048,19 +7129,15 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (thd->query_id == cur_field->query_id) { - bool is_covered= FALSE; KEY_PART_INFO *key_part= cur_index_info->key_part; KEY_PART_INFO *key_part_end= key_part + cur_index_info->key_parts; - for (; key_part != key_part_end ; key_part++) + for (;;) { if (key_part->field == cur_field) - { - is_covered= TRUE; break; - } + if (++key_part == key_part_end) + goto next_index; // Field was not part of key } - if (!is_covered) - goto next_index; } } } diff --git a/sql/opt_range.h b/sql/opt_range.h index 37d77033c8d..f84058f3b64 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -716,4 +716,6 @@ public: QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, struct st_table_ref *ref, ha_rows records); +uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit); + #endif diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 33c8eadc065..37acce2934b 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -80,6 +80,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) List_iterator_fast<Item> it(all_fields); int const_result= 1; bool recalc_const_item= 0; + longlong count= 1; + bool is_exact_count= TRUE; table_map removed_tables= 0, outer_tables= 0, used_tables= 0; table_map where_tables= 0; Item *item; @@ -88,9 +90,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (conds) where_tables= conds->used_tables(); - /* Don't replace expression on a table that is part of an outer join */ + /* + Analyze outer join dependencies, and, if possible, compute the number + of returned rows. + */ for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf) { + /* Don't replace expression on a table that is part of an outer join */ if (tl->on_expr) { outer_tables|= tl->table->map; @@ -106,11 +112,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } else used_tables|= tl->table->map; + + /* + If the storage manager of 'tl' gives exact row count, compute the total + number of rows. If there are no outer table dependencies, this count + may be used as the real count. + */ + if (tl->table->file->table_flags() & HA_NOT_EXACT_COUNT) + { + is_exact_count= FALSE; + count= 1; // ensure count != 0 + } + else + { + tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + count*= tl->table->file->records; + } } /* - Iterate through item is select part and replace COUNT(), MIN() and MAX() - with constants (if possible) + Iterate through all items in the SELECT clause and replace + COUNT(), MIN() and MAX() with constants (if possible). */ while ((item= it++)) @@ -122,9 +144,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) case Item_sum::COUNT_FUNC: /* If the expr in count(expr) can never be null we can change this - to the number of rows in the tables + to the number of rows in the tables if this number is exact and + there are no outer joins. */ - if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null) + if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null && + !outer_tables && is_exact_count) { longlong count= 1; TABLE_LIST *table; @@ -210,12 +234,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item() || !is_exact_count) { + /* + The optimization is not applicable in both cases: + (a) 'expr' is a non-constant expression. Then we can't + replace 'expr' by a constant. + (b) 'expr' is a costant. According to ANSI, MIN/MAX must return + NULL if the query does not return any rows. Thus, if we are not + able to determine if the query returns any rows, we can't apply + the optimization and replace MIN/MAX with a constant. + */ const_result= 0; break; } - ((Item_sum_min*) item_sum)->reset(); + if (!count) + { + /* If count == 0, then we know that is_exact_count == TRUE. */ + ((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */ + } + else + ((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */ ((Item_sum_min*) item_sum)->make_const(); recalc_const_item= 1; break; @@ -282,13 +321,28 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item() || !is_exact_count) { + /* + The optimization is not applicable in both cases: + (a) 'expr' is a non-constant expression. Then we can't + replace 'expr' by a constant. + (b) 'expr' is a costant. According to ANSI, MIN/MAX must return + NULL if the query does not return any rows. Thus, if we are not + able to determine if the query returns any rows, we can't apply + the optimization and replace MIN/MAX with a constant. + */ const_result= 0; break; } - ((Item_sum_min*) item_sum)->reset(); - ((Item_sum_min*) item_sum)->make_const(); + if (!count) + { + /* If count != 1, then we know that is_exact_count == TRUE. */ + ((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */ + } + else + ((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */ + ((Item_sum_max*) item_sum)->make_const(); recalc_const_item= 1; break; } diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 82ce2f2d7b5..d3e5645bafc 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -333,6 +333,60 @@ err_w_file: DBUG_RETURN(TRUE); } +/* + Renames a frm file (including backups) in same schema + + SYNOPSIS + rename_in_schema_file + schema name of given schema + old_name original file name + new_name new file name + revision revision number + num_view_backups number of backups + + RETURN + 0 - OK + 1 - Error (only if renaming of frm failed) + +*/ +my_bool rename_in_schema_file(const char *schema, const char *old_name, + const char *new_name, ulonglong revision, + uint num_view_backups) +{ + char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN]; + + strxnmov(old_path, FN_REFLEN, mysql_data_home, "/", schema, "/", + old_name, reg_ext, NullS); + (void) unpack_filename(old_path, old_path); + + strxnmov(new_path, FN_REFLEN, mysql_data_home, "/", schema, "/", + new_name, reg_ext, NullS); + (void) unpack_filename(new_path, new_path); + + if (my_rename(old_path, new_path, MYF(MY_WME))) + return 1; + + /* check if arc_dir exists */ + strxnmov(arc_path, FN_REFLEN, mysql_data_home, "/", schema, "/arc", NullS); + (void) unpack_filename(arc_path, arc_path); + + if (revision > 0 && !access(arc_path, F_OK)) + { + ulonglong limit= ((revision > num_view_backups) ? + revision - num_view_backups : 0); + for (; revision > limit ; revision--) + { + my_snprintf(old_path, FN_REFLEN, "%s/%s%s-%04lu", + arc_path, old_name, reg_ext, (ulong)revision); + (void) unpack_filename(old_path, old_path); + my_snprintf(new_path, FN_REFLEN, "%s/%s%s-%04lu", + arc_path, new_name, reg_ext, (ulong)revision); + (void) unpack_filename(new_path, new_path); + my_rename(old_path, new_path, MYF(0)); + } + } + return 0; +} /* Prepare frm to parse (read to memory) diff --git a/sql/parse_file.h b/sql/parse_file.h index cc0aa6556f6..b4199e4fbf1 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -48,6 +48,9 @@ my_bool sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, const LEX_STRING *type, gptr base, File_option *parameters, uint versions); +my_bool rename_in_schema_file(const char *schema, const char *old_name, + const char *new_name, ulonglong revision, + uint num_view_backups); class File_parser: public Sql_alloc { diff --git a/sql/password.c b/sql/password.c index 60cc0ac0c97..562df3ae226 100644 --- a/sql/password.c +++ b/sql/password.c @@ -316,18 +316,21 @@ void create_random_string(char *to, uint length, struct rand_struct *rand_st) octet2hex() buf OUT output buffer. Must be at least 2*len+1 bytes str, len IN the beginning and the length of the input string + + RETURN + buf+len*2 */ -static void -octet2hex(char *to, const uint8 *str, uint len) +char *octet2hex(char *to, const char *str, uint len) { - const uint8 *str_end= str + len; + const byte *str_end= str + len; for (; str != str_end; ++str) { - *to++= _dig_vec_upper[(*str & 0xF0) >> 4]; - *to++= _dig_vec_upper[*str & 0x0F]; + *to++= _dig_vec_upper[((uchar) *str) >> 4]; + *to++= _dig_vec_upper[((uchar) *str) & 0x0F]; } *to= '\0'; + return to; } diff --git a/sql/protocol.cc b/sql/protocol.cc index ade94a483a8..8c3e5a62820 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -76,6 +76,8 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) if (thd->spcont && thd->spcont->find_handler(sql_errno, MYSQL_ERROR::WARN_LEVEL_ERROR)) { + if (! thd->spcont->found_handler_here()) + thd->net.report_error= 1; /* Make "select" abort correctly */ DBUG_VOID_RETURN; } thd->query_error= 1; // needed to catch query errors during replication @@ -181,6 +183,8 @@ net_printf_error(THD *thd, uint errcode, ...) if (thd->spcont && thd->spcont->find_handler(errcode, MYSQL_ERROR::WARN_LEVEL_ERROR)) { + if (! thd->spcont->found_handler_here()) + thd->net.report_error= 1; /* Make "select" abort correctly */ DBUG_VOID_RETURN; } thd->query_error= 1; // needed to catch query errors during replication diff --git a/sql/protocol.h b/sql/protocol.h index 2717d2258fa..c00bbba4cc9 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -150,30 +150,6 @@ public: virtual bool store(Field *field); }; -class Protocol_cursor :public Protocol_simple -{ -public: - MEM_ROOT *alloc; - MYSQL_FIELD *fields; - MYSQL_ROWS *data; - MYSQL_ROWS **prev_record; - ulong row_count; - - Protocol_cursor() :data(NULL) {} - Protocol_cursor(THD *thd_arg, MEM_ROOT *ini_alloc) :Protocol_simple(thd_arg), alloc(ini_alloc), data(NULL) {} - bool prepare_for_send(List<Item> *item_list) - { - row_count= 0; - fields= NULL; - data= NULL; - prev_record= &data; - return Protocol_simple::prepare_for_send(item_list); - } - bool send_fields(List<Item> *list, uint flags); - bool write(); - uint get_field_count() { return field_count; } -}; - void send_warning(THD *thd, uint sql_errno, const char *err=0); void net_printf_error(THD *thd, uint sql_errno, ...); void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc deleted file mode 100644 index 093a2bf2b90..00000000000 --- a/sql/protocol_cursor.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* Copyright (C) 2000-2003 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - Low level functions for storing data to be send to the MySQL client - The actual communction is handled by the net_xxx functions in net_serv.cc -*/ - -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation // gcc: Class implementation -#endif - -#include "mysql_priv.h" -#include <mysql.h> - -bool Protocol_cursor::send_fields(List<Item> *list, uint flags) -{ - List_iterator_fast<Item> it(*list); - Item *item; - MYSQL_FIELD *client_field; - DBUG_ENTER("Protocol_cursor::send_fields"); - - if (prepare_for_send(list)) - return FALSE; - - fields= (MYSQL_FIELD *)alloc_root(alloc, sizeof(MYSQL_FIELD) * field_count); - if (!fields) - goto err; - - for (client_field= fields; (item= it++) ; client_field++) - { - Send_field server_field; - item->make_field(&server_field); - - client_field->db= strdup_root(alloc, server_field.db_name); - client_field->table= strdup_root(alloc, server_field.table_name); - client_field->name= strdup_root(alloc, server_field.col_name); - client_field->org_table= strdup_root(alloc, server_field.org_table_name); - client_field->org_name= strdup_root(alloc, server_field.org_col_name); - client_field->catalog= strdup_root(alloc, ""); - client_field->length= server_field.length; - client_field->type= server_field.type; - client_field->flags= server_field.flags; - client_field->decimals= server_field.decimals; - client_field->db_length= strlen(client_field->db); - client_field->table_length= strlen(client_field->table); - client_field->name_length= strlen(client_field->name); - client_field->org_name_length= strlen(client_field->org_name); - client_field->org_table_length= strlen(client_field->org_table); - client_field->catalog_length= 0; - client_field->charsetnr= server_field.charsetnr; - - if (INTERNAL_NUM_FIELD(client_field)) - client_field->flags|= NUM_FLAG; - - if (flags & (uint) Protocol::SEND_DEFAULTS) - { - char buff[80]; - String tmp(buff, sizeof(buff), default_charset_info), *res; - - if (!(res=item->val_str(&tmp))) - client_field->def= (char*) ""; - else - client_field->def= strmake_root(alloc, res->ptr(), res->length()); - } - else - client_field->def=0; - client_field->max_length= 0; - } - - DBUG_RETURN(FALSE); - -err: - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), - MYF(0)); /* purecov: inspected */ - DBUG_RETURN(TRUE); /* purecov: inspected */ -} - - -/* Get the length of next field. Change parameter to point at fieldstart */ - -bool Protocol_cursor::write() -{ - byte *cp= (byte *)packet->ptr(); - byte *end_pos= (byte *)packet->ptr() + packet->length(); - ulong len; - MYSQL_FIELD *cur_field= fields; - MYSQL_FIELD *fields_end= fields + field_count; - MYSQL_ROWS *new_record; - byte **data_tmp; - byte *to; - - new_record= (MYSQL_ROWS *)alloc_root(alloc, - sizeof(MYSQL_ROWS) + (field_count + 2)*sizeof(char *) + packet->length()); - if (!new_record) - goto err; - data_tmp= (byte **)(new_record + 1); - new_record->data= (char **)data_tmp; - - to= (byte *)data_tmp + (field_count + 2)*sizeof(char *); - - for (; cur_field < fields_end; cur_field++, data_tmp++) - { - if ((len= net_field_length((uchar **)&cp)) == NULL_LENGTH) - { - *data_tmp= 0; - } - else - { - if ((long)len > (end_pos - cp)) - { - // TODO error signal send_error(thd, CR_MALFORMED_PACKET); - return TRUE; - } - *data_tmp= to; - memcpy(to,(char*) cp,len); - to[len]=0; - to+=len+1; - cp+=len; - if (cur_field->max_length < len) - cur_field->max_length=len; - } - } - data_tmp[0]= to; // Pointer to last used byte - data_tmp[1]= 0; - - *prev_record= new_record; - prev_record= &new_record->next; - new_record->next= NULL; - row_count++; - return FALSE; - err: - // TODO error signal send_error(thd, ER_OUT_OF_RESOURCES); - return TRUE; -} diff --git a/sql/records.cc b/sql/records.cc index 9b05dc3e291..52c3dbdb798 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -29,7 +29,59 @@ static int rr_from_cache(READ_RECORD *info); static int init_rr_cache(THD *thd, READ_RECORD *info); static int rr_cmp(uchar *a,uchar *b); - /* init struct for read with info->read_record */ +static int rr_index(READ_RECORD *info); + + + +/* + Initialize READ_RECORD structure to perform full index scan + + SYNOPSIS + init_read_record_idx() + info READ_RECORD structure to initialize. + thd Thread handle + table Table to be accessed + print_error If true, call table->file->print_error() if an error + occurs (except for end-of-records error) + idx index to scan + + DESCRIPTION + Initialize READ_RECORD structure to perform full index scan (in forward + direction) using read_record.read_record() interface. + + This function has been added at late stage and is used only by + UPDATE/DELETE. Other statements perform index scans using + join_read_first/next functions. +*/ + +void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, + bool print_error, uint idx) +{ + bzero((char*) info,sizeof(*info)); + info->thd=thd; + info->table=table; + info->file= table->file; + info->forms= &info->table; /* Only one table */ + + info->record= table->record[0]; + info->ref_length= table->file->ref_length; + + info->select=NULL; + info->print_error=print_error; + info->ignore_not_found_rows= 0; + table->status=0; /* And it's always found */ + + if (!table->file->inited) + { + table->file->ha_index_init(idx); + table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); + } + info->read_record= rr_index; + info->first= TRUE; +} + + +/* init struct for read with info->read_record */ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, SQL_SELECT *select, @@ -187,6 +239,60 @@ static int rr_quick(READ_RECORD *info) } +/* + A READ_RECORD::read_record implementation that reads index sequentially + + SYNOPSIS + rr_index() + info Scan info + + DESCRIPTION + Read the next index record (in forward direction) and translate return + value. + + RETURN + 0 Ok + -1 End of records + 1 Error +*/ + +static int rr_index(READ_RECORD *info) +{ + int tmp; + while (1) + { + if (info->first) + { + info->first= FALSE; + tmp= info->file->index_first(info->record); + } + else + tmp= info->file->index_next(info->record); + + if (!tmp) + break; + if (info->thd->killed) + { + my_error(ER_SERVER_SHUTDOWN,MYF(0)); + return 1; + } + if (tmp != HA_ERR_RECORD_DELETED) + { + if (tmp == HA_ERR_END_OF_FILE) + tmp= -1; + else + { + if (info->print_error) + info->table->file->print_error(tmp,MYF(0)); + if (tmp < 0) // Fix negative BDB errno + tmp=1; + } + break; + } + } + return tmp; +} + static int rr_sequential(READ_RECORD *info) { int tmp; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 0b6e44c0272..2f00e43deec 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -66,13 +66,10 @@ static int init_failsafe_rpl_thread(THD* thd) this thread has no other error reporting method). */ thd->system_thread = thd->bootstrap = 1; - thd->host_or_ip= ""; - thd->client_capabilities = 0; + thd->security_ctx->skip_grants(); my_net_init(&thd->net, 0); thd->net.read_timeout = slave_net_timeout; thd->max_client_packet_length=thd->net.max_packet; - thd->master_access= ~(ulong)0; - thd->priv_user = 0; pthread_mutex_lock(&LOCK_thread_count); thd->thread_id = thread_id++; pthread_mutex_unlock(&LOCK_thread_count); @@ -162,7 +159,7 @@ int register_slave(THD* thd, uchar* packet, uint packet_length) SLAVE_INFO *si; uchar *p= packet, *p_end= packet + packet_length; - if (check_access(thd, REPL_SLAVE_ACL, any_db,0,0,0)) + if (check_access(thd, REPL_SLAVE_ACL, any_db,0,0,0,0)) return 1; if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME)))) goto err2; @@ -580,7 +577,7 @@ int find_recovery_captain(THD* thd, MYSQL* mysql) } -pthread_handler_decl(handle_failsafe_rpl,arg) +pthread_handler_t handle_failsafe_rpl(void *arg) { DBUG_ENTER("handle_failsafe_rpl"); THD *thd = new THD; diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h index dfaacf557e8..19849e63af9 100644 --- a/sql/repl_failsafe.h +++ b/sql/repl_failsafe.h @@ -31,7 +31,7 @@ extern pthread_cond_t COND_rpl_status; extern TYPELIB rpl_role_typelib, rpl_status_typelib; extern const char* rpl_role_type[], *rpl_status_type[]; -pthread_handler_decl(handle_failsafe_rpl,arg); +pthread_handler_t handle_failsafe_rpl(void *arg); void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status); int find_recovery_captain(THD* thd, MYSQL* mysql); int update_slave_list(MYSQL* mysql, MASTER_INFO* mi); diff --git a/sql/set_var.cc b/sql/set_var.cc index 26912becc81..8cf7311265c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -142,11 +142,8 @@ sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size", sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size", &SV::bulk_insert_buff_size); sys_var_character_set_server sys_character_set_server("character_set_server"); -sys_var_str sys_charset_system("character_set_system", - sys_check_charset, - sys_update_charset, - sys_set_default_charset, - (char *)my_charset_utf8_general_ci.name); +sys_var_const_str sys_charset_system("character_set_system", + (char *)my_charset_utf8_general_ci.name); sys_var_character_set_database sys_character_set_database("character_set_database"); sys_var_character_set_client sys_character_set_client("character_set_client"); sys_var_character_set_connection sys_character_set_connection("character_set_connection"); @@ -273,6 +270,12 @@ sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size", sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1); sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads); sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size); + +sys_var_thd_enum sys_myisam_stats_method("myisam_stats_method", + &SV::myisam_stats_method, + &myisam_stats_method_typelib, + NULL); + sys_var_thd_ulong sys_net_buffer_length("net_buffer_length", &SV::net_buffer_length); sys_var_thd_ulong sys_net_read_timeout("net_read_timeout", @@ -450,10 +453,10 @@ sys_var_thd_date_time_format sys_datetime_format("datetime_format", /* Variables that are bits in THD */ -static sys_var_thd_bit sys_autocommit("autocommit", 0, - set_option_autocommit, - OPTION_NOT_AUTOCOMMIT, - 1); +sys_var_thd_bit sys_autocommit("autocommit", 0, + set_option_autocommit, + OPTION_NOT_AUTOCOMMIT, + 1); static sys_var_thd_bit sys_big_tables("big_tables", 0, set_option_bit, OPTION_BIG_TABLES); @@ -569,6 +572,7 @@ sys_var *sys_variables[]= &sys_character_set_client, &sys_character_set_connection, &sys_character_set_results, + &sys_charset_system, &sys_collation_connection, &sys_collation_database, &sys_collation_server, @@ -632,6 +636,7 @@ sys_var *sys_variables[]= &sys_myisam_max_sort_file_size, &sys_myisam_repair_threads, &sys_myisam_sort_buffer_size, + &sys_myisam_stats_method, &sys_net_buffer_length, &sys_net_read_timeout, &sys_net_retry_count, @@ -898,6 +903,9 @@ struct show_var_st init_vars[]= { {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads, SHOW_SYS}, {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, + + {sys_myisam_stats_method.name, (char*) &sys_myisam_stats_method, SHOW_SYS}, + #ifdef __NT__ {"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL}, #endif @@ -1094,9 +1102,10 @@ static void sys_default_init_slave(THD* thd, enum_var_type type) static int sys_check_ftb_syntax(THD *thd, set_var *var) { - if (thd->master_access & SUPER_ACL) - return ft_boolean_check_syntax_string((byte*) var->value->str_value.c_ptr()) ? - -1 : 0; + if (thd->security_ctx->master_access & SUPER_ACL) + return (ft_boolean_check_syntax_string((byte*) + var->value->str_value.c_ptr()) ? + -1 : 0); else { my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); @@ -1117,27 +1126,6 @@ static void sys_default_ftb_syntax(THD *thd, enum_var_type type) sizeof(ft_boolean_syntax)-1); } -/* - The following 3 functions need to be changed in 4.1 when we allow - one to change character sets -*/ - -static int sys_check_charset(THD *thd, set_var *var) -{ - return 0; -} - - -static bool sys_update_charset(THD *thd, set_var *var) -{ - return 0; -} - - -static void sys_set_default_charset(THD *thd, enum_var_type type) -{ -} - /* If one sets the LOW_PRIORIY UPDATES flag, we also must change the @@ -1725,11 +1713,17 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1); case SHOW_CHAR: { - Item_string *tmp; + Item *tmp; pthread_mutex_lock(&LOCK_global_system_variables); char *str= (char*) value_ptr(thd, var_type, base); - tmp= new Item_string(str, strlen(str), - system_charset_info, DERIVATION_SYSCONST); + if (str) + tmp= new Item_string(str, strlen(str), + system_charset_info, DERIVATION_SYSCONST); + else + { + tmp= new Item_null(); + tmp->collation.set(system_charset_info, DERIVATION_SYSCONST); + } pthread_mutex_unlock(&LOCK_global_system_variables); return tmp; } @@ -2019,7 +2013,7 @@ byte *sys_var_character_set::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { CHARSET_INFO *cs= ci_ptr(thd,type)[0]; - return cs ? (byte*) cs->csname : (byte*) "NULL"; + return cs ? (byte*) cs->csname : (byte*) NULL; } @@ -2706,7 +2700,7 @@ static bool set_option_autocommit(THD *thd, set_var *var) static int check_log_update(THD *thd, set_var *var) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!(thd->master_access & SUPER_ACL)) + if (!(thd->security_ctx->master_access & SUPER_ACL)) { my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); return 1; @@ -2752,7 +2746,7 @@ static int check_pseudo_thread_id(THD *thd, set_var *var) { var->save_result.ulonglong_value= var->value->val_int(); #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (thd->master_access & SUPER_ACL) + if (thd->security_ctx->master_access & SUPER_ACL) return 0; else { @@ -3117,10 +3111,10 @@ int set_var_password::check(THD *thd) #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!user->host.str) { - if (thd->priv_host != 0) + if (*thd->security_ctx->priv_host != 0) { - user->host.str= (char *) thd->priv_host; - user->host.length= strlen(thd->priv_host); + user->host.str= (char *) thd->security_ctx->priv_host; + user->host.length= strlen(thd->security_ctx->priv_host); } else { diff --git a/sql/set_var.h b/sql/set_var.h index c8b075ddd35..854409c159e 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -190,6 +190,7 @@ public: return 1; } bool check_default(enum_var_type type) { return 1; } + bool is_readonly() const { return 1; } }; @@ -900,10 +901,11 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list); bool not_all_support_one_shot(List<set_var_base> *var_list); void fix_delay_key_write(THD *thd, enum_var_type type); ulong fix_sql_mode(ulong sql_mode); -extern sys_var_str sys_charset_system; +extern sys_var_const_str sys_charset_system; extern sys_var_str sys_init_connect; extern sys_var_str sys_init_slave; extern sys_var_thd_time_zone sys_time_zone; +extern sys_var_thd_bit sys_autocommit; CHARSET_INFO *get_old_charset_by_name(const char *old_name); gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length, NAMED_LIST **found); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index b49b7248021..ccf11248a1f 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5311,7 +5311,8 @@ ER_XAER_NOTA XAE04 ER_XAER_INVAL XAE05 eng "XAER_INVAL: Invalid arguments (or unsupported command)" ER_XAER_RMFAIL XAE07 - eng "XAER_RMFAIL: The command cannot be executed in the %.64s state" + eng "XAER_RMFAIL: The command cannot be executed when global transaction is in the %.64s state" + rus "XAER_RMFAIL: ÜÔÕ ËÏÍÁÎÄÕ ÎÅÌØÚÑ ×ÙÐÏÌÎÑÔØ ËÏÇÄÁ ÇÌÏÂÁÌØÎÁÑ ÔÒÁÎÚÁËÃÉÑ ÎÁÈÏÄÉÔÓÑ × ÓÏÓÔÏÑÎÉÉ '%.64s'" ER_XAER_OUTSIDE XAE09 eng "XAER_OUTSIDE: Some work is done outside global transaction" ER_XAER_RMERR XAE03 @@ -5366,12 +5367,12 @@ ER_TOO_BIG_SCALE 42000 S1009 eng "Too big scale %d specified for column '%-.64s'. Maximum is %d." ER_TOO_BIG_PRECISION 42000 S1009 eng "Too big precision %d specified for column '%-.64s'. Maximum is %d." -ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009 - eng "Scale may not be larger than the precision (column '%-.64s')." +ER_M_BIGGER_THAN_D 42000 S1009 + eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.64s')." ER_WRONG_LOCK_OF_SYSTEM_TABLE eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables" ER_CONNECT_TO_FOREIGN_DATA_SOURCE - eng "Unable to connect to foreign data source - database '%s'!" + eng "Unable to connect to foreign data source - database '%.64s'!" ER_QUERY_ON_FOREIGN_DATA_SOURCE eng "There was a problem processing the query on the foreign data source. Data source error: '%-.64s'" ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST @@ -5399,3 +5400,25 @@ ER_DATETIME_FUNCTION_OVERFLOW 22008 eng "Datetime function: %-.32s field overflow" ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG eng "Can't update table '%-.64s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger." +ER_VIEW_PREVENT_UPDATE + eng "The definition of table '%-.64s' prevents operation %.64s on table '%-.64s'." +ER_PS_NO_RECURSION + eng "The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner" +ER_SP_CANT_SET_AUTOCOMMIT + eng "Not allowed to set autocommit from a stored function or trigger" +ER_NO_VIEW_USER + eng "View definer is not fully qualified" +ER_VIEW_FRM_NO_USER + eng "View %-.64s.%-.64s has not definer information (old table format). Current user is used as definer. Please recreate view!" +ER_VIEW_OTHER_USER + eng "You need the SUPER privilege for creation view with %-.64s@%-.64s definer" +ER_NO_SUCH_USER + eng "There is not %-.64s@%-.64s registered" +ER_FORBID_SCHEMA_CHANGE + eng "Changing schema from '%-.64s' to '%-.64s' is not allowed." +ER_ROW_IS_REFERENCED_2 23000 + eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)" +ER_NO_REFERENCED_ROW_2 23000 + eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)" +ER_SP_BAD_VAR_SHADOW 42000 + eng "Variable '%-.64s' must be quoted with `...`, or renamed" diff --git a/sql/slave.cc b/sql/slave.cc index d2a60076cef..f785bdcd4d7 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -40,7 +40,8 @@ HASH replicate_do_table, replicate_ignore_table; DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; bool do_table_inited = 0, ignore_table_inited = 0; bool wild_do_table_inited = 0, wild_ignore_table_inited = 0; -bool table_rules_on= 0, replicate_same_server_id; +bool table_rules_on= 0; +my_bool replicate_same_server_id; ulonglong relay_log_space_limit = 0; /* @@ -861,14 +862,6 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len) rules (see code below). For that reason, users should not set conflicting rules because they may get unpredicted results (precedence order is explained in the manual). - If no table of the list is marked "updating" (so far this can only happen - if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables" - is the tables in the FROM): then we always return 0, because there is no - reason we play this statement on this slave if it updates nothing. In the - case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(), - with tables having "updating==TRUE" (those after the DELETE), so this - second call will make the decision (because - all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)). Thought which arose from a question of a big customer "I want to include all tables like "abc.%" except the "%.EFG"". This can't be done now. If we @@ -1729,9 +1722,26 @@ static int init_relay_log_info(RELAY_LOG_INFO* rli, { char buf[FN_REFLEN]; const char *ln; + static bool name_warning_sent= 0; ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin", 1, buf); - + /* We send the warning only at startup, not after every RESET SLAVE */ + if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent) + { + /* + User didn't give us info to name the relay log index file. + Picking `hostname`-relay-bin.index like we do, causes replication to + fail if this slave's hostname is changed later. So, we would like to + instead require a name. But as we don't want to break many existing + setups, we only give warning, not error. + */ + sql_print_warning("Neither --relay-log nor --relay-log-index were used;" + " so replication " + "may break when this MySQL server acts as a " + "slave and has his hostname changed!! Please " + "use '--relay-log=%s' to avoid this problem.", ln); + name_warning_sent= 1; + } /* note, that if open() fails, we'll still have index file open but a destructor will take care of that @@ -1955,6 +1965,55 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli) } +/* + Builds a Rotate from the ignored events' info and writes it to relay log. + + SYNOPSIS + write_ignored_events_info_to_relay_log() + thd pointer to I/O thread's thd + mi + + DESCRIPTION + Slave I/O thread, going to die, must leave a durable trace of the + ignored events' end position for the use of the slave SQL thread, by + calling this function. Only that thread can call it (see assertion). + */ +static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi) +{ + RELAY_LOG_INFO *rli= &mi->rli; + pthread_mutex_t *log_lock= rli->relay_log.get_log_lock(); + DBUG_ASSERT(thd == mi->io_thd); + pthread_mutex_lock(log_lock); + if (rli->ign_master_log_name_end[0]) + { + DBUG_PRINT("info",("writing a Rotate event to track down ignored events")); + Rotate_log_event *ev= new Rotate_log_event(thd, rli->ign_master_log_name_end, + 0, rli->ign_master_log_pos_end, + Rotate_log_event::DUP_NAME); + rli->ign_master_log_name_end[0]= 0; + /* can unlock before writing as slave SQL thd will soon see our Rotate */ + pthread_mutex_unlock(log_lock); + if (likely((bool)ev)) + { + ev->server_id= 0; // don't be ignored by slave SQL thread + if (unlikely(rli->relay_log.append(ev))) + sql_print_error("Slave I/O thread failed to write a Rotate event" + " to the relay log, " + "SHOW SLAVE STATUS may be inaccurate"); + rli->relay_log.harvest_bytes_written(&rli->log_space_total); + flush_master_info(mi, 1); + delete ev; + } + else + sql_print_error("Slave I/O thread failed to create a Rotate event" + " (out of memory?), " + "SHOW SLAVE STATUS may be inaccurate"); + } + else + pthread_mutex_unlock(log_lock); +} + + void init_master_info_with_options(MASTER_INFO* mi) { mi->master_log_name[0] = 0; @@ -2551,7 +2610,7 @@ st_relay_log_info::st_relay_log_info() { group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0; - last_slave_error[0]=0; until_log_name[0]= 0; + last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0; bzero((char*) &info_file, sizeof(info_file)); bzero((char*) &cache_buf, sizeof(cache_buf)); @@ -2754,7 +2813,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, else pthread_cond_wait(&data_cond, &data_lock); DBUG_PRINT("info",("Got signal of master update or timed out")); - if (error == ETIMEDOUT) + if (error == ETIMEDOUT || error == ETIME) { error= -1; break; @@ -2809,17 +2868,9 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) DBUG_ENTER("init_slave_thread"); thd->system_thread = (thd_type == SLAVE_THD_SQL) ? SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; - /* - The two next lines are needed for replication of SP (CREATE PROCEDURE - needs a valid user to store in mysql.proc). - */ - thd->priv_user= (char *) ""; - thd->priv_host[0]= '\0'; - thd->host_or_ip= ""; - thd->client_capabilities = 0; + thd->security_ctx->skip_grants(); my_net_init(&thd->net, 0); thd->net.read_timeout = slave_net_timeout; - thd->master_access= ~(ulong)0; thd->slave_thread = 1; set_slave_thread_options(thd); /* @@ -3151,12 +3202,20 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) wait for something for example inside of next_event(). */ pthread_mutex_lock(&rli->data_lock); - + /* + This tests if the position of the end of the last previous executed event + hits the UNTIL barrier. + We would prefer to test if the position of the start (or possibly) end of + the to-be-read event hits the UNTIL barrier, this is different if there + was an event ignored by the I/O thread just before (BUG#13861 to be + fixed). + */ if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE && rli->is_until_satisfied()) { + char buf[22]; sql_print_error("Slave SQL thread stopped because it reached its" - " UNTIL position %ld", (long) rli->until_pos()); + " UNTIL position %s", llstr(rli->until_pos(), buf)); /* Setting abort_slave flag because we do not want additional message about error in query execution to be printed. @@ -3339,11 +3398,12 @@ on this slave.\ /* Slave I/O Thread entry point */ -extern "C" pthread_handler_decl(handle_slave_io,arg) +pthread_handler_t handle_slave_io(void *arg) { THD *thd; // needs to be first for thread_stack MYSQL *mysql; MASTER_INFO *mi = (MASTER_INFO*)arg; + RELAY_LOG_INFO *rli= &mi->rli; char llbuff[22]; uint retry_count; @@ -3586,16 +3646,16 @@ reconnect done to recover from failed read"); char llbuf1[22], llbuf2[22]; DBUG_PRINT("info", ("log_space_limit=%s log_space_total=%s \ ignore_log_space_limit=%d", - llstr(mi->rli.log_space_limit,llbuf1), - llstr(mi->rli.log_space_total,llbuf2), - (int) mi->rli.ignore_log_space_limit)); + llstr(rli->log_space_limit,llbuf1), + llstr(rli->log_space_total,llbuf2), + (int) rli->ignore_log_space_limit)); } #endif - if (mi->rli.log_space_limit && mi->rli.log_space_limit < - mi->rli.log_space_total && - !mi->rli.ignore_log_space_limit) - if (wait_for_relay_log_space(&mi->rli)) + if (rli->log_space_limit && rli->log_space_limit < + rli->log_space_total && + !rli->ignore_log_space_limit) + if (wait_for_relay_log_space(rli)) { sql_print_error("Slave I/O thread aborted while waiting for relay \ log space"); @@ -3626,10 +3686,20 @@ err: mysql_close(mysql); mi->mysql=0; } + write_ignored_events_info_to_relay_log(thd, mi); thd->proc_info = "Waiting for slave mutex on exit"; pthread_mutex_lock(&mi->run_lock); mi->slave_running = 0; mi->io_thd = 0; + + /* Close log file and free buffers */ + if (mi->rli.cur_log_fd >= 0) + { + end_io_cache(&mi->rli.cache_buf); + my_close(mi->rli.cur_log_fd, MYF(MY_WME)); + mi->rli.cur_log_fd= -1; + } + /* Forget the relay log's format */ delete mi->rli.relay_log.description_event_for_queue; mi->rli.relay_log.description_event_for_queue= 0; @@ -3648,7 +3718,7 @@ err: #ifndef DBUG_OFF if (abort_slave_event_count && !events_till_abort) goto slave_begin; -#endif +#endif my_thread_end(); pthread_exit(0); DBUG_RETURN(0); // Can't return anything here @@ -3657,11 +3727,11 @@ err: /* Slave SQL Thread entry point */ -extern "C" pthread_handler_decl(handle_slave_sql,arg) +pthread_handler_t handle_slave_sql(void *arg) { THD *thd; /* needs to be first for thread_stack */ char llbuff[22],llbuff1[22]; - RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli; + RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli; const char *errmsg; // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff @@ -3669,7 +3739,7 @@ extern "C" pthread_handler_decl(handle_slave_sql,arg) DBUG_ENTER("handle_slave_sql"); #ifndef DBUG_OFF -slave_begin: +slave_begin: #endif DBUG_ASSERT(rli->inited); @@ -3846,6 +3916,14 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ rli->cached_charset_invalidate(); rli->save_temporary_tables = thd->temporary_tables; + /* Close log file and free buffers if it's already open */ + if (rli->cur_log_fd >= 0) + { + end_io_cache(&rli->cache_buf); + my_close(rli->cur_log_fd, MYF(MY_WME)); + rli->cur_log_fd = -1; + } + /* TODO: see if we can do this conditionally in next_event() instead to avoid unneeded position re-init @@ -4010,6 +4088,7 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev) if (unlikely(!rev->is_valid())) DBUG_RETURN(1); + /* Safe copy as 'rev' has been "sanitized" in Rotate_log_event's ctor */ memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1); mi->master_log_pos= rev->pos; DBUG_PRINT("info", ("master_log_pos: '%s' %d", @@ -4260,6 +4339,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) int error= 0; ulong inc_pos; RELAY_LOG_INFO *rli= &mi->rli; + pthread_mutex_t *log_lock= rli->relay_log.get_log_lock(); DBUG_ENTER("queue_event"); if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 && @@ -4268,11 +4348,6 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) pthread_mutex_lock(&mi->data_lock); - /* - TODO: figure out if other events in addition to Rotate - require special processing. - Guilhem 2003-06 : I don't think so. - */ switch (buf[EVENT_TYPE_OFFSET]) { case STOP_EVENT: /* @@ -4357,14 +4432,21 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) direct master (an unsupported, useless setup!). */ + pthread_mutex_lock(log_lock); + if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) && !replicate_same_server_id) { /* Do not write it to the relay log. - We still want to increment, so that we won't re-read this event from the - master if the slave IO thread is now stopped/restarted (more efficient if - the events we are ignoring are big LOAD DATA INFILE). + a) We still want to increment mi->master_log_pos, so that we won't + re-read this event from the master if the slave IO thread is now + stopped/restarted (more efficient if the events we are ignoring are big + LOAD DATA INFILE). + b) We want to record that we are skipping events, for the information of + the slave SQL thread, otherwise that thread may let + rli->group_relay_log_pos stay too small if the last binlog's event is + ignored. But events which were generated by this slave and which do not exist in the master's binlog (i.e. Format_desc, Rotate & Stop) should not increment mi->master_log_pos. @@ -4372,7 +4454,13 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT && buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT && buf[EVENT_TYPE_OFFSET]!=STOP_EVENT) + { mi->master_log_pos+= inc_pos; + memcpy(rli->ign_master_log_name_end, mi->master_log_name, FN_REFLEN); + DBUG_ASSERT(rli->ign_master_log_name_end[0]); + rli->ign_master_log_pos_end= mi->master_log_pos; + } + rli->relay_log.signal_update(); // the slave SQL thread needs to re-check DBUG_PRINT("info", ("master_log_pos: %d, event originating from the same server, ignored", (ulong) mi->master_log_pos)); } else @@ -4385,8 +4473,11 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) rli->relay_log.harvest_bytes_written(&rli->log_space_total); } else - error=3; + error= 3; + rli->ign_master_log_name_end[0]= 0; // last event is not ignored } + pthread_mutex_unlock(log_lock); + err: pthread_mutex_unlock(&mi->data_lock); @@ -4769,7 +4860,28 @@ Log_event* next_event(RELAY_LOG_INFO* rli) time_t save_timestamp= rli->last_master_timestamp; rli->last_master_timestamp= 0; - DBUG_ASSERT(rli->relay_log.get_open_count() == rli->cur_log_old_open_count); + DBUG_ASSERT(rli->relay_log.get_open_count() == + rli->cur_log_old_open_count); + + if (rli->ign_master_log_name_end[0]) + { + /* We generate and return a Rotate, to make our positions advance */ + DBUG_PRINT("info",("seeing an ignored end segment")); + ev= new Rotate_log_event(thd, rli->ign_master_log_name_end, + 0, rli->ign_master_log_pos_end, + Rotate_log_event::DUP_NAME); + rli->ign_master_log_name_end[0]= 0; + pthread_mutex_unlock(log_lock); + if (unlikely(!ev)) + { + errmsg= "Slave SQL thread failed to create a Rotate event " + "(out of memory?), SHOW SLAVE STATUS may be inaccurate"; + goto err; + } + ev->server_id= 0; // don't be ignored by slave SQL thread + DBUG_RETURN(ev); + } + /* We can, and should release data_lock while we are waiting for update. If we do not, show slave status will block diff --git a/sql/slave.h b/sql/slave.h index c41234ab2ed..4d3c338680d 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -302,6 +302,17 @@ typedef struct st_relay_log_info */ ulong trans_retries, retried_trans; + /* + If the end of the hot relay log is made of master's events ignored by the + slave I/O thread, these two keep track of the coords (in the master's + binlog) of the last of these events seen by the slave I/O thread. If not, + ign_master_log_name_end[0] == 0. + As they are like a Rotate event read/written from/to the relay log, they + are both protected by rli->relay_log.LOCK_log. + */ + char ign_master_log_name_end[FN_REFLEN]; + ulonglong ign_master_log_pos_end; + st_relay_log_info(); ~st_relay_log_info(); @@ -572,8 +583,8 @@ void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli); void rotate_relay_log(MASTER_INFO* mi); -extern "C" pthread_handler_decl(handle_slave_io,arg); -extern "C" pthread_handler_decl(handle_slave_sql,arg); +pthread_handler_t handle_slave_io(void *arg); +pthread_handler_t handle_slave_sql(void *arg); extern bool volatile abort_loop; extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */ extern LIST master_list; @@ -581,7 +592,8 @@ extern HASH replicate_do_table, replicate_ignore_table; extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; extern bool do_table_inited, ignore_table_inited, wild_do_table_inited, wild_ignore_table_inited; -extern bool table_rules_on, replicate_same_server_id; +extern bool table_rules_on; +extern my_bool replicate_same_server_id; extern int disconnect_slave_event_count, abort_slave_event_count ; diff --git a/sql/sp.cc b/sql/sp.cc index 56da38e6cab..8386c5d58a2 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -107,7 +107,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) { TABLE_LIST tables; TABLE *table; - bool refresh; + bool not_used; DBUG_ENTER("open_proc_table"); /* @@ -122,7 +122,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) bzero((char*) &tables, sizeof(tables)); tables.db= (char*) "mysql"; tables.table_name= tables.alias= (char*)"proc"; - if (!(table= open_table(thd, &tables, thd->mem_root, &refresh, + if (!(table= open_table(thd, &tables, thd->mem_root, ¬_used, MYSQL_LOCK_IGNORE_FLUSH))) { thd->restore_backup_open_tables_state(backup); @@ -138,7 +138,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) could lead to a deadlock if we have other tables opened. */ if (!(thd->lock= mysql_lock_tables(thd, &table, 1, - MYSQL_LOCK_IGNORE_FLUSH))) + MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) { close_proc_table(thd, backup); DBUG_RETURN(0); @@ -208,7 +208,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table) { byte key[MAX_KEY_LENGTH]; // db, name, optional key length type DBUG_ENTER("db_find_routine_aux"); - DBUG_PRINT("enter", ("type: %d name: %*s", + DBUG_PRINT("enter", ("type: %d name: %.*s", type, name->m_name.length, name->m_name.str)); /* @@ -223,7 +223,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table) table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin); table->field[1]->store(name->m_name.str, name->m_name.length, &my_charset_bin); - table->field[2]->store((longlong) type); + table->field[2]->store((longlong) type, TRUE); key_copy(key, table->record[0], table->key_info, table->key_info->key_length); @@ -275,7 +275,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) ulong sql_mode; Open_tables_state open_tables_state_backup; DBUG_ENTER("db_find_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s", + DBUG_PRINT("enter", ("type: %d name: %.*s", type, name->m_name.length, name->m_name.str)); *sphp= 0; // In case of errors @@ -479,7 +479,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) char olddb[128]; bool dbchanged; DBUG_ENTER("db_create_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s",type,sp->m_name.length,sp->m_name.str)); + DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length, + sp->m_name.str)); dbchanged= FALSE; if ((ret= sp_use_new_db(thd, sp->m_db.str, olddb, sizeof(olddb), @@ -494,7 +495,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) else { restore_record(table, s->default_values); // Get default values for fields - strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS); + strxmov(definer, thd->security_ctx->priv_user, "@", + thd->security_ctx->priv_host, NullS); if (table->s->fields != MYSQL_PROC_FIELD_COUNT) { @@ -569,7 +571,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) goto done; } } - if (!(thd->master_access & SUPER_ACL)) + if (!(thd->security_ctx->master_access & SUPER_ACL)) { my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); @@ -605,7 +607,7 @@ db_drop_routine(THD *thd, int type, sp_name *name) TABLE *table; int ret; DBUG_ENTER("db_drop_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s", + DBUG_PRINT("enter", ("type: %d name: %.*s", type, name->m_name.length, name->m_name.str)); if (!(table= open_proc_table_for_update(thd))) @@ -627,7 +629,7 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) int ret; bool opened; DBUG_ENTER("db_update_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s", + DBUG_PRINT("enter", ("type: %d name: %.*s", type, name->m_name.length, name->m_name.str)); if (!(table= open_proc_table_for_update(thd))) @@ -921,7 +923,7 @@ sp_find_procedure(THD *thd, sp_name *name, bool cache_only) { sp_head *sp; DBUG_ENTER("sp_find_procedure"); - DBUG_PRINT("enter", ("name: %*s.%*s", + DBUG_PRINT("enter", ("name: %.*s.%.*s", name->m_db.length, name->m_db.str, name->m_name.length, name->m_name.str)); @@ -979,7 +981,7 @@ sp_create_procedure(THD *thd, sp_head *sp) { int ret; DBUG_ENTER("sp_create_procedure"); - DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str)); ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp); DBUG_RETURN(ret); @@ -991,7 +993,7 @@ sp_drop_procedure(THD *thd, sp_name *name) { int ret; DBUG_ENTER("sp_drop_procedure"); - DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name); if (!ret) @@ -1005,7 +1007,7 @@ sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; DBUG_ENTER("sp_update_procedure"); - DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics); if (!ret) @@ -1019,7 +1021,7 @@ sp_show_create_procedure(THD *thd, sp_name *name) { sp_head *sp; DBUG_ENTER("sp_show_create_procedure"); - DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); if ((sp= sp_find_procedure(thd, name))) { @@ -1071,7 +1073,7 @@ sp_find_function(THD *thd, sp_name *name, bool cache_only) { sp_head *sp; DBUG_ENTER("sp_find_function"); - DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) && !cache_only) @@ -1088,7 +1090,7 @@ sp_create_function(THD *thd, sp_head *sp) { int ret; DBUG_ENTER("sp_create_function"); - DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str)); ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp); DBUG_RETURN(ret); @@ -1100,7 +1102,7 @@ sp_drop_function(THD *thd, sp_name *name) { int ret; DBUG_ENTER("sp_drop_function"); - DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name); if (!ret) @@ -1114,7 +1116,7 @@ sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; DBUG_ENTER("sp_update_procedure"); - DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics); if (!ret) @@ -1128,7 +1130,7 @@ sp_show_create_function(THD *thd, sp_name *name) { sp_head *sp; DBUG_ENTER("sp_show_create_function"); - DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); + DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); if ((sp= sp_find_function(thd, name))) { @@ -1265,7 +1267,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, /* - Add routine to the set of stored routines used by statement. + Add routine which is explicitly used by statement to the set of stored + routines used by this statement. SYNOPSIS sp_add_used_routine() @@ -1276,7 +1279,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...) NOTES - Will also add element to end of 'LEX::sroutines_list' list. + Will also add element to end of 'LEX::sroutines_list' list (and will + take into account that this is explicitly used routine). To be friendly towards prepared statements one should pass persistent arena as second argument. @@ -1287,6 +1291,37 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena, { rt->set_routine_type(rt_type); (void)add_used_routine(lex, arena, &rt->m_sroutines_key); + lex->sroutines_list_own_last= lex->sroutines_list.next; + lex->sroutines_list_own_elements= lex->sroutines_list.elements; +} + + +/* + Remove routines which are only indirectly used by statement from + the set of routines used by this statement. + + SYNOPSIS + sp_remove_not_own_routines() + lex LEX representing statement +*/ + +void sp_remove_not_own_routines(LEX *lex) +{ + Sroutine_hash_entry *not_own_rt, *next_rt; + for (not_own_rt= *(Sroutine_hash_entry **)lex->sroutines_list_own_last; + not_own_rt; not_own_rt= next_rt) + { + /* + It is safe to obtain not_own_rt->next after calling hash_delete() now + but we want to be more future-proof. + */ + next_rt= not_own_rt->next; + hash_delete(&lex->sroutines, (byte *)not_own_rt); + } + + *(Sroutine_hash_entry **)lex->sroutines_list_own_last= NULL; + lex->sroutines_list.next= lex->sroutines_list_own_last; + lex->sroutines_list.elements= lex->sroutines_list_own_elements; } @@ -1338,12 +1373,34 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src) for (uint i=0 ; i < src->records ; i++) { Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i); - (void)add_used_routine(lex, thd->current_arena, &rt->key); + (void)add_used_routine(lex, thd->stmt_arena, &rt->key); } } /* + Add contents of list representing set of routines to the set of + routines used by statement. + + SYNOPSIS + sp_update_stmt_used_routines() + thd Thread context + lex LEX representing statement + src List representing set from which routines will be added + + NOTE + It will also add elements to end of 'LEX::sroutines_list' list. +*/ + +static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src) +{ + for (Sroutine_hash_entry *rt= (Sroutine_hash_entry *)src->first; + rt; rt= rt->next) + (void)add_used_routine(lex, thd->stmt_arena, &rt->key); +} + + +/* Cache sub-set of routines used by statement, add tables used by these routines to statement table list. Do the same for all routines used by these routines. @@ -1463,7 +1520,7 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) { Sroutine_hash_entry **last_cached_routine_ptr= (Sroutine_hash_entry **)lex->sroutines_list.next; - sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines); + sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines_list); (void)sp_cache_routines_and_add_tables_aux(thd, lex, *last_cached_routine_ptr, FALSE); } @@ -1485,7 +1542,7 @@ void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, Table_triggers_list *triggers) { - if (add_used_routine(lex, thd->current_arena, &triggers->sroutines_key)) + if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key)) { Sroutine_hash_entry **last_cached_routine_ptr= (Sroutine_hash_entry **)lex->sroutines_list.next; @@ -84,6 +84,7 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking, bool *first_no_prelocking); void sp_add_used_routine(LEX *lex, Query_arena *arena, sp_name *rt, char rt_type); +void sp_remove_not_own_routines(LEX *lex); void sp_update_sp_used_routines(HASH *dst, HASH *src); bool sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock); diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 495f969eeac..fea6a67f32c 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -132,7 +132,7 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp) return; // End of memory error c->version= Cversion; // No need to lock when reading long variable } - DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, + DBUG_PRINT("info",("sp_cache: inserting: %.*s", sp->m_qname.length, sp->m_qname.str)); c->insert(sp); *cp= c; // Update *cp if it was NULL diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 4358a37daa6..abc66ce0b21 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -47,15 +47,30 @@ sp_map_result_type(enum enum_field_types type) } /* - * Returns TRUE if the 'cmd' is a command that might result in - * multiple result sets being sent back. - * Note: This does not include SQLCOM_SELECT which is treated - * separately in sql_yacc.yy. - */ -bool -sp_multi_results_command(enum enum_sql_command cmd) + SYNOPSIS + sp_get_flags_for_command() + + DESCRIPTION + Returns a combination of: + * sp_head::MULTI_RESULTS: added if the 'cmd' is a command that might + result in multiple result sets being sent back. + * sp_head::CONTAINS_DYNAMIC_SQL: added if 'cmd' is one of PREPARE, + EXECUTE, DEALLOCATE. +*/ + +uint +sp_get_flags_for_command(LEX *lex) { - switch (cmd) { + uint flags; + + switch (lex->sql_command) { + case SQLCOM_SELECT: + if (lex->result) + { + flags= 0; /* This is a SELECT with INTO clause */ + break; + } + /* fallthrough */ case SQLCOM_ANALYZE: case SQLCOM_CHECKSUM: case SQLCOM_HA_READ: @@ -90,10 +105,26 @@ sp_multi_results_command(enum enum_sql_command cmd) case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_WARNS: - return TRUE; + flags= sp_head::MULTI_RESULTS; + break; + /* + EXECUTE statement may return a result set, but doesn't have to. + We can't, however, know it in advance, and therefore must add + this statement here. This is ok, as is equivalent to a result-set + statement within an IF condition. + */ + case SQLCOM_EXECUTE: + flags= sp_head::MULTI_RESULTS | sp_head::CONTAINS_DYNAMIC_SQL; + break; + case SQLCOM_PREPARE: + case SQLCOM_DEALLOCATE_PREPARE: + flags= sp_head::CONTAINS_DYNAMIC_SQL; + break; default: - return FALSE; + flags= 0; + break; } + return flags; } @@ -131,12 +162,12 @@ sp_prepare_func_item(THD* thd, Item **it_addr) do \ { \ if (condition) \ - thd->set_n_backup_item_arena(thd->spcont->callers_arena, \ - backup_arena); \ + thd->set_n_backup_active_arena(thd->spcont->callers_arena, \ + backup_arena); \ new_command; \ if (condition) \ - thd->restore_backup_item_arena(thd->spcont->callers_arena, \ - &backup_current_arena); \ + thd->restore_active_arena(thd->spcont->callers_arena, \ + backup_arena); \ } while(0) /* @@ -167,12 +198,19 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, DBUG_ENTER("sp_eval_func_item"); Item *it= sp_prepare_func_item(thd, it_addr); uint rsize; - Query_arena backup_current_arena; + Query_arena backup_arena; + Item *old_item_next, *old_free_list, **p_free_list; DBUG_PRINT("info", ("type: %d", type)); if (!it) - { DBUG_RETURN(NULL); + + if (reuse) + { + old_item_next= reuse->next; + p_free_list= use_callers_arena ? &thd->spcont->callers_arena->free_list : + &thd->free_list; + old_free_list= *p_free_list; } switch (sp_map_result_type(type)) { @@ -187,7 +225,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, } DBUG_PRINT("info", ("INT_RESULT: %d", i)); CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i), - use_callers_arena, &backup_current_arena); + use_callers_arena, &backup_arena); break; } case REAL_RESULT: @@ -210,7 +248,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, max_length= it->max_length; DBUG_PRINT("info", ("REAL_RESULT: %g", d)); CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d), - use_callers_arena, &backup_current_arena); + use_callers_arena, &backup_arena); it->decimals= decimals; it->max_length= max_length; break; @@ -221,7 +259,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, if (it->null_value) goto return_null_item; CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val), - use_callers_arena, &backup_current_arena); + use_callers_arena, &backup_arena); #ifndef DBUG_OFF { char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; @@ -242,11 +280,38 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, DBUG_PRINT("info", ("STRING_RESULT: null")); goto return_null_item; } - DBUG_PRINT("info",("STRING_RESULT: %*s", + DBUG_PRINT("info",("STRING_RESULT: %.*s", s->length(), s->c_ptr_quick())); + /* + Reuse mechanism in sp_eval_func_item() is only employed for assignments + to local variables and OUT/INOUT SP parameters repsesented by + Item_splocal. Usually we have some expression, which needs + to be calculated and stored into the local variable. However in the + case if "it" equals to "reuse", there is no "calculation" step. So, + no reason to employ reuse mechanism to save variable into itself. + */ + if (it == reuse) + DBUG_RETURN(it); + + /* + For some functions, 's' is now pointing to an argument of the + function, which might be a local variable that is to be reused. + In this case, new(reuse, &rsize) below will call the destructor + and 's' ends up pointing to freed memory. + A somewhat ugly fix is to simply copy the string to our local one + (which is unused by most functions anyway), but only if 's' is + pointing somewhere else than to 'tmp' or 'it->str_value'. + */ + if (reuse && s != &tmp && s != &it->str_value) + { + if (tmp.copy((const String)(*s))) + DBUG_RETURN(NULL); + s= &tmp; + } + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_string(it->collation.collation), - use_callers_arena, &backup_current_arena); + use_callers_arena, &backup_arena); /* We have to use special constructor and allocate string on system heap here. This is because usual Item_string @@ -270,15 +335,23 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, default: DBUG_ASSERT(0); } - it->rsize= rsize; - - DBUG_RETURN(it); + goto end; return_null_item: CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(), - use_callers_arena, &backup_current_arena); + use_callers_arena, &backup_arena); +end: it->rsize= rsize; + if (reuse && it == reuse) + { + /* + The Item constructor registered itself in the arena free list, + while the item slot is reused, so we have to restore the list. + */ + it->next= old_item_next; + *p_free_list= old_free_list; + } DBUG_RETURN(it); } @@ -297,7 +370,7 @@ sp_name::init_qname(THD *thd) return; m_qname.length= m_sroutines_key.length - 1; m_qname.str= m_sroutines_key.str + 1; - sprintf(m_qname.str, "%*s.%*s", + sprintf(m_qname.str, "%.*s.%.*s", m_db.length, (m_db.length ? m_db.str : ""), m_name.length, m_name.str); } @@ -364,9 +437,7 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), - m_returns_cs(NULL), m_has_return(FALSE), - m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE), - m_is_invoked(FALSE) + m_flags(0), m_returns_cs(NULL) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); @@ -649,10 +720,35 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) * If this function invocation is done from a statement that is written into the binary log. * If there were any attempts to write events to the binary log during - function execution. + function execution (grep for start_union_events and stop_union_events) + If the answers are No and Yes, we write the function call into the binary log as "DO spfunc(<param1value>, <param2value>, ...)" - + + + 4. Miscellaneous issues. + + 4.1 User variables. + + When we call mysql_bin_log.write() for an SP statement, thd->user_var_events + must hold set<{var_name, value}> pairs for all user variables used during + the statement execution. + This set is produced by tracking user variable reads during statement + execution. + + Fo SPs, this has the following implications: + 1) thd->user_var_events may contain events from several SP statements and + needs to be valid after exection of these statements was finished. In + order to achieve that, we + * Allocate user_var_events array elements on appropriate mem_root (grep + for user_var_events_alloc). + * Use is_query_in_union() to determine if user_var_event is created. + + 2) We need to empty thd->user_var_events after we have wrote a function + call. This is currently done by making + reset_dynamic(&thd->user_var_events); + calls in several different places. (TODO cosider moving this into + mysql_bin_log.write() function) */ @@ -714,6 +810,7 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) splocal < sp_vars_uses.back(); splocal++) { Item *val; + (*splocal)->thd= thd; // fix_fields() is not yet done /* append the text between sp ref occurences */ res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos); prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length; @@ -765,7 +862,7 @@ int sp_head::execute(THD *thd) /* per-instruction arena */ MEM_ROOT execute_mem_root; Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP), - execute_backup_arena; + backup_arena; query_id_t old_query_id; TABLE *old_derived_tables; LEX *old_lex; @@ -782,7 +879,7 @@ int sp_head::execute(THD *thd) DBUG_RETURN(-1); } - if (m_is_invoked) + if (m_flags & IS_INVOKED) { /* We have to disable recursion for stored routines since in @@ -802,7 +899,7 @@ int sp_head::execute(THD *thd) my_error(ER_SP_NO_RECURSION, MYF(0)); DBUG_RETURN(-1); } - m_is_invoked= TRUE; + m_flags|= IS_INVOKED; dbchanged= FALSE; if (m_db.length && @@ -812,7 +909,7 @@ int sp_head::execute(THD *thd) if ((ctx= thd->spcont)) ctx->clear_handler(); thd->query_error= 0; - old_arena= thd->current_arena; + old_arena= thd->stmt_arena; /* We have to save/restore this info when we are changing call level to @@ -848,13 +945,13 @@ int sp_head::execute(THD *thd) Switch to per-instruction arena here. We can do it since we cleanup arena after every instruction. */ - thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena); + thd->set_n_backup_active_arena(&execute_arena, &backup_arena); /* Save callers arena in order to store instruction results and out parameters in it later during sp_eval_func_item() */ - thd->spcont->callers_arena= &execute_backup_arena; + thd->spcont->callers_arena= &backup_arena; do { @@ -868,13 +965,22 @@ int sp_head::execute(THD *thd) /* Don't change NOW() in FUNCTION or TRIGGER */ if (!thd->in_sub_stmt) thd->set_time(); // Make current_time() et al work + /* - We have to set thd->current_arena before executing the instruction + We have to set thd->stmt_arena before executing the instruction to store in the instruction free_list all new items, created during the first execution (for example expanding of '*' or the items made during other permanent subquery transformations). */ - thd->current_arena= i; + thd->stmt_arena= i; + + /* + Will write this SP statement into binlog separately + (TODO: consider changing the condition to "not inside event union") + */ + if (thd->prelocked_mode == NON_PRELOCKED) + thd->user_var_events_alloc= thd->mem_root; + ret= i->execute(thd, &ip); /* @@ -886,10 +992,20 @@ int sp_head::execute(THD *thd) if (i->free_list) cleanup_items(i->free_list); i->state= Query_arena::EXECUTED; + + /* + If we've set thd->user_var_events_alloc to mem_root of this SP + statement, clean all the events allocated in it. + */ + if (thd->prelocked_mode == NON_PRELOCKED) + { + reset_dynamic(&thd->user_var_events); + thd->user_var_events_alloc= NULL;//DEBUG + } /* we should cleanup free_list and memroot, used by instruction */ thd->free_items(); - free_root(&execute_mem_root, MYF(0)); + free_root(&execute_mem_root, MYF(0)); /* Check if an exception has occurred and a handler has been found @@ -907,16 +1023,16 @@ int sp_head::execute(THD *thd) case SP_HANDLER_NONE: break; case SP_HANDLER_CONTINUE: - thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena); + thd->restore_active_arena(&execute_arena, &backup_arena); ctx->save_variables(hf); - thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena); + thd->set_n_backup_active_arena(&execute_arena, &backup_arena); ctx->push_hstack(ip); // Fall through default: ip= hip; ret= 0; ctx->clear_handler(); - ctx->in_handler= TRUE; + ctx->enter_handler(hip); thd->clear_error(); thd->killed= THD::NOT_KILLED; continue; @@ -924,7 +1040,7 @@ int sp_head::execute(THD *thd) } } while (ret == 0 && !thd->killed); - thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena); + thd->restore_active_arena(&execute_arena, &backup_arena); /* Restore all saved */ @@ -939,7 +1055,7 @@ int sp_head::execute(THD *thd) thd->derived_tables= old_derived_tables; thd->variables.sql_mode= save_sql_mode; - thd->current_arena= old_arena; + thd->stmt_arena= old_arena; state= EXECUTED; done: @@ -952,10 +1068,12 @@ int sp_head::execute(THD *thd) original thd->db will then have been freed */ if (dbchanged) { + /* No access check when changing back to where we came from. + (It would generate an error from mysql_change_db() when olddb=="") */ if (! thd->killed) - ret= mysql_change_db(thd, olddb, 0); + ret= mysql_change_db(thd, olddb, 1); } - m_is_invoked= FALSE; + m_flags&= ~IS_INVOKED; DBUG_RETURN(ret); } @@ -994,7 +1112,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; uint i; - Item_null *nit; int ret= -1; // Assume error if (argcount != params) @@ -1012,7 +1129,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) DBUG_RETURN(-1); // QQ Should have some error checking here? (types, etc...) - if (!(nctx= new sp_rcontext(csize, hmax, cmax))) + if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax))) goto end; for (i= 0 ; i < argcount ; i++) { @@ -1025,28 +1142,24 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) nctx->push_item(it); } + /* The rest of the frame are local variables which are all IN. - Default all variables to null (those with default clauses will - be set by an set instruction). + Push NULLs to get the right size (and make the reuse mechanism work) - + the will be initialized by set instructions in each frame. */ - - nit= NULL; // Re-use this, and only create if needed for (; i < csize ; i++) - { - if (! nit) - { - if (!(nit= new Item_null())) - DBUG_RETURN(-1); - } - nctx->push_item(nit); - } + nctx->push_item(NULL); + thd->spcont= nctx; binlog_save_options= thd->options; need_binlog_call= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG); if (need_binlog_call) + { + reset_dynamic(&thd->user_var_events); mysql_bin_log.start_union_events(thd); + } thd->options&= ~OPTION_BIN_LOG; ret= execute(thd); @@ -1080,6 +1193,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) "Invoked ROUTINE modified a transactional table but MySQL " "failed to reflect this change in the binary log"); } + reset_dynamic(&thd->user_var_events); } if (m_type == TYPE_ENUM_FUNCTION && ret == 0) @@ -1159,7 +1273,7 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) save_spcont= octx= thd->spcont; if (! octx) { // Create a temporary old context - if (!(octx= new sp_rcontext(csize, hmax, cmax))) + if (!(octx= new sp_rcontext(octx, csize, hmax, cmax))) DBUG_RETURN(-1); thd->spcont= octx; @@ -1167,12 +1281,12 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) thd->spcont->callers_arena= thd; } - if (!(nctx= new sp_rcontext(csize, hmax, cmax))) + if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax))) { thd->spcont= save_spcont; DBUG_RETURN(-1); } - + if (csize > 0 || hmax > 0 || cmax > 0) { Item_null *nit= NULL; // Re-use this, and only create if needed @@ -1233,23 +1347,14 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) close_thread_tables(thd, 0, 0); DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str)); + /* The rest of the frame are local variables which are all IN. - Default all variables to null (those with default clauses will - be set by an set instruction). + Push NULLs to get the right size (and make the reuse mechanism work) - + the will be initialized by set instructions in each frame. */ for (; i < csize ; i++) - { - if (! nit) - { - if (!(nit= new Item_null())) - { - ret= -1; - break; - } - } - nctx->push_item(nit); - } + nctx->push_item(NULL); } thd->spcont= nctx; @@ -1287,14 +1392,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) uint offset= static_cast<Item_splocal *>(it)->get_offset(); Item *val= nctx->get_item(i); Item *orig= octx->get_item(offset); - Item *o_item_next; - /* we'll use callers_arena in sp_eval_func_item */ - Item *o_free_list= thd->spcont->callers_arena->free_list; - - LINT_INIT(o_item_next); - - if (orig) - o_item_next= orig->next; /* We might need to allocate new item if we weren't able to @@ -1309,15 +1406,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) } if (copy != orig) octx->set_item(offset, copy); - if (orig && copy == orig) - { - /* - A reused item slot, where the constructor put it in the - free_list, so we have to restore the list. - */ - thd->spcont->callers_arena->free_list= o_free_list; - copy->next= o_item_next; - } } else { @@ -1349,7 +1437,7 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) nctx->pop_all_cursors(); // To avoid memory leaks after an error delete nctx; // Does nothing thd->spcont= save_spcont; - + DBUG_RETURN(ret); } @@ -1397,7 +1485,6 @@ sp_head::restore_lex(THD *thd) LEX *sublex= thd->lex; LEX *oldlex= (LEX *)m_lex.pop(); - init_stmt_after_parse(thd, sublex); if (! oldlex) return; // Nothing to restore @@ -1532,7 +1619,7 @@ sp_head::restore_thd_mem_root(THD *thd) { DBUG_ENTER("sp_head::restore_thd_mem_root"); Item *flist= free_list; // The old list - set_item_arena(thd); // Get new free_list and mem_root + set_query_arena(thd); // Get new free_list and mem_root state= INITIALIZED_FOR_SP; DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx", @@ -1566,8 +1653,10 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) tables.db= (char*) "mysql"; tables.table_name= tables.alias= (char*) "proc"; *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) || - (!strcmp(sp->m_definer_user.str, thd->priv_user) && - !strcmp(sp->m_definer_host.str, thd->priv_host))); + (!strcmp(sp->m_definer_user.str, + thd->security_ctx->priv_user) && + !strcmp(sp->m_definer_host.str, + thd->security_ctx->priv_host))); if (!*full_access) return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str, sp->m_type == TYPE_ENUM_PROCEDURE); @@ -1790,17 +1879,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, thd->query_id= next_query_id(); VOID(pthread_mutex_unlock(&LOCK_thread_count)); - /* - FIXME. Resetting statement (and using it) is not reentrant, thus recursive - functions which try to use the same LEX twice will crash server. - We should prevent such situations by tracking if LEX is already - in use and throwing error about unallowed recursion if needed. - OTOH it is nice to allow recursion in cases when LEX is not really - used (e.g. in mathematical functions), so such tracking should be - implemented at the same time as ability not to store LEX for - instruction if it is not really used. - */ - if (thd->prelocked_mode == NON_PRELOCKED) { /* @@ -1850,10 +1928,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, attached it above in this function). Now we'll save the 'tail', and detach it. */ - DBUG_ASSERT(!lex_query_tables_own_last || - lex_query_tables_own_last == m_lex->query_tables_own_last && - prelocking_tables == *(m_lex->query_tables_own_last)); - lex_query_tables_own_last= m_lex->query_tables_own_last; prelocking_tables= *lex_query_tables_own_last; *lex_query_tables_own_last= NULL; @@ -2323,7 +2397,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) thd->spcont->restore_variables(m_frame); *nextp= thd->spcont->pop_hstack(); } - thd->spcont->in_handler= FALSE; + thd->spcont->exit_handler(); DBUG_RETURN(0); } @@ -2335,7 +2409,10 @@ sp_instr_hreturn::print(String *str) str->append("hreturn "); str->qs_append(m_frame); if (m_dest) + { + str->append(' '); str->qs_append(m_dest); + } } @@ -2359,20 +2436,18 @@ sp_instr_hreturn::opt_mark(sp_head *sp) int sp_instr_cpush::execute(THD *thd, uint *nextp) { - Query_arena backup_current_arena; + Query_arena backup_arena; DBUG_ENTER("sp_instr_cpush::execute"); /* We should create cursors in the callers arena, as it could be (and usually is) used in several instructions. */ - thd->set_n_backup_item_arena(thd->spcont->callers_arena, - &backup_current_arena); + thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena); thd->spcont->push_cursor(&m_lex_keeper, this); - thd->restore_backup_item_arena(thd->spcont->callers_arena, - &backup_current_arena); + thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena); *nextp= m_ip+1; @@ -2423,6 +2498,10 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx) int sp_instr_copen::execute(THD *thd, uint *nextp) { + /* + We don't store a pointer to the cursor in the instruction to be + able to reuse the same instruction among different threads in future. + */ sp_cursor *c= thd->spcont->get_cursor(m_cursor); int res; DBUG_ENTER("sp_instr_copen::execute"); @@ -2431,41 +2510,33 @@ sp_instr_copen::execute(THD *thd, uint *nextp) res= -1; else { - sp_lex_keeper *lex_keeper= c->pre_open(thd); - if (!lex_keeper) // cursor already open or OOM - { - res= -1; - *nextp= m_ip+1; - } - else - { - Query_arena *old_arena= thd->current_arena; + sp_lex_keeper *lex_keeper= c->get_lex_keeper(); + Query_arena *old_arena= thd->stmt_arena; - /* - Get the Query_arena from the cpush instruction, which contains - the free_list of the query, so new items (if any) are stored in - the right free_list, and we can cleanup after each open. - */ - thd->current_arena= c->get_instr(); - res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this); - /* Cleanup the query's items */ - if (thd->current_arena->free_list) - cleanup_items(thd->current_arena->free_list); - thd->current_arena= old_arena; - /* - Work around the fact that errors in selects are not returned properly - (but instead converted into a warning), so if a condition handler - caught, we have lost the result code. - */ - if (!res) - { - uint dummy1, dummy2; + /* + Get the Query_arena from the cpush instruction, which contains + the free_list of the query, so new items (if any) are stored in + the right free_list, and we can cleanup after each open. + */ + thd->stmt_arena= c->get_instr(); + res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this); + /* Cleanup the query's items */ + if (thd->stmt_arena->free_list) + cleanup_items(thd->stmt_arena->free_list); + thd->stmt_arena= old_arena; + /* + Work around the fact that errors in selects are not returned properly + (but instead converted into a warning), so if a condition handler + caught, we have lost the result code. + */ + if (!res) + { + uint dummy1, dummy2; - if (thd->spcont->found_handler(&dummy1, &dummy2)) - res= -1; - } - c->post_open(thd, res ? FALSE : TRUE); + if (thd->spcont->found_handler(&dummy1, &dummy2)) + res= -1; } + /* TODO: Assert here that we either have an error or a cursor */ } DBUG_RETURN(res); } @@ -2474,7 +2545,8 @@ sp_instr_copen::execute(THD *thd, uint *nextp) int sp_instr_copen::exec_core(THD *thd, uint *nextp) { - int res= mysql_execute_command(thd); + sp_cursor *c= thd->spcont->get_cursor(m_cursor); + int res= c->open(thd); *nextp= m_ip+1; return res; } @@ -2526,19 +2598,10 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) { sp_cursor *c= thd->spcont->get_cursor(m_cursor); int res; - Query_arena backup_current_arena; + Query_arena backup_arena; DBUG_ENTER("sp_instr_cfetch::execute"); - if (! c) - res= -1; - else - { - thd->set_n_backup_item_arena(thd->spcont->callers_arena, - &backup_current_arena); - res= c->fetch(thd, &m_varlist); - thd->restore_backup_item_arena(thd->spcont->callers_arena, - &backup_current_arena); - } + res= c ? c->fetch(thd, &m_varlist) : -1; *nextp= m_ip+1; DBUG_RETURN(res); @@ -2594,54 +2657,51 @@ sp_instr_error::print(String *str) */ #ifndef NO_EMBEDDED_ACCESS_CHECKS -void -sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) -{ - ctxp->changed= (sp->m_chistics->suid != SP_IS_NOT_SUID && - (strcmp(sp->m_definer_user.str, thd->priv_user) || - strcmp(sp->m_definer_host.str, thd->priv_host))); - - if (ctxp->changed) +bool +sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup) +{ + *backup= 0; + if (sp->m_chistics->suid != SP_IS_NOT_SUID && + (strcmp(sp->m_definer_user.str, + thd->security_ctx->priv_user) || + my_strcasecmp(system_charset_info, sp->m_definer_host.str, + thd->security_ctx->priv_host))) { - ctxp->master_access= thd->master_access; - ctxp->db_access= thd->db_access; - ctxp->priv_user= thd->priv_user; - strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host)); - ctxp->user= thd->user; - ctxp->host= thd->host; - ctxp->ip= thd->ip; - - /* Change thise just to do the acl_getroot_no_password */ - thd->user= sp->m_definer_user.str; - thd->host= thd->ip = sp->m_definer_host.str; - - if (acl_getroot_no_password(thd)) - { // Failed, run as invoker for now - ctxp->changed= FALSE; - thd->master_access= ctxp->master_access; - thd->db_access= ctxp->db_access; - thd->priv_user= ctxp->priv_user; - strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); + if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str, + sp->m_definer_host.str, + sp->m_definer_host.str, + sp->m_db.str)) + { +#ifdef NOT_YET_REPLICATION_SAFE + /* + Until we don't properly replicate information about stored routine + definer with stored routine creation statement all stored routines + on slave are created under ''@'' definer. Therefore we won't be able + to run any routine which was replicated from master on slave server + if we emit error here. This will cause big problems for users + who use slave for fail-over. So until we fully implement WL#2897 + "Complete definer support in the stored routines" we run suid + stored routines for which we were unable to find definer under + invoker security context. + */ + my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str, + sp->m_definer_host.str); + return TRUE; +#else + return FALSE; +#endif } - - /* Restore these immiediately */ - thd->user= ctxp->user; - thd->host= ctxp->host; - thd->ip= ctxp->ip; + *backup= thd->security_ctx; + thd->security_ctx= &sp->m_security_ctx; } + return FALSE; } void -sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) +sp_restore_security_context(THD *thd, Security_context *backup) { - if (ctxp->changed) - { - ctxp->changed= FALSE; - thd->master_access= ctxp->master_access; - thd->db_access= ctxp->db_access; - thd->priv_user= ctxp->priv_user; - strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); - } + if (backup) + thd->security_ctx= backup; } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ @@ -2790,7 +2850,7 @@ sp_head::add_used_tables_to_table_list(THD *thd, /* Use persistent arena for table list allocation to be PS friendly. */ - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); for (i=0 ; i < m_sptabs.records ; i++) { @@ -2835,7 +2895,7 @@ sp_head::add_used_tables_to_table_list(THD *thd, } if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); DBUG_RETURN(result); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 1d4bfb514d3..ed0f3987e01 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -33,8 +33,8 @@ Item_result sp_map_result_type(enum enum_field_types type); -bool -sp_multi_results_command(enum enum_sql_command cmd); +uint +sp_get_flags_for_command(LEX *lex); struct sp_label; class sp_instr; @@ -107,18 +107,25 @@ class sp_head :private Query_arena MEM_ROOT main_mem_root; public: + /* Possible values of m_flags */ + enum { + HAS_RETURN= 1, // For FUNCTIONs only: is set if has RETURN + IN_SIMPLE_CASE= 2, // Is set if parsing a simple CASE + IN_HANDLER= 4, // Is set if the parser is in a handler body + MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s) + CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE + IS_INVOKED= 32, // Is set if this sp_head is being used + HAS_SET_AUTOCOMMIT_STMT = 64 // Is set if a procedure with 'set autocommit' + }; int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE + uint m_flags; // Boolean attributes of a stored routine enum enum_field_types m_returns; // For FUNCTIONs only Field::geometry_type m_geom_returns; CHARSET_INFO *m_returns_cs; // For FUNCTIONs only TYPELIB *m_returns_typelib; // For FUNCTIONs only uint m_returns_len; // For FUNCTIONs only uint m_returns_pack; // For FUNCTIONs only - my_bool m_has_return; // For FUNCTIONs only - my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise - my_bool m_multi_results; // TRUE if a procedure with SELECT(s) - my_bool m_in_handler; // TRUE if parser in a handler body uchar *m_tmp_query; // Temporary pointer to sub query string uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value st_sp_chistics *m_chistics; @@ -144,6 +151,12 @@ public: // Pointers set during parsing uchar *m_param_begin, *m_param_end, *m_body_begin; + /* + Security context for stored routine which should be run under + definer privileges. + */ + Security_context m_security_ctx; + static void * operator new(size_t size); @@ -265,6 +278,22 @@ public: bool add_used_tables_to_table_list(THD *thd, TABLE_LIST ***query_tables_last_ptr); + /* + Check if this stored routine contains statements disallowed + in a stored function or trigger, and set an appropriate error message + if this is the case. + */ + bool is_not_allowed_in_function(const char *where) + { + if (m_flags & CONTAINS_DYNAMIC_SQL) + my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "Dynamic SQL"); + else if (m_flags & MULTI_RESULTS) + my_error(ER_SP_NO_RETSET, MYF(0), where); + else if (m_flags & HAS_SET_AUTOCOMMIT_STMT) + my_error(ER_SP_CANT_SET_AUTOCOMMIT, MYF(0)); + return test(m_flags & + (CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT)); + } private: MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root @@ -290,9 +319,6 @@ private: */ HASH m_sptabs; - /* Used for tracking of routine invocations and preventing recursion. */ - bool m_is_invoked; - int execute(THD *thd); @@ -840,6 +866,12 @@ public: virtual void print(String *str); + /* + This call is used to cleanup the instruction when a sensitive + cursor is closed. For now stored procedures always use materialized + cursors and the call is not used. + */ + virtual void cleanup_stmt() { /* no op */ } private: sp_lex_keeper m_lex_keeper; @@ -997,23 +1029,12 @@ private: }; // class sp_instr_error : public sp_instr -struct st_sp_security_context -{ - bool changed; - uint master_access; - uint db_access; - char *priv_user; - char priv_host[MAX_HOSTNAME]; - char *user; - char *host; - char *ip; -}; - #ifndef NO_EMBEDDED_ACCESS_CHECKS +bool +sp_change_security_context(THD *thd, sp_head *sp, + Security_context **backup); void -sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp); -void -sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp); +sp_restore_security_context(THD *thd, Security_context *backup); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ TABLE_LIST * @@ -1021,4 +1042,7 @@ sp_add_to_query_tables(THD *thd, LEX *lex, const char *db, const char *name, thr_lock_type locktype); +Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type, + Item *reuse, bool use_callers_arena); + #endif /* _SP_HEAD_H_ */ diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 0de7fe212c0..f873b676925 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -184,7 +184,6 @@ sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type, p->type= type; p->mode= mode; p->offset= current_pvars(); - p->isset= (mode == sp_param_out ? FALSE : TRUE); p->dflt= NULL; insert_dynamic(&m_pvar, (gptr)&p); } diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 196f9ccb24b..bd2259cb6fb 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -35,7 +35,6 @@ typedef struct sp_pvar enum enum_field_types type; sp_param_mode_t mode; uint offset; // Offset in current frame - my_bool isset; Item *dflt; } sp_pvar_t; @@ -148,15 +147,6 @@ class sp_pcontext : public Sql_alloc } inline void - set_isset(uint i, my_bool val) - { - sp_pvar_t *p= find_pvar(i); - - if (p) - p->isset= val; - } - - inline void set_default(uint i, Item *it) { sp_pvar_t *p= find_pvar(i); diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 748c09f56c7..ccb38358049 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -25,17 +25,18 @@ #include "mysql.h" #include "sp_head.h" +#include "sql_cursor.h" #include "sp_rcontext.h" #include "sp_pcontext.h" -sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) +sp_rcontext::sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax) : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0), - m_hfound(-1), m_ccount(0) + m_ihsp(0), m_hfound(-1), m_ccount(0), m_prev_ctx(prev) { - in_handler= FALSE; m_frame= (Item **)sql_alloc(fsize * sizeof(Item*)); m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t)); m_hstack= (uint *)sql_alloc(hmax * sizeof(uint)); + m_in_handler= (uint *)sql_alloc(hmax * sizeof(uint)); m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *)); m_saved.empty(); } @@ -45,31 +46,18 @@ int sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr, enum_field_types type) { - extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type, - Item *reuse, bool use_callers_arena); Item *it; Item *reuse_it; - Item *old_item_next; /* sp_eval_func_item will use callers_arena */ - Item *old_free_list= thd->spcont->callers_arena->free_list; int res; - LINT_INIT(old_item_next); - if ((reuse_it= get_item(idx))) - old_item_next= reuse_it->next; + reuse_it= get_item(idx); it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE); if (! it) res= -1; else { res= 0; - if (reuse_it && it == reuse_it) - { - // A reused item slot, where the constructor put it in the free_list, - // so we have to restore the list. - thd->spcont->callers_arena->free_list= old_free_list; - it->next= old_item_next; - } set_item(idx, it); } @@ -80,8 +68,6 @@ bool sp_rcontext::find_handler(uint sql_errno, MYSQL_ERROR::enum_warning_level level) { - if (in_handler) - return 0; // Already executing a handler if (m_hfound >= 0) return 1; // Already got one @@ -91,6 +77,13 @@ sp_rcontext::find_handler(uint sql_errno, while (i--) { sp_cond_type_t *cond= m_handler[i].cond; + int j= m_ihsp; + + while (j--) + if (m_in_handler[j] == m_handler[i].handler) + break; + if (j >= 0) + continue; // Already executing this handler switch (cond->type) { @@ -123,7 +116,11 @@ sp_rcontext::find_handler(uint sql_errno, } } if (found < 0) + { + if (m_prev_ctx) + return m_prev_ctx->find_handler(sql_errno, level); return FALSE; + } m_hfound= found; return TRUE; } @@ -170,7 +167,8 @@ sp_rcontext::pop_cursors(uint count) */ sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) - :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL), + :m_lex_keeper(lex_keeper), + server_side_cursor(NULL), m_i(i) { /* @@ -182,59 +180,37 @@ sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) /* - pre_open cursor + Open an SP cursor SYNOPSIS - pre_open() - THD Thread handler + open() + THD Thread handler - NOTES - We have to open cursor in two steps to make it easy for sp_instr_copen - to reuse the sp_instr::exec_stmt() code. - If this function returns 0, post_open should not be called RETURN - 0 ERROR + 0 in case of success, -1 otherwise */ -sp_lex_keeper* -sp_cursor::pre_open(THD *thd) +int +sp_cursor::open(THD *thd) { - if (m_isopen) + if (server_side_cursor) { my_message(ER_SP_CURSOR_ALREADY_OPEN, ER(ER_SP_CURSOR_ALREADY_OPEN), MYF(0)); - return NULL; + return -1; } - init_alloc_root(&m_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); - if ((m_prot= new Protocol_cursor(thd, &m_mem_root)) == NULL) - return NULL; - - /* Save for execution. Will be restored in post_open */ - m_oprot= thd->protocol; - m_nseof= thd->net.no_send_eof; - - /* Change protocol for execution */ - thd->protocol= m_prot; - thd->net.no_send_eof= TRUE; - return m_lex_keeper; -} - - -void -sp_cursor::post_open(THD *thd, my_bool was_opened) -{ - thd->net.no_send_eof= m_nseof; // Restore the originals - thd->protocol= m_oprot; - if ((m_isopen= was_opened)) - m_current_row= m_prot->data; + if (mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, &result, + &server_side_cursor)) + return -1; + return 0; } int sp_cursor::close(THD *thd) { - if (! m_isopen) + if (! server_side_cursor) { my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0)); return -1; @@ -247,106 +223,82 @@ sp_cursor::close(THD *thd) void sp_cursor::destroy() { - if (m_prot) - { - delete m_prot; - m_prot= NULL; - free_root(&m_mem_root, MYF(0)); - } - m_isopen= FALSE; + delete server_side_cursor; + server_side_cursor= 0; } + int sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars) { - List_iterator_fast<struct sp_pvar> li(*vars); - sp_pvar_t *pv; - MYSQL_ROW row; - uint fldcount; - - if (! m_isopen) + if (! server_side_cursor) { my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0)); return -1; } - if (m_current_row == NULL) + if (vars->elements != result.get_field_count()) { - my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0)); + my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS, + ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0)); return -1; } - row= m_current_row->data; - for (fldcount= 0 ; (pv= li++) ; fldcount++) - { - Item *it; - Item *reuse; - uint rsize; - Item *old_item_next; - Item *old_free_list= thd->free_list; - const char *s; - LINT_INIT(old_item_next); - - if (fldcount >= m_prot->get_field_count()) - { - my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS, - ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0)); - return -1; - } + result.set_spvar_list(vars); - if ((reuse= thd->spcont->get_item(pv->offset))) - old_item_next= reuse->next; + /* Attempt to fetch one row */ + if (server_side_cursor->is_open()) + server_side_cursor->fetch(1); - s= row[fldcount]; - if (!s) - it= new(reuse, &rsize) Item_null(); - else - { - /* - Length of data can be calculated as: - pointer_to_next_not_null_object - s -1 - where the last -1 is to remove the end \0 - */ - uint len; - MYSQL_ROW next= row+fldcount+1; - while (!*next) // Skip nulls - next++; - len= (*next -s)-1; - switch (sp_map_result_type(pv->type)) { - case INT_RESULT: - it= new(reuse, &rsize) Item_int(s); - break; - case REAL_RESULT: - it= new(reuse, &rsize) Item_float(s, len); - break; - case DECIMAL_RESULT: - it= new(reuse, &rsize) Item_decimal(s, len, thd->db_charset); - break; - case STRING_RESULT: - /* TODO: Document why we do an extra copy of the string 's' here */ - it= new(reuse, &rsize) Item_string(thd->strmake(s, len), len, - thd->db_charset); - break; - case ROW_RESULT: - default: - DBUG_ASSERT(0); - } - } - it->rsize= rsize; - if (reuse && it == reuse) - { - // A reused item slot, where the constructor put it in the free_list, - // so we have to restore the list. - thd->free_list= old_free_list; - it->next= old_item_next; - } - thd->spcont->set_item(pv->offset, it); - } - if (fldcount < m_prot->get_field_count()) + /* + If the cursor was pointing after the last row, the fetch will + close it instead of sending any rows. + */ + if (! server_side_cursor->is_open()) { - my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS, - ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0)); + my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0)); return -1; } - m_current_row= m_current_row->next; + return 0; } + + +/*************************************************************************** + Select_fetch_into_spvars +****************************************************************************/ + +int Select_fetch_into_spvars::prepare(List<Item> &fields, SELECT_LEX_UNIT *u) +{ + /* + Cache the number of columns in the result set in order to easily + return an error if column count does not match value count. + */ + field_count= fields.elements; + return select_result_interceptor::prepare(fields, u); +} + + +bool Select_fetch_into_spvars::send_data(List<Item> &items) +{ + List_iterator_fast<struct sp_pvar> pv_iter(*spvar_list); + List_iterator_fast<Item> item_iter(items); + sp_pvar_t *pv; + Item *item; + + /* Must be ensured by the caller */ + DBUG_ASSERT(spvar_list->elements == items.elements); + + /* + Assign the row fetched from a server side cursor to stored + procedure variables. + */ + for (; pv= pv_iter++, item= item_iter++; ) + { + Item *reuse= thd->spcont->get_item(pv->offset); + /* Evaluate a new item on the arena of the calling instruction */ + Item *it= sp_eval_func_item(thd, &item, pv->type, reuse, TRUE); + + thd->spcont->set_item(pv->offset, it); + } + return FALSE; +} diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 36380952e5d..cae5c5467c9 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -58,7 +58,6 @@ class sp_rcontext : public Sql_alloc public: - bool in_handler; /* Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT SP parameters when they don't fit into prealloced items. This @@ -67,7 +66,7 @@ class sp_rcontext : public Sql_alloc */ Query_arena *callers_arena; - sp_rcontext(uint fsize, uint hmax, uint cmax); + sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax); ~sp_rcontext() { @@ -150,6 +149,13 @@ class sp_rcontext : public Sql_alloc return m_handler[m_hfound].type; } + // Returns true if we found a handler in this context + inline bool + found_handler_here() + { + return (m_hfound >= 0); + } + // Clears the handler find state inline void clear_handler() @@ -169,6 +175,18 @@ class sp_rcontext : public Sql_alloc return m_hstack[--m_hsp]; } + inline void + enter_handler(int hid) + { + m_in_handler[m_ihsp++]= hid; + } + + inline void + exit_handler() + { + m_ihsp-= 1; + } + // Save variables starting at fp and up void save_variables(uint fp); @@ -203,19 +221,44 @@ private: Item *m_result; // For FUNCTIONs - sp_handler_t *m_handler; - uint m_hcount; - uint *m_hstack; - uint m_hsp; - int m_hfound; // Set by find_handler; -1 if not found - List<Item> m_saved; // Saved variables + sp_handler_t *m_handler; // Visible handlers + uint m_hcount; // Stack pointer for m_handler + uint *m_hstack; // Return stack for continue handlers + uint m_hsp; // Stack pointer for m_hstack + uint *m_in_handler; // Active handler, for recursion check + uint m_ihsp; // Stack pointer for m_in_handler + int m_hfound; // Set by find_handler; -1 if not found + List<Item> m_saved; // Saved variables during handler exec. sp_cursor **m_cstack; uint m_ccount; + sp_rcontext *m_prev_ctx; // Previous context (NULL if none) + }; // class sp_rcontext : public Sql_alloc +/* + An interceptor of cursor result set used to implement + FETCH <cname> INTO <varlist>. +*/ + +class Select_fetch_into_spvars: public select_result_interceptor +{ + List<struct sp_pvar> *spvar_list; + uint field_count; +public: + uint get_field_count() { return field_count; } + void set_spvar_list(List<struct sp_pvar> *vars) { spvar_list= vars; } + + virtual bool send_eof() { return FALSE; } + virtual bool send_data(List<Item> &items); + virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u); +}; + + +/* A mediator between stored procedures and server side cursors */ + class sp_cursor : public Sql_alloc { public: @@ -227,12 +270,11 @@ public: destroy(); } - // We have split this in two to make it easy for sp_instr_copen - // to reuse the sp_instr::exec_stmt() code. sp_lex_keeper * - pre_open(THD *thd); - void - post_open(THD *thd, my_bool was_opened); + get_lex_keeper() { return m_lex_keeper; } + + int + open(THD *thd); int close(THD *thd); @@ -240,7 +282,7 @@ public: inline my_bool is_open() { - return m_isopen; + return test(server_side_cursor); } int @@ -251,18 +293,13 @@ public: { return m_i; } - + private: - MEM_ROOT m_mem_root; // My own mem_root + Select_fetch_into_spvars result; sp_lex_keeper *m_lex_keeper; - Protocol_cursor *m_prot; - my_bool m_isopen; - my_bool m_nseof; // Original no_send_eof - Protocol *m_oprot; // Original protcol - MYSQL_ROWS *m_current_row; + Server_side_cursor *server_side_cursor; sp_instr_cpush *m_i; // My push instruction - void destroy(); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 4629752c6a7..0691708f19b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -63,18 +63,21 @@ static bool allow_all_hosts=1; static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash; static DYNAMIC_ARRAY acl_wild_hosts; static hash_filo *acl_cache; -static uint grant_version=0; /* Version of priv tables. incremented by acl_init */ +static uint grant_version=0; /* Version of priv tables. incremented by acl_load */ static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); static ulong get_sort(uint count,...); static void init_check_host(void); static ACL_USER *find_acl_user(const char *host, const char *user, my_bool exact); -static bool update_user_table(THD *thd, const char *host, const char *user, +static bool update_user_table(THD *thd, TABLE *table, + const char *host, const char *user, const char *new_password, uint new_password_len); static void update_hostname(acl_host_and_ip *host, const char *hostname); static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); +static my_bool acl_load(THD *thd, TABLE_LIST *tables); +static my_bool grant_load(TABLE_LIST *tables); /* Convert scrambled password to binary form, according to scramble type, @@ -119,68 +122,86 @@ static void restrict_update_of_old_passwords_var(THD *thd, /* - Read grant privileges from the privilege tables in the 'mysql' database. + Initialize structures responsible for user/db-level privilege checking and + load privilege information for them from tables in the 'mysql' database. SYNOPSIS acl_init() - thd Thread handler - dont_read_acl_tables Set to 1 if run with --skip-grant + dont_read_acl_tables TRUE if we want to skip loading data from + privilege tables and disable privilege checking. + + NOTES + This function is mostly responsible for preparatory steps, main work + on initialization and grants loading is done in acl_reload(). RETURN VALUES 0 ok 1 Could not initialize grant's */ - -my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) +my_bool acl_init(bool dont_read_acl_tables) { THD *thd; - TABLE_LIST tables[3]; - TABLE *table; - READ_RECORD read_record_info; - my_bool return_val=1; - bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; - char tmp_name[NAME_LEN+1]; - + my_bool return_val; DBUG_ENTER("acl_init"); - if (!acl_cache) - acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0, - (hash_get_key) acl_entry_get_key, - (hash_free_key) free, system_charset_info); + acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0, + (hash_get_key) acl_entry_get_key, + (hash_free_key) free, system_charset_info); if (dont_read_acl_tables) { DBUG_RETURN(0); /* purecov: tested */ } - grant_version++; /* Privileges updated */ - mysql_proc_table_exists= 1; // Assume mysql.proc exists - /* To be able to run this from boot, we allocate a temporary THD */ if (!(thd=new THD)) DBUG_RETURN(1); /* purecov: inspected */ thd->store_globals(); + /* + It is safe to call acl_reload() since acl_* arrays and hashes which + will be freed there are global static objects and thus are initialized + by zeros at startup. + */ + return_val= acl_reload(thd); + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + DBUG_RETURN(return_val); +} + + +/* + Initialize structures responsible for user/db-level privilege checking + and load information about grants from open privilege tables. + + SYNOPSIS + acl_load() + thd Current thread + tables List containing open "mysql.host", "mysql.user" and + "mysql.db" tables. + + RETURN VALUES + FALSE Success + TRUE Error +*/ + +static my_bool acl_load(THD *thd, TABLE_LIST *tables) +{ + TABLE *table; + READ_RECORD read_record_info; + my_bool return_val= 1; + bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; + char tmp_name[NAME_LEN+1]; + int password_length; + DBUG_ENTER("acl_load"); + + grant_version++; /* Privileges updated */ + mysql_proc_table_exists= 1; // Assume mysql.proc exists acl_cache->clear(1); // Clear locked hostname cache - thd->db= my_strdup("mysql",MYF(0)); - thd->db_length=5; // Safety - bzero((char*) &tables,sizeof(tables)); - tables[0].alias=tables[0].table_name=(char*) "host"; - tables[1].alias=tables[1].table_name=(char*) "user"; - tables[2].alias=tables[2].table_name=(char*) "db"; - tables[0].next_local= tables[0].next_global= tables+1; - tables[1].next_local= tables[1].next_global= tables+2; - tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; - tables[0].db=tables[1].db=tables[2].db=thd->db; - if (simple_open_n_lock_tables(thd, tables)) - { - sql_print_error("Fatal error: Can't open and lock privilege tables: %s", - thd->net.last_error); - goto end; - } init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0); VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); @@ -230,7 +251,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0); VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100)); - if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323) + password_length= table->field[2]->field_length / + table->field[2]->charset()->mbmaxlen; + if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323) { sql_print_error("Fatal error: mysql.user table is damaged or in " "unsupported 3.20 format."); @@ -238,10 +261,10 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) } DBUG_PRINT("info",("user table fields: %d, password length: %d", - table->s->fields, table->field[2]->field_length)); + table->s->fields, password_length)); pthread_mutex_lock(&LOCK_global_system_variables); - if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) + if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) { if (opt_secure_auth) { @@ -454,19 +477,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) init_check_host(); initialized=1; - thd->version--; // Force close to free memory return_val=0; end: - close_thread_tables(thd); - delete thd; - if (org_thd) - org_thd->store_globals(); /* purecov: inspected */ - else - { - /* Remember that we don't have a THD */ - my_pthread_setspecific_ptr(THR_THD, 0); - } DBUG_RETURN(return_val); } @@ -490,27 +503,60 @@ void acl_free(bool end) /* - Forget current privileges and read new privileges from the privilege tables + Forget current user/db-level privileges and read new privileges + from the privilege tables. SYNOPSIS acl_reload() - thd Thread handle. Note that this may be NULL if we refresh - because we got a signal + thd Current thread + + NOTE + All tables of calling thread which were open and locked by LOCK TABLES + statement will be unlocked and closed. + This function is also used for initialization of structures responsible + for user/db-level privilege checking. + + RETURN VALUE + FALSE Success + TRUE Failure */ -void acl_reload(THD *thd) +my_bool acl_reload(THD *thd) { + TABLE_LIST tables[3]; DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs; MEM_ROOT old_mem; bool old_initialized; + my_bool return_val= 1; DBUG_ENTER("acl_reload"); - if (thd && thd->locked_tables) + if (thd->locked_tables) { // Can't have locked tables here thd->lock=thd->locked_tables; thd->locked_tables=0; close_thread_tables(thd); } + + /* + To avoid deadlocks we should obtain table locks before + obtaining acl_cache->lock mutex. + */ + bzero((char*) tables, sizeof(tables)); + tables[0].alias= tables[0].table_name= (char*) "host"; + tables[1].alias= tables[1].table_name= (char*) "user"; + tables[2].alias= tables[2].table_name= (char*) "db"; + tables[0].db=tables[1].db=tables[2].db=(char*) "mysql"; + tables[0].next_local= tables[0].next_global= tables+1; + tables[1].next_local= tables[1].next_global= tables+2; + tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; + + if (simple_open_n_lock_tables(thd, tables)) + { + sql_print_error("Fatal error: Can't open and lock privilege tables: %s", + thd->net.last_error); + goto end; + } + if ((old_initialized=initialized)) VOID(pthread_mutex_lock(&acl_cache->lock)); @@ -521,7 +567,7 @@ void acl_reload(THD *thd) delete_dynamic(&acl_wild_hosts); hash_free(&acl_check_hosts); - if (acl_init(thd, 0)) + if ((return_val= acl_load(thd, tables))) { // Error. Revert to old list DBUG_PRINT("error",("Reverting to old privileges")); acl_free(); /* purecov: inspected */ @@ -540,7 +586,9 @@ void acl_reload(THD *thd) } if (old_initialized) VOID(pthread_mutex_unlock(&acl_cache->lock)); - DBUG_VOID_RETURN; +end: + close_thread_tables(thd); + DBUG_RETURN(return_val); } @@ -648,8 +696,8 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) SYNOPSIS acl_getroot() thd thread handle. If all checks are OK, - thd->priv_user, thd->master_access are updated. - thd->host, thd->ip, thd->user are used for checks. + thd->security_ctx->priv_user/master_access are updated. + thd->security_ctx->host/ip/user are used for checks. mqh user resources; on success mqh is reset, else unchanged passwd scrambled & crypted password, received from client @@ -674,6 +722,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, ulong user_access= NO_ACCESS; int res= 1; ACL_USER *acl_user= 0; + Security_context *sctx= thd->security_ctx; DBUG_ENTER("acl_getroot"); if (!initialized) @@ -681,9 +730,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, /* here if mysqld's been started with --skip-grant-tables option. */ - thd->priv_user= (char *) ""; // privileges for - *thd->priv_host= '\0'; // the user are unknown - thd->master_access= ~NO_ACCESS; // everything is allowed + sctx->skip_grants(); bzero((char*) mqh, sizeof(*mqh)); DBUG_RETURN(0); } @@ -699,9 +746,9 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, for (uint i=0 ; i < acl_users.elements ; i++) { ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*); - if (!acl_user_tmp->user || !strcmp(thd->user, acl_user_tmp->user)) + if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user)) { - if (compare_hostname(&acl_user_tmp->host, thd->host, thd->ip)) + if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip)) { /* check password: it should be empty or valid */ if (passwd_len == acl_user_tmp->salt_len) @@ -848,14 +895,14 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, break; #endif /* HAVE_OPENSSL */ } - thd->master_access= user_access; - thd->priv_user= acl_user->user ? thd->user : (char *) ""; + sctx->master_access= user_access; + sctx->priv_user= acl_user->user ? sctx->user : (char *) ""; *mqh= acl_user->user_resource; if (acl_user->host.hostname) - strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME); + strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME); else - *thd->priv_host= 0; + *sctx->priv_host= 0; } VOID(pthread_mutex_unlock(&acl_cache->lock)); DBUG_RETURN(res); @@ -863,47 +910,62 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, /* - * This is like acl_getroot() above, but it doesn't check password, - * and we don't care about the user resources. - * Used to get access rights for SQL SECURITY DEFINER invocation of - * stored procedures. - */ -int acl_getroot_no_password(THD *thd) + This is like acl_getroot() above, but it doesn't check password, + and we don't care about the user resources. + + SYNOPSIS + acl_getroot_no_password() + sctx Context which should be initialized + user user name + host host name + ip IP + db current data base name + + RETURN + FALSE OK + TRUE Error +*/ + +bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, + char *ip, char *db) { int res= 1; uint i; ACL_USER *acl_user= 0; DBUG_ENTER("acl_getroot_no_password"); + sctx->user= user; + sctx->host= host; + sctx->ip= ip; + sctx->host_or_ip= host ? host : (ip ? ip : ""); + if (!initialized) { - /* + /* here if mysqld's been started with --skip-grant-tables option. */ - thd->priv_user= (char *) ""; // privileges for - *thd->priv_host= '\0'; // the user are unknown - thd->master_access= ~NO_ACCESS; // everything is allowed - DBUG_RETURN(0); + sctx->skip_grants(); + DBUG_RETURN(FALSE); } VOID(pthread_mutex_lock(&acl_cache->lock)); - thd->master_access= 0; - thd->db_access= 0; + sctx->master_access= 0; + sctx->db_access= 0; /* Find acl entry in user database. This is specially tailored to suit the check we do for CALL of - a stored procedure; thd->user is set to what is actually a + a stored procedure; user is set to what is actually a priv_user, which can be ''. */ for (i=0 ; i < acl_users.elements ; i++) { acl_user= dynamic_element(&acl_users,i,ACL_USER*); - if ((!acl_user->user && (!thd->user || !thd->user[0])) || - (acl_user->user && strcmp(thd->user, acl_user->user) == 0)) + if ((!acl_user->user && (!user || !user[0])) || + (acl_user->user && strcmp(user, acl_user->user) == 0)) { - if (compare_hostname(&acl_user->host, thd->host, thd->ip)) + if (compare_hostname(&acl_user->host, host, ip)) { res= 0; break; @@ -917,25 +979,25 @@ int acl_getroot_no_password(THD *thd) { ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*); if (!acl_db->user || - (thd->user && thd->user[0] && !strcmp(thd->user, acl_db->user))) + (user && user[0] && !strcmp(user, acl_db->user))) { - if (compare_hostname(&acl_db->host, thd->host, thd->ip)) + if (compare_hostname(&acl_db->host, host, ip)) { - if (!acl_db->db || (thd->db && !strcmp(acl_db->db, thd->db))) + if (!acl_db->db || (db && !strcmp(acl_db->db, db))) { - thd->db_access= acl_db->access; + sctx->db_access= acl_db->access; break; } } } } - thd->master_access= acl_user->access; - thd->priv_user= acl_user->user ? thd->user : (char *) ""; + sctx->master_access= acl_user->access; + sctx->priv_user= acl_user->user ? user : (char *) ""; if (acl_user->host.hostname) - strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME); + strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME); else - *thd->priv_host= 0; + *sctx->priv_host= 0; } VOID(pthread_mutex_unlock(&acl_cache->lock)); DBUG_RETURN(res); @@ -1289,13 +1351,14 @@ bool check_change_password(THD *thd, const char *host, const char *user, return(1); } if (!thd->slave_thread && - (strcmp(thd->user,user) || - my_strcasecmp(system_charset_info, host, thd->priv_host))) + (strcmp(thd->security_ctx->user, user) || + my_strcasecmp(system_charset_info, host, + thd->security_ctx->priv_host))) { - if (check_access(thd, UPDATE_ACL, "mysql",0,1,0)) + if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0)) return(1); } - if (!thd->slave_thread && !thd->user[0]) + if (!thd->slave_thread && !thd->security_ctx->user[0]) { my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER), MYF(0)); @@ -1330,7 +1393,13 @@ bool check_change_password(THD *thd, const char *host, const char *user, bool change_password(THD *thd, const char *host, const char *user, char *new_password) { + TABLE_LIST tables; + TABLE *table; + /* Buffer should be extended when password length is extended. */ + char buff[512]; + ulong query_length; uint new_password_len= strlen(new_password); + bool result= 1; DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -1339,40 +1408,97 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user, new_password, new_password_len)) DBUG_RETURN(1); + bzero((char*) &tables, sizeof(tables)); + tables.alias= tables.table_name= (char*) "user"; + tables.db= (char*) "mysql"; + +#ifdef HAVE_REPLICATION + /* + GRANT and REVOKE are applied the slave in/exclusion rules as they are + some kind of updates to the mysql.% tables. + */ + if (thd->slave_thread && table_rules_on) + { + /* + The tables must be marked "updating" so that tables_ok() takes them into + account in tests. It's ok to leave 'updating' set after tables_ok. + */ + tables.updating= 1; + /* Thanks to bzero, tables.next==0 */ + if (!tables_ok(thd, &tables)) + DBUG_RETURN(0); + } +#endif + + if (!(table= open_ltable(thd, &tables, TL_WRITE))) + DBUG_RETURN(1); + VOID(pthread_mutex_lock(&acl_cache->lock)); ACL_USER *acl_user; if (!(acl_user= find_acl_user(host, user, TRUE))) { VOID(pthread_mutex_unlock(&acl_cache->lock)); my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0)); - DBUG_RETURN(1); + goto end; } /* update loaded acl entry: */ set_user_salt(acl_user, new_password, new_password_len); - if (update_user_table(thd, + if (update_user_table(thd, table, acl_user->host.hostname ? acl_user->host.hostname : "", acl_user->user ? acl_user->user : "", new_password, new_password_len)) { VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ - DBUG_RETURN(1); /* purecov: deadcode */ + goto end; } acl_cache->clear(1); // Clear locked hostname cache VOID(pthread_mutex_unlock(&acl_cache->lock)); + result= 0; + if (mysql_bin_log.is_open()) + { + query_length= + my_sprintf(buff, + (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", + acl_user->user ? acl_user->user : "", + acl_user->host.hostname ? acl_user->host.hostname : "", + new_password)); + thd->clear_error(); + Query_log_event qinfo(thd, buff, query_length, 0, FALSE); + mysql_bin_log.write(&qinfo); + } +end: + close_thread_tables(thd); + DBUG_RETURN(result); +} - char buff[512]; /* Extend with extended password length*/ - ulong query_length= - my_sprintf(buff, - (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", - acl_user->user ? acl_user->user : "", - acl_user->host.hostname ? acl_user->host.hostname : "", - new_password)); - thd->clear_error(); - Query_log_event qinfo(thd, buff, query_length, 0, FALSE); - mysql_bin_log.write(&qinfo); - DBUG_RETURN(0); + +/* + Find user in ACL + + SYNOPSIS + is_acl_user() + host host name + user user name + + RETURN + FALSE user not fond + TRUE there are such user +*/ + +bool is_acl_user(const char *host, const char *user) +{ + bool res; + + /* --skip-grants */ + if (!initialized) + return TRUE; + + VOID(pthread_mutex_lock(&acl_cache->lock)); + res= find_acl_user(host, user, TRUE) != NULL; + VOID(pthread_mutex_unlock(&acl_cache->lock)); + return res; } @@ -1486,44 +1612,29 @@ bool hostname_requires_resolving(const char *hostname) return FALSE; } + /* - Update grants in the user and database privilege tables + Update record for user in mysql.user privilege table with new password. + + SYNOPSIS + update_user_table() + thd Thread handle + table Pointer to TABLE object for open mysql.user table + host/user Hostname/username pair identifying user for which + new password should be set + new_password New password + new_password_len Length of new password */ -static bool update_user_table(THD *thd, const char *host, const char *user, +static bool update_user_table(THD *thd, TABLE *table, + const char *host, const char *user, const char *new_password, uint new_password_len) { - TABLE_LIST tables; - TABLE *table; - bool error=1; char user_key[MAX_KEY_LENGTH]; + int error; DBUG_ENTER("update_user_table"); DBUG_PRINT("enter",("user: %s host: %s",user,host)); - bzero((char*) &tables,sizeof(tables)); - tables.alias=tables.table_name=(char*) "user"; - tables.db=(char*) "mysql"; - -#ifdef HAVE_REPLICATION - /* - GRANT and REVOKE are applied the slave in/exclusion rules as they are - some kind of updates to the mysql.% tables. - */ - if (thd->slave_thread && table_rules_on) - { - /* - The tables must be marked "updating" so that tables_ok() takes them into - account in tests. It's ok to leave 'updating' set after tables_ok. - */ - tables.updating= 1; - /* Thanks to bzero, tables.next==0 */ - if (!tables_ok(thd, &tables)) - DBUG_RETURN(0); - } -#endif - - if (!(table=open_ltable(thd,&tables,TL_WRITE))) - DBUG_RETURN(1); /* purecov: deadcode */ table->field[0]->store(host,(uint) strlen(host), system_charset_info); table->field[1]->store(user,(uint) strlen(user), system_charset_info); key_copy((byte *) user_key, table->record[0], table->key_info, @@ -1543,13 +1654,9 @@ static bool update_user_table(THD *thd, const char *host, const char *user, if ((error=table->file->update_row(table->record[1],table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: deadcode */ - goto end; /* purecov: deadcode */ + DBUG_RETURN(1); } - error=0; // Record updated - -end: - close_thread_tables(thd); - DBUG_RETURN(error); + DBUG_RETURN(0); } @@ -1562,9 +1669,10 @@ end: static bool test_if_create_new_users(THD *thd) { - bool create_new_users= test(thd->master_access & INSERT_ACL) || + Security_context *sctx= thd->security_ctx; + bool create_new_users= test(sctx->master_access & INSERT_ACL) || (!opt_safe_user_create && - test(thd->master_access & CREATE_USER_ACL)); + test(sctx->master_access & CREATE_USER_ACL)); if (!create_new_users) { TABLE_LIST tl; @@ -1574,8 +1682,8 @@ static bool test_if_create_new_users(THD *thd) tl.table_name= (char*) "user"; create_new_users= 1; - db_access=acl_get(thd->host, thd->ip, - thd->priv_user, tl.db, 0); + db_access=acl_get(sctx->host, sctx->ip, + sctx->priv_user, tl.db, 0); if (!(db_access & INSERT_ACL)) { if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1)) @@ -1654,7 +1762,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, else if (!can_create_user) { my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0), - thd->user, thd->host_or_ip); + thd->security_ctx->user, thd->security_ctx->host_or_ip); goto end; } old_row_exists = 0; @@ -1739,11 +1847,11 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, USER_RESOURCES mqh= lex->mqh; if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR) - table->field[next_field]->store((longlong) mqh.questions); + table->field[next_field]->store((longlong) mqh.questions, TRUE); if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR) - table->field[next_field+1]->store((longlong) mqh.updates); + table->field[next_field+1]->store((longlong) mqh.updates, TRUE); if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR) - table->field[next_field+2]->store((longlong) mqh.conn_per_hour); + table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE); if (table->s->fields >= 36 && (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS)) table->field[next_field+3]->store((longlong) mqh.user_conn); @@ -2245,7 +2353,7 @@ static int replace_column_table(GRANT_TABLE *g_t, store_record(table,record[1]); // copy original row } - table->field[6]->store((longlong) get_rights_for_column(privileges)); + table->field[6]->store((longlong) get_rights_for_column(privileges), TRUE); if (old_row_exists) { @@ -2312,7 +2420,7 @@ static int replace_column_table(GRANT_TABLE *g_t, privileges&= ~rights; table->field[6]->store((longlong) - get_rights_for_column(privileges)); + get_rights_for_column(privileges), TRUE); table->field[4]->val_str(&column_name); grant_column = column_hash_search(g_t, column_name.ptr(), @@ -2366,7 +2474,8 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, byte user_key[MAX_KEY_LENGTH]; DBUG_ENTER("replace_table_table"); - strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS); + strxmov(grantor, thd->security_ctx->user, "@", + thd->security_ctx->host_or_ip, NullS); /* The following should always succeed as new users are created before @@ -2431,8 +2540,8 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info); - table->field[6]->store((longlong) store_table_rights); - table->field[7]->store((longlong) store_col_rights); + table->field[6]->store((longlong) store_table_rights, TRUE); + table->field[7]->store((longlong) store_col_rights, TRUE); rights=fix_rights_for_table(store_table_rights); col_rights=fix_rights_for_column(store_col_rights); @@ -2488,7 +2597,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, DBUG_RETURN(-1); } - strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS); + strxmov(grantor, thd->security_ctx->user, "@", + thd->security_ctx->host_or_ip, NullS); /* The following should always succeed as new users are created before @@ -2507,7 +2617,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, table->field[3]->store(routine_name,(uint) strlen(routine_name), &my_charset_latin1); table->field[4]->store((longlong)(is_proc ? - TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION)); + TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION), + TRUE); store_record(table,record[1]); // store at pos 1 if (table->file->index_read_idx(table->record[0],0, @@ -2548,7 +2659,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, } table->field[5]->store(grantor,(uint) strlen(grantor), &my_charset_latin1); - table->field[6]->store((longlong) store_proc_rights); + table->field[6]->store((longlong) store_proc_rights, TRUE); rights=fix_rights_for_procedure(store_proc_rights); if (old_row_exists) @@ -2678,7 +2789,8 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, get_privilege_desc(command, sizeof(command), table_list->grant.want_privilege); my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), - command, thd->priv_user, thd->host_or_ip, table_list->alias); + command, thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, table_list->alias); DBUG_RETURN(-1); } } @@ -3125,17 +3237,59 @@ void grant_free(void) } -/* Init grant array if possible */ +/* + Initialize structures responsible for table/column-level privilege checking + and load information for them from tables in the 'mysql' database. + + SYNOPSIS + grant_init() + + RETURN VALUES + 0 ok + 1 Could not initialize grant's +*/ -my_bool grant_init(THD *org_thd) +my_bool grant_init() { THD *thd; - TABLE_LIST tables[3]; + my_bool return_val; + DBUG_ENTER("grant_init"); + + if (!(thd= new THD)) + DBUG_RETURN(1); /* purecov: deadcode */ + thd->store_globals(); + return_val= grant_reload(thd); + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + DBUG_RETURN(return_val); +} + + +/* + Initialize structures responsible for table/column-level privilege + checking and load information about grants from open privilege tables. + + SYNOPSIS + grant_load() + thd Current thread + tables List containing open "mysql.tables_priv" and + "mysql.columns_priv" tables. + + RETURN VALUES + FALSE - success + TRUE - error +*/ + +static my_bool grant_load(TABLE_LIST *tables) +{ MEM_ROOT *memex_ptr; my_bool return_val= 1; TABLE *t_table, *c_table, *p_table; bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; - DBUG_ENTER("grant_init"); + MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, + THR_MALLOC); + DBUG_ENTER("grant_load"); grant_option = FALSE; (void) hash_init(&column_priv_hash,system_charset_info, @@ -3149,34 +3303,12 @@ my_bool grant_init(THD *org_thd) 0,0); init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); - /* Don't do anything if running with --skip-grant */ - if (!initialized) - DBUG_RETURN(0); /* purecov: tested */ - - if (!(thd=new THD)) - DBUG_RETURN(1); /* purecov: deadcode */ - thd->store_globals(); - thd->db= my_strdup("mysql",MYF(0)); - thd->db_length=5; // Safety - bzero((char*) &tables, sizeof(tables)); - tables[0].alias=tables[0].table_name= (char*) "tables_priv"; - tables[1].alias=tables[1].table_name= (char*) "columns_priv"; - tables[2].alias=tables[2].table_name= (char*) "procs_priv"; - tables[0].next_local= tables[0].next_global= tables+1; - tables[1].next_local= tables[1].next_global= tables+2; - tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; - tables[0].db=tables[1].db=tables[2].db=thd->db; - - if (simple_open_n_lock_tables(thd, tables)) - goto end; - t_table = tables[0].table; c_table = tables[1].table; p_table= tables[2].table; t_table->file->ha_index_init(0); p_table->file->ha_index_init(0); if (!t_table->file->index_first(t_table->record[0])) { - /* Will be restored by org_thd->store_globals() */ memex_ptr= &memex; my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr); do @@ -3214,7 +3346,6 @@ my_bool grant_init(THD *org_thd) } if (!p_table->file->index_first(p_table->record[0])) { - /* Will be restored by org_thd->store_globals() */ memex_ptr= &memex; my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr); do @@ -3274,40 +3405,58 @@ my_bool grant_init(THD *org_thd) end_unlock: t_table->file->ha_index_end(); p_table->file->ha_index_end(); - thd->version--; // Force close to free memory - -end: - close_thread_tables(thd); - delete thd; - if (org_thd) - org_thd->store_globals(); - else - { - /* Remember that we don't have a THD */ - my_pthread_setspecific_ptr(THR_THD, 0); - } + my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr); DBUG_RETURN(return_val); } /* - Reload grant array (table and column privileges) if possible + Reload information about table and column level privileges if possible. SYNOPSIS grant_reload() - thd Thread handler (can be NULL) + thd Current thread NOTES - Locked tables are checked by acl_init and doesn't have to be checked here + Locked tables are checked by acl_reload() and doesn't have to be checked + in this call. + This function is also used for initialization of structures responsible + for table/column-level privilege checking. + + RETURN VALUE + FALSE Success + TRUE Error */ -void grant_reload(THD *thd) +my_bool grant_reload(THD *thd) { + TABLE_LIST tables[3]; HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash; bool old_grant_option; MEM_ROOT old_mem; + my_bool return_val= 1; DBUG_ENTER("grant_reload"); + /* Don't do anything if running with --skip-grant-tables */ + if (!initialized) + DBUG_RETURN(0); + + bzero((char*) tables, sizeof(tables)); + tables[0].alias= tables[0].table_name= (char*) "tables_priv"; + tables[1].alias= tables[1].table_name= (char*) "columns_priv"; + tables[2].alias= tables[2].table_name= (char*) "procs_priv"; + tables[0].db= tables[1].db= tables[2].db= (char *) "mysql"; + tables[0].next_local= tables[0].next_global= tables+1; + tables[1].next_local= tables[1].next_global= tables+2; + tables[0].lock_type= tables[1].lock_type= tables[2].lock_type= TL_READ; + + /* + To avoid deadlocks we should obtain table locks before + obtaining LOCK_grant rwlock. + */ + if (simple_open_n_lock_tables(thd, tables)) + goto end; + rw_wrlock(&LOCK_grant); grant_version++; old_column_priv_hash= column_priv_hash; @@ -3316,7 +3465,7 @@ void grant_reload(THD *thd) old_grant_option= grant_option; old_mem= memex; - if (grant_init(thd)) + if ((return_val= grant_load(tables))) { // Error. Revert to old hash DBUG_PRINT("error",("Reverting to old privileges")); grant_free(); /* purecov: deadcode */ @@ -3334,7 +3483,9 @@ void grant_reload(THD *thd) free_root(&old_mem,MYF(0)); } rw_unlock(&LOCK_grant); - DBUG_VOID_RETURN; +end: + close_thread_tables(thd); + DBUG_RETURN(return_val); } @@ -3362,11 +3513,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, uint show_table, uint number, bool no_errors) { TABLE_LIST *table; - char *user = thd->priv_user; + Security_context *sctx= thd->security_ctx; DBUG_ENTER("check_grant"); DBUG_ASSERT(number > 0); - want_access&= ~thd->master_access; + want_access&= ~sctx->master_access; if (!want_access) DBUG_RETURN(0); // ok @@ -3384,8 +3535,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, table->grant.want_privilege= 0; continue; // Already checked } - if (!(grant_table= table_hash_search(thd->host,thd->ip, - table->db,user, table->table_name,0))) + if (!(grant_table= table_hash_search(sctx->host, sctx->ip, + table->db, sctx->priv_user, + table->table_name,0))) { want_access &= ~table->grant.privilege; goto err; // No grants @@ -3419,8 +3571,8 @@ err: get_privilege_desc(command, sizeof(command), want_access); my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), command, - thd->priv_user, - thd->host_or_ip, + sctx->priv_user, + sctx->host_or_ip, table ? table->table_name : "unknown"); } DBUG_RETURN(1); @@ -3431,6 +3583,7 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, const char *db_name, const char *table_name, const char *name, uint length, uint show_tables) { + Security_context *sctx= thd->security_ctx; GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; ulong want_access= grant->want_privilege & ~grant->privilege; @@ -3447,8 +3600,8 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, if (grant->version != grant_version) { grant->grant_table= - table_hash_search(thd->host, thd->ip, db_name, - thd->priv_user, + table_hash_search(sctx->host, sctx->ip, db_name, + sctx->priv_user, table_name, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ } @@ -3477,8 +3630,8 @@ err: get_privilege_desc(command, sizeof(command), want_access); my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), command, - thd->priv_user, - thd->host_or_ip, + sctx->priv_user, + sctx->host_or_ip, name, table_name); } @@ -3490,6 +3643,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, const char* db_name, const char *table_name, Field_iterator *fields) { + Security_context *sctx= thd->security_ctx; GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; @@ -3506,8 +3660,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, if (grant->version != grant_version) { grant->grant_table= - table_hash_search(thd->host, thd->ip, db_name, - thd->priv_user, + table_hash_search(sctx->host, sctx->ip, db_name, + sctx->priv_user, table_name, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ } @@ -3533,8 +3687,8 @@ err2: get_privilege_desc(command, sizeof(command), want_access); my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), command, - thd->priv_user, - thd->host_or_ip, + sctx->priv_user, + sctx->host_or_ip, fields->name(), table_name); return 1; @@ -3549,11 +3703,12 @@ err2: bool check_grant_db(THD *thd,const char *db) { + Security_context *sctx= thd->security_ctx; char helping [NAME_LEN+USERNAME_LENGTH+2]; uint len; bool error= 1; - len= (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1; + len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1; rw_rdlock(&LOCK_grant); for (uint idx=0 ; idx < column_priv_hash.records ; idx++) @@ -3562,7 +3717,7 @@ bool check_grant_db(THD *thd,const char *db) idx); if (len < grant_table->key_length && !memcmp(grant_table->hash_key,helping,len) && - compare_hostname(&grant_table->host, thd->host, thd->ip)) + compare_hostname(&grant_table->host, sctx->host, sctx->ip)) { error=0; // Found match break; @@ -3590,15 +3745,16 @@ bool check_grant_db(THD *thd,const char *db) 1 Error: User did not have the requested privielges ****************************************************************************/ -bool check_grant_routine(THD *thd, ulong want_access, +bool check_grant_routine(THD *thd, ulong want_access, TABLE_LIST *procs, bool is_proc, bool no_errors) { TABLE_LIST *table; - char *user= thd->priv_user; - char *host= thd->priv_host; + Security_context *sctx= thd->security_ctx; + char *user= sctx->priv_user; + char *host= sctx->priv_host; DBUG_ENTER("check_grant_routine"); - want_access&= ~thd->master_access; + want_access&= ~sctx->master_access; if (!want_access) DBUG_RETURN(0); // ok @@ -3606,7 +3762,7 @@ bool check_grant_routine(THD *thd, ulong want_access, for (table= procs; table; table= table->next_global) { GRANT_NAME *grant_proc; - if ((grant_proc= routine_hash_search(host,thd->ip, table->db, user, + if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user, table->table_name, is_proc, 0))) table->grant.privilege|= grant_proc->privs; @@ -3661,9 +3817,12 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, if (grant_option) { GRANT_NAME *grant_proc; + Security_context *sctx= thd->security_ctx; rw_rdlock(&LOCK_grant); - if ((grant_proc= routine_hash_search(thd->priv_host, thd->ip, db, - thd->priv_user, name, is_proc, 0))) + if ((grant_proc= routine_hash_search(sctx->priv_host, + sctx->ip, db, + sctx->priv_user, + name, is_proc, 0))) no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); rw_unlock(&LOCK_grant); } @@ -3678,7 +3837,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, ulong get_table_grant(THD *thd, TABLE_LIST *table) { ulong privilege; - char *user = thd->priv_user; + Security_context *sctx= thd->security_ctx; const char *db = table->db ? table->db : thd->db; GRANT_TABLE *grant_table; @@ -3686,7 +3845,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) #ifdef EMBEDDED_LIBRARY grant_table= NULL; #else - grant_table= table_hash_search(thd->host, thd->ip, db, user, + grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user, table->table_name, 0); #endif table->grant.grant_table=grant_table; // Remember for column test @@ -3729,9 +3888,10 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant, /* reload table if someone has modified any grants */ if (grant->version != grant_version) { + Security_context *sctx= thd->security_ctx; grant->grant_table= - table_hash_search(thd->host, thd->ip, db_name, - thd->priv_user, + table_hash_search(sctx->host, sctx->ip, + db_name, sctx->priv_user, table_name, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ } @@ -5301,22 +5461,24 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc) { + Security_context *sctx= thd->security_ctx; LEX_USER *combo; TABLE_LIST tables[1]; List<LEX_USER> user_list; bool result; - DBUG_ENTER("sp_grant_privileges"); + DBUG_ENTER("sp_grant_privileges"); if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) DBUG_RETURN(TRUE); - combo->user.str= thd->user; + combo->user.str= sctx->user; - if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str, + if (!find_acl_user(combo->host.str=(char*)sctx->host_or_ip, combo->user.str, + FALSE) && + !find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str, FALSE) && - !find_acl_user(combo->host.str=(char*)thd->host, combo->user.str, + !find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str, FALSE) && - !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str, FALSE) && !find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)) DBUG_RETURN(TRUE); @@ -5432,8 +5594,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) ulong want_access; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1); - char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; + bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_user_privileges"); for (counter=0 ; counter < acl_users.elements ; counter++) @@ -5446,7 +5608,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) host= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, host))) continue; @@ -5485,8 +5647,8 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) ulong want_access; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1); - char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; + bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_schema_privileges"); for (counter=0 ; counter < acl_dbs.elements ; counter++) @@ -5500,7 +5662,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) host= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, host))) continue; @@ -5540,8 +5702,8 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) uint index; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1); - char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; + bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_table_privileges"); for (index=0 ; index < column_priv_hash.records ; index++) @@ -5553,7 +5715,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) user= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, grant_table->host.hostname))) continue; @@ -5602,8 +5764,8 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) uint index; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1); - char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; + bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_table_privileges"); for (index=0 ; index < column_priv_hash.records ; index++) @@ -5615,7 +5777,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) user= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, grant_table->host.hostname))) continue; @@ -5679,6 +5841,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table) { + Security_context *sctx= thd->security_ctx; /* --skip-grants */ if (!initialized) { @@ -5687,13 +5850,13 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, } /* global privileges */ - grant->privilege= thd->master_access; + grant->privilege= sctx->master_access; - if (!thd->priv_user) + if (!sctx->priv_user) return; // it is slave /* db privileges */ - grant->privilege|= acl_get(thd->host, thd->ip, thd->priv_user, db, 0); + grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0); if (!grant_option) return; @@ -5703,8 +5866,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, { rw_rdlock(&LOCK_grant); grant->grant_table= - table_hash_search(thd->host, thd->ip, db, - thd->priv_user, + table_hash_search(sctx->host, sctx->ip, db, + sctx->priv_user, table, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ rw_unlock(&LOCK_grant); diff --git a/sql/sql_acl.h b/sql/sql_acl.h index eba000a627a..0e50737f84c 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -174,14 +174,15 @@ public: /* prototypes */ bool hostname_requires_resolving(const char *hostname); -my_bool acl_init(THD *thd, bool dont_read_acl_tables); -void acl_reload(THD *thd); +my_bool acl_init(bool dont_read_acl_tables); +my_bool acl_reload(THD *thd); void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *user, const char *db, my_bool db_is_pattern); int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, uint passwd_len); -int acl_getroot_no_password(THD *thd); +bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, + char *ip, char *db); bool acl_check_host(const char *host, const char *ip); bool check_change_password(THD *thd, const char *host, const char *user, char *password, uint password_len); @@ -196,9 +197,9 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc, List <LEX_USER> &user_list, ulong rights, bool revoke, bool no_error); ACL_USER *check_acl_user(LEX_USER *user_name, uint *acl_acl_userdx); -my_bool grant_init(THD *thd); +my_bool grant_init(); void grant_free(void); -void grant_reload(THD *thd); +my_bool grant_reload(THD *thd); bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, uint show_command, uint number, bool dont_print_error); bool check_grant_column (THD *thd, GRANT_INFO *grant, @@ -229,7 +230,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc); bool check_routine_level_acl(THD *thd, const char *db, const char *name, bool is_proc); - +bool is_acl_user(const char *host, const char *user); #ifdef NO_EMBEDDED_ACCESS_CHECKS #define check_grant(A,B,C,D,E,F) 0 #define check_grant_db(A,B) 0 diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 6706cee8e9d..669f998cde5 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -879,19 +879,22 @@ void field_real::get_opt_type(String *answer, if (!max_notzero_dec_len) { + int len= (int) max_length - ((item->decimals == NOT_FIXED_DEC) ? + 0 : (item->decimals + 1)); + if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127)) - sprintf(buff, "TINYINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "TINYINT(%d)", len); else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ? UINT_MAX16 : INT_MAX16)) - sprintf(buff, "SMALLINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "SMALLINT(%d)", len); else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ? UINT_MAX24 : INT_MAX24)) - sprintf(buff, "MEDIUMINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "MEDIUMINT(%d)", len); else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ? UINT_MAX32 : INT_MAX32)) - sprintf(buff, "INT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "INT(%d)", len); else - sprintf(buff, "BIGINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "BIGINT(%d)", len); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) answer->append(" UNSIGNED"); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b8b96f14205..d4376a65594 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -774,6 +774,60 @@ TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list) } +/* + Issue correct error message in case we found 2 duplicate tables which + prevent some update operation + + SYNOPSIS + update_non_unique_table_error() + update table which we try to update + operation name of update operation + duplicate duplicate table which we found + + NOTE: + here we hide view underlying tables if we have them +*/ + +void update_non_unique_table_error(TABLE_LIST *update, + const char *operation, + TABLE_LIST *duplicate) +{ + update= update->top_table(); + duplicate= duplicate->top_table(); + if (!update->view || !duplicate->view || + update->view == duplicate->view || + update->view_name.length != duplicate->view_name.length || + update->view_db.length != duplicate->view_db.length || + my_strcasecmp(table_alias_charset, + update->view_name.str, duplicate->view_name.str) != 0 || + my_strcasecmp(table_alias_charset, + update->view_db.str, duplicate->view_db.str) != 0) + { + /* + it is not the same view repeated (but it can be parts of the same copy + of view), so we have to hide underlying tables. + */ + if (update->view) + { + if (update->view == duplicate->view) + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), update->alias, operation); + else + my_error(ER_VIEW_PREVENT_UPDATE, MYF(0), + (duplicate->view ? duplicate->alias : update->alias), + operation, update->alias); + return; + } + if (duplicate->view) + { + my_error(ER_VIEW_PREVENT_UPDATE, MYF(0), duplicate->alias, operation, + update->alias); + return; + } + } + my_error(ER_UPDATE_TABLE_USED, MYF(0), update->alias); +} + + TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) { char key[MAX_DBKEY_LENGTH]; @@ -922,32 +976,57 @@ void wait_for_refresh(THD *thd) } -TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) +/* + Open table which is already name-locked by this thread. + + SYNOPSIS + reopen_name_locked_table() + thd Thread handle + table_list TABLE_LIST object for table to be open, TABLE_LIST::table + member should point to TABLE object which was used for + name-locking. + + NOTE + This function assumes that its caller already acquired LOCK_open mutex. + + RETURN VALUE + FALSE - Success + TRUE - Error +*/ + +bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) { - DBUG_ENTER("reopen_name_locked_table"); - if (thd->killed) - DBUG_RETURN(0); - TABLE *table; + TABLE *table= table_list->table; TABLE_SHARE *share; - if (!(table = table_list->table)) - DBUG_RETURN(0); + char *db= table_list->db; + char *table_name= table_list->table_name; + char key[MAX_DBKEY_LENGTH]; + uint key_length; + TABLE orig_table; + DBUG_ENTER("reopen_name_locked_table"); - char* db = thd->db ? thd->db : table_list->db; - char* table_name = table_list->table_name; - char key[MAX_DBKEY_LENGTH]; - uint key_length; + safe_mutex_assert_owner(&LOCK_open); + + if (thd->killed || !table) + DBUG_RETURN(TRUE); + + orig_table= *table; key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; - pthread_mutex_lock(&LOCK_open); if (open_unireg_entry(thd, table, db, table_name, table_name, 0, thd->mem_root) || !(table->s->table_cache_key= memdup_root(&table->mem_root, (char*) key, key_length))) { - delete table->triggers; - closefrm(table); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(0); + intern_close_table(table); + /* + If there was an error during opening of table (for example if it + does not exist) '*table' object can be wiped out. To be able + properly release name-lock in this case we should restore this + object to its original state. + */ + *table= orig_table; + DBUG_RETURN(TRUE); } share= table->s; @@ -957,7 +1036,6 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) share->flush_version=0; table->in_use = thd; check_unused(); - pthread_mutex_unlock(&LOCK_open); table->next = thd->open_tables; thd->open_tables = table; table->tablenr=thd->current_tablenr++; @@ -967,7 +1045,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= share->keys_in_use; table->used_keys= share->keys_for_keyread; - DBUG_RETURN(table); + DBUG_RETURN(FALSE); } @@ -976,23 +1054,23 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) SYNOPSIS open_table() - thd Thread context - table_list Open first table in list - refresh Pointer to memory that will be set to 1 if - we need to close all tables and reopen them - If this is a NULL pointer, then the is no version - number checking and the table is not put in the - thread-open-list - flags Bitmap of flags to modify how open works: - MYSQL_LOCK_IGNORE_FLUSH - Open table even if someone - has done a flush or namelock on it. + thd Thread context. + table_list Open first table in list. + refresh INOUT Pointer to memory that will be set to 1 if + we need to close all tables and reopen them. + If this is a NULL pointer, then the table is not + put in the thread-open-list. + flags Bitmap of flags to modify how open works: + MYSQL_LOCK_IGNORE_FLUSH - Open table even if + someone has done a flush or namelock on it. + No version number checking is done. IMPLEMENTATION Uses a cache of open tables to find a table not in use. RETURN NULL Open failed. If refresh is set then one should close - all other tables and retry the open + all other tables and retry the open. # Success. Pointer to TABLE object for open table. */ @@ -1147,10 +1225,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (!thd->open_tables) thd->version=refresh_version; - else if (thd->version != refresh_version && refresh) + else if ((thd->version != refresh_version) && + ! (flags & MYSQL_LOCK_IGNORE_FLUSH)) { /* Someone did a refresh while thread was opening tables */ - *refresh=1; + if (refresh) + *refresh=1; VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(0); } @@ -1271,6 +1351,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->keys_in_use_for_query= table->s->keys_in_use; table->insert_values= 0; table->used_keys= table->s->keys_for_keyread; + table->fulltext_searched= 0; + table->file->ft_handler= 0; if (table->timestamp_field) table->timestamp_field_type= table->timestamp_field->get_auto_set_type(); table_list->updatable= 1; // It is not derived table nor non-updatable VIEW @@ -1343,7 +1425,6 @@ bool reopen_table(TABLE *table,bool locked) tmp.status= table->status; tmp.keys_in_use_for_query= tmp.s->keys_in_use; tmp.used_keys= tmp.s->keys_for_keyread; - tmp.force_index= tmp.force_index; /* Get state */ tmp.s->key_length= table->s->key_length; @@ -1374,6 +1455,9 @@ bool reopen_table(TABLE *table,bool locked) for (key=0 ; key < table->s->keys ; key++) for (part=0 ; part < table->key_info[key].usable_key_parts ; part++) table->key_info[key].key_part[part].field->table= table; + if (table->triggers) + table->triggers->set_table(table); + VOID(pthread_cond_broadcast(&COND_refresh)); error=0; @@ -1422,7 +1506,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) TABLE *table,*next,**prev; TABLE **tables,**tables_ptr; // For locks - bool error=0; + bool error=0, not_used; if (get_locks) { /* The ptr is checked later */ @@ -1463,7 +1547,8 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) MYSQL_LOCK *lock; /* We should always get these locks */ thd->some_tables_deleted=0; - if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables), 0))) + if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables), + 0, ¬_used))) { thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock); } @@ -1810,7 +1895,7 @@ err: if (thd->net.last_errno == ER_NO_SUCH_TABLE && table_desc && table_desc->belong_to_view) { - TABLE_LIST * view= table_desc->belong_to_view; + TABLE_LIST *view= table_desc->belong_to_view; thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), view->view_db.str, view->view_name.str); } @@ -1913,9 +1998,15 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) /* Ignore placeholders for derived tables. After derived tables processing, link to created temporary table will be put here. + If this is derived table for view then we still want to process + routines used by this view. */ if (tables->derived) + { + if (tables->view) + goto process_view_routines; continue; + } if (tables->schema_table) { if (!mysql_schema_table(thd, thd->lex, tables)) @@ -1947,23 +2038,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) if (query_tables_last_own == &(tables->next_global) && tables->view->query_tables) query_tables_last_own= tables->view->query_tables_last; - /* - Again if needed we have to get cache all routines used by this view - and add tables used by them to table list. + Let us free memory used by 'sroutines' hash here since we never + call destructor for this LEX. */ - if (!thd->prelocked_mode && !thd->lex->requires_prelocking() && - tables->view->sroutines.records) - { - /* We have at least one table in TL here */ - if (!query_tables_last_own) - query_tables_last_own= thd->lex->query_tables_last; - sp_cache_routines_and_add_tables_for_view(thd, thd->lex, - tables->view); - } - /* Cleanup hashes because destructo for this LEX is never called */ hash_free(&tables->view->sroutines); - continue; + goto process_view_routines; } if (refresh) // Refresh in progress @@ -1975,11 +2055,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) thd->version=refresh_version; TABLE **prev_table= &thd->open_tables; bool found=0; - /* - QQ: What we should do if we have started building of table list - for prelocking ??? Probably throw it away ? But before we should - mark all temporary tables as free? How about locked ? - */ for (TABLE_LIST *tmp= *start; tmp; tmp= tmp->next_global) { /* Close normal (not temporary) changed tables */ @@ -2003,6 +2078,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) pthread_mutex_unlock(&LOCK_open); if (found) VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh + /* + Let us prepare for recalculation of set of prelocked tables. + First we pretend that we have finished calculation which we + were doing currently. Then we restore list of tables to be + opened and set of used routines to the state in which they were + before first open_tables() call for this statement (i.e. before + we have calculated current set of tables for prelocking). + */ + if (query_tables_last_own) + thd->lex->mark_as_requiring_prelocking(query_tables_last_own); + thd->lex->chop_off_not_own_tables(); + sp_remove_not_own_routines(thd->lex); goto restart; } result= -1; // Fatal error @@ -2033,6 +2120,21 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables) tables->table->reginfo.lock_type=tables->lock_type; tables->table->grant= tables->grant; + +process_view_routines: + /* + Again we may need cache all routines used by this view and add + tables used by them to table list. + */ + if (tables->view && !thd->prelocked_mode && + !thd->lex->requires_prelocking() && + tables->view->sroutines_list.elements) + { + /* We have at least one table in TL here. */ + if (!query_tables_last_own) + query_tables_last_own= thd->lex->query_tables_last; + sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables->view); + } } thd->proc_info=0; free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block @@ -2070,7 +2172,7 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table, my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias); DBUG_RETURN(1); } - if ((error=table->file->start_stmt(thd))) + if ((error=table->file->start_stmt(thd, lock_type))) { table->file->print_error(error,MYF(0)); DBUG_RETURN(1); @@ -2137,7 +2239,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) { DBUG_ASSERT(thd->lock == 0); // You must lock everything at once if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK) - if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0))) + if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0, + &refresh))) table= 0; } } @@ -2165,11 +2268,20 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) { - DBUG_ENTER("simple_open_n_lock_tables"); uint counter; - if (open_tables(thd, &tables, &counter, 0) || - lock_tables(thd, tables, counter)) - DBUG_RETURN(-1); /* purecov: inspected */ + bool need_reopen; + DBUG_ENTER("simple_open_n_lock_tables"); + + for ( ; ; ) + { + if (open_tables(thd, &tables, &counter, 0)) + DBUG_RETURN(-1); + if (!lock_tables(thd, tables, counter, &need_reopen)) + break; + if (!need_reopen) + DBUG_RETURN(-1); + close_tables_for_reopen(thd, tables); + } DBUG_RETURN(0); } @@ -2194,10 +2306,20 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) { uint counter; + bool need_reopen; DBUG_ENTER("open_and_lock_tables"); - if (open_tables(thd, &tables, &counter, 0) || - lock_tables(thd, tables, counter) || - mysql_handle_derived(thd->lex, &mysql_derived_prepare) || + + for ( ; ; ) + { + if (open_tables(thd, &tables, &counter, 0)) + DBUG_RETURN(-1); + if (!lock_tables(thd, tables, counter, &need_reopen)) + break; + if (!need_reopen) + DBUG_RETURN(-1); + close_tables_for_reopen(thd, tables); + } + if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || (thd->fill_derived_tables() && mysql_handle_derived(thd->lex, &mysql_derived_filling))) DBUG_RETURN(TRUE); /* purecov: inspected */ @@ -2265,7 +2387,12 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) lock_tables() thd Thread handler tables Tables to lock - count umber of opened tables + count Number of opened tables + need_reopen Out parameter which if TRUE indicates that some + tables were dropped or altered during this call + and therefore invoker should reopen tables and + try to lock them once again (in this case + lock_tables() will also return error). NOTES You can't call lock_tables twice, as this would break the dead-lock-free @@ -2281,7 +2408,7 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) -1 Error */ -int lock_tables(THD *thd, TABLE_LIST *tables, uint count) +int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) { TABLE_LIST *table; @@ -2297,6 +2424,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) */ DBUG_ASSERT(!thd->lex->requires_prelocking() || tables); + *need_reopen= FALSE; + if (!tables) DBUG_RETURN(0); @@ -2329,7 +2458,9 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) thd->options|= OPTION_TABLE_LOCK; } - if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), 0))) + if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, + need_reopen))) { if (thd->lex->requires_prelocking()) { @@ -2409,6 +2540,28 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) /* + Prepare statement for reopening of tables and recalculation of set of + prelocked tables. + + SYNOPSIS + close_tables_for_reopen() + thd Thread context + tables List of tables which we were trying to open and lock + +*/ + +void close_tables_for_reopen(THD *thd, TABLE_LIST *tables) +{ + thd->lex->chop_off_not_own_tables(); + sp_remove_not_own_routines(thd->lex); + for (TABLE_LIST *tmp= tables; tmp; tmp= tmp->next_global) + if (tmp->table && !tmp->table->s->tmp_table) + tmp->table= 0; + close_thread_tables(thd); +} + + +/* Open a single table without table caching and don't set it in open_list Used by alter_table to open a temporary table and when creating a temporary table with CREATE TEMPORARY ... @@ -2558,6 +2711,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, table_list->alias, name, item_name, (ulong) ref)); Field_iterator_view field_it; field_it.set(table_list); + Query_arena *arena, backup; + DBUG_ASSERT(table_list->schema_table_reformed || (ref != 0 && table_list->view != 0)); for (; !field_it.end_of_fields(); field_it.next()) @@ -2579,17 +2734,28 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, name, length)) DBUG_RETURN(WRONG_GRANT); #endif + // in PS use own arena or data will be freed after prepare + if (register_tree_change) + arena= thd->activate_stmt_arena_if_needed(&backup); Item *item= field_it.create_item(thd); + if (register_tree_change && arena) + thd->restore_active_arena(arena, &backup); + if (!item) DBUG_RETURN(0); /* *ref != NULL means that *ref contains the item that we need to replace. If the item was aliased by the user, set the alias to the replacing item. + We need to set alias on both ref itself and on ref real item. */ if (*ref && !(*ref)->is_autogenerated_name) + { item->set_name((*ref)->name, (*ref)->name_length, system_charset_info); + item->real_item()->set_name((*ref)->name, (*ref)->name_length, + system_charset_info); + } if (register_tree_change) thd->change_item_tree(ref, item); else @@ -2641,6 +2807,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, field_it(*(table_ref->join_columns)); Natural_join_column *nj_col; Field *found_field; + Query_arena *arena, backup; DBUG_ENTER("find_field_in_natural_join"); DBUG_PRINT("enter", ("field name: '%s', ref 0x%lx", name, (ulong) ref)); @@ -2665,11 +2832,19 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, if (nj_col->view_field) { + Item *item; /* The found field is a view field, we do as in find_field_in_view() and return a pointer to pointer to the Item of that field. */ - Item *item= nj_col->create_item(thd); + if (register_tree_change) + arena= thd->activate_stmt_arena_if_needed(&backup); + + item= nj_col->create_item(thd); + + if (register_tree_change && arena) + thd->restore_active_arena(arena, &backup); + if (!item) DBUG_RETURN(NULL); DBUG_ASSERT(nj_col->table_field == NULL); @@ -2799,6 +2974,18 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, belongs - differs from 'table_list' only for NATURAL_USING joins. + DESCRIPTION + Find a field in a table reference depending on the type of table + reference. There are three types of table references with respect + to the representation of their result columns: + - an array of Field_translator objects for MERGE views and some + information_schema tables, + - an array of Field objects (and possibly a name hash) for stored + tables, + - a list of Natural_join_column objects for NATURAL/USING joins. + This procedure detects the type of the table reference 'table_list' + and calls the corresponding search routine. + RETURN 0 field is not found view_ref_found found value in VIEW (real result is in *ref) @@ -2822,15 +3009,29 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, /* Check that the table and database that qualify the current field name - are the same as the table we are going to search for the field. - This is done differently for NATURAL/USING joins because there we can't - simply compare the qualifying table and database names with the ones of - 'table_list' because each field in such a join may originate from a - different table. + are the same as the table reference we are going to search for the field. + + Exclude from the test below nested joins because the columns in a + nested join generally originate from different tables. Nested joins + also have no table name, except when a nested join is a merge view + or an information schema table. + + We include explicitly table references with a 'field_translation' table, + because if there are views over natural joins we don't want to search + inside the view, but we want to search directly in the view columns + which are represented as a 'field_translation'. + TODO: Ensure that table_name, db_name and tables->db always points to something ! */ - if (!table_list->is_natural_join && + if (/* Exclude nested joins. */ + (!table_list->nested_join || + /* Include merge views and information schema tables. */ + table_list->field_translation) && + /* + Test if the field qualifiers match the table reference we plan + to search. + */ table_name && table_name[0] && (my_strcasecmp(table_alias_charset, table_list->alias, table_name) || (db_name && db_name[0] && table_list->db && table_list->db[0] && @@ -2838,20 +3039,45 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(0); *actual_table= NULL; + if (table_list->field_translation) { + /* 'table_list' is a view or an information schema table. */ if ((fld= find_field_in_view(thd, table_list, name, item_name, length, ref, check_grants_view, register_tree_change))) *actual_table= table_list; } - else if (table_list->is_natural_join) + else if (!table_list->nested_join) + { + /* 'table_list' is a stored table. */ + DBUG_ASSERT(table_list->table); + if ((fld= find_field_in_table(thd, table_list->table, name, length, + check_grants_table, allow_rowid, + cached_field_index_ptr))) + *actual_table= table_list; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* check for views with temporary table algorithm */ + if (check_grants_view && table_list->view && + fld && fld != WRONG_GRANT && + check_grant_column(thd, &table_list->grant, + table_list->view_db.str, + table_list->view_name.str, + name, length)) + fld= WRONG_GRANT; +#endif + } + else { + /* + 'table_list' is a NATURAL/USING join, or an operand of such join that + is a nested join itself. + + If the field name we search for is qualified, then search for the field + in the table references used by NATURAL/USING the join. + */ if (table_name && table_name[0]) { - /* - Qualified field; Search for it in the tables used by the natural join. - */ List_iterator<TABLE_LIST> it(table_list->nested_join->join_list); TABLE_LIST *table; while ((table= it++)) @@ -2868,30 +3094,15 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, } /* Non-qualified field, search directly in the result columns of the - natural join. + natural join. The condition of the outer IF is true for the top-most + natural join, thus if the field is not qualified, we will search + directly the top-most NATURAL/USING join. */ fld= find_field_in_natural_join(thd, table_list, name, length, ref, /* TIMOUR_TODO: check this with Sanja */ check_grants_table || check_grants_view, register_tree_change, actual_table); } - else - { - if ((fld= find_field_in_table(thd, table_list->table, name, length, - check_grants_table, allow_rowid, - cached_field_index_ptr))) - *actual_table= table_list; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - /* check for views with temporary table algorithm */ - if (check_grants_view && table_list->view && - fld && fld != WRONG_GRANT && - check_grant_column(thd, &table_list->grant, - table_list->view_db.str, - table_list->view_name.str, - name, length)) - fld= WRONG_GRANT; -#endif - } DBUG_RETURN(fld); } @@ -3166,9 +3377,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, for (uint i= 0; (item=li++); i++) { - if (field_name && item->type() == Item::FIELD_ITEM) + if (field_name && item->real_item()->type() == Item::FIELD_ITEM) { - Item_field *item_field= (Item_field*) item; + Item_ident *item_field= (Item_ident*) item; /* In case of group_concat() with ORDER BY condition in the QUERY @@ -3268,7 +3479,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, } } } - else if (!table_name && (item->eq(find,0) || + else if (!table_name && (find->eq(item,0) || find->name && item->name && !my_strcasecmp(system_charset_info, item->name,find->name))) @@ -3335,7 +3546,7 @@ test_if_string_in_list(const char *find, List<String> *str_list) { if (find_length != curr_str->length()) continue; - if (!strncmp(find, curr_str->ptr(), find_length)) + if (!my_strcasecmp(system_charset_info, find, curr_str->ptr())) return TRUE; } return FALSE; @@ -3422,7 +3633,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, table_ref_1->alias, table_ref_2->alias)); *found_using_fields= 0; - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); /* TABLE_LIST::join_columns could be allocated by the previous call to @@ -3474,10 +3685,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (add_columns && is_created_2) table_ref_2->join_columns->push_back(cur_nj_col_2); - /* Compare the two columns and check for duplicate common fields. */ + /* + Compare the two columns and check for duplicate common fields. + A common field is duplicate either if it was already found in + table_ref_2 (then found == TRUE), or if a field in table_ref_2 + was already matched by some previous field in table_ref_1 + (then cur_nj_col_2->is_common == TRUE). + */ if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { - if (found) + if (found || cur_nj_col_2->is_common) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; @@ -3585,7 +3802,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, err: if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); DBUG_RETURN(result); } @@ -3643,7 +3860,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, DBUG_ASSERT(!natural_using_join->join_columns); - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); if (!(non_join_columns= new List<Natural_join_column>) || !(natural_using_join->join_columns= new List<Natural_join_column>)) @@ -3728,7 +3945,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, err: if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); DBUG_RETURN(result); } @@ -3773,7 +3990,7 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, DBUG_ENTER("store_top_level_join_columns"); - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); /* Call the procedure recursively for each nested table reference. */ if (table_ref->nested_join) @@ -3886,7 +4103,7 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, err: if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); DBUG_RETURN(result); } @@ -3985,7 +4202,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, Don't use arena if we are not in prepared statements or stored procedures For PS/SP we have to use arena to remember the changes */ - arena= thd->change_arena_if_needed(&backup); + arena= thd->activate_stmt_arena_if_needed(&backup); while (wild_num && (item= it++)) { @@ -4013,7 +4230,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, any_privileges)) { if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); DBUG_RETURN(-1); } if (sum_func_list) @@ -4035,7 +4252,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, select_lex->with_wild= 0; select_lex->item_list= fields; - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); } DBUG_RETURN(0); } @@ -4173,9 +4390,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, { TABLE *table= table_list->table; if (first_select_table && - (table_list->belong_to_view ? - table_list->belong_to_view : - table_list) == first_select_table) + table_list->top_table() == first_select_table) { /* new counting for SELECT of INSERT ... SELECT command */ first_select_table= 0; @@ -4213,15 +4428,15 @@ bool setup_tables(THD *thd, Name_resolution_context *context, if (table_list->ancestor) { DBUG_ASSERT(table_list->view); - Query_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->stmt_arena, backup; bool res; if (arena->is_conventional()) arena= 0; // For easier test else - thd->set_n_backup_item_arena(arena, &backup); + thd->set_n_backup_active_arena(arena, &backup); res= table_list->setup_ancestor(thd); if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); if (res) DBUG_RETURN(1); } @@ -4302,7 +4517,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, bool found; char name_buff[NAME_LEN+1]; DBUG_ENTER("insert_fields"); - DBUG_PRINT("arena", ("current arena: 0x%lx", (ulong)thd->current_arena)); + DBUG_PRINT("arena", ("stmt arena: 0x%lx", (ulong)thd->stmt_arena)); if (db_name && lower_case_table_names) { @@ -4411,7 +4626,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, VIEW_ANY_ACL))) { my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", - thd->priv_user, thd->host_or_ip, + thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, fld->field_name, field_table_name); DBUG_RETURN(TRUE); } @@ -4508,7 +4724,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { SELECT_LEX *select_lex= thd->lex->current_select; - Query_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->stmt_arena, backup; TABLE_LIST *table= NULL; // For HP compilers /* it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX @@ -4572,9 +4788,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, /* process CHECK OPTION */ if (it_is_update) { - TABLE_LIST *view= table->belong_to_view; - if (!view) - view= table; + TABLE_LIST *view= table->top_table(); if (view->effective_with_check) { if (view->prepare_check_option(thd)) @@ -4584,7 +4798,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, } } - if (!thd->current_arena->is_conventional()) + if (!thd->stmt_arena->is_conventional()) { /* We are in prepared statement preparation code => we should store @@ -4597,9 +4811,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, } DBUG_RETURN(test(thd->net.report_error)); -err: - if (arena) - thd->restore_backup_item_arena(arena, &backup); err_no_arena: DBUG_RETURN(1); } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 828a9c4d15c..ed781e9bba3 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -573,13 +573,18 @@ void query_cache_insert(NET *net, const char *packet, ulong length) { DBUG_ENTER("query_cache_insert"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) + STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); DBUG_VOID_RETURN; -#endif + } - STRUCT_LOCK(&query_cache.structure_guard_mutex); Query_cache_block *query_block = ((Query_cache_block*) net->query_cache_query); if (query_block) @@ -623,14 +628,20 @@ void query_cache_abort(NET *net) { DBUG_ENTER("query_cache_abort"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) - DBUG_VOID_RETURN; -#endif if (net->query_cache_query != 0) // Quick check on unlocked structure { STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + Query_cache_block *query_block = ((Query_cache_block*) net->query_cache_query); if (query_block) // Test if changed by other thread @@ -652,11 +663,6 @@ void query_cache_end_of_result(THD *thd) { DBUG_ENTER("query_cache_end_of_result"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN; -#endif - if (thd->net.query_cache_query != 0) // Quick check on unlocked structure { #ifdef EMBEDDED_LIBRARY @@ -664,6 +670,17 @@ void query_cache_end_of_result(THD *thd) emb_count_querycache_size(thd)); #endif STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + Query_cache_block *query_block = ((Query_cache_block*) thd->net.query_cache_query); if (query_block) @@ -743,9 +760,14 @@ ulong Query_cache::resize(ulong query_cache_size_arg) DBUG_ENTER("Query_cache::resize"); DBUG_PRINT("qcache", ("from %lu to %lu",query_cache_size, query_cache_size_arg)); - free_cache(0); + DBUG_ASSERT(initialized); + STRUCT_LOCK(&structure_guard_mutex); + if (query_cache_size > 0) + free_cache(); query_cache_size= query_cache_size_arg; - DBUG_RETURN(::query_cache_size= init_cache()); + ::query_cache_size= init_cache(); + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_RETURN(::query_cache_size); } @@ -779,6 +801,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) CLIENT_PROTOCOL_41); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.pkt_nr= net->pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= @@ -792,12 +815,13 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) flags.sql_mode= thd->variables.sql_mode; flags.max_sort_length= thd->variables.max_sort_length; flags.group_concat_max_len= thd->variables.group_concat_max_len; - DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \ + DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.more_results_exists, + flags.pkt_nr, flags.character_set_client_num, flags.character_set_results_num, flags.collation_connection_num, @@ -997,6 +1021,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) CLIENT_PROTOCOL_41); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.pkt_nr= thd->net.pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= (thd->variables.character_set_results ? @@ -1008,12 +1033,13 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) flags.sql_mode= thd->variables.sql_mode; flags.max_sort_length= thd->variables.max_sort_length; flags.group_concat_max_len= thd->variables.group_concat_max_len; - DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \ + DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.more_results_exists, + flags.pkt_nr, flags.character_set_client_num, flags.character_set_results_num, flags.collation_connection_num, @@ -1274,7 +1300,8 @@ void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used) DUMP(this); for (; tables_used; tables_used= tables_used->next_local) { - if (tables_used->lock_type & (TL_WRITE_LOW_PRIORITY | TL_WRITE)) + if (tables_used->lock_type & (TL_WRITE_LOW_PRIORITY | TL_WRITE) && + tables_used->table) invalidate_table(tables_used->table); } } @@ -1439,7 +1466,7 @@ void Query_cache::destroy() } else { - free_cache(1); + free_cache(); pthread_mutex_destroy(&structure_guard_mutex); initialized = 0; } @@ -1468,8 +1495,6 @@ ulong Query_cache::init_cache() int align; DBUG_ENTER("Query_cache::init_cache"); - if (!initialized) - init(); approx_additional_data_size = (sizeof(Query_cache) + sizeof(gptr)*(def_query_hash_size+ def_table_hash_size)); @@ -1527,14 +1552,9 @@ ulong Query_cache::init_cache() goto err; query_cache_size -= additional_data_size; - STRUCT_LOCK(&structure_guard_mutex); - - if (!(cache = (byte *) - my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) - { - STRUCT_UNLOCK(&structure_guard_mutex); + if (!(cache= (byte *) + my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) goto err; - } DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins", query_cache_size, min_allocation_unit, mem_bin_num)); @@ -1630,7 +1650,6 @@ ulong Query_cache::init_cache() queries_in_cache = 0; queries_blocks = 0; - STRUCT_UNLOCK(&structure_guard_mutex); DBUG_RETURN(query_cache_size + additional_data_size + approx_additional_data_size); @@ -1646,6 +1665,7 @@ void Query_cache::make_disabled() { DBUG_ENTER("Query_cache::make_disabled"); query_cache_size= 0; + queries_blocks= 0; free_memory= 0; bins= 0; steps= 0; @@ -1657,14 +1677,11 @@ void Query_cache::make_disabled() } -void Query_cache::free_cache(my_bool destruction) +void Query_cache::free_cache() { DBUG_ENTER("Query_cache::free_cache"); if (query_cache_size > 0) { - if (!destruction) - STRUCT_LOCK(&structure_guard_mutex); - flush_cache(); #ifndef DBUG_OFF if (bins[0].free_blocks == 0) @@ -1686,8 +1703,6 @@ void Query_cache::free_cache(my_bool destruction) make_disabled(); hash_free(&queries); hash_free(&tables); - if (!destruction) - STRUCT_UNLOCK(&structure_guard_mutex); } DBUG_VOID_RETURN; } @@ -2402,7 +2417,19 @@ Query_cache::allocate_block(ulong len, my_bool not_less, ulong min, } if (!under_guard) + { STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_RETURN(0); + } + } /* Free old queries until we have enough memory to store this block */ Query_cache_block *block; @@ -2948,6 +2975,17 @@ void Query_cache::pack_cache() { DBUG_ENTER("Query_cache::pack_cache"); STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache_size == 0)) + { + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_VOID_RETURN; + } + DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); byte *border = 0; @@ -3257,6 +3295,7 @@ my_bool Query_cache::join_results(ulong join_limit) STRUCT_LOCK(&structure_guard_mutex); if (queries_blocks != 0) { + DBUG_ASSERT(query_cache_size > 0); Query_cache_block *block = queries_blocks; do { @@ -3553,7 +3592,19 @@ my_bool Query_cache::check_integrity(bool not_locked) DBUG_RETURN(0); } if (!not_locked) + { STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_RETURN(0); + } + } if (hash_check(&queries)) { diff --git a/sql/sql_cache.h b/sql/sql_cache.h index c1b08904f51..123d16b606d 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -327,10 +327,9 @@ protected: Following function control structure_guard_mutex by themself or don't need structure_guard_mutex */ - void init(); ulong init_cache(); void make_disabled(); - void free_cache(my_bool destruction); + void free_cache(); Query_cache_block *write_block_data(ulong data_len, gptr data, ulong header_len, Query_cache_block::block_type type, @@ -366,6 +365,8 @@ protected: uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); + /* initialize cache (mutex) */ + void init(); /* resize query cache (return real query size, 0 if disabled) */ ulong resize(ulong query_cache_size); /* set limit on result size */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4089042315f..609156ef5a8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -180,10 +180,11 @@ THD::THD() in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE), spcont(NULL) { - current_arena= this; - host= user= priv_user= db= ip= 0; + stmt_arena= this; + db= 0; catalog= (char*)"std"; // the only catalog we have for now - host_or_ip= "connecting host"; + main_security_ctx.init(); + security_ctx= &main_security_ctx; locked=some_tables_deleted=no_errors=password= 0; query_start_used= 0; count_cuted_fields= CHECK_FIELD_IGNORE; @@ -217,6 +218,7 @@ THD::THD() #ifndef EMBEDDED_LIBRARY net.vio=0; #endif + client_capabilities= 0; // minimalistic client net.last_error[0]=0; // If error on boot net.query_cache_query=0; // If error on boot ull=0; @@ -236,9 +238,6 @@ THD::THD() server_id = ::server_id; slave_net = 0; command=COM_CONNECT; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - db_access=NO_ACCESS; -#endif *scramble= '\0'; init(); @@ -377,14 +376,16 @@ void THD::cleanup(void) mysql_ha_flush(this, (TABLE_LIST*) 0, MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); hash_free(&handler_tables_hash); + delete_dynamic(&user_var_events); + hash_free(&user_vars); close_temporary_tables(this); my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR)); - delete_dynamic(&user_var_events); - hash_free(&user_vars); + sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_func_cache); + if (global_read_lock) unlock_global_read_lock(this); if (ull) @@ -424,15 +425,8 @@ THD::~THD() ha_close_connection(this); - sp_cache_clear(&sp_proc_cache); - sp_cache_clear(&sp_func_cache); - - DBUG_PRINT("info", ("freeing host")); - if (host != my_localhost) // If not pointer to constant - safeFree(host); - if (user != delayed_user) - safeFree(user); - safeFree(ip); + DBUG_PRINT("info", ("freeing security context")); + main_security_ctx.destroy(); safeFree(db); free_root(&warn_root,MYF(0)); #ifdef USING_TRANSACTIONS @@ -551,11 +545,6 @@ void THD::cleanup_after_query() } /* Free Items that were created during this execution */ free_items(); - /* - In the rest of code we assume that free_list never points to garbage: - Keep this predicate true. - */ - free_list= 0; } /* @@ -794,7 +783,7 @@ struct Item_change_record: public ilink /* Register an item tree tree transformation, performed by the query optimizer. We need a pointer to runtime_memroot because it may be != - thd->mem_root (due to possible set_n_backup_item_arena called for thd). + thd->mem_root (due to possible set_n_backup_active_arena called for thd). */ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, @@ -871,9 +860,34 @@ sql_exchange::sql_exchange(char *name,bool flag) bool select_send::send_fields(List<Item> &list, uint flags) { - return thd->protocol->send_fields(&list, flags); + bool res; + if (!(res= thd->protocol->send_fields(&list, flags))) + status= 1; + return res; } +void select_send::abort() +{ + DBUG_ENTER("select_send::abort"); + if (status && thd->spcont && + thd->spcont->find_handler(thd->net.last_errno, + MYSQL_ERROR::WARN_LEVEL_ERROR)) + { + /* + Executing stored procedure without a handler. + Here we should actually send an error to the client, + but as an error will break a multiple result set, the only thing we + can do for now is to nicely end the current data set and remembering + the error so that the calling routine will abort + */ + thd->net.report_error= 0; + send_eof(); + thd->net.report_error= 1; // Abort SP + } + DBUG_VOID_RETURN; +} + + /* Send data to client. Returns 0 if ok */ bool select_send::send_data(List<Item> &items) @@ -936,6 +950,7 @@ bool select_send::send_eof() if (!thd->net.report_error) { ::send_eof(thd); + status= 0; return 0; } else @@ -1524,6 +1539,19 @@ void Query_arena::free_items() } +void Query_arena::set_query_arena(Query_arena *set) +{ + mem_root= set->mem_root; + free_list= set->free_list; + state= set->state; +} + + +void Query_arena::cleanup_stmt() +{ + DBUG_ASSERT("Query_arena::cleanup_stmt()" == "not implemented"); +} + /* Statement functions */ @@ -1581,12 +1609,6 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup) } -void Statement::close_cursor() -{ - DBUG_ASSERT("Statement::close_cursor()" == "not implemented"); -} - - void THD::end_statement() { /* Cleanup SQL processing state to resuse this statement in next query. */ @@ -1602,13 +1624,13 @@ void THD::end_statement() } -void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) +void THD::set_n_backup_active_arena(Query_arena *set, Query_arena *backup) { - DBUG_ENTER("Query_arena::set_n_backup_item_arena"); + DBUG_ENTER("THD::set_n_backup_active_arena"); DBUG_ASSERT(backup->is_backup_arena == FALSE); - backup->set_item_arena(this); - set_item_arena(set); + backup->set_query_arena(this); + set_query_arena(set); #ifndef DBUG_OFF backup->is_backup_arena= TRUE; #endif @@ -1616,25 +1638,18 @@ void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) } -void Query_arena::restore_backup_item_arena(Query_arena *set, Query_arena *backup) +void THD::restore_active_arena(Query_arena *set, Query_arena *backup) { - DBUG_ENTER("Query_arena::restore_backup_item_arena"); + DBUG_ENTER("THD::restore_active_arena"); DBUG_ASSERT(backup->is_backup_arena); - set->set_item_arena(this); - set_item_arena(backup); + set->set_query_arena(this); + set_query_arena(backup); #ifndef DBUG_OFF backup->is_backup_arena= FALSE; #endif DBUG_VOID_RETURN; } -void Query_arena::set_item_arena(Query_arena *set) -{ - mem_root= set->mem_root; - free_list= set->free_list; - state= set->state; -} - Statement::~Statement() { /* @@ -1686,32 +1701,32 @@ Statement_map::Statement_map() : NULL,MYF(0)); } + int Statement_map::insert(Statement *statement) { - int rc= my_hash_insert(&st_hash, (byte *) statement); - if (rc == 0) - last_found_statement= statement; + int res= my_hash_insert(&st_hash, (byte *) statement); + if (res) + return res; if (statement->name.str) { - /* - If there is a statement with the same name, remove it. It is ok to - remove old and fail to insert new one at the same time. - */ - Statement *old_stmt; - if ((old_stmt= find_by_name(&statement->name))) - erase(old_stmt); - if ((rc= my_hash_insert(&names_hash, (byte*)statement))) + if ((res= my_hash_insert(&names_hash, (byte*)statement))) + { hash_delete(&st_hash, (byte*)statement); + return res; + } } - return rc; + last_found_statement= statement; + return res; } void Statement_map::close_transient_cursors() { +#ifdef TO_BE_IMPLEMENTED Statement *stmt; while ((stmt= transient_cursor_list.head())) stmt->close_cursor(); /* deletes itself from the list */ +#endif } @@ -1813,6 +1828,38 @@ void THD::set_status_var_init() bzero((char*) &status_var, sizeof(status_var)); } + +void Security_context::init() +{ + host= user= priv_user= ip= 0; + host_or_ip= "connecting host"; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + db_access= NO_ACCESS; +#endif +} + + +void Security_context::destroy() +{ + // If not pointer to constant + if (host != my_localhost) + safeFree(host); + if (user != delayed_user) + safeFree(user); + safeFree(ip); +} + + +void Security_context::skip_grants() +{ + /* privileges for the user are unknown everything is allowed */ + host_or_ip= (char *)""; + master_access= ~NO_ACCESS; + priv_user= (char *)""; + *priv_host= '\0'; +} + + /**************************************************************************** Handling of open and locked tables states. @@ -1940,8 +1987,8 @@ HASH xid_cache; static byte *xid_get_hash_key(const byte *ptr,uint *length, my_bool not_used __attribute__((unused))) { - *length=((XID_STATE*)ptr)->xid.length(); - return (byte *)&((XID_STATE*)ptr)->xid; + *length=((XID_STATE*)ptr)->xid.key_length(); + return ((XID_STATE*)ptr)->xid.key(); } static void xid_free_hash (void *ptr) @@ -1969,7 +2016,7 @@ void xid_cache_free() XID_STATE *xid_cache_search(XID *xid) { pthread_mutex_lock(&LOCK_xid_cache); - XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, (byte *)xid, xid->length()); + XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, xid->key(), xid->key_length()); pthread_mutex_unlock(&LOCK_xid_cache); return res; } @@ -1980,7 +2027,7 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state) XID_STATE *xs; my_bool res; pthread_mutex_lock(&LOCK_xid_cache); - if (hash_search(&xid_cache, (byte *)xid, xid->length())) + if (hash_search(&xid_cache, xid->key(), xid->key_length())) res=0; else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME)))) res=1; @@ -1999,8 +2046,8 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state) bool xid_cache_insert(XID_STATE *xid_state) { pthread_mutex_lock(&LOCK_xid_cache); - DBUG_ASSERT(hash_search(&xid_cache, (byte *)&xid_state->xid, - xid_state->xid.length())==0); + DBUG_ASSERT(hash_search(&xid_cache, xid_state->xid.key(), + xid_state->xid.key_length())==0); my_bool res=my_hash_insert(&xid_cache, (byte*)xid_state); pthread_mutex_unlock(&LOCK_xid_cache); return res; diff --git a/sql/sql_class.h b/sql/sql_class.h index 305a03a9e8d..2679143e9a5 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -189,8 +189,11 @@ class MYSQL_LOG: public TC_LOG { private: /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ - pthread_mutex_t LOCK_log, LOCK_index; + pthread_mutex_t LOCK_log, LOCK_index, LOCK_readers; pthread_cond_t update_cond; + pthread_cond_t reset_cond; + bool reset_pending; + int readers_count; ulonglong bytes_written; time_t last_time,query_start; IO_CACHE log_file; @@ -313,6 +316,7 @@ public: void start_union_events(THD *thd); void stop_union_events(THD *thd); + bool is_query_in_union(THD *thd, query_id_t query_id_param); /* v stands for vector @@ -333,6 +337,9 @@ public: int purge_logs_before_date(time_t purge_time); int purge_first_log(struct st_relay_log_info* rli, bool included); bool reset_logs(THD* thd); + inline bool is_reset_pending() { return reset_pending; } + void readers_addref(); + void readers_release(); void close(uint exiting); // iterating through the log index file @@ -508,6 +515,7 @@ struct system_variables ulong multi_range_count; ulong myisam_repair_threads; ulong myisam_sort_buff_size; + ulong myisam_stats_method; ulong net_buffer_length; ulong net_interactive_timeout; ulong net_read_timeout; @@ -733,15 +741,15 @@ public: return ptr; } - void set_n_backup_item_arena(Query_arena *set, Query_arena *backup); - void restore_backup_item_arena(Query_arena *set, Query_arena *backup); - void set_item_arena(Query_arena *set); + void set_query_arena(Query_arena *set); void free_items(); + /* Close the active state associated with execution of this statement */ + virtual void cleanup_stmt(); }; -class Cursor; +class Server_side_cursor; /* State of a single command executed against this connection. @@ -817,7 +825,7 @@ public: */ char *query; uint32 query_length; // current query length - Cursor *cursor; + Server_side_cursor *cursor; public: @@ -834,8 +842,6 @@ public: void restore_backup_statement(Statement *stmt, Statement *backup); /* return class type */ virtual Type type() const; - /* Close the cursor open for this statement, if there is one */ - virtual void close_cursor(); }; @@ -887,9 +893,6 @@ public: } hash_delete(&st_hash, (byte *) statement); } - void add_transient_cursor(Statement *stmt) - { transient_cursor_list.append(stmt); } - void erase_transient_cursor(Statement *stmt) { stmt->unlink(); } /* Close all cursors of this connection that use tables of a storage engine that has transaction-specific state and therefore can not @@ -942,6 +945,34 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state); bool xid_cache_insert(XID_STATE *xid_state); void xid_cache_delete(XID_STATE *xid_state); + +class Security_context { +public: + /* + host - host of the client + user - user of the client, set to NULL until the user has been read from + the connection + priv_user - The user privilege we are using. May be "" for anonymous user. + ip - client IP + */ + char *host, *user, *priv_user, *ip; + /* The host privilege we are using */ + char priv_host[MAX_HOSTNAME]; + /* points to host if host is available, otherwise points to ip */ + const char *host_or_ip; + ulong master_access; /* Global privileges from mysql.user */ + ulong db_access; /* Privileges for current db */ + + void init(); + void destroy(); + void skip_grants(); + inline char *priv_host_name() + { + return (*priv_host ? priv_host : (char *)"%"); + } +}; + + /* A registry for item tree transformations performed during query optimization. We register only those changes which require @@ -1114,23 +1145,20 @@ public: char *thread_stack; /* - host - host of the client - user - user of the client, set to NULL until the user has been read from - the connection - priv_user - The user privilege we are using. May be '' for anonymous user. db - currently selected database catalog - currently selected catalog - ip - client IP WARNING: some members of THD (currently 'db', 'catalog' and 'query') are set and alloced by the slave SQL thread (for the THD of that thread); that thread is (and must remain, for now) the only responsible for freeing these 3 members. If you add members here, and you add code to set them in replication, don't forget to free_them_and_set_them_to_0 in replication - properly. For details see the 'err:' label of the pthread_handler_decl of - the slave SQL thread, in sql/slave.cc. + properly. For details see the 'err:' label of the handle_slave_sql() + in sql/slave.cc. */ - char *host,*user,*priv_user,*db,*catalog,*ip; - char priv_host[MAX_HOSTNAME]; + char *db, *catalog; + Security_context main_security_ctx; + Security_context *security_ctx; + /* remote (peer) port */ uint16 peer_port; /* @@ -1139,13 +1167,9 @@ public: a time-consuming piece that MySQL can get stuck in for a long time. */ const char *proc_info; - /* points to host if host is available, otherwise points to ip */ - const char *host_or_ip; ulong client_capabilities; /* What the client supports */ ulong max_client_packet_length; - ulong master_access; /* Global privileges from mysql.user */ - ulong db_access; /* Privileges for current db */ HASH handler_tables_hash; /* @@ -1230,16 +1254,16 @@ public: /* A permanent memory area of the statement. For conventional execution, the parsed tree and execution runtime reside in the same - memory root. In this case current_arena points to THD. In case of + memory root. In this case stmt_arena points to THD. In case of a prepared statement or a stored procedure statement, thd->mem_root - conventionally points to runtime memory, and thd->current_arena + conventionally points to runtime memory, and thd->stmt_arena points to the memory of the PS/SP, where the parsed tree of the statement resides. Whenever you need to perform a permanent transformation of a parsed tree, you should allocate new memory in - current_arena, to allow correct re-execution of PS/SP. - Note: in the parser, current_arena == thd, even for PS/SP. + stmt_arena, to allow correct re-execution of PS/SP. + Note: in the parser, stmt_arena == thd, even for PS/SP. */ - Query_arena *current_arena; + Query_arena *stmt_arena; /* next_insert_id is set on SET INSERT_ID= #. This is used as the next generated auto_increment value in handler.cc @@ -1305,8 +1329,9 @@ public: /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; enum_check_fields count_cuted_fields; - /* for user variables replication*/ - DYNAMIC_ARRAY user_var_events; + + DYNAMIC_ARRAY user_var_events; /* For user variables replication */ + MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */ enum killed_state { NOT_KILLED=0, KILL_BAD_DATA=1, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED }; killed_state volatile killed; @@ -1368,6 +1393,12 @@ public: mysql_bin_log.start_union_events() call. */ bool unioned_events_trans; + + /* + 'queries' (actually SP statements) that run under inside this binlog + union have thd->query_id >= first_query_id. + */ + query_id_t first_query_id; } binlog_evt_union; THD(); @@ -1467,7 +1498,7 @@ public: } inline bool fill_derived_tables() { - return !current_arena->is_stmt_prepare() && !lex->only_view_structure(); + return !stmt_arena->is_stmt_prepare() && !lex->only_view_structure(); } inline gptr trans_alloc(unsigned int size) { @@ -1506,17 +1537,16 @@ public: inline CHARSET_INFO *charset() { return variables.character_set_client; } void update_charset(); - inline Query_arena *change_arena_if_needed(Query_arena *backup) + inline Query_arena *activate_stmt_arena_if_needed(Query_arena *backup) { /* - use new arena if we are in a prepared statements and we have not - already changed to use this arena. + Use the persistent arena if we are in a prepared statement or a stored + procedure statement and we have not already changed to use this arena. */ - if (!current_arena->is_conventional() && - mem_root != current_arena->mem_root) + if (!stmt_arena->is_conventional() && mem_root != stmt_arena->mem_root) { - set_n_backup_item_arena(current_arena, backup); - return current_arena; + set_n_backup_active_arena(stmt_arena, backup); + return stmt_arena; } return 0; } @@ -1524,7 +1554,7 @@ public: void change_item_tree(Item **place, Item *new_value) { /* TODO: check for OOM condition here */ - if (!current_arena->is_conventional()) + if (!stmt_arena->is_conventional()) nocheck_register_item_tree_change(place, *place, mem_root); *place= new_value; } @@ -1556,11 +1586,13 @@ public: } void set_status_var_init(); bool is_context_analysis_only() - { return current_arena->is_stmt_prepare() || lex->view_prepare_mode; } + { return stmt_arena->is_stmt_prepare() || lex->view_prepare_mode; } void reset_n_backup_open_tables_state(Open_tables_state *backup); void restore_backup_open_tables_state(Open_tables_state *backup); void reset_sub_statement_state(Sub_statement_state *backup, uint new_state); void restore_sub_statement_state(Sub_statement_state *backup); + void set_n_backup_active_arena(Query_arena *set, Query_arena *backup); + void restore_active_arena(Query_arena *set, Query_arena *backup); }; @@ -1651,12 +1683,14 @@ public: class select_send :public select_result { + int status; public: - select_send() {} + select_send() :status(0) {} bool send_fields(List<Item> &list, uint flags); bool send_data(List<Item> &items); bool send_eof(); bool simple_select() { return 1; } + void abort(); }; @@ -1803,18 +1837,21 @@ public: } }; -class select_union :public select_result_interceptor { - public: - TABLE *table; +class select_union :public select_result_interceptor +{ TMP_TABLE_PARAM tmp_table_param; +public: + TABLE *table; - select_union(TABLE *table_par); - ~select_union(); + select_union() :table(0) {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &items); bool send_eof(); bool flush(); - void set_table(TABLE *tbl) { table= tbl; } + + bool create_result_table(THD *thd, List<Item> *column_types, + bool is_distinct, ulonglong options, + const char *alias); }; /* Base subselect interface class */ @@ -1868,6 +1905,7 @@ typedef struct st_sort_field { Field *field; /* Field to sort */ Item *item; /* Item if not sorting fields */ uint length; /* Length of sort field */ + uint suffix_length; /* Length suffix (0-4) */ Item_result result_type; /* Type of item */ bool reverse; /* if descending sort */ bool need_strxnfrm; /* If we have to use strxnfrm() */ diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc new file mode 100644 index 00000000000..e8da691ea18 --- /dev/null +++ b/sql/sql_cursor.cc @@ -0,0 +1,660 @@ +/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef USE_PRAGMA_IMPLEMENTATION +#pragma implementation /* gcc class implementation */ +#endif + +#include "mysql_priv.h" +#include "sql_cursor.h" +#include "sql_select.h" + +/**************************************************************************** + Declarations. +****************************************************************************/ + +/* + Sensitive_cursor -- a sensitive non-materialized server side + cursor An instance of this class cursor has its own runtime + state -- list of used items and memory root for runtime memory, + open and locked tables, change list for the changes of the + parsed tree. This state is freed when the cursor is closed. +*/ + +class Sensitive_cursor: public Server_side_cursor +{ + MEM_ROOT main_mem_root; + Query_arena *stmt_arena; + JOIN *join; + TABLE *open_tables; + MYSQL_LOCK *lock; + TABLE *derived_tables; + /* List of items created during execution */ + query_id_t query_id; + struct Engine_info + { + const handlerton *ht; + void *read_view; + }; + Engine_info ht_info[MAX_HA]; + Item_change_list change_list; + my_bool close_at_commit; + THR_LOCK_OWNER lock_id; +private: + /* bzero cursor state in THD */ + void reset_thd(THD *thd); +public: + Sensitive_cursor(THD *thd, select_result *result_arg); + + THR_LOCK_OWNER *get_lock_id() { return &lock_id; } + /* Save THD state into cursor */ + void post_open(THD *thd); + + virtual bool is_open() const { return join != 0; } + virtual int open(JOIN *join); + virtual void fetch(ulong num_rows); + virtual void close(); + virtual ~Sensitive_cursor(); +}; + + +/* + Materialized_cursor -- an insensitive materialized server-side + cursor. The result set of this cursor is saved in a temporary + table at open. The cursor itself is simply an interface for the + handler of the temporary table. +*/ + +class Materialized_cursor: public Server_side_cursor +{ + MEM_ROOT main_mem_root; + /* A fake unit to supply to select_send when fetching */ + SELECT_LEX_UNIT fake_unit; + TABLE *table; + List<Item> item_list; + ulong fetch_limit; + ulong fetch_count; +public: + Materialized_cursor(select_result *result, TABLE *table); + + virtual bool is_open() const { return table != 0; } + virtual int open(JOIN *join __attribute__((unused))); + virtual void fetch(ulong num_rows); + virtual void close(); + virtual ~Materialized_cursor(); +}; + + +/* + Select_materialize -- a mediator between a cursor query and the + protocol. In case we were not able to open a non-materialzed + cursor, it creates an internal temporary HEAP table, and insert + all rows into it. When the table reaches max_heap_table_size, + it's converted to a MyISAM table. Later this table is used to + create a Materialized_cursor. +*/ + +class Select_materialize: public select_union +{ + select_result *result; /* the result object of the caller (PS or SP) */ +public: + Select_materialize(select_result *result_arg) :result(result_arg) {} + virtual bool send_fields(List<Item> &list, uint flags); +}; + + +/**************************************************************************/ + +/* + Attempt to open a materialized or non-materialized cursor. + + SYNOPSIS + mysql_open_cursor() + thd thread handle + flags [in] create a materialized cursor or not + result [in] result class of the caller used as a destination + for the rows fetched from the cursor + pcursor [out] a pointer to store a pointer to cursor in + + RETURN VALUE + 0 the query has been successfully executed; in this + case pcursor may or may not contain + a pointer to an open cursor. + non-zero an error, 'pcursor' has been left intact. +*/ + +int mysql_open_cursor(THD *thd, uint flags, select_result *result, + Server_side_cursor **pcursor) +{ + Sensitive_cursor *sensitive_cursor; + select_result *save_result; + Select_materialize *result_materialize; + LEX *lex= thd->lex; + int rc; + + /* + The lifetime of the sensitive cursor is the same or less as the + lifetime of the runtime memory of the statement it's opened for. + */ + if (! (result_materialize= new (thd->mem_root) Select_materialize(result))) + return 1; + + if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result))) + { + delete result; + return 1; + } + + save_result= lex->result; + + lex->result= result_materialize; + if (! (flags & (uint) ALWAYS_MATERIALIZED_CURSOR)) + { + thd->lock_id= sensitive_cursor->get_lock_id(); + thd->cursor= sensitive_cursor; + } + + rc= mysql_execute_command(thd); + + lex->result= save_result; + thd->lock_id= &thd->main_lock_id; + thd->cursor= 0; + + /* + Possible options here: + - a sensitive cursor is open. In this case rc is 0 and + result_materialize->table is NULL, or + - a materialized cursor is open. In this case rc is 0 and + result_materialize->table is not NULL + - an error occured during materializaton. + result_materialize->table is not NULL, but rc != 0 + - successful completion of mysql_execute_command without + a cursor: rc is 0, result_materialize->table is NULL, + sensitive_cursor is not open. + This is possible if some command writes directly to the + network, bypassing select_result mechanism. An example of + such command is SHOW VARIABLES or SHOW STATUS. + */ + if (rc) + goto err_open; + + if (sensitive_cursor->is_open()) + { + DBUG_ASSERT(!result_materialize->table); + /* + It's safer if we grab THD state after mysql_execute_command + is finished and not in Sensitive_cursor::open(), because + currently the call to Sensitive_cursor::open is buried deep + in JOIN::exec of the top level join. + */ + sensitive_cursor->post_open(thd); + *pcursor= sensitive_cursor; + goto end; + } + else if (result_materialize->table) + { + Materialized_cursor *materialized_cursor; + TABLE *table= result_materialize->table; + MEM_ROOT *mem_root= &table->mem_root; + + if (!(materialized_cursor= new (mem_root) + Materialized_cursor(result, table))) + { + rc= 1; + goto err_open; + } + + if ((rc= materialized_cursor->open(0))) + { + delete materialized_cursor; + goto err_open; + } + + *pcursor= materialized_cursor; + thd->stmt_arena->cleanup_stmt(); + goto end; + } + +err_open: + DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open())); + delete sensitive_cursor; + if (result_materialize->table) + free_tmp_table(thd, result_materialize->table); +end: + delete result_materialize; + return rc; +} + +/**************************************************************************** + Server_side_cursor +****************************************************************************/ + +Server_side_cursor::~Server_side_cursor() +{ +} + + +void Server_side_cursor::operator delete(void *ptr, size_t size) +{ + Server_side_cursor *cursor= (Server_side_cursor*) ptr; + MEM_ROOT own_root= *cursor->mem_root; + + DBUG_ENTER("Server_side_cursor::operator delete"); + TRASH(ptr, size); + /* + If this cursor has never been opened mem_root is empty. Otherwise + mem_root points to the memory the cursor object was allocated in. + In this case it's important to call free_root last, and free a copy + instead of *mem_root to avoid writing into freed memory. + */ + free_root(&own_root, MYF(0)); + DBUG_VOID_RETURN; +} + +/**************************************************************************** + Sensitive_cursor +****************************************************************************/ + +Sensitive_cursor::Sensitive_cursor(THD *thd, select_result *result_arg) + :Server_side_cursor(&main_mem_root, result_arg), + stmt_arena(0), + join(0), + close_at_commit(FALSE) +{ + /* We will overwrite it at open anyway. */ + init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); + thr_lock_owner_init(&lock_id, &thd->lock_info); + bzero((void*) ht_info, sizeof(ht_info)); +} + + +void +Sensitive_cursor::post_open(THD *thd) +{ + Engine_info *info; + /* + We need to save and reset thd->mem_root, otherwise it'll be + freed later in mysql_parse. + + We can't just change thd->mem_root here as we want to keep the + things that are already allocated in thd->mem_root for + Sensitive_cursor::fetch() + */ + *mem_root= *thd->mem_root; + stmt_arena= thd->stmt_arena; + state= stmt_arena->state; + /* Allocate a new memory root for thd */ + init_sql_alloc(thd->mem_root, + thd->variables.query_alloc_block_size, + thd->variables.query_prealloc_size); + + /* + Save tables and zero THD pointers to prevent table close in + close_thread_tables. + */ + derived_tables= thd->derived_tables; + open_tables= thd->open_tables; + lock= thd->lock; + query_id= thd->query_id; + free_list= thd->free_list; + change_list= thd->change_list; + reset_thd(thd); + /* Now we have an active cursor and can cause a deadlock */ + thd->lock_info.n_cursors++; + + close_at_commit= FALSE; /* reset in case we're reusing the cursor */ + info= &ht_info[0]; + for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++) + { + const handlerton *ht= *pht; + close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); + if (ht->create_cursor_read_view) + { + info->ht= ht; + info->read_view= (ht->create_cursor_read_view)(); + ++info; + } + } + /* + XXX: thd->locked_tables is not changed. + What problems can we have with it if cursor is open? + TODO: must be fixed because of the prelocked mode. + */ +} + + +void +Sensitive_cursor::reset_thd(THD *thd) +{ + thd->derived_tables= 0; + thd->open_tables= 0; + thd->lock= 0; + thd->free_list= 0; + thd->change_list.empty(); +} + + +int +Sensitive_cursor::open(JOIN *join_arg) +{ + join= join_arg; + THD *thd= join->thd; + /* First non-constant table */ + JOIN_TAB *join_tab= join->join_tab + join->const_tables; + DBUG_ENTER("Sensitive_cursor::open"); + + join->change_result(result); + /* + Send fields description to the client; server_status is sent + in 'EOF' packet, which follows send_fields(). + We don't simply use SEND_EOF flag of send_fields because we also + want to flush the network buffer, which is done only in a standalone + send_eof(). + */ + result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS); + thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; + result->send_eof(); + thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + + /* Prepare JOIN for reading rows. */ + join->tmp_table= 0; + join->join_tab[join->tables-1].next_select= setup_end_select_func(join); + join->send_records= 0; + join->fetch_limit= join->unit->offset_limit_cnt; + + /* Disable JOIN CACHE as it is not working with cursors yet */ + for (JOIN_TAB *tab= join_tab; + tab != join->join_tab + join->tables - 1; + tab++) + { + if (tab->next_select == sub_select_cache) + tab->next_select= sub_select; + } + + DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0); + DBUG_ASSERT(join_tab->not_used_in_distinct == 0); + /* + null_row is set only if row not found and it's outer join: should never + happen for the first table in join_tab list + */ + DBUG_ASSERT(join_tab->table->null_row == 0); + DBUG_RETURN(0); +} + + +/* + SYNOPSIS + Sensitive_cursor::fetch() + num_rows fetch up to this number of rows (maybe less) + + DESCRIPTION + Fetch next num_rows rows from the cursor and send them to the client + + Precondition: + Sensitive_cursor is open + + RETURN VALUES: + none, this function will send OK to the clinet or set an error + message in THD +*/ + +void +Sensitive_cursor::fetch(ulong num_rows) +{ + THD *thd= join->thd; + JOIN_TAB *join_tab= join->join_tab + join->const_tables; + enum_nested_loop_state error= NESTED_LOOP_OK; + Query_arena backup_arena; + Engine_info *info; + DBUG_ENTER("Sensitive_cursor::fetch"); + DBUG_PRINT("enter",("rows: %lu", num_rows)); + + DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 && + thd->lock == 0); + + thd->derived_tables= derived_tables; + thd->open_tables= open_tables; + thd->lock= lock; + thd->query_id= query_id; + thd->change_list= change_list; + /* save references to memory allocated during fetch */ + thd->set_n_backup_active_arena(this, &backup_arena); + + for (info= ht_info; info->read_view ; info++) + (info->ht->set_cursor_read_view)(info->read_view); + + join->fetch_limit+= num_rows; + + error= sub_select(join, join_tab, 0); + if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) + error= sub_select(join,join_tab,1); + if (error == NESTED_LOOP_QUERY_LIMIT) + error= NESTED_LOOP_OK; /* select_limit used */ + if (error == NESTED_LOOP_CURSOR_LIMIT) + join->resume_nested_loop= TRUE; + +#ifdef USING_TRANSACTIONS + ha_release_temporary_latches(thd); +#endif + /* Grab free_list here to correctly free it in close */ + thd->restore_active_arena(this, &backup_arena); + + change_list= thd->change_list; + reset_thd(thd); + + for (info= ht_info; info->read_view; info++) + (info->ht->set_cursor_read_view)(0); + + if (error == NESTED_LOOP_CURSOR_LIMIT) + { + /* Fetch limit worked, possibly more rows are there */ + thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; + result->send_eof(); + thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + } + else + { + close(); + if (error == NESTED_LOOP_OK) + { + thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; + result->send_eof(); + thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT; + } + else if (error != NESTED_LOOP_KILLED) + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + } + DBUG_VOID_RETURN; +} + + +void +Sensitive_cursor::close() +{ + THD *thd= join->thd; + DBUG_ENTER("Sensitive_cursor::close"); + + for (Engine_info *info= ht_info; info->read_view; info++) + { + (info->ht->close_cursor_read_view)(info->read_view); + info->read_view= 0; + info->ht= 0; + } + + thd->change_list= change_list; + { + /* + XXX: Another hack: we need to set THD state as if in a fetch to be + able to call stmt close. + */ + DBUG_ASSERT(lock || open_tables || derived_tables); + + TABLE *tmp_derived_tables= thd->derived_tables; + MYSQL_LOCK *tmp_lock= thd->lock; + + thd->open_tables= open_tables; + thd->derived_tables= derived_tables; + thd->lock= lock; + + /* Is expected to at least close tables and empty thd->change_list */ + stmt_arena->cleanup_stmt(); + + thd->open_tables= tmp_derived_tables; + thd->derived_tables= tmp_derived_tables; + thd->lock= tmp_lock; + } + thd->lock_info.n_cursors--; /* Decrease the number of active cursors */ + join= 0; + stmt_arena= 0; + free_items(); + change_list.empty(); + DBUG_VOID_RETURN; +} + + +Sensitive_cursor::~Sensitive_cursor() +{ + if (is_open()) + close(); +} + +/*************************************************************************** + Materialized_cursor +****************************************************************************/ + +Materialized_cursor::Materialized_cursor(select_result *result_arg, + TABLE *table_arg) + :Server_side_cursor(&table_arg->mem_root, result_arg), + table(table_arg), + fetch_limit(0), + fetch_count(0) +{ + fake_unit.init_query(); + fake_unit.thd= table->in_use; +} + + +int Materialized_cursor::open(JOIN *join __attribute__((unused))) +{ + THD *thd= fake_unit.thd; + int rc; + Query_arena backup_arena; + + thd->set_n_backup_active_arena(this, &backup_arena); + /* Create a list of fields and start sequential scan */ + rc= (table->fill_item_list(&item_list) || + result->prepare(item_list, &fake_unit) || + table->file->ha_rnd_init(TRUE)); + thd->restore_active_arena(this, &backup_arena); + return rc; +} + + +/* + Fetch up to the given number of rows from a materialized cursor. + + DESCRIPTION + Precondition: the cursor is open. + + If the cursor points after the last row, the fetch will automatically + close the cursor and not send any data (except the 'EOF' packet + with SERVER_STATUS_LAST_ROW_SENT). This is an extra round trip + and probably should be improved to return + SERVER_STATUS_LAST_ROW_SENT along with the last row. + + RETURN VALUE + none, in case of success the row is sent to the client, otherwise + an error message is set in THD +*/ + +void Materialized_cursor::fetch(ulong num_rows) +{ + THD *thd= table->in_use; + + int res= 0; + for (fetch_limit+= num_rows; fetch_count < fetch_limit; fetch_count++) + { + if ((res= table->file->rnd_next(table->record[0]))) + break; + /* Send data only if the read was successful. */ + result->send_data(item_list); + } + + switch (res) { + case 0: + thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; + result->send_eof(); + thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + break; + case HA_ERR_END_OF_FILE: + thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; + result->send_eof(); + thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT; + close(); + break; + default: + table->file->print_error(res, MYF(0)); + close(); + break; + } +} + + +void Materialized_cursor::close() +{ + /* Free item_list items */ + free_items(); + (void) table->file->ha_rnd_end(); + /* + We need to grab table->mem_root to prevent free_tmp_table from freeing: + the cursor object was allocated in this memory. + */ + main_mem_root= table->mem_root; + mem_root= &main_mem_root; + clear_alloc_root(&table->mem_root); + free_tmp_table(table->in_use, table); + table= 0; +} + + +Materialized_cursor::~Materialized_cursor() +{ + if (is_open()) + close(); +} + + +/*************************************************************************** + Select_materialize +****************************************************************************/ + +bool Select_materialize::send_fields(List<Item> &list, uint flags) +{ + bool rc; + DBUG_ASSERT(table == 0); + if (create_result_table(unit->thd, unit->get_unit_column_types(), + FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, "")) + return TRUE; + /* + We can't simply supply SEND_EOF flag to send_fields, because send_fields + doesn't flush the network buffer. + */ + rc= result->send_fields(list, Protocol::SEND_NUM_ROWS); + thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; + result->send_eof(); + thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + return rc; +} + diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h new file mode 100644 index 00000000000..d1156dfba8d --- /dev/null +++ b/sql/sql_cursor.h @@ -0,0 +1,65 @@ +#ifndef _sql_cursor_h_ +#define _sql_cursor_h_ +/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class interface */ +#endif + +/* + Declarations for implementation of server side cursors. Only + read-only non-scrollable cursors are currently implemented. +*/ + +/* + Server_side_cursor -- an interface for materialized and + sensitive (non-materialized) implementation of cursors. All + cursors are self-contained (created in their own memory root). + For that reason they must be deleted only using a pointer to + Server_side_cursor, not to its base class. +*/ + +class Server_side_cursor: protected Query_arena, public Sql_alloc +{ +protected: + /* Row destination used for fetch */ + select_result *result; +public: + Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg) + :Query_arena(mem_root_arg, INITIALIZED), result(result_arg) + {} + + virtual bool is_open() const= 0; + + virtual int open(JOIN *top_level_join)= 0; + virtual void fetch(ulong num_rows)= 0; + virtual void close()= 0; + virtual ~Server_side_cursor(); + + static void operator delete(void *ptr, size_t size); +}; + + +int mysql_open_cursor(THD *thd, uint flags, + select_result *result, + Server_side_cursor **res); + +/* Possible values for flags */ + +enum { ANY_CURSOR= 1, ALWAYS_MATERIALIZED_CURSOR= 2 }; + +#endif /* _sql_cusor_h_ */ diff --git a/sql/sql_db.cc b/sql/sql_db.cc index f24e2cdc0ad..a5dabc8140c 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -437,7 +437,12 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, error= -1; goto exit; } - result= 0; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db); + error= 0; + if (!silent) + send_ok(thd); + goto exit; } else { @@ -1089,6 +1094,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) bool system_db= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; + Security_context *sctx= thd->security_ctx; #endif DBUG_ENTER("mysql_change_db"); DBUG_PRINT("enter",("name: '%s'",name)); @@ -1126,22 +1132,20 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!no_access_check) { - if (test_all_bits(thd->master_access,DB_ACLS)) + if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); + db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | + sctx->master_access); if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, + sctx->priv_user, + sctx->priv_host, dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, - thd->priv_host, - dbname); + mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), + sctx->priv_user, sctx->priv_host, dbname); my_free(dbname,MYF(0)); DBUG_RETURN(1); } @@ -1163,7 +1167,7 @@ end: thd->db_length=db_length; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!no_access_check) - thd->db_access=db_access; + sctx->db_access= db_access; #endif if (system_db) { diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4e86e3972c2..83f50ba3ac5 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -37,6 +37,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, bool using_limit=limit != HA_POS_ERROR; bool transactional_table, safe_update, const_cond; ha_rows deleted; + uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_delete"); @@ -140,27 +141,40 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, tables.table = table; tables.alias = table_list->alias; - table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), - MYF(MY_FAE | MY_ZEROFILL)); if (select_lex->setup_ref_array(thd, order->elements) || setup_order(thd, select_lex->ref_pointer_array, &tables, - fields, all_fields, (ORDER*) order->first) || - !(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) || + fields, all_fields, (ORDER*) order->first)) + { + delete select; + free_underlaid_joins(thd, &thd->lex->select_lex); + DBUG_RETURN(TRUE); + } + + if (!select && limit != HA_POS_ERROR) + usable_index= get_index_for_order(table, (ORDER*)(order->first), limit); + + if (usable_index == MAX_KEY) + { + table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE), + MYF(MY_FAE | MY_ZEROFILL)); + + if ( !(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) || (table->sort.found_records = filesort(thd, table, sortorder, length, select, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) - { + { + delete select; + free_underlaid_joins(thd, &thd->lex->select_lex); + } + /* + Filesort has already found and selected the rows we want to delete, + so we don't need the where clause + */ delete select; free_underlaid_joins(thd, select_lex); - DBUG_RETURN(TRUE); + select= 0; } - /* - Filesort has already found and selected the rows we want to delete, - so we don't need the where clause - */ - delete select; - select= 0; } /* If quick select is used, initialize it before retrieving rows. */ @@ -170,7 +184,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, free_underlaid_joins(thd, select_lex); DBUG_RETURN(TRUE); } - init_read_record(&info,thd,table,select,1,1); + if (usable_index==MAX_KEY) + init_read_record(&info,thd,table,select,1,1); + else + init_read_record_idx(&info, thd, table, 1, usable_index); + deleted=0L; init_ftfuncs(thd, select_lex, 1); thd->proc_info="updating"; @@ -258,19 +276,12 @@ cleanup: delete select; transactional_table= table->file->has_transactions(); - /* - We write to the binary log even if we deleted no row, because maybe the - user is using this command to ensure that a table is clean on master *and - on slave*. Think of the case of a user having played separately with the - master's table and slave's table and wanting to take a fresh identical - start now. - error < 0 means "really no error". error <= 0 means "maybe some error". - */ - if ((deleted || (error < 0)) && (error <= 0 || !transactional_table)) + /* See similar binlogging code in sql_update.cc, for comments */ + if ((error < 0) || (deleted && !transactional_table)) { if (mysql_bin_log.is_open()) { - if (error <= 0) + if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_table, FALSE); @@ -320,6 +331,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_delete"); + thd->allow_sum_func= 0; if (setup_tables(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, table_list, conds, &select_lex->leaf_tables, @@ -332,10 +344,13 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); DBUG_RETURN(TRUE); } - if (unique_table(table_list, table_list->next_global)) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); - DBUG_RETURN(TRUE); + TABLE_LIST *duplicate; + if ((duplicate= unique_table(table_list, table_list->next_global))) + { + update_non_unique_table_error(table_list, "DELETE", duplicate); + DBUG_RETURN(TRUE); + } } select_lex->fix_prepare_information(thd, conds); DBUG_RETURN(FALSE); @@ -418,11 +433,15 @@ bool mysql_multi_delete_prepare(THD *thd) Check that table from which we delete is not used somewhere inside subqueries/view. */ - if (unique_table(target_tbl->correspondent_table, lex->query_tables)) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), - target_tbl->correspondent_table->table_name); - DBUG_RETURN(TRUE); + TABLE_LIST *duplicate; + if ((duplicate= unique_table(target_tbl->correspondent_table, + lex->query_tables))) + { + update_non_unique_table_error(target_tbl->correspondent_table, + "DELETE", duplicate); + DBUG_RETURN(TRUE); + } } } DBUG_RETURN(FALSE); @@ -711,6 +730,9 @@ bool multi_delete::send_eof() /* Does deletes for the last n - 1 tables, returns 0 if ok */ int local_error= do_deletes(); // returns 0 if success + /* compute a total error to know if something failed */ + local_error= local_error || error; + /* reset used flags */ thd->proc_info="end"; @@ -723,19 +745,11 @@ bool multi_delete::send_eof() query_cache_invalidate3(thd, delete_tables, 1); } - /* - Write the SQL statement to the binlog if we deleted - rows and we succeeded, or also in an error case when there - was a non-transaction-safe table involved, since - modifications in it cannot be rolled back. - Note that if we deleted nothing we don't write to the binlog (TODO: - fix this). - */ - if (deleted && ((error <= 0 && !local_error) || normal_tables)) + if ((local_error == 0) || (deleted && normal_tables)) { if (mysql_bin_log.is_open()) { - if (error <= 0 && !local_error) + if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); @@ -791,7 +805,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) TABLE *table= *table_ptr; table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK); db_type table_type= table->s->db_type; - if (!ha_supports_generate(table_type)) + if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE)) goto trunc_by_del; strmov(path, table->s->path); *table_ptr= table->next; // Unlink table from list @@ -822,7 +836,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) table_list->db, table_list->table_name); DBUG_RETURN(TRUE); } - if (!ha_supports_generate(table_type) || thd->lex->sphead) + if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE) + || thd->lex->sphead) goto trunc_by_del; if (lock_and_wait_for_table_name(thd, table_list)) DBUG_RETURN(TRUE); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 7b9191cd841..74b239e1637 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -27,7 +27,7 @@ /* - call given derived table processor (preparing or filling tables) + Call given derived table processor (preparing or filling tables) SYNOPSIS mysql_handle_derived() @@ -36,7 +36,6 @@ RETURN 0 ok - -1 Error 1 Error and error message given */ @@ -97,14 +96,14 @@ out: RETURN 0 ok - 1 Error - -1 Error and error message given - */ + 1 Error and an error message was given +*/ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) { SELECT_LEX_UNIT *unit= orig_table_list->derived; int res= 0; + ulonglong create_options; DBUG_ENTER("mysql_derived_prepare"); if (unit) { @@ -118,21 +117,18 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) sl->context.outer_context= 0; - if (!(derived_result= new select_union(0))) + if (!(derived_result= new select_union)) DBUG_RETURN(1); // out of memory // st_select_lex_unit::prepare correctly work for single select - if ((res= unit->prepare(thd, derived_result, 0, orig_table_list->alias))) + if ((res= unit->prepare(thd, derived_result, 0))) goto exit; - if (check_duplicate_names(unit->types, 0)) - { - res= -1; + if ((res= check_duplicate_names(unit->types, 0))) goto exit; - } - derived_result->tmp_table_param.init(); - derived_result->tmp_table_param.field_count= unit->types.elements; + create_options= (first_select->options | thd->options | + TMP_TABLE_ALL_COLUMNS); /* Temp table is created so that it hounours if UNION without ALL is to be processed @@ -143,18 +139,12 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) !unit->union_distinct->next_select() (i.e. it is union and last distinct SELECT is last SELECT of UNION). */ - if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param, - unit->types, (ORDER*) 0, - FALSE, 1, - (first_select->options | thd->options | - TMP_TABLE_ALL_COLUMNS), - HA_POS_ERROR, - orig_table_list->alias))) - { - res= -1; + if ((res= derived_result->create_result_table(thd, &unit->types, FALSE, + create_options, + orig_table_list->alias))) goto exit; - } - derived_result->set_table(table); + + table= derived_result->table; exit: /* Hide "Unknown column" or "Unknown function" error */ @@ -231,9 +221,8 @@ exit: RETURN 0 ok - 1 Error - -1 Error and error message given - */ + 1 Error and an error message was given +*/ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) { diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 2e262569386..191a6e0a1fd 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -144,6 +144,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, thd->really_abort_on_warning()) ? MYSQL_ERROR::WARN_LEVEL_ERROR : level)) { + if (! thd->spcont->found_handler_here()) + thd->net.report_error= 1; /* Make "select" abort correctly */ DBUG_RETURN(NULL); } query_cache_abort(&thd->net); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 169132e2185..cc45a7001cd 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -346,6 +346,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, uint num_rows; byte *key; uint key_len; + bool not_used; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", tables->db, tables->table_name, tables->alias)); @@ -431,7 +432,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); HANDLER_TABLES_HACK(thd); - lock= mysql_lock_tables(thd, &tables->table, 1, 0); + lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used); HANDLER_TABLES_HACK(thd); if (!lock) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 799758f7d1e..b47412981ea 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -289,7 +289,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations, topics->file->ha_index_init(iindex_topic); relations->file->ha_index_init(iindex_relations); - rkey_id->store((longlong) key_id); + rkey_id->store((longlong) key_id, TRUE); rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW); int key_res= relations->file->index_read(relations->record[0], (byte *)buff, rkey_id->pack_length(), @@ -302,7 +302,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations, char topic_id_buff[8]; longlong topic_id= rtopic_id->val_int(); Field *field= find_fields[help_topic_help_topic_id].field; - field->store((longlong) topic_id); + field->store((longlong) topic_id, TRUE); field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW); if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff, @@ -599,7 +599,8 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, { Item *cond= new Item_func_like(new Item_field(pfname), new Item_string(mask,mlen,pfname->charset()), - new Item_string("\\",1,&my_charset_latin1)); + new Item_string("\\",1,&my_charset_latin1), + FALSE); if (thd->is_fatal_error) return 0; // OOM return prepare_simple_select(thd, cond, table, error); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 93c9991418d..088b55c2fd8 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -28,7 +28,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list); static int write_delayed(THD *thd,TABLE *table, enum_duplicates dup, bool ignore, char *query, uint query_length, bool log_on); static void end_delayed_insert(THD *thd); -extern "C" pthread_handler_decl(handle_delayed_insert,arg); +pthread_handler_t handle_delayed_insert(void *arg); static void unlink_blobs(register TABLE *table); #endif static bool check_view_insertability(THD *thd, TABLE_LIST *view); @@ -272,7 +272,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, By default, both logs are enabled (this won't cause problems if the server runs without --log-update or --log-bin). */ - bool log_on= (thd->options & OPTION_BIN_LOG) || (!(thd->master_access & SUPER_ACL)); + bool log_on= (thd->options & OPTION_BIN_LOG) || + (!(thd->security_ctx->master_access & SUPER_ACL)); bool transactional_table; uint value_count; ulong counter = 1; @@ -917,9 +918,10 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!select_insert) { Item *fake_conds= 0; - if (unique_table(table_list, table_list->next_global)) + TABLE_LIST *duplicate; + if ((duplicate= unique_table(table_list, table_list->next_global))) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); + update_non_unique_table_error(table_list, "INSERT", duplicate); DBUG_RETURN(TRUE); } select_lex->fix_prepare_information(thd, &fake_conds); @@ -1194,9 +1196,7 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, bool view= FALSE; if (table_list) { - table_list= (table_list->belong_to_view ? - table_list->belong_to_view : - table_list); + table_list= table_list->top_table(); view= test(table_list->view); } if (view) @@ -1265,8 +1265,8 @@ public: table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0), group_count(0) { - thd.user=thd.priv_user=(char*) delayed_user; - thd.host=(char*) my_localhost; + thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user; + thd.security_ctx->host=(char*) my_localhost; thd.current_tablenr=0; thd.version=refresh_version; thd.command=COM_DELAYED_INSERT; @@ -1276,7 +1276,7 @@ public: bzero((char*) &thd.net, sizeof(thd.net)); // Safety bzero((char*) &table_list, sizeof(table_list)); // Safety thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT; - thd.host_or_ip= ""; + thd.security_ctx->host_or_ip= ""; bzero((char*) &info,sizeof(info)); pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST); pthread_cond_init(&cond,NULL); @@ -1299,7 +1299,7 @@ public: pthread_cond_destroy(&cond_client); thd.unlink(); // Must be unlinked under lock x_free(thd.query); - thd.user=thd.host=0; + thd.security_ctx->user= thd.security_ctx->host=0; thread_count--; delayed_insert_threads--; VOID(pthread_mutex_unlock(&LOCK_thread_count)); @@ -1691,7 +1691,7 @@ void kill_delayed_threads(void) * Create a new delayed insert thread */ -extern "C" pthread_handler_decl(handle_delayed_insert,arg) +pthread_handler_t handle_delayed_insert(void *arg) { delayed_insert *di=(delayed_insert*) arg; THD *thd= &di->thd; @@ -1809,7 +1809,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) #endif if (thd->killed || di->status) break; - if (error == ETIMEDOUT) + if (error == ETIMEDOUT || error == ETIME) { thd->killed= THD::KILL_CONNECTION; break; @@ -1827,6 +1827,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) if (di->tables_in_use && ! thd->lock) { + bool not_used; /* Request for new delayed insert. Lock the table, but avoid to be blocked by a global read lock. @@ -1838,7 +1839,8 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) inserts are done. */ if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, - MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))) + MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK, + ¬_used))) { /* Fatal error */ di->dead= 1; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 86823919378..11f056d6510 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -128,6 +128,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->update_list.empty(); lex->param_list.empty(); lex->view_list.empty(); + lex->prepared_stmt_params.empty(); lex->unit.next= lex->unit.master= lex->unit.link_next= lex->unit.return_to= 0; lex->unit.prev= lex->unit.link_prev= 0; @@ -143,6 +144,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->describe= 0; lex->subqueries= FALSE; lex->view_prepare_mode= FALSE; + lex->stmt_prepare_mode= FALSE; lex->derived_tables= 0; lex->lock_option= TL_READ; lex->found_semicolon= 0; @@ -173,10 +175,13 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->spcont= NULL; lex->proc_list.first= 0; lex->query_tables_own_last= 0; + lex->escape_used= FALSE; if (lex->sroutines.records) my_hash_reset(&lex->sroutines); lex->sroutines_list.empty(); + lex->sroutines_list_own_last= lex->sroutines_list.next; + lex->sroutines_list_own_elements= 0; DBUG_VOID_RETURN; } @@ -568,8 +573,7 @@ int yylex(void *arg, void *yythd) its value in a query for the binlog, the query must stay grammatically correct. */ - else if (c == '?' && ((THD*) yythd)->command == COM_STMT_PREPARE && - !ident_map[yyPeek()]) + else if (c == '?' && lex->stmt_prepare_mode && !ident_map[yyPeek()]) return(PARAM_MARKER); return((int) c); @@ -981,7 +985,7 @@ int yylex(void *arg, void *yythd) { THD* thd= (THD*)yythd; if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) && - (thd->command != COM_STMT_PREPARE)) + !lex->stmt_prepare_mode) { lex->safe_to_cache_query= 0; lex->found_semicolon=(char*) lex->ptr; @@ -1130,6 +1134,7 @@ void st_select_lex::init_query() ref_pointer_array= 0; select_n_having_items= 0; subquery_in_having= explicit_limit= 0; + is_item_list_lookup= 0; first_execution= 1; first_cond_optimization= 1; parsing_place= NO_MATTER; @@ -1162,6 +1167,7 @@ void st_select_lex::init_select() select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ offset_limit= 0; /* denotes the default offset = 0 */ with_sum_func= 0; + } /* @@ -1504,7 +1510,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) We have to create array in prepared statement memory if it is prepared statement */ - Query_arena *arena= thd->current_arena; + Query_arena *arena= thd->stmt_arena; return (ref_pointer_array= (Item **)arena->alloc(sizeof(Item*) * (item_list.elements + @@ -1612,6 +1618,8 @@ st_lex::st_lex() { hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); sroutines_list.empty(); + sroutines_list_own_last= sroutines_list.next; + sroutines_list_own_elements= 0; } @@ -1826,7 +1834,7 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) { ha_rows select_limit_val; - DBUG_ASSERT(! thd->current_arena->is_stmt_prepare()); + DBUG_ASSERT(! thd->stmt_arena->is_stmt_prepare()); select_limit_val= (ha_rows)(sl->select_limit ? sl->select_limit->val_uint() : HA_POS_ERROR); offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() : @@ -2024,6 +2032,8 @@ void st_lex::cleanup_after_one_table_open() if (sroutines.records) my_hash_reset(&sroutines); sroutines_list.empty(); + sroutines_list_own_last= sroutines_list.next; + sroutines_list_own_elements= 0; } @@ -2038,7 +2048,7 @@ void st_lex::cleanup_after_one_table_open() void st_select_lex::fix_prepare_information(THD *thd, Item **conds) { - if (!thd->current_arena->is_conventional() && first_execution) + if (!thd->stmt_arena->is_conventional() && first_execution) { first_execution= 0; if (*conds) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d777abca29a..1e935c6dc2a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -53,7 +53,7 @@ enum enum_sql_command { SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS, SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS, - SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_MUTEX_STATUS, + SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_NDBCLUSTER_STATUS, SQLCOM_SHOW_MUTEX_STATUS, SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, @@ -386,12 +386,12 @@ protected: select_result *result; ulong found_rows_for_union; bool res; +public: bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) executed, // already executed cleaned; -public: // list of fields which points to temporary table for union List<Item> item_list; /* @@ -432,10 +432,6 @@ public: { return my_reinterpret_cast(st_select_lex*)(slave); } - st_select_lex* first_select_in_union() - { - return my_reinterpret_cast(st_select_lex*)(slave); - } st_select_lex_unit* next_unit() { return my_reinterpret_cast(st_select_lex_unit*)(next); @@ -445,8 +441,7 @@ public: void exclude_tree(); /* UNION methods */ - bool prepare(THD *thd, select_result *result, ulong additional_options, - const char *tmp_table_alias); + bool prepare(THD *thd, select_result *result, ulong additional_options); bool exec(); bool cleanup(); inline void unclean() { cleaned= 0; } @@ -462,7 +457,10 @@ public: friend void lex_start(THD *thd, uchar *buf, uint length); friend int subselect_union_engine::exec(); + + List<Item> *get_unit_column_types(); }; + typedef class st_select_lex_unit SELECT_LEX_UNIT; /* @@ -484,6 +482,7 @@ public: List<Item> item_list; /* list of fields & expressions */ List<String> interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; + bool is_item_list_lookup; /* Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake select_lex for calling mysql_select under results of union @@ -640,6 +639,11 @@ public: SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs). */ bool cleanup(); + /* + Recursively cleanup the join of this select lex and of all nested + select lexes. + */ + void cleanup_all_joins(bool full); }; typedef class st_select_lex SELECT_LEX; @@ -733,6 +737,8 @@ typedef struct st_lex TABLE_LIST **query_tables_last; /* store original leaf_tables for INSERT SELECT and PS/SP */ TABLE_LIST *leaf_tables_insert; + st_lex_user *create_view_definer; + char *create_view_select_start; List<key_part_spec> col_list; List<key_part_spec> ref_list; @@ -808,6 +814,11 @@ typedef struct st_lex to an .frm file. We need this definition to stay untouched. */ bool view_prepare_mode; + /* + TRUE if we're parsing a prepared statement: in this mode + we should allow placeholders and disallow multistatements. + */ + bool stmt_prepare_mode; bool safe_to_cache_query; bool subqueries, ignore; bool variables_used; @@ -838,8 +849,15 @@ typedef struct st_lex /* List linking elements of 'sroutines' set. Allows you to add new elements to this set as you iterate through the list of existing elements. + 'sroutines_list_own_last' is pointer to ::next member of last element of + this list which represents routine which is explicitly used by query. + 'sroutines_list_own_elements' number of explicitly used routines. + We use these two members for restoring of 'sroutines_list' to the state + in which it was right after query parsing. */ SQL_LIST sroutines_list; + byte **sroutines_list_own_last; + uint sroutines_list_own_elements; st_sp_chistics sp_chistics; bool only_view; /* used for SHOW CREATE TABLE/VIEW */ @@ -848,6 +866,10 @@ typedef struct st_lex rexecuton */ bool empty_field_list_on_rset; + /* + view created to be run from definer (standard behaviour) + */ + bool create_view_suid; /* Characterstics of trigger being created */ st_trg_chistics trg_chistics; /* @@ -872,6 +894,8 @@ typedef struct st_lex during replication ("LOCAL 'filename' REPLACE INTO" part). */ uchar *fname_start, *fname_end; + + bool escape_used; st_lex(); @@ -951,6 +975,15 @@ typedef struct st_lex { return ( query_tables_own_last ? *query_tables_own_last : 0); } + void chop_off_not_own_tables() + { + if (query_tables_own_last) + { + *query_tables_own_last= 0; + query_tables_last= query_tables_own_last; + query_tables_own_last= 0; + } + } void cleanup_after_one_table_open(); void push_context(Name_resolution_context *context) diff --git a/sql/sql_list.h b/sql/sql_list.h index e4a34cc0aa1..285f1d6e501 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -32,6 +32,8 @@ public: { return (void*) sql_alloc((uint) size); } + static void *operator new[](size_t size, MEM_ROOT *mem_root) + { return (void*) alloc_root(mem_root, (uint) size); } static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index e1684f9bb11..ff2be0ae6fb 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -147,6 +147,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, MYF(0)); DBUG_RETURN(TRUE); } + /* + This needs to be done before external_lock + */ + ha_enable_transaction(thd, FALSE); if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); if (setup_tables(thd, &thd->lex->select_lex.context, @@ -352,7 +356,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (ignore || handle_duplicates == DUP_REPLACE) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - ha_enable_transaction(thd, FALSE); table->file->start_bulk_insert((ha_rows) 0); table->copy_blobs=1; @@ -372,10 +375,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, *enclosed, skip_lines, ignore); if (table->file->end_bulk_insert()) error=1; /* purecov: inspected */ - ha_enable_transaction(thd, TRUE); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->next_number_field=0; } + ha_enable_transaction(thd, TRUE); if (file >= 0) my_close(file,MYF(0)); free_blobs(table); /* if pack_blob was used */ @@ -541,6 +544,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, while ((sql_field= (Item_field*) it++)) { Field *field= sql_field->field; + if (field == table->next_number_field) + table->auto_increment_field_not_null= TRUE; /* No fields specified in fields_vars list can be null in this format. Mark field as not null, we should do this for each row because of @@ -559,6 +564,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, { uint length; byte save_chr; + if (field == table->next_number_field) + table->auto_increment_field_not_null= TRUE; if ((length=(uint) (read_info.row_end-pos)) > field->field_length) length=field->field_length; @@ -681,6 +688,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, Field *field= ((Item_field *)item)->field; field->reset(); field->set_null(); + if (field == table->next_number_field) + table->auto_increment_field_not_null= TRUE; if (!field->maybe_null()) { if (field->type() == FIELD_TYPE_TIMESTAMP) @@ -698,9 +707,12 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (item->type() == Item::FIELD_ITEM) { + Field *field= ((Item_field *)item)->field; field->set_notnull(); read_info.row_end[0]=0; // Safe to change end marker + if (field == table->next_number_field) + table->auto_increment_field_not_null= TRUE; field->store((char*) pos, length, read_info.read_charset); } else diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc index 0af6a80d4c2..1d3acd1696c 100644 --- a/sql/sql_manager.cc +++ b/sql/sql_manager.cc @@ -32,7 +32,7 @@ pthread_t manager_thread; pthread_mutex_t LOCK_manager; pthread_cond_t COND_manager; -extern "C" pthread_handler_decl(handle_manager,arg __attribute__((unused))) +pthread_handler_t handle_manager(void *arg __attribute__((unused))) { int error = 0; ulong status; @@ -58,12 +58,14 @@ extern "C" pthread_handler_decl(handle_manager,arg __attribute__((unused))) set_timespec(abstime, flush_time); reset_flush_time = FALSE; } - while (!manager_status && !error && !abort_loop) - error = pthread_cond_timedwait(&COND_manager, &LOCK_manager, &abstime); + while (!manager_status && (!error || error == EINTR) && !abort_loop) + error= pthread_cond_timedwait(&COND_manager, &LOCK_manager, &abstime); } else - while (!manager_status && !error && !abort_loop) - error = pthread_cond_wait(&COND_manager, &LOCK_manager); + { + while (!manager_status && (!error || error == EINTR) && !abort_loop) + error= pthread_cond_wait(&COND_manager, &LOCK_manager); + } status = manager_status; manager_status = 0; pthread_mutex_unlock(&LOCK_manager); @@ -71,7 +73,7 @@ extern "C" pthread_handler_decl(handle_manager,arg __attribute__((unused))) if (abort_loop) break; - if (error) /* == ETIMEDOUT */ + if (error == ETIMEDOUT || error == ETIME) { flush_tables(); error = 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b0502753b1c..d0585dd1a65 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -25,6 +25,10 @@ #include "ha_innodb.h" #endif +#ifdef HAVE_NDBCLUSTER_DB +#include "ha_ndbcluster.h" +#endif + #include "sp_head.h" #include "sp.h" #include "sp_cache.h" @@ -130,6 +134,12 @@ static bool end_active_trans(THD *thd) my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); DBUG_RETURN(1); } + if (thd->transaction.xid_state.xa_state != XA_NOTR) + { + my_error(ER_XAER_RMFAIL, MYF(0), + xa_state_names[thd->transaction.xid_state.xa_state]); + DBUG_RETURN(1); + } if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK)) { @@ -174,12 +184,12 @@ static bool begin_trans(THD *thd) } #ifdef HAVE_REPLICATION +/* + Returns true if all tables should be ignored +*/ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) { - return (table_rules_on && tables && !tables_ok(thd,tables) && - ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) || - !tables_ok(thd, - (TABLE_LIST *)thd->lex->auxilliary_table_list.first))); + return table_rules_on && tables && !tables_ok(thd,tables); } #endif @@ -242,7 +252,7 @@ end: SYNOPSIS check_user() - thd thread handle, thd->{host,user,ip} are used + thd thread handle, thd->security_ctx->{host,user,ip} are used command originator of the check: now check_user is called during connect and change user procedures; used for logging. @@ -257,8 +267,8 @@ end: are 'IN'. RETURN VALUE - 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and - thd->db_access are updated; OK is sent to client; + 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and + thd->db are updated; OK is sent to client; -1 access denied or handshake error; error is sent to client; >0 error, not sent to client */ @@ -270,7 +280,7 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_ENTER("check_user"); #ifdef NO_EMBEDDED_ACCESS_CHECKS - thd->master_access= GLOBAL_ACLS; // Full rights + thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights /* Change database if necessary */ if (db && db[0]) { @@ -337,15 +347,17 @@ int check_user(THD *thd, enum enum_server_command command, if (opt_secure_auth_local) { net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, - thd->user, thd->host_or_ip); + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), - thd->user, thd->host_or_ip); + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); DBUG_RETURN(-1); } /* We have to read very specific packet size */ if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) - { + { inc_host_errors(&thd->remote.sin_addr); DBUG_RETURN(ER_HANDSHAKE_ERROR); } @@ -357,22 +369,27 @@ int check_user(THD *thd, enum enum_server_command command, /* here res is always >= 0 */ if (res == 0) { - if (!(thd->master_access & NO_ACCESS)) // authentication is OK + if (!(thd->main_security_ctx.master_access & + NO_ACCESS)) // authentication is OK { DBUG_PRINT("info", ("Capabilities: %d packet_length: %ld Host: '%s' " "Login user: '%s' Priv_user: '%s' Using password: %s " "Access: %u db: '%s'", - thd->client_capabilities, thd->max_client_packet_length, - thd->host_or_ip, thd->user, thd->priv_user, + thd->client_capabilities, + thd->max_client_packet_length, + thd->main_security_ctx.host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.priv_user, passwd_len ? "yes": "no", - thd->master_access, thd->db ? thd->db : "*none*")); + thd->main_security_ctx.master_access, + (thd->db ? thd->db : "*none*"))); if (check_count) { VOID(pthread_mutex_lock(&LOCK_thread_count)); bool count_ok= thread_count <= max_connections + delayed_insert_threads - || (thd->master_access & SUPER_ACL); + || (thd->main_security_ctx.master_access & SUPER_ACL); VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (!count_ok) { // too many connections @@ -382,11 +399,13 @@ int check_user(THD *thd, enum enum_server_command command, } /* Why logging is performed before all checks've passed? */ - mysql_log.write(thd,command, - (thd->priv_user == thd->user ? + mysql_log.write(thd, command, + (thd->main_security_ctx.priv_user == + thd->main_security_ctx.user ? (char*) "%s@%s on %s" : (char*) "%s@%s as anonymous on %s"), - thd->user, thd->host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, db ? db : (char*) ""); /* @@ -394,14 +413,16 @@ int check_user(THD *thd, enum enum_server_command command, set to 0 here because we don't have an active database yet (and we may not have an active database to set. */ - thd->db_access=0; + thd->main_security_ctx.db_access=0; /* Don't allow user to connect if he has done too many queries */ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || max_user_connections) && get_or_create_user_conn(thd, - opt_old_style_user_limits ? thd->user : thd->priv_user, - opt_old_style_user_limits ? thd->host_or_ip : thd->priv_host, + (opt_old_style_user_limits ? thd->main_security_ctx.user : + thd->main_security_ctx.priv_user), + (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : + thd->main_security_ctx.priv_host), &ur)) DBUG_RETURN(-1); if (thd->user_connect && @@ -436,12 +457,12 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(-1); } net_printf_error(thd, ER_ACCESS_DENIED_ERROR, - thd->user, - thd->host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, passwd_len ? ER(ER_YES) : ER(ER_NO)); mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), - thd->user, - thd->host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, passwd_len ? ER(ER_YES) : ER(ER_NO)); DBUG_RETURN(-1); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ @@ -765,41 +786,45 @@ static int check_connection(THD *thd) DBUG_PRINT("info", ("New connection received on %s", vio_description(net->vio))); - if (!thd->host) // If TCP/IP connection + if (!thd->main_security_ctx.host) // If TCP/IP connection { char ip[30]; if (vio_peer_addr(net->vio, ip, &thd->peer_port)) return (ER_BAD_HOST_ERROR); - if (!(thd->ip= my_strdup(ip,MYF(0)))) + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) return (ER_OUT_OF_RESOURCES); - thd->host_or_ip= thd->ip; + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; vio_in_addr(net->vio,&thd->remote.sin_addr); if (!(specialflag & SPECIAL_NO_RESOLVE)) { vio_in_addr(net->vio,&thd->remote.sin_addr); - thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); + thd->main_security_ctx.host= + ip_to_hostname(&thd->remote.sin_addr, &connect_errors); /* Cut very long hostnames to avoid possible overflows */ - if (thd->host) + if (thd->main_security_ctx.host) { - if (thd->host != my_localhost) - thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; - thd->host_or_ip= thd->host; + if (thd->main_security_ctx.host != my_localhost) + thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host), + HOSTNAME_LENGTH)]= 0; + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; } if (connect_errors > max_connect_errors) return(ER_HOST_IS_BLOCKED); } DBUG_PRINT("info",("Host: %s ip: %s", - thd->host ? thd->host : "unknown host", - thd->ip ? thd->ip : "unknown ip")); - if (acl_check_host(thd->host,thd->ip)) + (thd->main_security_ctx.host ? + thd->main_security_ctx.host : "unknown host"), + (thd->main_security_ctx.ip ? + thd->main_security_ctx.ip : "unknown ip"))); + if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) return(ER_HOST_NOT_PRIVILEGED); } else /* Hostname given means that the connection was on a socket */ { - DBUG_PRINT("info",("Host: %s",thd->host)); - thd->host_or_ip= thd->host; - thd->ip= 0; + DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host)); + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; + thd->main_security_ctx.ip= 0; /* Reset sin_addr */ bzero((char*) &thd->remote, sizeof(thd->remote)); } @@ -872,11 +897,13 @@ static int check_connection(THD *thd) DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); /* Use server character set and collation if + - opt_character_set_client_handshake is not set - client has not specified a character set - client character set is the same as the servers - client character set doesn't exists in server */ - if (!(thd->variables.character_set_client= + if (!opt_character_set_client_handshake || + !(thd->variables.character_set_client= get_charset((uint) net->read_pos[8], MYF(0))) || !my_strcasecmp(&my_charset_latin1, global_system_variables.character_set_client->name, @@ -919,8 +946,7 @@ static int check_connection(THD *thd) DBUG_PRINT("info", ("IO layer change in progress...")); if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout)) { - DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", - pkt_len)); + DBUG_PRINT("error", ("Failed to accept new SSL connection")); inc_host_errors(&thd->remote.sin_addr); return(ER_HANDSHAKE_ERROR); } @@ -981,9 +1007,9 @@ static int check_connection(THD *thd) thd->charset(), &dummy_errors)]= '\0'; user= user_buff; - if (thd->user) - x_free(thd->user); - if (!(thd->user= my_strdup(user, MYF(0)))) + if (thd->main_security_ctx.user) + x_free(thd->main_security_ctx.user); + if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) return (ER_OUT_OF_RESOURCES); return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); } @@ -1020,7 +1046,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, } -pthread_handler_decl(handle_one_connection,arg) +pthread_handler_t handle_one_connection(void *arg) { THD *thd=(THD*) arg; uint launch_time = @@ -1071,13 +1097,14 @@ pthread_handler_decl(handle_one_connection,arg) { int error; NET *net= &thd->net; + Security_context *sctx= thd->security_ctx; thd->thread_stack= (char*) &thd; net->no_send_error= 0; if ((error=check_connection(thd))) { // Wrong permissions if (error > 0) - net_printf_error(thd, error, thd->host_or_ip); + net_printf_error(thd, error, sctx->host_or_ip); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) my_sleep(1000); /* must wait after eof() */ @@ -1086,7 +1113,7 @@ pthread_handler_decl(handle_one_connection,arg) goto end_thread; } #ifdef __NETWARE__ - netware_reg_user(thd->ip, thd->user, "MySQL"); + netware_reg_user(sctx->ip, sctx->user, "MySQL"); #endif if (thd->variables.max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; @@ -1099,7 +1126,7 @@ pthread_handler_decl(handle_one_connection,arg) thd->set_time(); thd->init_for_queries(); - if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL)) + if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) { execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); if (thd->query_error) @@ -1123,8 +1150,8 @@ pthread_handler_decl(handle_one_connection,arg) if (!thd->killed && thd->variables.log_warnings > 1) sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), thd->thread_id,(thd->db ? thd->db : "unconnected"), - thd->user ? thd->user : "unauthenticated", - thd->host_or_ip, + sctx->user ? sctx->user : "unauthenticated", + sctx->host_or_ip, (net->last_errno ? ER(net->last_errno) : ER(ER_UNKNOWN_ERROR))); net_send_error(thd, net->last_errno, NullS); @@ -1155,7 +1182,7 @@ end_thread: Used when creating the initial grant tables */ -extern "C" pthread_handler_decl(handle_bootstrap,arg) +pthread_handler_t handle_bootstrap(void *arg) { THD *thd=(THD*) arg; FILE *file=bootstrap_file; @@ -1187,7 +1214,8 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) thd->proc_info=0; thd->version=refresh_version; - thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME)); + thd->security_ctx->priv_user= + thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME)); buff= (char*) thd->net.buff; thd->init_for_queries(); @@ -1346,6 +1374,12 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); DBUG_RETURN(1); } + if (thd->transaction.xid_state.xa_state != XA_NOTR) + { + my_error(ER_XAER_RMFAIL, MYF(0), + xa_state_names[thd->transaction.xid_state.xa_state]); + DBUG_RETURN(1); + } switch (completion) { case COMMIT: /* @@ -1582,17 +1616,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, db= db_buff; /* Save user and privileges */ - uint save_master_access= thd->master_access; - uint save_db_access= thd->db_access; uint save_db_length= thd->db_length; - char *save_user= thd->user; - char *save_priv_user= thd->priv_user; char *save_db= thd->db; + Security_context save_security_ctx= *thd->security_ctx; USER_CONN *save_user_connect= thd->user_connect; - - if (!(thd->user= my_strdup(user, MYF(0)))) + + if (!(thd->security_ctx->user= my_strdup(user, MYF(0)))) { - thd->user= save_user; + thd->security_ctx->user= save_security_ctx.user; my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); break; } @@ -1606,12 +1637,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* authentication failure, we shall restore old user */ if (res > 0) my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); - x_free(thd->user); - thd->user= save_user; - thd->priv_user= save_priv_user; + x_free(thd->security_ctx->user); + *thd->security_ctx= save_security_ctx; thd->user_connect= save_user_connect; - thd->master_access= save_master_access; - thd->db_access= save_db_access; thd->db= save_db; thd->db_length= save_db_length; } @@ -1621,7 +1649,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (save_user_connect) decrease_user_connections(save_user_connect); x_free((gptr) save_db); - x_free((gptr) save_user); + x_free((gptr) save_security_ctx.user); } break; } @@ -1642,7 +1670,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_STMT_PREPARE: { - mysql_stmt_prepare(thd, packet, packet_length, 0); + mysql_stmt_prepare(thd, packet, packet_length); break; } case COM_STMT_CLOSE: @@ -1662,6 +1690,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *packet_end= thd->query + thd->query_length; mysql_log.write(thd,command,"%s",thd->query); DBUG_PRINT("query",("%-.4096s",thd->query)); + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),QUERY_PRIOR); + mysql_parse(thd,thd->query, thd->query_length); while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error) @@ -1768,7 +1800,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, remove_escape(table_list.table_name); // This can't have wildcards if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege, - 0, 0)) + 0, 0, test(table_list.schema_table))) break; if (grant_option && check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0)) @@ -1809,7 +1841,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL"); break; } - if (check_access(thd,CREATE_ACL,db,0,1,0)) + if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db))) break; mysql_log.write(thd,command,packet); bzero(&create_info, sizeof(create_info)); @@ -1828,7 +1860,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL"); break; } - if (check_access(thd,DROP_ACL,db,0,1,0)) + if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db))) break; if (thd->locked_tables || thd->active_transaction()) { @@ -1959,12 +1991,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_PROCESS_INFO: statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST], &LOCK_status); - if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL)) + if (!thd->security_ctx->priv_user[0] && + check_global_access(thd, PROCESS_ACL)) break; mysql_log.write(thd,command,NullS); mysqld_list_processes(thd, - thd->master_access & PROCESS_ACL ? - NullS : thd->priv_user, 0); + thd->security_ctx->master_access & PROCESS_ACL ? + NullS : thd->security_ctx->priv_user, 0); break; case COM_PROCESS_KILL: { @@ -2126,12 +2159,14 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, my_error(ER_WRONG_DB_NAME, MYF(0), db); DBUG_RETURN(1); } - if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0)) + if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0, + is_schema_db(db))) DBUG_RETURN(1); /* purecov: inspected */ if (!thd->col_access && check_grant_db(thd,db)) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, thd->priv_host, db); + thd->security_ctx->priv_user, thd->security_ctx->priv_host, + db); DBUG_RETURN(1); } /* @@ -2165,7 +2200,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, remove_escape(db); // Fix escaped '_' remove_escape(table_list->table_name); if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, - &table_list->grant.privilege, 0, 0)) + &table_list->grant.privilege, 0, 0, + test(table_list->schema_table))) DBUG_RETURN(1); /* purecov: inspected */ if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2, UINT_MAX, 0)) @@ -2218,7 +2254,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, TRUE error; In this case thd->fatal_error is set */ -bool alloc_query(THD *thd, char *packet, ulong packet_length) +bool alloc_query(THD *thd, const char *packet, uint packet_length) { packet_length--; // Remove end null /* Remove garbage at start and end of query */ @@ -2227,7 +2263,7 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length) packet++; packet_length--; } - char *pos=packet+packet_length; // Point at end null + const char *pos= packet + packet_length; // Point at end null while (packet_length > 0 && (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1]))) { @@ -2248,11 +2284,25 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length) thd->packet.shrink(thd->variables.net_buffer_length); thd->convert_buffer.shrink(thd->variables.net_buffer_length); - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); return FALSE; } +static void reset_one_shot_variables(THD *thd) +{ + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.collation_database= + global_system_variables.collation_database; + thd->variables.collation_server= + global_system_variables.collation_server; + thd->update_charset(); + thd->variables.time_zone= + global_system_variables.time_zone; + thd->one_shot_set= 0; +} + /**************************************************************************** ** mysql_execute_command @@ -2267,8 +2317,6 @@ mysql_execute_command(THD *thd) LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ SELECT_LEX *select_lex= &lex->select_lex; - bool slave_fake_lock= 0; - MYSQL_LOCK *fake_prev_lock= 0; /* first table of first SELECT_LEX */ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first; /* list of all tables in query */ @@ -2317,35 +2365,28 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION if (thd->slave_thread) { - if (lex->sql_command == SQLCOM_UPDATE_MULTI) - { - DBUG_PRINT("info",("need faked locked tables")); - - if (check_multi_update_lock(thd)) - goto error; - - /* Fix for replication, the tables are opened and locked, - now we pretend that we have performed a LOCK TABLES action */ - - fake_prev_lock= thd->locked_tables; - if (thd->lock) - thd->locked_tables= thd->lock; - thd->lock= 0; - slave_fake_lock= 1; - } /* - Skip if we are in the slave thread, some table rules have been - given and the table list says the query should not be replicated. - Exception is DROP TEMPORARY TABLE IF EXISTS: we always execute it - (otherwise we have stale files on slave caused by exclusion of one tmp - table). + Check if statment should be skipped because of slave filtering + rules + + Exceptions are: + - UPDATE MULTI: For this statement, we want to check the filtering + rules later in the code + - SET: we always execute it (Not that many SET commands exists in + the binary log anyway -- only 4.1 masters write SET statements, + in 5.0 there are no SET statements in the binary log) + - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we + have stale files on slave caused by exclusion of one tmp table). */ - if (!(lex->sql_command == SQLCOM_DROP_TABLE && + if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) && + !(lex->sql_command == SQLCOM_SET_OPTION) && + !(lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary && lex->drop_if_exists) && all_tables_not_ok(thd, all_tables)) { /* we warn the slave SQL thread */ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + reset_one_shot_variables(thd); DBUG_RETURN(0); } #ifndef TO_BE_DELETED @@ -2361,14 +2402,15 @@ mysql_execute_command(THD *thd) } #endif } -#endif /* !HAVE_REPLICATION */ +#endif /* HAVE_REPLICATION */ /* When option readonly is set deny operations which change tables. Except for the replication thread and the 'super' users. */ if (opt_readonly && - !(thd->slave_thread || (thd->master_access & SUPER_ACL)) && + !(thd->slave_thread || + (thd->security_ctx->master_access & SUPER_ACL)) && uc_update_queries[lex->sql_command]) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); @@ -2402,7 +2444,7 @@ mysql_execute_command(THD *thd) else res= check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, - any_db, 0, 0, 0); + any_db, 0, 0, 0, 0); if (res) goto error; @@ -2410,6 +2452,12 @@ mysql_execute_command(THD *thd) { if (lex->describe) { + /* + We always use select_send for EXPLAIN, even if it's an EXPLAIN + for SELECT ... INTO OUTFILE: a user application should be able + to prepend EXPLAIN to any query and receive output for it, + even if the query itself redirects the output. + */ if (!(result= new select_send())) goto error; else @@ -2442,112 +2490,17 @@ mysql_execute_command(THD *thd) } case SQLCOM_PREPARE: { - char *query_str; - uint query_len; - if (lex->prepared_stmt_code_is_varref) - { - /* This is PREPARE stmt FROM @var. */ - String str; - CHARSET_INFO *to_cs= thd->variables.collation_connection; - bool need_conversion; - user_var_entry *entry; - String *pstr= &str; - uint32 unused; - /* - Convert @var contents to string in connection character set. Although - it is known that int/real/NULL value cannot be a valid query we still - convert it for error messages to uniform. - */ - if ((entry= - (user_var_entry*)hash_search(&thd->user_vars, - (byte*)lex->prepared_stmt_code.str, - lex->prepared_stmt_code.length)) - && entry->value) - { - my_bool is_var_null; - pstr= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC); - /* - NULL value of variable checked early as entry->value so here - we can't get NULL in normal conditions - */ - DBUG_ASSERT(!is_var_null); - if (!pstr) - goto error; - } - else - { - /* - variable absent or equal to NULL, so we need to set variable to - something reasonable to get readable error message during parsing - */ - str.set("NULL", 4, &my_charset_latin1); - } - - need_conversion= - String::needs_conversion(pstr->length(), pstr->charset(), - to_cs, &unused); - - query_len= need_conversion? (pstr->length() * to_cs->mbmaxlen) : - pstr->length(); - if (!(query_str= alloc_root(thd->mem_root, query_len+1))) - goto error; - - if (need_conversion) - { - uint dummy_errors; - query_len= copy_and_convert(query_str, query_len, to_cs, - pstr->ptr(), pstr->length(), - pstr->charset(), &dummy_errors); - } - else - memcpy(query_str, pstr->ptr(), pstr->length()); - query_str[query_len]= 0; - } - else - { - query_str= lex->prepared_stmt_code.str; - query_len= lex->prepared_stmt_code.length; - DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n", - lex->prepared_stmt_name.length, - lex->prepared_stmt_name.str, - query_len, query_str)); - } - thd->command= COM_STMT_PREPARE; - if (!(res= mysql_stmt_prepare(thd, query_str, query_len + 1, - &lex->prepared_stmt_name))) - send_ok(thd, 0L, 0L, "Statement prepared"); + mysql_sql_stmt_prepare(thd); break; } case SQLCOM_EXECUTE: { - DBUG_PRINT("info", ("EXECUTE: %.*s\n", - lex->prepared_stmt_name.length, - lex->prepared_stmt_name.str)); - mysql_sql_stmt_execute(thd, &lex->prepared_stmt_name); - lex->prepared_stmt_params.empty(); + mysql_sql_stmt_execute(thd); break; } case SQLCOM_DEALLOCATE_PREPARE: { - Statement* stmt; - DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", - lex->prepared_stmt_name.length, - lex->prepared_stmt_name.str)); - /* We account deallocate in the same manner as mysql_stmt_close */ - statistic_increment(thd->status_var.com_stmt_close, &LOCK_status); - if ((stmt= thd->stmt_map.find_by_name(&lex->prepared_stmt_name))) - { - thd->stmt_map.erase(stmt); - send_ok(thd); - } - else - { - my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), - lex->prepared_stmt_name.length, - lex->prepared_stmt_name.str, - "DEALLOCATE PREPARE"); - goto error; - } + mysql_sql_stmt_close(thd); break; } case SQLCOM_DO: @@ -2673,7 +2626,8 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_db_used(thd, all_tables) || check_access(thd, INDEX_ACL, first_table->db, - &first_table->grant.privilege, 0, 0)) + &first_table->grant.privilege, 0, 0, + test(first_table->schema_table))) goto error; res= mysql_assign_to_keycache(thd, first_table, &lex->ident); break; @@ -2683,7 +2637,8 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_db_used(thd, all_tables) || check_access(thd, INDEX_ACL, first_table->db, - &first_table->grant.privilege, 0, 0)) + &first_table->grant.privilege, 0, 0, + test(first_table->schema_table))) goto error; res = mysql_preload_keys(thd, first_table); break; @@ -2726,6 +2681,13 @@ mysql_execute_command(THD *thd) res = load_master_data(thd); break; #endif /* HAVE_REPLICATION */ +#ifdef HAVE_NDBCLUSTER_DB + case SQLCOM_SHOW_NDBCLUSTER_STATUS: + { + res = ndbcluster_show_status(thd); + break; + } +#endif #ifdef HAVE_INNOBASE_DB case SQLCOM_SHOW_INNODB_STATUS: { @@ -2749,7 +2711,8 @@ mysql_execute_command(THD *thd) if (!first_table->db) first_table->db= thd->db; if (check_access(thd, CREATE_ACL, first_table->db, - &first_table->grant.privilege, 0, 0)) + &first_table->grant.privilege, 0, 0, + test(first_table->schema_table))) goto error; /* purecov: inspected */ if (grant_option) { @@ -2856,12 +2819,15 @@ mysql_execute_command(THD *thd) Is table which we are changing used somewhere in other parts of query */ - if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && - unique_table(create_table, select_tables)) + if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->table_name); - res= 1; - goto end_with_restart_wait; + TABLE_LIST *duplicate; + if ((duplicate= unique_table(create_table, select_tables))) + { + update_non_unique_table_error(create_table, "CREATE", duplicate); + res= 1; + goto end_with_restart_wait; + } } /* If we create merge table, we have to test tables in merge, too */ if (lex->create_info.used_fields & HA_CREATE_USED_UNION) @@ -2871,9 +2837,10 @@ mysql_execute_command(THD *thd) tab; tab= tab->next_local) { - if (unique_table(tab, select_tables)) + TABLE_LIST *duplicate; + if ((duplicate= unique_table(tab, select_tables))) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), tab->table_name); + update_non_unique_table_error(tab, "CREATE", duplicate); res= 1; goto end_with_restart_wait; } @@ -2962,7 +2929,7 @@ end_with_restore_list: To prevent that, refuse SLAVE STOP if the client thread has locked tables */ - if (thd->locked_tables || thd->active_transaction()) + if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock) { my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); @@ -3010,8 +2977,10 @@ end_with_restore_list: select_lex->db= first_table->db; } if (check_access(thd, ALTER_ACL, first_table->db, - &first_table->grant.privilege, 0, 0) || - check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)|| + &first_table->grant.privilege, 0, 0, + test(first_table->schema_table)) || + check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0, + is_schema_db(select_lex->db))|| check_merge_table_access(thd, first_table->db, (TABLE_LIST *) lex->create_info.merge_list.first)) @@ -3061,9 +3030,10 @@ end_with_restore_list: for (table= first_table; table; table= table->next_local->next_local) { if (check_access(thd, ALTER_ACL | DROP_ACL, table->db, - &table->grant.privilege,0,0) || + &table->grant.privilege,0,0, test(table->schema_table)) || check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db, - &table->next_local->grant.privilege, 0, 0)) + &table->next_local->grant.privilege, 0, 0, + test(table->next_local->schema_table))) goto error; if (grant_option) { @@ -3115,7 +3085,8 @@ end_with_restore_list: if (check_db_used(thd, all_tables) || check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db, - &first_table->grant.privilege, 0, 0)) + &first_table->grant.privilege, 0, 0, + test(first_table->schema_table))) goto error; if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0)) goto error; @@ -3223,23 +3194,36 @@ end_with_restore_list: if (result != 2) break; case SQLCOM_UPDATE_MULTI: + { + DBUG_ASSERT(first_table == all_tables && first_table != 0); + /* if we switched from normal update, rights are checked */ + if (result != 2) { - DBUG_ASSERT(first_table == all_tables && first_table != 0); - /* if we switched from normal update, rights are checked */ - if (result != 2) - { - if ((res= multi_update_precheck(thd, all_tables))) - break; - } - else - res= 0; - - res= mysql_multi_update(thd, all_tables, - &select_lex->item_list, - &lex->value_list, - select_lex->where, - select_lex->options, - lex->duplicates, lex->ignore, unit, select_lex); + if ((res= multi_update_precheck(thd, all_tables))) + break; + } + else + res= 0; + + if ((res= mysql_multi_update_prepare(thd))) + break; + +#ifdef HAVE_REPLICATION + /* Check slave filtering rules */ + if (thd->slave_thread && all_tables_not_ok(thd, all_tables)) + { + /* we warn the slave SQL thread */ + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + break; + } +#endif /* HAVE_REPLICATION */ + + res= mysql_multi_update(thd, all_tables, + &select_lex->item_list, + &lex->value_list, + select_lex->where, + select_lex->options, + lex->duplicates, lex->ignore, unit, select_lex); break; } case SQLCOM_REPLACE: @@ -3425,11 +3409,14 @@ end_with_restore_list: res = mysql_drop_index(thd, first_table, &lex->alter_info); break; case SQLCOM_SHOW_PROCESSLIST: - if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL)) + if (!thd->security_ctx->priv_user[0] && + check_global_access(thd,PROCESS_ACL)) break; mysqld_list_processes(thd, - thd->master_access & PROCESS_ACL ? NullS : - thd->priv_user,lex->verbose); + (thd->security_ctx->master_access & PROCESS_ACL ? + NullS : + thd->security_ctx->priv_user), + lex->verbose); break; case SQLCOM_SHOW_STORAGE_ENGINES: res= mysqld_show_storage_engines(thd); @@ -3447,7 +3434,7 @@ end_with_restore_list: goto error; #else { - if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0)) + if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0)) goto error; res= mysqld_show_logs(thd); break; @@ -3468,7 +3455,7 @@ end_with_restore_list: if (lex->local_file) { if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) || - ! opt_local_infile) + !opt_local_infile) { my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); goto error; @@ -3576,7 +3563,7 @@ end_with_restore_list: break; } #endif - if (check_access(thd,CREATE_ACL,lex->name,0,1,0)) + if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name))) break; res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name), &lex->create_info, 0); @@ -3610,7 +3597,7 @@ end_with_restore_list: break; } #endif - if (check_access(thd,DROP_ACL,lex->name,0,1,0)) + if (check_access(thd,DROP_ACL,lex->name,0,1,0,is_schema_db(lex->name))) break; if (thd->locked_tables || thd->active_transaction()) { @@ -3650,7 +3637,7 @@ end_with_restore_list: break; } #endif - if (check_access(thd, ALTER_ACL, db, 0, 1, 0)) + if (check_access(thd, ALTER_ACL, db, 0, 1, 0, is_schema_db(db))) break; if (thd->locked_tables || thd->active_transaction()) { @@ -3668,14 +3655,14 @@ end_with_restore_list: my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); break; } - if (check_access(thd,SELECT_ACL,lex->name,0,1,0)) + if (check_access(thd,SELECT_ACL,lex->name,0,1,0,is_schema_db(lex->name))) break; res=mysqld_show_create_db(thd,lex->name,&lex->create_info); break; } case SQLCOM_CREATE_FUNCTION: // UDF function { - if (check_access(thd,INSERT_ACL,"mysql",0,1,0)) + if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0)) break; #ifdef HAVE_DLOPEN if (sp_find_function(thd, lex->spname)) @@ -3694,9 +3681,11 @@ end_with_restore_list: #ifndef NO_EMBEDDED_ACCESS_CHECKS case SQLCOM_CREATE_USER: { - if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1) && + if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) && check_global_access(thd,CREATE_USER_ACL)) break; + if (end_active_trans(thd)) + goto error; if (!(res= mysql_create_user(thd, lex->users_list))) { if (mysql_bin_log.is_open()) @@ -3710,9 +3699,11 @@ end_with_restore_list: } case SQLCOM_DROP_USER: { - if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1) && + if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) && check_global_access(thd,CREATE_USER_ACL)) break; + if (end_active_trans(thd)) + goto error; if (!(res= mysql_drop_user(thd, lex->users_list))) { if (mysql_bin_log.is_open()) @@ -3726,9 +3717,11 @@ end_with_restore_list: } case SQLCOM_RENAME_USER: { - if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) && + if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && check_global_access(thd,CREATE_USER_ACL)) break; + if (end_active_trans(thd)) + goto error; if (!(res= mysql_rename_user(thd, lex->users_list))) { if (mysql_bin_log.is_open()) @@ -3742,7 +3735,7 @@ end_with_restore_list: } case SQLCOM_REVOKE_ALL: { - if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) && + if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && check_global_access(thd,CREATE_USER_ACL)) break; if (!(res = mysql_revoke_all(thd, lex->users_list))) @@ -3762,10 +3755,12 @@ end_with_restore_list: if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL, first_table ? first_table->db : select_lex->db, first_table ? &first_table->grant.privilege : 0, - first_table ? 0 : 1, 0)) + first_table ? 0 : 1, 0, + first_table ? (bool) first_table->schema_table : + select_lex->db ? is_schema_db(select_lex->db) : 0)) goto error; - if (thd->user) // If not replication + if (thd->security_ctx->user) // If not replication { LEX_USER *user; uint counter; @@ -3781,13 +3776,13 @@ end_with_restore_list: user->host.str); // Are we trying to change a password of another user DBUG_ASSERT(user->host.str != 0); - if (strcmp(thd->user, user->user.str) || + if (strcmp(thd->security_ctx->user, user->user.str) || my_strcasecmp(system_charset_info, - user->host.str, thd->host_or_ip)) + user->host.str, thd->security_ctx->host_or_ip)) { // TODO: use check_change_password() if (check_acl_user(user, &counter) && user->password.str && - check_access(thd, UPDATE_ACL,"mysql",0,1,1)) + check_access(thd, UPDATE_ACL,"mysql",0,1,1,0)) { my_message(ER_PASSWORD_NOT_ALLOWED, ER(ER_PASSWORD_NOT_ALLOWED), MYF(0)); @@ -3910,9 +3905,9 @@ end_with_restore_list: } #ifndef NO_EMBEDDED_ACCESS_CHECKS case SQLCOM_SHOW_GRANTS: - if ((thd->priv_user && - !strcmp(thd->priv_user,lex->grant_user->user.str)) || - !check_access(thd, SELECT_ACL, "mysql",0,1,0)) + if ((thd->security_ctx->priv_user && + !strcmp(thd->security_ctx->priv_user, lex->grant_user->user.str)) || + !check_access(thd, SELECT_ACL, "mysql",0,1,0,0)) { res = mysql_show_grants(thd,lex->grant_user); } @@ -3947,6 +3942,12 @@ end_with_restore_list: break; case SQLCOM_BEGIN: + if (thd->transaction.xid_state.xa_state != XA_NOTR) + { + my_error(ER_XAER_RMFAIL, MYF(0), + xa_state_names[thd->transaction.xid_state.xa_state]); + break; + } if (begin_trans(thd)) goto error; send_ok(thd); @@ -4067,18 +4068,32 @@ end_with_restore_list: DBUG_ASSERT(lex->sphead != 0); - if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0)) + if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0]) + { + if (! thd->db) + { + my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); + delete lex->sphead; + lex->sphead= 0; + goto error; + } + lex->sphead->m_db.length= strlen(thd->db); + lex->sphead->m_db.str= thd->db; + } + + if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0, + is_schema_db(lex->sphead->m_db.str))) { delete lex->sphead; lex->sphead= 0; goto error; } - if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0]) + if (end_active_trans(thd)) { - lex->sphead->m_db.length= strlen(thd->db); - lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db, - lex->sphead->m_db.length); + delete lex->sphead; + lex->sphead= 0; + goto error; } name= lex->sphead->name(&namelen); @@ -4097,7 +4112,7 @@ end_with_restore_list: } #endif if (lex->sphead->m_type == TYPE_ENUM_FUNCTION && - !lex->sphead->m_has_return) + !(lex->sphead->m_flags & sp_head::HAS_RETURN)) { my_error(ER_SP_NORETURN, MYF(0), name); delete lex->sphead; @@ -4105,11 +4120,23 @@ end_with_restore_list: goto error; } + /* + We need to copy name and db in order to use them for + check_routine_access which is called after lex->sphead has + been deleted. + */ name= thd->strdup(name); - db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length); + lex->sphead->m_db.str= db= thd->strmake(lex->sphead->m_db.str, + lex->sphead->m_db.length); res= (result= lex->sphead->create(thd)); if (result == SP_OK) { + /* + We must cleanup the unit and the lex here because + sp_grant_privileges calls (indirectly) db_find_routine, + which in turn may call yyparse with THD::lex. + TODO: fix db_find_routine to use a temporary lex. + */ lex->unit.cleanup(); delete lex->sphead; lex->sphead= 0; @@ -4181,20 +4208,36 @@ end_with_restore_list: else { #ifndef NO_EMBEDDED_ACCESS_CHECKS - st_sp_security_context save_ctx; + Security_context *save_ctx; #endif ha_rows select_limit; /* bits that should be cleared in thd->server_status */ uint bits_to_be_cleared= 0; + /* + Check that the stored procedure doesn't contain Dynamic SQL + and doesn't return result sets: such stored procedures can't + be called from a function or trigger. + */ + if (thd->in_sub_stmt) + { + const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ? + "trigger" : "function"); + if (sp->is_not_allowed_in_function(where)) + goto error; + } #ifndef EMBEDDED_LIBRARY my_bool nsok= thd->net.no_send_ok; thd->net.no_send_ok= TRUE; #endif - if (sp->m_multi_results) + if (sp->m_flags & sp_head::MULTI_RESULTS) { if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS)) { + /* + The client does not support multiple result sets being sent + back + */ my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; @@ -4211,23 +4254,23 @@ end_with_restore_list: } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_routine_access(thd, EXECUTE_ACL, - sp->m_db.str, sp->m_name.str, TRUE, 0)) + if (check_routine_access(thd, EXECUTE_ACL, + sp->m_db.str, sp->m_name.str, TRUE, 0) || + sp_change_security_context(thd, sp, &save_ctx)) { #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; #endif goto error; } - sp_change_security_context(thd, sp, &save_ctx); - if (save_ctx.changed && - check_routine_access(thd, EXECUTE_ACL, - sp->m_db.str, sp->m_name.str, TRUE, 0)) + if (save_ctx && + check_routine_access(thd, EXECUTE_ACL, + sp->m_db.str, sp->m_name.str, TRUE, 0)) { #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; #endif - sp_restore_security_context(thd, sp, &save_ctx); + sp_restore_security_context(thd, save_ctx); goto error; } @@ -4238,7 +4281,7 @@ end_with_restore_list: thd->row_count_func= 0; /* - We never write CALL statements int binlog: + We never write CALL statements into binlog: - If the mode is non-prelocked, each statement will be logged separately. - If the mode is prelocked, the invoking statement will care @@ -4267,7 +4310,7 @@ end_with_restore_list: thd->variables.select_limit= select_limit; #ifndef NO_EMBEDDED_ACCESS_CHECKS - sp_restore_security_context(thd, sp, &save_ctx); + sp_restore_security_context(thd, save_ctx); #endif #ifndef EMBEDDED_LIBRARY @@ -4312,6 +4355,9 @@ end_with_restore_list: sp->m_name.str, lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0)) goto error; + + if (end_active_trans(thd)) + goto error; memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics)); if (!trust_routine_creators && mysql_bin_log.is_open() && !sp->m_chistics->detistic && @@ -4371,6 +4417,9 @@ end_with_restore_list: if (check_routine_access(thd, ALTER_PROC_ACL, db, name, lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) goto error; + + if (end_active_trans(thd)) + goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (sp_automatic_privileges && !opt_noacl && sp_revoke_privileges(thd, db, name, @@ -4395,7 +4444,7 @@ end_with_restore_list: lex->spname->m_name.length); if (udf) { - if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0)) + if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0)) goto error; if (!(res = mysql_drop_function(thd, &lex->spname->m_name))) { @@ -4489,11 +4538,36 @@ end_with_restore_list: } case SQLCOM_CREATE_VIEW: { + if (end_active_trans(thd)) + goto error; + if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) && mysql_bin_log.is_open()) { + String buff; + const LEX_STRING command[3]= + {{(char *)STRING_WITH_LEN("CREATE ")}, + {(char *)STRING_WITH_LEN("ALTER ")}, + {(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}}; thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + + buff.append(command[thd->lex->create_view_mode].str, + command[thd->lex->create_view_mode].length); + view_store_options(thd, first_table, &buff); + buff.append("VIEW ", 5); + /* Test if user supplied a db (ie: we did not use thd->db) */ + if (first_table->db != thd->db && first_table->db[0]) + { + append_identifier(thd, &buff, first_table->db, + first_table->db_length); + buff.append('.'); + } + append_identifier(thd, &buff, first_table->table_name, + first_table->table_name_length); + buff.append(" AS ", 4); + buff.append(first_table->source.str, first_table->source.length); + + Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE); mysql_bin_log.write(&qinfo); } break; @@ -4514,6 +4588,9 @@ end_with_restore_list: } case SQLCOM_CREATE_TRIGGER: { + if (end_active_trans(thd)) + goto error; + res= mysql_create_or_drop_trigger(thd, all_tables, 1); /* We don't care about trigger body after this point */ @@ -4523,6 +4600,9 @@ end_with_restore_list: } case SQLCOM_DROP_TRIGGER: { + if (end_active_trans(thd)) + goto error; + res= mysql_create_or_drop_trigger(thd, all_tables, 0); break; } @@ -4703,30 +4783,19 @@ end_with_restore_list: } thd->proc_info="query end"; /* Two binlog-related cleanups: */ - if (thd->one_shot_set) - { - /* - If this is a SET, do nothing. This is to allow mysqlbinlog to print - many SET commands (in this case we want the charset temp setting to - live until the real query). This is also needed so that SET - CHARACTER_SET_CLIENT... does not cancel itself immediately. - */ - if (lex->sql_command != SQLCOM_SET_OPTION) - { - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.collation_database= - global_system_variables.collation_database; - thd->variables.collation_server= - global_system_variables.collation_server; - thd->update_charset(); - thd->variables.time_zone= - global_system_variables.time_zone; - thd->one_shot_set= 0; - } - } + + /* + Reset system variables temporarily modified by SET ONE SHOT. + + Exception: If this is a SET, do nothing. This is to allow + mysqlbinlog to print many SET commands (in this case we want the + charset temp setting to live until the real query). This is also + needed so that SET CHARACTER_SET_CLIENT... does not cancel itself + immediately. + */ + if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) + reset_one_shot_variables(thd); + /* The return value for ROW_COUNT() is "implementation dependent" if @@ -4741,14 +4810,6 @@ error: res= 1; cleanup: - if (unlikely(slave_fake_lock)) - { - DBUG_PRINT("info",("undoing faked lock")); - thd->lock= thd->locked_tables; - thd->locked_tables= fake_prev_lock; - if (thd->lock == thd->locked_tables) - thd->lock= 0; - } DBUG_RETURN(res || thd->net.report_error); } @@ -4771,7 +4832,8 @@ cleanup: bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) { if (check_access(thd, privilege, all_tables->db, - &all_tables->grant.privilege, 0, 0)) + &all_tables->grant.privilege, 0, 0, + test(all_tables->schema_table))) return 1; /* Show only 1 table for check_grant */ @@ -4810,8 +4872,9 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, - bool dont_check_global_grants, bool no_errors) + bool dont_check_global_grants, bool no_errors, bool schema_db) { + Security_context *sctx= thd->security_ctx; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; bool db_is_pattern= test(want_access & GRANT_ACL); @@ -4819,7 +4882,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, ulong dummy; DBUG_ENTER("check_access"); DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu", - db ? db : "", want_access, thd->master_access)); + db ? db : "", want_access, sctx->master_access)); if (save_priv) *save_priv=0; else @@ -4834,31 +4897,51 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, DBUG_RETURN(TRUE); /* purecov: tested */ } + if (schema_db) + { + if (want_access & ~(SELECT_ACL | EXTRA_ACL)) + { + if (!no_errors) + { + const char *db_name= db ? db : thd->db; + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, sctx->priv_host, db_name); + } + DBUG_RETURN(TRUE); + } + else + { + *save_priv= SELECT_ACL; + DBUG_RETURN(FALSE); + } + } + #ifdef NO_EMBEDDED_ACCESS_CHECKS DBUG_RETURN(0); #else - if ((thd->master_access & want_access) == want_access) + if ((sctx->master_access & want_access) == want_access) { /* If we don't have a global SELECT privilege, we have to get the database specific access rights to be able to handle queries of type UPDATE t1 SET a=1 WHERE b > 0 */ - db_access= thd->db_access; - if (!(thd->master_access & SELECT_ACL) && + db_access= sctx->db_access; + if (!(sctx->master_access & SELECT_ACL) && (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))) - db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern); - *save_priv=thd->master_access | db_access; + db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db, + db_is_pattern); + *save_priv=sctx->master_access | db_access; DBUG_RETURN(FALSE); } - if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) || + if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) || ! db && dont_check_global_grants) { // We can never grant this DBUG_PRINT("error",("No possible access")); if (!no_errors) my_error(ER_ACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, + sctx->priv_user, + sctx->priv_host, (thd->password ? ER(ER_YES) : ER(ER_NO))); /* purecov: tested */ @@ -4869,15 +4952,16 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, DBUG_RETURN(FALSE); // Allow select on anything if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))) - db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern); + db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, + db_is_pattern); else - db_access=thd->db_access; + db_access= sctx->db_access; DBUG_PRINT("info",("db_access: %lu", db_access)); /* Remove SHOW attribute and access rights we already have */ - want_access &= ~(thd->master_access | EXTRA_ACL); + want_access &= ~(sctx->master_access | EXTRA_ACL); DBUG_PRINT("info",("db_access: %lu want_access: %lu", db_access, want_access)); - db_access= ((*save_priv=(db_access | thd->master_access)) & want_access); + db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access); /* grant_option is set if there exists a single table or column grant */ if (db_access == want_access || @@ -4888,8 +4972,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, DBUG_PRINT("error",("Access denied")); if (!no_errors) my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, + sctx->priv_user, sctx->priv_host, (db ? db : (thd->db ? thd->db : "unknown"))); /* purecov: tested */ @@ -4923,7 +5006,7 @@ bool check_global_access(THD *thd, ulong want_access) return 0; #else char command[128]; - if ((thd->master_access & want_access)) + if ((thd->security_ctx->master_access & want_access)) return 0; get_privilege_desc(command, sizeof(command), want_access); my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); @@ -4946,12 +5029,22 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, TABLE_LIST *org_tables=tables; for (; tables; tables= tables->next_global) { + if (tables->schema_table && + (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL))) + { + if (!no_errors) + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + thd->security_ctx->priv_user, thd->security_ctx->priv_host, + information_schema_name.str); + return TRUE; + } if (tables->derived || tables->schema_table || tables->belong_to_view || (tables->table && (int)tables->table->s->tmp_table) || my_tz_check_n_skip_implicit_tables(&tables, thd->lex->time_zone_tables_used)) continue; - if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) && + if ((thd->security_ctx->master_access & want_access) == + (want_access & ~EXTRA_ACL) && thd->db) tables->grant.privilege= want_access; else if (tables->db && tables->db == thd->db) @@ -4961,14 +5054,14 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, else { if (check_access(thd,want_access,tables->db,&tables->grant.privilege, - 0, no_errors)) + 0, no_errors, test(tables->schema_table))) return TRUE; // Access denied found_access=tables->grant.privilege; found=1; } } else if (check_access(thd,want_access,tables->db,&tables->grant.privilege, - 0, no_errors)) + 0, no_errors, test(tables->schema_table))) return TRUE; } if (grant_option) @@ -4988,10 +5081,16 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name, tables->db= db; tables->table_name= tables->alias= name; - if ((thd->master_access & want_access) == want_access && !thd->db) + /* + The following test is just a shortcut for check_access() (to avoid + calculating db_access) under the assumption that it's common to + give persons global right to execute all stored SP (but not + necessary to create them). + */ + if ((thd->security_ctx->master_access & want_access) == want_access) tables->grant.privilege= want_access; else if (check_access(thd,want_access,db,&tables->grant.privilege, - 0, no_errors)) + 0, no_errors, 0)) return TRUE; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -5021,9 +5120,13 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc) { ulong save_priv; - if (thd->master_access & SHOW_PROC_ACLS) + if (thd->security_ctx->master_access & SHOW_PROC_ACLS) return FALSE; - if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) || + /* + There are no routines in information_schema db. So we can safely + pass zero to last paramter of check_access function + */ + if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1, 0) || (save_priv & SHOW_PROC_ACLS)) return FALSE; return check_routine_level_acl(thd, db, name, is_proc); @@ -5055,7 +5158,8 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) if (access & want_access) { if (!check_access(thd, access, table->db, - &table->grant.privilege, 0, 1) && + &table->grant.privilege, 0, 1, + test(table->schema_table)) && !grant_option || !check_grant(thd, access, table, 0, 1, 1)) DBUG_RETURN(0); } @@ -5213,11 +5317,15 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); + DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx); thd->tmp_table_used= 0; if (!thd->in_sub_stmt) { if (opt_bin_log) + { reset_dynamic(&thd->user_var_events); + thd->user_var_events_alloc= thd->mem_root; + } thd->clear_error(); thd->total_warn_count=0; // Warnings for this query thd->rand_used= 0; @@ -5259,7 +5367,7 @@ mysql_new_select(LEX *lex, bool move_down) it's a constant one. The flag is switched off in the end of mysql_stmt_prepare. */ - if (thd->current_arena->is_stmt_prepare()) + if (thd->stmt_arena->is_stmt_prepare()) select_lex->uncacheable|= UNCACHEABLE_PREPARE; if (move_down) { @@ -5587,8 +5695,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, and so on, the display width is ignored. */ char buf[32]; - my_snprintf(buf, sizeof(buf), - "TIMESTAMP(%s)", length, system_charset_info); + my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length); push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), @@ -5694,7 +5801,7 @@ new_create_field(THD *thd, char *field_name, enum_field_types type, } if (new_field->length < new_field->decimals) { - my_error(ER_SCALE_BIGGER_THAN_PRECISION, MYF(0), field_name); + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name); DBUG_RETURN(NULL); } new_field->length= @@ -5757,19 +5864,31 @@ new_create_field(THD *thd, char *field_name, enum_field_types type, new_field->decimals= NOT_FIXED_DEC; break; } - if (!length) + if (!length && !decimals) { new_field->length = FLT_DIG+6; new_field->decimals= NOT_FIXED_DEC; } + if (new_field->length < new_field->decimals && + new_field->decimals != NOT_FIXED_DEC) + { + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name); + DBUG_RETURN(NULL); + } break; case FIELD_TYPE_DOUBLE: allowed_type_modifier= AUTO_INCREMENT_FLAG; - if (!length) + if (!length && !decimals) { new_field->length = DBL_DIG+7; new_field->decimals=NOT_FIXED_DEC; } + if (new_field->length < new_field->decimals && + new_field->decimals != NOT_FIXED_DEC) + { + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name); + DBUG_RETURN(NULL); + } break; case FIELD_TYPE_TIMESTAMP: if (!length) @@ -6065,7 +6184,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->db= empty_c_string; ptr->db_length= 0; } - if (thd->current_arena->is_stmt_prepare_or_first_sp_execute()) + if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) ptr->db= thd->strdup(ptr->db); ptr->alias= alias_str; @@ -6078,8 +6197,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; - if (!my_strcasecmp(system_charset_info, ptr->db, - information_schema_name.str)) + if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db, + information_schema_name.str)) { ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name); if (!schema_table || @@ -6105,7 +6224,10 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, /* check that used name is unique */ if (lock_type != TL_IGNORE) { - for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ; + TABLE_LIST *first_table= (TABLE_LIST*) table_list.first; + if (lex->sql_command == SQLCOM_CREATE_VIEW) + first_table= first_table ? first_table->next_local : NULL; + for (TABLE_LIST *tables= first_table ; tables ; tables=tables->next_local) { @@ -6409,7 +6531,7 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) SYNOPSIS make_join_on_context() thd pointer to current thread - left_op lefto operand of the JOIN + left_op left operand of the JOIN right_op rigth operand of the JOIN DESCRIPTION @@ -6553,8 +6675,25 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, #ifndef NO_EMBEDDED_ACCESS_CHECKS if (options & REFRESH_GRANT) { - acl_reload(thd); - grant_reload(thd); + THD *tmp_thd= 0; + /* + If reload_acl_and_cache() is called from SIGHUP handler we have to + allocate temporary THD for execution of acl_reload()/grant_reload(). + */ + if (!thd && (thd= (tmp_thd= new THD))) + thd->store_globals(); + if (thd) + { + (void)acl_reload(thd); + (void)grant_reload(thd); + } + if (tmp_thd) + { + delete tmp_thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + thd= 0; + } reset_mqh((LEX_USER *)NULL, TRUE); } #endif @@ -6712,8 +6851,8 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query) VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (tmp) { - if ((thd->master_access & SUPER_ACL) || - !strcmp(thd->user,tmp->user)) + if ((thd->security_ctx->master_access & SUPER_ACL) || + !strcmp(thd->security_ctx->user, tmp->security_ctx->user)) { tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION); error=0; @@ -6806,56 +6945,6 @@ bool check_simple_select() return 0; } -/* - Setup locking for multi-table updates. Used by the replication slave. - Replication slave SQL thread examines (all_tables_not_ok()) the - locking state of referenced tables to determine if the query has to - be executed or ignored. Since in multi-table update, the - 'default' lock is read-only, this lock is corrected early enough by - calling this function, before the slave decides to execute/ignore. - - SYNOPSIS - check_multi_update_lock() - thd Current thread - - RETURN VALUES - 0 ok - 1 error -*/ -static bool check_multi_update_lock(THD *thd) -{ - bool res= 1; - LEX *lex= thd->lex; - TABLE_LIST *table, *tables= lex->query_tables; - DBUG_ENTER("check_multi_update_lock"); - - if (check_db_used(thd, tables)) - goto error; - - /* - Ensure that we have UPDATE or SELECT privilege for each table - The exact privilege is checked in mysql_multi_update() - */ - for (table= tables ; table ; table= table->next_local) - { - TABLE_LIST *save= table->next_local; - table->next_local= 0; - if ((check_access(thd, UPDATE_ACL, table->db, &table->grant.privilege,0,1) || - (grant_option && check_grant(thd, UPDATE_ACL, table,0,1,1))) && - check_one_table_access(thd, SELECT_ACL, table)) - goto error; - table->next_local= save; - } - - if (mysql_multi_update_prepare(thd)) - goto error; - - res= 0; - -error: - DBUG_RETURN(res); -} - Comp_creator *comp_eq_creator(bool invert) { @@ -7008,11 +7097,13 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) if (table->derived) table->grant.privilege= SELECT_ACL; else if ((check_access(thd, UPDATE_ACL, table->db, - &table->grant.privilege, 0, 1) || + &table->grant.privilege, 0, 1, + test(table->schema_table)) || grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) && (check_access(thd, SELECT_ACL, table->db, - &table->grant.privilege, 0, 0) || + &table->grant.privilege, 0, 0, + test(table->schema_table)) || grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))) DBUG_RETURN(TRUE); @@ -7031,7 +7122,8 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) !table->table_in_first_from_clause) { if (check_access(thd, SELECT_ACL, table->db, - &table->grant.privilege, 0, 0) || + &table->grant.privilege, 0, 0, + test(table->schema_table)) || grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)) DBUG_RETURN(TRUE); } @@ -7126,6 +7218,12 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) target_tbl->table_name, "MULTI DELETE"); DBUG_RETURN(TRUE); } + if (!walk->derived) + { + target_tbl->table_name= walk->table_name; + target_tbl->table_name_length= walk->table_name_length; + } + walk->updating= target_tbl->updating; walk->lock_type= target_tbl->lock_type; target_tbl->correspondent_table= walk; // Remember corresponding table } @@ -7248,7 +7346,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, CREATE_TMP_ACL : CREATE_ACL); lex->create_info.alias= create_table->alias; if (check_access(thd, want_priv, create_table->db, - &create_table->grant.privilege, 0, 0) || + &create_table->grant.privilege, 0, 0, + test(create_table->schema_table)) || check_merge_table_access(thd, create_table->db, (TABLE_LIST *) lex->create_info.merge_list.first)) @@ -7268,7 +7367,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, against the opened tables to ensure we don't use a table that is part of the view (which can only be done after the table has been opened). */ - if (thd->current_arena->is_stmt_prepare_or_first_sp_execute()) + if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) { /* For temporary tables we don't have to check if the created table exists @@ -7326,3 +7425,33 @@ Item *negate_expression(THD *thd, Item *expr) return negated; return new Item_func_not(expr); } + + +/* + Assign as view definer current user + + SYNOPSIS + default_view_definer() + sctx current security context + definer structure where it should be assigned + + RETURN + FALSE OK + TRUE Error +*/ + +bool default_view_definer(Security_context *sctx, st_lex_user *definer) +{ + definer->user.str= sctx->priv_user; + definer->user.length= strlen(sctx->priv_user); + + if (!*sctx->priv_host) + { + my_error(ER_NO_VIEW_USER, MYF(0)); + return TRUE; + } + + definer->host.str= sctx->priv_host; + definer->host.length= strlen(sctx->priv_host); + return FALSE; +} diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 112c4a3dd47..5f3539ca1e9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -15,9 +15,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /********************************************************************** -This file contains the implementation of prepare and executes. +This file contains the implementation of prepared statements. -Prepare: +When one prepares a statement: - Server gets the query from client with command 'COM_STMT_PREPARE'; in the following format: @@ -25,21 +25,21 @@ Prepare: - Parse the query and recognize any parameter markers '?' and store its information list in lex->param_list - Allocate a new statement for this prepare; and keep this in - 'thd->prepared_statements' pool. + 'thd->stmt_map'. - Without executing the query, return back to client the total number of parameters along with result-set metadata information (if any) in the following format: [STMT_ID:4] [Column_count:2] [Param_count:2] + [Params meta info (stubs only for now)] (if Param_count > 0) [Columns meta info] (if Column_count > 0) - [Params meta info] (if Param_count > 0 ) (TODO : 4.1.1) -Prepare-execute: +When one executes a statement: - Server gets the command 'COM_STMT_EXECUTE' to execute the - previously prepared query. If there is any param markers; then client - will send the data in the following format: + previously prepared query. If there are any parameter markers, then the + client will send the data in the following format: [COM_STMT_EXECUTE:1] [STMT_ID:4] [NULL_BITS:(param_count+7)/8)] @@ -48,29 +48,30 @@ Prepare-execute: [[length]data] .. [[length]data]. (Note: Except for string/binary types; all other types will not be supplied with length field) - - Replace the param items with this new data. If it is a first execute - or types altered by client; then setup the conversion routines. + - If it is a first execute or types of parameters were altered by client, + then setup the conversion routines. + - Assign parameter items from the supplied data. - Execute the query without re-parsing and send back the results to client -Long data handling: +When one supplies long data for a placeholder: - Server gets the long data in pieces with command type 'COM_STMT_SEND_LONG_DATA'. - The packet recieved will have the format as: [COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data] - - data from the packet is appended to long data value buffer for this + - data from the packet is appended to the long data value buffer for this placeholder. - - It's up to the client to check for read data ended. The server doesn't - care; and also server doesn't notify to the client that it got the - data or not; if there is any error; then during execute; the error - will be returned + - It's up to the client to stop supplying data chunks at any point. The + server doesn't care; also, the server doesn't notify the client whether + it got the data or not; if there is any error, then it will be returned + at statement execute. ***********************************************************************/ #include "mysql_priv.h" #include "sql_select.h" // for JOIN -#include <m_ctype.h> // for isspace() +#include "sql_cursor.h" #include "sp_head.h" #include "sp.h" #include "sp_cache.h" @@ -81,18 +82,37 @@ Long data handling: #include <mysql_com.h> #endif +/* A result class used to send cursor rows using the binary protocol. */ + +class Select_fetch_protocol_prep: public select_send +{ + Protocol_prep protocol; +public: + Select_fetch_protocol_prep(THD *thd); + virtual bool send_fields(List<Item> &list, uint flags); + virtual bool send_data(List<Item> &items); + virtual bool send_eof(); +}; + /****************************************************************************** - Prepared_statement: statement which can contain placeholders + Prepared_statement: a statement that can contain placeholders ******************************************************************************/ class Prepared_statement: public Statement { public: + enum flag_values + { + IS_IN_USE= 1 + }; + THD *thd; + Select_fetch_protocol_prep result; Protocol *protocol; Item_param **param_array; uint param_count; uint last_errno; + uint flags; char last_error[MYSQL_ERRMSG_SIZE]; #ifndef EMBEDDED_LIBRARY bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end, @@ -104,15 +124,20 @@ public: List<LEX_STRING>& varnames, String *expanded_query); public: - Prepared_statement(THD *thd_arg); + Prepared_statement(THD *thd_arg, Protocol *protocol_arg); virtual ~Prepared_statement(); void setup_set_params(); virtual Query_arena::Type type() const; - virtual void close_cursor(); + virtual void cleanup_stmt(); + bool set_name(LEX_STRING *name); + inline void close_cursor() { delete cursor; cursor= 0; } + + bool prepare(const char *packet, uint packet_length); + bool execute(String *expanded_query, bool open_cursor); + /* Destroy this statement */ + bool deallocate(); }; -static void execute_stmt(THD *thd, Prepared_statement *stmt, - String *expanded_query); /****************************************************************************** Implementation @@ -124,16 +149,31 @@ inline bool is_param_null(const uchar *pos, ulong param_no) return pos[param_no/8] & (1 << (param_no & 7)); } -enum { STMT_QUERY_LOG_LENGTH= 8192 }; - /* - Seek prepared statement in statement map by id: returns zero if statement - was not found, pointer otherwise. + Find a prepared statement in the statement map by id. + + SYNOPSIS + find_prepared_statement() + thd thread handle + id statement id + where the place from which this function is called (for + error reporting). + + DESCRIPTION + Try to find a prepared statement and set THD error if it's not found. + + RETURN VALUE + 0 if the statement was not found, a pointer otherwise. */ static Prepared_statement * find_prepared_statement(THD *thd, ulong id, const char *where) { + /* + To strictly separate namespaces of SQL prepared statements and C API + prepared statements find() will return 0 if there is a named prepared + statement with such id. + */ Statement *stmt= thd->stmt_map.find(id); if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT) @@ -148,7 +188,13 @@ find_prepared_statement(THD *thd, ulong id, const char *where) /* - Send prepared stmt info to client after prepare + Send prepared statement id and metadata to the client after prepare. + + SYNOPSIS + send_prep_stmt() + + RETURN VALUE + 0 in case of success, 1 otherwise */ #ifndef EMBEDDED_LIBRARY @@ -193,8 +239,20 @@ static bool send_prep_stmt(Prepared_statement *stmt, /* - Read the length of the parameter data and return back to - caller by positing the pointer to param data. + Read the length of the parameter data and return it back to + the caller. + + SYNOPSIS + get_param_length() + packet a pointer to the data + len remaining packet length + + DESCRIPTION + Read data length, position the packet to the first byte after it, + and return the length to the caller. + + RETURN VALUE + Length of data piece. */ #ifndef EMBEDDED_LIBRARY @@ -239,19 +297,21 @@ static ulong get_param_length(uchar **packet, ulong len) #endif /*!EMBEDDED_LIBRARY*/ /* - Data conversion routines + Data conversion routines. + SYNOPSIS - set_param_xx() - param parameter item - pos input data buffer - len length of data in the buffer + set_param_xx() + param parameter item + pos input data buffer + len length of data in the buffer - All these functions read the data from pos, convert it to requested type - and assign to param; pos is advanced to predefined length. + DESCRIPTION + All these functions read the data from pos, convert it to requested + type and assign to param; pos is advanced to predefined length. - Make a note that the NULL handling is examined at first execution - (i.e. when input types altered) and for all subsequent executions - we don't read any values for this. + Make a note that the NULL handling is examined at first execution + (i.e. when input types altered) and for all subsequent executions + we don't read any values for this. RETURN VALUE none @@ -594,8 +654,35 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, #ifndef EMBEDDED_LIBRARY /* - Update the parameter markers by reading data from client packet - and if binary/update log is set, generate the valid query. + Routines to assign parameters from data supplied by the client. + + DESCRIPTION + Update the parameter markers by reading data from the packet and + and generate a valid query for logging. + + NOTES + This function, along with other _withlog functions is called when one of + binary, slow or general logs is open. Logging of prepared statements in + all cases is performed by means of conventional queries: if parameter + data was supplied from C API, each placeholder in the query is + replaced with its actual value; if we're logging a [Dynamic] SQL + prepared statement, parameter markers are replaced with variable names. + Example: + mysql_stmt_prepare("UPDATE t1 SET a=a*1.25 WHERE a=?") + --> general logs gets [Prepare] UPDATE t1 SET a*1.25 WHERE a=?" + mysql_stmt_execute(stmt); + --> general and binary logs get + [Execute] UPDATE t1 SET a*1.25 WHERE a=1" + If a statement has been prepared using SQL syntax: + PREPARE stmt FROM "UPDATE t1 SET a=a*1.25 WHERE a=?" + --> general log gets + [Query] PREPARE stmt FROM "UPDATE ..." + EXECUTE stmt USING @a + --> general log gets + [Query] EXECUTE stmt USING @a; + + RETURN VALUE + 0 if success, 1 otherwise */ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, @@ -707,6 +794,17 @@ static bool setup_conversion_functions(Prepared_statement *stmt, #else +/* + Embedded counterparts of parameter assignment routines. + + DESCRIPTION + The main difference between the embedded library and the server is + that in embedded case we don't serialize/deserialize parameters data. + Additionally, for unknown reason, the client-side flag raised for + changed types of placeholders is ignored and we simply setup conversion + functions at each execute (TODO: fix). +*/ + static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query) { THD *thd= stmt->thd; @@ -791,7 +889,8 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) /* - Set prepared statement parameters from user variables. + Assign prepared statement parameters from user variables. + SYNOPSIS insert_params_from_vars() stmt Statement @@ -829,12 +928,14 @@ static bool insert_params_from_vars(Prepared_statement *stmt, /* Do the same as insert_params_from_vars but also construct query text for binary log. + SYNOPSIS insert_params_from_vars() - stmt Statement + stmt Prepared statement varnames List of variables. Caller must ensure that number of variables in the list is equal to number of statement parameters - query The query with parameter markers replaced with their values + query The query with parameter markers replaced with corresponding + user variables that were used to execute the query. */ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, @@ -845,12 +946,13 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, Item_param **end= begin + stmt->param_count; user_var_entry *entry; LEX_STRING *varname; - DBUG_ENTER("insert_params_from_vars"); - List_iterator<LEX_STRING> var_it(varnames); String buf; const String *val; uint32 length= 0; + + DBUG_ENTER("insert_params_from_vars"); + if (query->copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); @@ -858,7 +960,8 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, { Item_param *param= *it; varname= var_it++; - if (get_var_with_binlog(stmt->thd, *varname, &entry)) + if (get_var_with_binlog(stmt->thd, stmt->lex->sql_command, + *varname, &entry)) DBUG_RETURN(1); if (param->set_from_user_var(stmt->thd, entry)) @@ -895,16 +998,16 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, } /* - Validate INSERT statement: + Validate INSERT statement. SYNOPSIS mysql_test_insert() - stmt prepared statemen handler - tables global/local table list + stmt prepared statement + tables global/local table list RETURN VALUE - FALSE success - TRUE error, error message is set in THD + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_insert(Prepared_statement *stmt, @@ -988,13 +1091,13 @@ error: SYNOPSIS mysql_test_update() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statement + tables list of tables used in this query RETURN VALUE - 0 success - 1 error, error message is set in THD - 2 convert to multi_update + 0 success + 1 error, error message is set in THD + 2 convert to multi_update */ static int mysql_test_update(Prepared_statement *stmt, @@ -1007,30 +1110,39 @@ static int mysql_test_update(Prepared_statement *stmt, #ifndef NO_EMBEDDED_ACCESS_CHECKS uint want_privilege; #endif + bool need_reopen; DBUG_ENTER("mysql_test_update"); if (update_precheck(thd, table_list)) goto error; - if (open_tables(thd, &table_list, &table_count, 0)) - goto error; - - if (table_list->multitable_view) + for ( ; ; ) { - DBUG_ASSERT(table_list->view != 0); - DBUG_PRINT("info", ("Switch to multi-update")); - /* pass counter value */ - thd->lex->table_count= table_count; - /* convert to multiupdate */ - DBUG_RETURN(2); + if (open_tables(thd, &table_list, &table_count, 0)) + goto error; + + if (table_list->multitable_view) + { + DBUG_ASSERT(table_list->view != 0); + DBUG_PRINT("info", ("Switch to multi-update")); + /* pass counter value */ + thd->lex->table_count= table_count; + /* convert to multiupdate */ + DBUG_RETURN(2); + } + + if (!lock_tables(thd, table_list, table_count, &need_reopen)) + break; + if (!need_reopen) + goto error; + close_tables_for_reopen(thd, table_list); } /* thd->fill_derived_tables() is false here for sure (because it is preparation of PS, so we even do not check it). */ - if (lock_tables(thd, table_list, table_count) || - mysql_handle_derived(thd->lex, &mysql_derived_prepare)) + if (mysql_handle_derived(thd->lex, &mysql_derived_prepare)) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1068,16 +1180,16 @@ error: /* - Validate DELETE statement + Validate DELETE statement. SYNOPSIS mysql_test_delete() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statement + tables list of tables used in this query RETURN VALUE - FALSE success - TRUE error, error message is set in THD + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_delete(Prepared_statement *stmt, @@ -1106,21 +1218,24 @@ error: /* Validate SELECT statement. - In case of success, if this query is not EXPLAIN, send column list info - back to client. SYNOPSIS mysql_test_select() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statement + tables list of tables used in the query + + DESCRIPTION + In case of success, if this query is not EXPLAIN, send column list info + back to the client. RETURN VALUE - FALSE success - TRUE error, sent to client + 0 success + 1 error, error message is set in THD + 2 success, and statement metadata has been sent */ -static bool mysql_test_select(Prepared_statement *stmt, - TABLE_LIST *tables, bool text_protocol) +static int mysql_test_select(Prepared_statement *stmt, + TABLE_LIST *tables, bool text_protocol) { THD *thd= stmt->thd; LEX *lex= stmt->lex; @@ -1136,7 +1251,7 @@ static bool mysql_test_select(Prepared_statement *stmt, if (check_table_access(thd, privilege, tables,0)) goto error; } - else if (check_access(thd, privilege, any_db,0,0,0)) + else if (check_access(thd, privilege, any_db,0,0,0,0)) goto error; #endif @@ -1156,53 +1271,45 @@ static bool mysql_test_select(Prepared_statement *stmt, It is not SELECT COMMAND for sure, so setup_tables will be called as usual, and we pass 0 as setup_tables_done_option */ - if (unit->prepare(thd, 0, 0, "")) + if (unit->prepare(thd, 0, 0)) goto error; - if (!text_protocol) + if (!lex->describe && !text_protocol) { - if (lex->describe) - { - if (send_prep_stmt(stmt, 0) || thd->protocol->flush()) - goto error; - } - else - { - /* Make copy of item list, as change_columns may change it */ - List<Item> fields(lex->select_lex.item_list); + /* Make copy of item list, as change_columns may change it */ + List<Item> fields(lex->select_lex.item_list); - /* Change columns if a procedure like analyse() */ - if (unit->last_procedure && - unit->last_procedure->change_columns(fields)) - goto error; + /* Change columns if a procedure like analyse() */ + if (unit->last_procedure && unit->last_procedure->change_columns(fields)) + goto error; - /* - We can use lex->result as it should've been - prepared in unit->prepare call above. - */ - if (send_prep_stmt(stmt, lex->result->field_count(fields)) || - lex->result->send_fields(fields, Protocol::SEND_EOF) || - thd->protocol->flush()) - goto error; - } + /* + We can use lex->result as it should've been prepared in + unit->prepare call above. + */ + if (send_prep_stmt(stmt, lex->result->field_count(fields)) || + lex->result->send_fields(fields, Protocol::SEND_EOF) || + thd->protocol->flush()) + goto error; + DBUG_RETURN(2); } - DBUG_RETURN(FALSE); + DBUG_RETURN(0); error: - DBUG_RETURN(TRUE); + DBUG_RETURN(1); } /* - Validate and prepare for execution DO statement expressions + Validate and prepare for execution DO statement expressions. SYNOPSIS mysql_test_do_fields() - stmt prepared statemen handler - tables list of tables queries - values list of expressions + stmt prepared statement + tables list of tables used in this query + values list of expressions RETURN VALUE - FALSE success - TRUE error, error message is set in THD + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_do_fields(Prepared_statement *stmt, @@ -1226,13 +1333,13 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, SYNOPSIS mysql_test_set_fields() - stmt prepared statemen handler - tables list of tables queries - values list of expressions + stmt prepared statement + tables list of tables used in this query + values list of expressions RETURN VALUE - FALSE success - TRUE error + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_set_fields(Prepared_statement *stmt, @@ -1264,9 +1371,9 @@ error: SYNOPSIS select_like_stmt_test() - stmt - prepared statement handler - specific_prepare - function of command specific prepare - setup_tables_done_option - options to be passed to LEX::unit.prepare() + stmt prepared statement + specific_prepare function of command specific prepare + setup_tables_done_option options to be passed to LEX::unit.prepare() NOTE This function won't directly open tables used in select. They should @@ -1275,8 +1382,8 @@ error: "specific_prepare" call (like this happens in case of multi-update). RETURN VALUE - FALSE success - TRUE error, error message is set in THD + FALSE success + TRUE error, error message is set in THD */ static bool select_like_stmt_test(Prepared_statement *stmt, @@ -1295,24 +1402,24 @@ static bool select_like_stmt_test(Prepared_statement *stmt, thd->used_tables= 0; // Updated by setup_fields /* Calls JOIN::prepare */ - DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option, "")); + DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option)); } /* Check internal SELECT of the prepared command (with opening and - locking tables used). + locking of used tables). SYNOPSIS select_like_stmt_test_with_open_n_lock() - stmt - prepared statement handler - tables - list of tables to be opened and locked - before calling specific_prepare function - specific_prepare - function of command specific prepare - setup_tables_done_option - options to be passed to LEX::unit.prepare() + stmt prepared statement + tables list of tables to be opened and locked + before calling specific_prepare function + specific_prepare function of command specific prepare + setup_tables_done_option options to be passed to LEX::unit.prepare() RETURN VALUE - FALSE success - TRUE error + FALSE success + TRUE error */ static bool @@ -1341,12 +1448,12 @@ select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt, SYNOPSIS mysql_test_create_table() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statement + tables list of tables used in this query RETURN VALUE - FALSE success - TRUE error, error message is set in THD + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_create_table(Prepared_statement *stmt) @@ -1377,17 +1484,17 @@ static bool mysql_test_create_table(Prepared_statement *stmt) /* - Validate and prepare for execution multi update statement + Validate and prepare for execution a multi update statement. SYNOPSIS mysql_test_multiupdate() - stmt prepared statemen handler - tables list of tables queries - converted converted to multi-update from usual update + stmt prepared statement + tables list of tables used in this query + converted converted to multi-update from usual update RETURN VALUE - FALSE success - TRUE error + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_multiupdate(Prepared_statement *stmt, @@ -1404,16 +1511,16 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, /* - Validate and prepare for execution multi delete statement + Validate and prepare for execution a multi delete statement. SYNOPSIS mysql_test_multidelete() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statement + tables list of tables used in this query RETURN VALUE - 0 success - 1 error, error message in THD is set. + FALSE success + TRUE error, error message in THD is set. */ static bool mysql_test_multidelete(Prepared_statement *stmt, @@ -1449,10 +1556,11 @@ error: SYNOPSIS mysql_insert_select_prepare_tester() - thd thread handler + thd thread handle - NOTE: we need remove first local tables after open_and_lock_tables, - because mysql_handle_derived use local tables lists + NOTE + We need to remove the first local table after open_and_lock_tables, + because mysql_handle_derived uses local tables lists. */ static bool mysql_insert_select_prepare_tester(THD *thd) @@ -1476,21 +1584,20 @@ static bool mysql_insert_select_prepare_tester(THD *thd) /* - Validate and prepare for execution INSERT ... SELECT statement + Validate and prepare for execution INSERT ... SELECT statement. SYNOPSIS mysql_test_insert_select() - stmt prepared statemen handler - tables list of tables of query + stmt prepared statement + tables list of tables used in this query RETURN VALUE - 0 success - 1 error, sent to client - -1 error, not sent to client + FALSE success + TRUE error, error message is set in THD */ -static int mysql_test_insert_select(Prepared_statement *stmt, - TABLE_LIST *tables) +static bool mysql_test_insert_select(Prepared_statement *stmt, + TABLE_LIST *tables) { int res; LEX *lex= stmt->lex; @@ -1525,7 +1632,7 @@ static int mysql_test_insert_select(Prepared_statement *stmt, SYNOPSIS check_prepared_statement() - stmt prepared statement + stmt prepared statement DESCRIPTION This function @@ -1534,8 +1641,8 @@ static int mysql_test_insert_select(Prepared_statement *stmt, by calling fix_fields. RETURN VALUE - FALSE success, statement metadata is sent to client - TRUE error, error message is set (but not sent) + FALSE success, statement metadata is sent to client + TRUE error, error message is set in THD (but not sent) */ static bool check_prepared_statement(Prepared_statement *stmt, @@ -1582,11 +1689,13 @@ static bool check_prepared_statement(Prepared_statement *stmt, break; case SQLCOM_SELECT: - if ((res= mysql_test_select(stmt, tables, text_protocol))) - goto error; - /* Statement and field info has already been sent */ - DBUG_RETURN(FALSE); - + res= mysql_test_select(stmt, tables, text_protocol); + if (res == 2) + { + /* Statement and field info has already been sent */ + DBUG_RETURN(FALSE); + } + break; case SQLCOM_CREATE_TABLE: res= mysql_test_create_table(stmt); break; @@ -1683,33 +1792,18 @@ static bool init_param_array(Prepared_statement *stmt) } -/* Cleanup PS after execute/prepare and restore THD state */ - -static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd) -{ - DBUG_ENTER("cleanup_stmt_and_thd_after_use"); - stmt->lex->unit.cleanup(); - cleanup_items(stmt->free_list); - thd->rollback_item_tree_changes(); - thd->cleanup_after_query(); - DBUG_VOID_RETURN; -} - /* - Given a query string with parameter markers, create a Prepared Statement - from it and send PS info back to the client. + COM_STMT_PREPARE handler. SYNOPSIS mysql_stmt_prepare() - packet query to be prepared - packet_length query string length, including ignored trailing NULL or - quote char. - name NULL or statement name. For unnamed statements binary PS - protocol is used, for named statements text protocol is - used. - RETURN - FALSE OK, statement prepared successfully - TRUE Error + packet query to be prepared + packet_length query string length, including ignored + trailing NULL or quote char. + + DESCRIPTION + Given a query string with parameter markers, create a prepared + statement from it and send PS info back to the client. NOTES This function parses the query and sends the total number of parameters @@ -1722,124 +1816,150 @@ static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd) that a fast and direct retrieval can be made without going through all field items. + RETURN VALUE + none: in case of success a new statement id and metadata is sent + to the client, otherwise an error message is set in THD. */ -bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, - LEX_STRING *name) +void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length) { - LEX *lex; - Statement stmt_backup; - Prepared_statement *stmt= new Prepared_statement(thd); + Prepared_statement *stmt= new Prepared_statement(thd, &thd->protocol_prep); bool error; DBUG_ENTER("mysql_stmt_prepare"); DBUG_PRINT("prep_query", ("%s", packet)); - /* - If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql. - However, it seems handy if com_stmt_prepare is increased always, - no matter what kind of prepare is processed. - */ - statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status); - if (stmt == 0) - DBUG_RETURN(TRUE); - - if (name) - { - stmt->name.length= name->length; - if (!(stmt->name.str= memdup_root(stmt->mem_root, (char*)name->str, - name->length))) - { - delete stmt; - DBUG_RETURN(TRUE); - } - } + DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */ if (thd->stmt_map.insert(stmt)) { delete stmt; - DBUG_RETURN(TRUE); + DBUG_VOID_RETURN; /* out of memory */ } - /* - alloc_query() uses thd->memroot && thd->query, so we have to call - both of backup_statement() and backup_item_area() here. - */ - thd->set_n_backup_statement(stmt, &stmt_backup); - thd->set_n_backup_item_arena(stmt, &stmt_backup); - - if (alloc_query(thd, packet, packet_length)) - { - thd->restore_backup_statement(stmt, &stmt_backup); - thd->restore_backup_item_arena(stmt, &stmt_backup); - /* Statement map deletes statement on erase */ - thd->stmt_map.erase(stmt); - DBUG_RETURN(TRUE); - } - - mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, packet); - - thd->current_arena= stmt; - mysql_init_query(thd, (uchar *) thd->query, thd->query_length); + mysql_reset_thd_for_next_command(thd); /* Reset warnings from previous command */ mysql_reset_errors(thd, 0); - lex= thd->lex; - lex->safe_to_cache_query= 0; - sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); - error= yyparse((void *)thd) || thd->is_fatal_error || - thd->net.report_error || init_param_array(stmt); - /* - While doing context analysis of the query (in check_prepared_statement) - we allocate a lot of additional memory: for open tables, JOINs, derived - tables, etc. Let's save a snapshot of current parse tree to the - statement and restore original THD. In cases when some tree - transformation can be reused on execute, we set again thd->mem_root from - stmt->mem_root (see setup_wild for one place where we do that). - */ - thd->restore_backup_item_arena(stmt, &stmt_backup); + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),QUERY_PRIOR); - if (!error) - error= check_prepared_statement(stmt, test(name)); + error= stmt->prepare(packet, packet_length); - /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */ if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); - if (error && thd->lex->sphead) - { - delete thd->lex->sphead; - thd->lex->sphead= NULL; - } - lex_end(lex); - close_thread_tables(thd); - cleanup_stmt_and_thd_after_use(stmt, thd); - thd->restore_backup_statement(stmt, &stmt_backup); - thd->current_arena= thd; if (error) { /* Statement map deletes statement on erase */ thd->stmt_map.erase(stmt); - stmt= NULL; + } + else + mysql_log.write(thd, COM_STMT_PREPARE, "[%lu] %s", stmt->id, packet); + + /* check_prepared_statemnt sends the metadata packet in case of success */ + DBUG_VOID_RETURN; +} + +/* + SYNOPSIS + get_dynamic_sql_string() + lex in main lex + query_len out length of the SQL statement (is set only + in case of success) + + DESCRIPTION + Get an SQL statement text from a user variable or from plain + text. If the statement is plain text, just assign the + pointers, otherwise allocate memory in thd->mem_root and copy + the contents of the variable, possibly with character + set conversion. + + RETURN VALUE + non-zero success, 0 in case of error (out of memory) +*/ + +static const char *get_dynamic_sql_string(LEX *lex, uint *query_len) +{ + THD *thd= lex->thd; + char *query_str= 0; + + if (lex->prepared_stmt_code_is_varref) + { + /* This is PREPARE stmt FROM or EXECUTE IMMEDIATE @var. */ + String str; + CHARSET_INFO *to_cs= thd->variables.collation_connection; + bool needs_conversion; + user_var_entry *entry; + String *var_value= &str; + uint32 unused, len; + /* + Convert @var contents to string in connection character set. Although + it is known that int/real/NULL value cannot be a valid query we still + convert it for error messages to be uniform. + */ + if ((entry= + (user_var_entry*)hash_search(&thd->user_vars, + (byte*)lex->prepared_stmt_code.str, + lex->prepared_stmt_code.length)) + && entry->value) + { + my_bool is_var_null; + var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC); + /* + NULL value of variable checked early as entry->value so here + we can't get NULL in normal conditions + */ + DBUG_ASSERT(!is_var_null); + if (!var_value) + goto end; + } + else + { + /* + variable absent or equal to NULL, so we need to set variable to + something reasonable to get a readable error message during parsing + */ + str.set("NULL", 4, &my_charset_latin1); + } + + needs_conversion= String::needs_conversion(var_value->length(), + var_value->charset(), to_cs, + &unused); + + len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen : + var_value->length()); + if (!(query_str= alloc_root(thd->mem_root, len+1))) + goto end; + + if (needs_conversion) + { + uint dummy_errors; + len= copy_and_convert(query_str, len, to_cs, var_value->ptr(), + var_value->length(), var_value->charset(), + &dummy_errors); + } + else + memcpy(query_str, var_value->ptr(), var_value->length()); + query_str[len]= '\0'; // Safety (mostly for debug) + *query_len= len; } else { - stmt->setup_set_params(); - init_stmt_after_parse(thd, stmt->lex); - stmt->state= Query_arena::PREPARED; + query_str= lex->prepared_stmt_code.str; + *query_len= lex->prepared_stmt_code.length; } - DBUG_RETURN(!stmt); +end: + return query_str; } -/* - Init PS/SP specific parse tree members. -*/ +/* Init PS/SP specific parse tree members. */ -void init_stmt_after_parse(THD *thd, LEX *lex) +static void init_stmt_after_parse(LEX *lex) { SELECT_LEX *sl= lex->all_selects_list; /* @@ -1850,6 +1970,65 @@ void init_stmt_after_parse(THD *thd, LEX *lex) sl->uncacheable&= ~UNCACHEABLE_PREPARE; } +/* + SQLCOM_PREPARE implementation. + + SYNOPSIS + mysql_sql_stmt_prepare() + thd thread handle + + DESCRIPTION + Prepare an SQL prepared statement. This is called from + mysql_execute_command and should therefore behave like an + ordinary query (e.g. should not reset any global THD data). + + RETURN VALUE + none: in case of success, OK packet is sent to the client, + otherwise an error message is set in THD +*/ + +void mysql_sql_stmt_prepare(THD *thd) +{ + LEX *lex= thd->lex; + LEX_STRING *name= &lex->prepared_stmt_name; + Prepared_statement *stmt; + const char *query; + uint query_len; + DBUG_ENTER("mysql_sql_stmt_prepare"); + DBUG_ASSERT(thd->protocol == &thd->protocol_simple); + + if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) + { + /* + If there is a statement with the same name, remove it. It is ok to + remove old and fail to insert a new one at the same time. + */ + if (stmt->deallocate()) + DBUG_VOID_RETURN; + } + + if (! (query= get_dynamic_sql_string(lex, &query_len)) || + ! (stmt= new Prepared_statement(thd, &thd->protocol_simple))) + { + DBUG_VOID_RETURN; /* out of memory */ + } + + if (stmt->set_name(name) || thd->stmt_map.insert(stmt)) + { + delete stmt; + DBUG_VOID_RETURN; + } + + if (stmt->prepare(query, query_len+1)) + { + /* Statement map deletes the statement on erase */ + thd->stmt_map.erase(stmt); + } + else + send_ok(thd, 0L, 0L, "Statement prepared"); + + DBUG_VOID_RETURN; +} /* Reinit prepared statement/stored procedure before execution */ @@ -1946,8 +2125,8 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) lex->result->cleanup(); lex->result->set_thd(thd); } - - DBUG_VOID_RETURN; + thd->allow_sum_func= 0; + DBUG_VOID_RETURN; } @@ -1956,7 +2135,8 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) SYNOPSIS reset_stmt_params() - stmt prepared statement for which parameters should be reset + stmt prepared statement for which parameters should + be reset */ static void reset_stmt_params(Prepared_statement *stmt) @@ -1969,81 +2149,50 @@ static void reset_stmt_params(Prepared_statement *stmt) /* - Executes previously prepared query. - If there is any parameters, then replace markers with the data supplied - from client, and then execute the query. + COM_STMT_EXECUTE handler: execute a previously prepared statement. SYNOPSIS mysql_stmt_execute() - thd Current thread - packet Query string - packet_length Query string length, including terminator character. + thd current thread + packet parameter types and data, if any + packet_length packet length, including the terminator character. + + DESCRIPTION + If there are any parameters, then replace parameter markers with the + data supplied from the client, and then execute the statement. + This function uses binary protocol to send a possible result set + to the client. + + RETURN VALUE + none: in case of success OK packet or a result set is sent to the + client, otherwise an error message is set in THD. */ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) { ulong stmt_id= uint4korr(packet); ulong flags= (ulong) ((uchar) packet[4]); - Statement stmt_backup; - Cursor *cursor; - /* - Query text for binary log, or empty string if the query is not put into - binary log. - */ + /* Query text for binary, general or slow log, if any of them is open */ String expanded_query; #ifndef EMBEDDED_LIBRARY uchar *packet_end= (uchar *) packet + packet_length - 1; #endif Prepared_statement *stmt; + bool error; DBUG_ENTER("mysql_stmt_execute"); packet+= 9; /* stmt_id + 5 bytes of flags */ - statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; DBUG_PRINT("exec_query", ("%s", stmt->query)); DBUG_PRINT("info",("stmt: %p", stmt)); - /* Check if we got an error when sending long data */ - if (stmt->state == Query_arena::ERROR) - { - my_message(stmt->last_errno, stmt->last_error, MYF(0)); - DBUG_VOID_RETURN; - } - - cursor= stmt->cursor; - if (cursor && cursor->is_open()) - stmt->close_cursor(); - - DBUG_ASSERT(thd->free_list == NULL); mysql_reset_thd_for_next_command(thd); - if (flags & (ulong) CURSOR_TYPE_READ_ONLY) - { - if (!stmt->lex->result || !stmt->lex->result->simple_select()) - { - DBUG_PRINT("info",("Cursor asked for not SELECT stmt")); - /* - If lex->result is set in the parser, this is not a SELECT - statement: we can't open a cursor for it. - */ - flags= 0; - my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0)); - goto err; - } - else - { - DBUG_PRINT("info",("Using READ_ONLY cursor")); - if (!cursor && - !(cursor= stmt->cursor= new (stmt->mem_root) Cursor(thd))) - DBUG_VOID_RETURN; - /* If lex->result is set, mysql_execute_command will use it */ - stmt->lex->result= &cursor->result; - stmt->protocol= &cursor->protocol; - thd->lock_id= &cursor->lock_id; - } - } + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); + #ifndef EMBEDDED_LIBRARY if (stmt->param_count) { @@ -2062,93 +2211,62 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query)) goto set_params_data_err; #endif - thd->set_n_backup_statement(stmt, &stmt_backup); - thd->current_arena= stmt; - reinit_stmt_before_use(thd, stmt->lex); - /* From now cursors assume that thd->mem_root is clean */ - if (expanded_query.length() && - alloc_query(thd, (char *)expanded_query.ptr(), - expanded_query.length()+1)) - { - my_error(ER_OUTOFMEMORY, 0, expanded_query.length()); - goto err; - } - mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query); - - thd->protocol= stmt->protocol; // Switch to binary protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); - sp_cache_flush_obsolete(&thd->sp_proc_cache); - sp_cache_flush_obsolete(&thd->sp_func_cache); - mysql_execute_command(thd); + error= stmt->execute(&expanded_query, + test(flags & (ulong) CURSOR_TYPE_READ_ONLY)); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - thd->protocol= &thd->protocol_simple; // Use normal protocol + if (error == 0) + mysql_log.write(thd, COM_STMT_EXECUTE, "[%lu] %s", stmt->id, thd->query); - if (cursor && cursor->is_open()) - { - /* - It's safer if we grab THD state after mysql_execute_command is - finished and not in Cursor::open(), because currently the call to - Cursor::open is buried deep in JOIN::exec of the top level join. - */ - cursor->init_from_thd(thd); - - if (cursor->close_at_commit) - thd->stmt_map.add_transient_cursor(stmt); - } - else - { - close_thread_tables(thd); - cleanup_stmt_and_thd_after_use(stmt, thd); - reset_stmt_params(stmt); - } - - log_slow_statement(thd); - /* Prevent from second logging in the end of dispatch_command */ - thd->enable_slow_log= FALSE; - - thd->set_statement(&stmt_backup); - thd->lock_id= &thd->main_lock_id; - thd->current_arena= thd; DBUG_VOID_RETURN; set_params_data_err: - reset_stmt_params(stmt); my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute"); -err: + reset_stmt_params(stmt); DBUG_VOID_RETURN; } /* - Execute prepared statement using parameter values from - lex->prepared_stmt_params and send result to the client using text protocol. + SQLCOM_EXECUTE implementation. + + SYNOPSIS + mysql_sql_stmt_execute() + thd thread handle + + DESCRIPTION + Execute prepared statement using parameter values from + lex->prepared_stmt_params and send result to the client using + text protocol. This is called from mysql_execute_command and + therefore should behave like an ordinary query (e.g. not change + global THD data, such as warning count, server status, etc). + This function uses text protocol to send a possible result set. + + RETURN + none: in case of success, OK (or result set) packet is sent to the + client, otherwise an error is set in THD */ -void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) +void mysql_sql_stmt_execute(THD *thd) { + LEX *lex= thd->lex; Prepared_statement *stmt; - /* - Query text for binary log, or empty string if the query is not put into - binary log. - */ + LEX_STRING *name= &lex->prepared_stmt_name; + /* Query text for binary, general or slow log, if any of them is open */ String expanded_query; - Statement stmt_backup; DBUG_ENTER("mysql_sql_stmt_execute"); + DBUG_PRINT("info", ("EXECUTE: %.*s\n", name->length, name->str)); - DBUG_ASSERT(thd->free_list == NULL); - /* See comment for statistic_increment in mysql_stmt_prepare */ - statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status); - - if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name))) + if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) { - my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_name->length, - stmt_name->str, "EXECUTE"); + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), + name->length, name->str, "EXECUTE"); DBUG_VOID_RETURN; } - if (stmt->param_count != thd->lex->prepared_stmt_params.elements) + if (stmt->param_count != lex->prepared_stmt_params.elements) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); DBUG_VOID_RETURN; @@ -2156,78 +2274,17 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) DBUG_PRINT("info",("stmt: %p", stmt)); - /* Must go before setting variables, as it clears thd->user_var_events */ - mysql_reset_thd_for_next_command(thd); - thd->set_n_backup_statement(stmt, &stmt_backup); - if (stmt->set_params_from_vars(stmt, - stmt_backup.lex->prepared_stmt_params, + if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params, &expanded_query)) - { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); - } - thd->command= COM_STMT_EXECUTE; /* For nice messages in general log */ - execute_stmt(thd, stmt, &expanded_query); - thd->set_statement(&stmt_backup); - DBUG_VOID_RETURN; -} - - -/* - Execute prepared statement. - SYNOPSIS - execute_stmt() - thd Current thread - stmt Statement to execute - expanded_query If binary log is enabled, query string with parameter - placeholders replaced with actual values. Otherwise empty - string. - NOTES - Caller must set parameter values and thd::protocol. -*/ - -static void execute_stmt(THD *thd, Prepared_statement *stmt, - String *expanded_query) -{ - DBUG_ENTER("execute_stmt"); + goto set_params_data_err; - reinit_stmt_before_use(thd, stmt->lex); + (void) stmt->execute(&expanded_query, FALSE); - if (expanded_query->length() && - alloc_query(thd, (char *)expanded_query->ptr(), - expanded_query->length()+1)) - { - my_error(ER_OUTOFMEMORY, MYF(0), expanded_query->length()); - DBUG_VOID_RETURN; - } - mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query); - /* - At first execution of prepared statement we will perform logical - transformations of the query tree (i.e. negations elimination). - This should be done permanently on the parse tree of this statement. - */ - thd->current_arena= stmt; - - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); - mysql_execute_command(thd); - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(), WAIT_PRIOR); - /* - 'start_time' is set in dispatch_command, but THD::query will - be freed when we return from this function. So let's log the slow - query here. - */ - log_slow_statement(thd); - /* Prevent from second logging in the end of dispatch_command */ - thd->enable_slow_log= FALSE; + DBUG_VOID_RETURN; - close_thread_tables(thd); // to close derived tables - cleanup_stmt_and_thd_after_use(stmt, thd); +set_params_data_err: + my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); reset_stmt_params(stmt); - thd->current_arena= thd; - - if (stmt->state == Query_arena::PREPARED) - stmt->state= Query_arena::EXECUTED; DBUG_VOID_RETURN; } @@ -2237,9 +2294,9 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, SYNOPSIS mysql_stmt_fetch() - thd Thread handler - packet Packet from client (with stmt_id & num_rows) - packet_length Length of packet + thd Thread handle + packet Packet from client (with stmt_id & num_rows) + packet_length Length of packet */ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) @@ -2249,7 +2306,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) ulong num_rows= uint4korr(packet+4); Prepared_statement *stmt; Statement stmt_backup; - Cursor *cursor; + Server_side_cursor *cursor; DBUG_ENTER("mysql_stmt_fetch"); statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status); @@ -2257,41 +2314,32 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) DBUG_VOID_RETURN; cursor= stmt->cursor; - if (!cursor || !cursor->is_open()) + if (!cursor) { my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id); DBUG_VOID_RETURN; } - thd->current_arena= stmt; + thd->stmt_arena= stmt; thd->set_n_backup_statement(stmt, &stmt_backup); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), QUERY_PRIOR); - thd->protocol= stmt->protocol; // Switch to binary protocol cursor->fetch(num_rows); - thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); if (!cursor->is_open()) { - /* We're done with the fetch: reset PS for next execution */ - cleanup_stmt_and_thd_after_use(stmt, thd); + stmt->close_cursor(); + thd->cursor= 0; reset_stmt_params(stmt); - /* - Must be the last, as some memory is still needed for - the previous calls. - */ - free_root(cursor->mem_root, MYF(0)); - if (cursor->close_at_commit) - thd->stmt_map.erase_transient_cursor(stmt); } thd->restore_backup_statement(stmt, &stmt_backup); - thd->current_arena= thd; + thd->stmt_arena= thd; DBUG_VOID_RETURN; } @@ -2301,8 +2349,8 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) Reset a prepared statement in case there was a recoverable error. SYNOPSIS mysql_stmt_reset() - thd Thread handle - packet Packet with stmt id + thd Thread handle + packet Packet with stmt id DESCRIPTION This function resets statement to the state it was right after prepare. @@ -2310,6 +2358,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) - clear an error happened during mysql_stmt_send_long_data - cancel long data stream for all placeholders without having to call mysql_stmt_execute. + - close an open cursor Sends 'OK' packet in case of success (statement was reset) or 'ERROR' packet (unrecoverable error/statement not found/etc). */ @@ -2319,14 +2368,19 @@ void mysql_stmt_reset(THD *thd, char *packet) /* There is always space for 4 bytes in buffer */ ulong stmt_id= uint4korr(packet); Prepared_statement *stmt; - Cursor *cursor; DBUG_ENTER("mysql_stmt_reset"); statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; - stmt->close_cursor(); /* will reset statement params */ + stmt->close_cursor(); + + /* + Clear parameters from data which could be set by + mysql_stmt_send_long_data() call. + */ + reset_stmt_params(stmt); stmt->state= Query_arena::PREPARED; @@ -2339,7 +2393,7 @@ void mysql_stmt_reset(THD *thd, char *packet) /* Delete a prepared statement from memory. - Note: we don't send any reply to that command. + Note: we don't send any reply to this command. */ void mysql_stmt_close(THD *thd, char *packet) @@ -2347,36 +2401,67 @@ void mysql_stmt_close(THD *thd, char *packet) /* There is always space for 4 bytes in packet buffer */ ulong stmt_id= uint4korr(packet); Prepared_statement *stmt; - DBUG_ENTER("mysql_stmt_close"); - statistic_increment(thd->status_var.com_stmt_close, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) DBUG_VOID_RETURN; - /* Statement map deletes statement on erase */ - thd->stmt_map.erase(stmt); + /* + The only way currently a statement can be deallocated when it's + in use is from within Dynamic SQL. + */ + DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); + (void) stmt->deallocate(); + DBUG_VOID_RETURN; } /* - Long data in pieces from client + SQLCOM_DEALLOCATE implementation. + + DESCRIPTION + Close an SQL prepared statement. As this can be called from Dynamic + SQL, we should be careful to not close a statement that is currently + being executed. + + RETURN VALUE + none: OK packet is sent in case of success, otherwise an error + message is set in THD +*/ + +void mysql_sql_stmt_close(THD *thd) +{ + Prepared_statement* stmt; + LEX_STRING *name= &thd->lex->prepared_stmt_name; + DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", name->length, name->str)); + + if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) + { + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), + name->length, name->str, "DEALLOCATE PREPARE"); + return; + } + + if (stmt->deallocate() == 0) + send_ok(thd); +} + +/* + Handle long data in pieces from client. SYNOPSIS mysql_stmt_get_longdata() - thd Thread handle - pos String to append - packet_length Length of string + thd Thread handle + packet String to append + packet_length Length of string (including end \0) DESCRIPTION - Get a part of a long data. - To make the protocol efficient, we are not sending any return packages - here. - If something goes wrong, then we will send the error on 'execute' - - We assume that the client takes care of checking that all parts are sent - to the server. (No checking that we get a 'end of column' in the server) + Get a part of a long data. To make the protocol efficient, we are + not sending any return packets here. If something goes wrong, then + we will send the error on 'execute' We assume that the client takes + care of checking that all parts are sent to the server. (No checking + that we get a 'end of column' in the server is performed). */ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) @@ -2386,13 +2471,12 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) Prepared_statement *stmt; Item_param *param; char *packet_end= packet + packet_length - 1; - DBUG_ENTER("mysql_stmt_get_longdata"); statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status); #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ - if ((ulong) (packet_end - packet) < MYSQL_LONG_DATA_HEADER) + if (packet_length <= MYSQL_LONG_DATA_HEADER) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data"); DBUG_VOID_RETURN; @@ -2436,15 +2520,70 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) } -Prepared_statement::Prepared_statement(THD *thd_arg) +/*************************************************************************** + Select_fetch_protocol_prep +****************************************************************************/ + +Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd) + :protocol(thd) +{} + +bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags) +{ + bool rc; + Protocol *save_protocol= thd->protocol; + + /* + Protocol::send_fields caches the information about column types: + this information is later used to send data. Therefore, the same + dedicated Protocol object must be used for all operations with + a cursor. + */ + thd->protocol= &protocol; + rc= select_send::send_fields(list, flags); + thd->protocol= save_protocol; + + return rc; +} + +bool Select_fetch_protocol_prep::send_eof() +{ + Protocol *save_protocol= thd->protocol; + + thd->protocol= &protocol; + ::send_eof(thd); + thd->protocol= save_protocol; + return FALSE; +} + + +bool +Select_fetch_protocol_prep::send_data(List<Item> &fields) +{ + Protocol *save_protocol= thd->protocol; + bool rc; + + thd->protocol= &protocol; + rc= select_send::send_data(fields); + thd->protocol= save_protocol; + return rc; +} + +/*************************************************************************** + Prepared_statement +****************************************************************************/ + +Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg) :Statement(INITIALIZED, ++thd_arg->statement_id_counter, thd_arg->variables.query_alloc_block_size, thd_arg->variables.query_prealloc_size), thd(thd_arg), - protocol(&thd_arg->protocol_prep), + result(thd_arg), + protocol(protocol_arg), param_array(0), param_count(0), - last_errno(0) + last_errno(0), + flags((uint) IS_IN_USE) { *last_error= '\0'; } @@ -2475,21 +2614,19 @@ void Prepared_statement::setup_set_params() } +/* + DESCRIPTION + Destroy this prepared statement, cleaning up all used memory + and resources. This is called from ::deallocate() to + handle COM_STMT_CLOSE and DEALLOCATE PREPARE or when + THD ends and all prepared statements are freed. +*/ + Prepared_statement::~Prepared_statement() { DBUG_ENTER("Prepared_statement::~Prepared_statement"); DBUG_PRINT("enter",("stmt: %p cursor: %p", this, cursor)); - if (cursor) - { - if (cursor->is_open()) - { - cursor->close(FALSE); - cleanup_items(free_list); - thd->rollback_item_tree_changes(); - free_root(cursor->mem_root, MYF(0)); - } - cursor->Cursor::~Cursor(); - } + delete cursor; /* We have to call free on the items even if cleanup is called as some items, like Item_param, don't free everything until free_items() @@ -2506,24 +2643,282 @@ Query_arena::Type Prepared_statement::type() const } -void Prepared_statement::close_cursor() +void Prepared_statement::cleanup_stmt() { - DBUG_ENTER("Prepared_statement::close_cursor"); + DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: %p", this)); - if (cursor && cursor->is_open()) + /* The order is important */ + lex->unit.cleanup(); + cleanup_items(free_list); + thd->cleanup_after_query(); + close_thread_tables(thd); + thd->rollback_item_tree_changes(); + + DBUG_VOID_RETURN; +} + + +bool Prepared_statement::set_name(LEX_STRING *name_arg) +{ + name.length= name_arg->length; + name.str= memdup_root(mem_root, (char*) name_arg->str, name_arg->length); + return name.str == 0; +} + +/************************************************************************** + Common parts of mysql_[sql]_stmt_prepare, mysql_[sql]_stmt_execute. + Essentially, these functions do all the magic of preparing/executing + a statement, leaving network communication, input data handling and + global THD state management to the caller. +***************************************************************************/ + +/* + Parse statement text, validate the statement, and prepare it for execution. + + SYNOPSIS + Prepared_statement::prepare() + packet statement text + packet_len + + DESCRIPTION + You should not change global THD state in this function, if at all + possible: it may be called from any context, e.g. when executing + a COM_* command, and SQLCOM_* command, or a stored procedure. + + NOTES + Precondition. + ------------- + The caller must ensure that thd->change_list and thd->free_list + is empty: this function will not back them up but will free + in the end of its execution. + + Postcondition. + -------------- + thd->mem_root contains unused memory allocated during validation. +*/ + +bool Prepared_statement::prepare(const char *packet, uint packet_len) +{ + bool error; + Statement stmt_backup; + Query_arena *old_stmt_arena; + DBUG_ENTER("Prepared_statement::prepare"); + /* + If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql. + However, it seems handy if com_stmt_prepare is increased always, + no matter what kind of prepare is processed. + */ + statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status); + + /* + alloc_query() uses thd->memroot && thd->query, so we should call + both of backup_statement() and backup_query_arena() here. + */ + thd->set_n_backup_statement(this, &stmt_backup); + thd->set_n_backup_active_arena(this, &stmt_backup); + + if (alloc_query(thd, packet, packet_len)) { - thd->change_list= cursor->change_list; - cursor->close(FALSE); - cleanup_stmt_and_thd_after_use(this, thd); - free_root(cursor->mem_root, MYF(0)); - if (cursor->close_at_commit) - thd->stmt_map.erase_transient_cursor(this); + thd->restore_backup_statement(this, &stmt_backup); + thd->restore_active_arena(this, &stmt_backup); + DBUG_RETURN(TRUE); } + + old_stmt_arena= thd->stmt_arena; + thd->stmt_arena= this; + lex_start(thd, (uchar*) thd->query, thd->query_length); + lex->safe_to_cache_query= FALSE; + lex->stmt_prepare_mode= TRUE; + + error= yyparse((void *)thd) || thd->is_fatal_error || + thd->net.report_error || init_param_array(this); /* - Clear parameters from data which could be set by - mysql_stmt_send_long_data() call. + While doing context analysis of the query (in check_prepared_statement) + we allocate a lot of additional memory: for open tables, JOINs, derived + tables, etc. Let's save a snapshot of current parse tree to the + statement and restore original THD. In cases when some tree + transformation can be reused on execute, we set again thd->mem_root from + stmt->mem_root (see setup_wild for one place where we do that). */ - reset_stmt_params(this); - DBUG_VOID_RETURN; + thd->restore_active_arena(this, &stmt_backup); + + /* + If called from a stored procedure, ensure that we won't rollback + external changes when cleaning up after validation. + */ + DBUG_ASSERT(thd->change_list.is_empty()); + /* + If the free_list is not empty, we'll wrongly free some externally + allocated items when cleaning up after validation of the prepared + statement. + */ + DBUG_ASSERT(thd->free_list == NULL); + + if (error == 0) + error= check_prepared_statement(this, name.str != 0); + + if (error && lex->sphead) + { + delete lex->sphead; + lex->sphead= NULL; + } + lex_end(lex); + cleanup_stmt(); + thd->restore_backup_statement(this, &stmt_backup); + thd->stmt_arena= old_stmt_arena; + + if (error == 0) + { + setup_set_params(); + init_stmt_after_parse(lex); + state= Query_arena::PREPARED; + flags&= ~ (uint) IS_IN_USE; + } + DBUG_RETURN(error); +} + +/* + Execute a prepared statement. + + SYNOPSIS + Prepared_statement::execute() + expanded_query A query for binlogging which has all parameter + markers ('?') replaced with their actual values. + open_cursor True if an attempt to open a cursor should be made. + Currenlty used only in the binary protocol. + + DESCRIPTION + You should not change global THD state in this function, if at all + possible: it may be called from any context, e.g. when executing + a COM_* command, and SQLCOM_* command, or a stored procedure. + + NOTES + Preconditions, postconditions. + ------------------------------ + See the comment for Prepared_statement::prepare(). + + RETURN + FALSE ok + TRUE Error +*/ + +bool Prepared_statement::execute(String *expanded_query, bool open_cursor) +{ + Statement stmt_backup; + Query_arena *old_stmt_arena; + Item *old_free_list; + bool error= TRUE; + + statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status); + + /* Check if we got an error when sending long data */ + if (state == Query_arena::ERROR) + { + my_message(last_errno, last_error, MYF(0)); + return TRUE; + } + if (flags & (uint) IS_IN_USE) + { + my_error(ER_PS_NO_RECURSION, MYF(0)); + return TRUE; + } + + /* + For SHOW VARIABLES lex->result is NULL, as it's a non-SELECT + command. For such queries we don't return an error and don't + open a cursor -- the client library will recognize this case and + materialize the result set. + For SELECT statements lex->result is created in + check_prepared_statement. lex->result->simple_select() is FALSE + in INSERT ... SELECT and similar commands. + */ + + if (open_cursor && lex->result && !lex->result->simple_select()) + { + DBUG_PRINT("info",("Cursor asked for not SELECT stmt")); + my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0)); + return TRUE; + } + + /* In case the command has a call to SP which re-uses this statement name */ + flags|= IS_IN_USE; + + close_cursor(); + + /* + If the free_list is not empty, we'll wrongly free some externally + allocated items when cleaning up after execution of this statement. + */ + DBUG_ASSERT(thd->change_list.is_empty()); + DBUG_ASSERT(thd->free_list == NULL); + thd->set_n_backup_statement(this, &stmt_backup); + if (expanded_query->length() && + alloc_query(thd, (char*) expanded_query->ptr(), + expanded_query->length()+1)) + { + my_error(ER_OUTOFMEMORY, 0, expanded_query->length()); + goto error; + } + /* + Expanded query is needed for slow logging, so we want thd->query + to point at it even after we restore from backup. This is ok, as + expanded query was allocated in thd->mem_root. + */ + stmt_backup.query= thd->query; + stmt_backup.query_length= thd->query_length; + + /* + At first execution of prepared statement we may perform logical + transformations of the query tree. Such changes should be performed + on the parse tree of current prepared statement and new items should + be allocated in its memory root. Set the appropriate pointer in THD + to the arena of the statement. + */ + old_stmt_arena= thd->stmt_arena; + thd->stmt_arena= this; + reinit_stmt_before_use(thd, lex); + + thd->protocol= protocol; /* activate stmt protocol */ + error= (open_cursor ? + mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, + &result, &cursor) : + mysql_execute_command(thd)); + thd->protocol= &thd->protocol_simple; /* use normal protocol */ + + /* Assert that if an error, no cursor is open */ + DBUG_ASSERT(! (error && cursor)); + + if (! cursor) + { + cleanup_stmt(); + reset_stmt_params(this); + } + + thd->set_statement(&stmt_backup); + thd->stmt_arena= old_stmt_arena; + + if (state == Query_arena::PREPARED) + state= Query_arena::EXECUTED; + +error: + flags&= ~ (uint) IS_IN_USE; + return error; +} + + +/* Common part of DEALLOCATE PREPARE and mysql_stmt_close */ + +bool Prepared_statement::deallocate() +{ + /* We account deallocate in the same manner as mysql_stmt_close */ + statistic_increment(thd->status_var.com_stmt_close, &LOCK_status); + if (flags & (uint) IS_IN_USE) + { + my_error(ER_PS_NO_RECURSION, MYF(0)); + return TRUE; + } + /* Statement map calls delete stmt on erase */ + thd->stmt_map.erase(this); + return FALSE; } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 3880aa428b9..154e828b47e 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -133,11 +133,12 @@ static TABLE_LIST * rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) { TABLE_LIST *ren_table,*new_table; + frm_type_enum frm_type; DBUG_ENTER("rename_tables"); for (ren_table= table_list; ren_table; ren_table= new_table->next_local) { - db_type table_type; + int rc= 1; char name[FN_REFLEN]; const char *new_alias, *old_alias; @@ -164,19 +165,36 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) ren_table->db, old_alias, reg_ext); unpack_filename(name, name); - if ((table_type=get_table_type(thd, name)) == DB_TYPE_UNKNOWN) - { - my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno); - if (!skip_error) - DBUG_RETURN(ren_table); - } - else if (mysql_rename_table(table_type, - ren_table->db, old_alias, - new_table->db, new_alias)) + + frm_type= mysql_frm_type(name); + switch (frm_type) { - if (!skip_error) - DBUG_RETURN(ren_table); + case FRMTYPE_TABLE: + { + db_type table_type; + if ((table_type= get_table_type(thd, name)) == DB_TYPE_UNKNOWN) + my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno); + else + rc= mysql_rename_table(table_type, ren_table->db, old_alias, + new_table->db, new_alias); + break; + } + case FRMTYPE_VIEW: + /* change of schema is not allowed */ + if (strcmp(ren_table->db, new_table->db)) + my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db, + new_table->db); + else + rc= mysql_rename_view(thd, new_alias, ren_table); + break; + default: + DBUG_ASSERT(0); // should never happen + case FRMTYPE_ERROR: + my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno); + break; } + if (rc && !skip_error) + DBUG_RETURN(ren_table); } DBUG_RETURN(0); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 32a8378d41d..b5865fa8816 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -372,6 +372,11 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, goto err; } + /* + Call readers_addref before opening log to track count + of binlog readers + */ + mysql_bin_log.readers_addref(); if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; @@ -569,7 +574,8 @@ impossible position"; goto err; if (!(flags & BINLOG_DUMP_NON_BLOCK) && - mysql_bin_log.is_active(log_file_name)) + mysql_bin_log.is_active(log_file_name) && + !mysql_bin_log.is_reset_pending()) { /* Block until there is more data in the log @@ -683,6 +689,13 @@ impossible position"; { bool loop_breaker = 0; // need this to break out of the for loop from switch + + // if we are going to switch log file anyway, close current log first + end_io_cache(&log); + (void) my_close(file, MYF(MY_WME)); + // decrease reference count of binlog readers + mysql_bin_log.readers_release(); + thd->proc_info = "Finished reading one binlog; switching to next binlog"; switch (mysql_bin_log.find_next_log(&linfo, 1)) { case LOG_INFO_EOF: @@ -691,16 +704,25 @@ impossible position"; case 0: break; default: + // need following call to do release on err label + mysql_bin_log.readers_addref(); errmsg = "could not find next log"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - if (loop_breaker) - break; + if (loop_breaker) + { + // need following call to do release on end label + mysql_bin_log.readers_addref(); + break; + } - end_io_cache(&log); - (void) my_close(file, MYF(MY_WME)); + /* + Call readers_addref before opening log to track count + of binlog readers + */ + mysql_bin_log.readers_addref(); /* Call fake_rotate_event() in case the previous log (the one which @@ -733,6 +755,8 @@ end: end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); + // decrease reference count of binlog readers + mysql_bin_log.readers_release(); send_eof(thd); thd->proc_info = "Waiting to finalize termination"; @@ -759,6 +783,9 @@ err: pthread_mutex_unlock(&LOCK_thread_count); if (file >= 0) (void) my_close(file, MYF(MY_WME)); + // decrease reference count of binlog readers + mysql_bin_log.readers_release(); + my_message(my_errno, errmsg, MYF(0)); DBUG_VOID_RETURN; } @@ -769,7 +796,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) int thread_mask; DBUG_ENTER("start_slave"); - if (check_access(thd, SUPER_ACL, any_db,0,0,0)) + if (check_access(thd, SUPER_ACL, any_db,0,0,0,0)) DBUG_RETURN(1); lock_slave_threads(mi); // this allows us to cleanly read slave_running // Get a mask of _stopped_ threads @@ -894,7 +921,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) if (!thd) thd = current_thd; - if (check_access(thd, SUPER_ACL, any_db,0,0,0)) + if (check_access(thd, SUPER_ACL, any_db,0,0,0,0)) return 1; thd->proc_info = "Killing slave"; int thread_mask; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0b6d63c1446..97d5bf4e1d5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -23,6 +23,7 @@ #include "mysql_priv.h" #include "sql_select.h" +#include "sql_cursor.h" #include <m_ctype.h> #include <hash.h> @@ -107,20 +108,15 @@ static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); static bool open_tmp_table(TABLE *table); static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, ulong options); -static Next_select_func setup_end_select_func(JOIN *join); static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table, Procedure *proc); static enum_nested_loop_state -sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static enum_nested_loop_state evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, int error, my_bool *report_error); static enum_nested_loop_state evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab); static enum_nested_loop_state -sub_select(JOIN *join,JOIN_TAB *join_tab, bool end_of_records); -static enum_nested_loop_state flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last); static enum_nested_loop_state end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); @@ -584,11 +580,11 @@ JOIN::optimize() MEMROOT for prepared statements and stored procedures. */ - Query_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->stmt_arena, backup; if (arena->is_conventional()) arena= 0; // For easier test else - thd->set_n_backup_item_arena(arena, &backup); + thd->set_n_backup_active_arena(arena, &backup); sel->first_cond_optimization= 0; @@ -598,7 +594,7 @@ JOIN::optimize() sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0; if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); } conds= optimize_cond(this, conds, join_list, &cond_value); @@ -758,7 +754,7 @@ JOIN::optimize() } if (group_list || tmp_table_param.sum_func_count) { - if (! hidden_group_fields) + if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) select_distinct=0; } else if (select_distinct && tables - const_tables == 1) @@ -1384,7 +1380,7 @@ JOIN::exec() DBUG_PRINT("info",("Creating group table")); /* Free first data from old join */ - curr_join->join_free(0); + curr_join->join_free(); if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; calc_group_buffer(curr_join, group_list); @@ -1482,7 +1478,7 @@ JOIN::exec() if (curr_tmp_table->distinct) curr_join->select_distinct=0; /* Each row is unique */ - curr_join->join_free(0); /* Free quick selects */ + curr_join->join_free(); /* Free quick selects */ if (curr_join->select_distinct && ! curr_join->group_list) { thd->proc_info="Removing duplicates"; @@ -1719,262 +1715,6 @@ JOIN::destroy() DBUG_RETURN(error); } - -/************************* Cursor ******************************************/ - -Cursor::Cursor(THD *thd) - :Query_arena(&main_mem_root, INITIALIZED), - join(0), unit(0), - protocol(thd), - close_at_commit(FALSE) -{ - /* We will overwrite it at open anyway. */ - init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); - thr_lock_owner_init(&lock_id, &thd->lock_info); - bzero((void*) ht_info, sizeof(ht_info)); -} - - -void -Cursor::init_from_thd(THD *thd) -{ - Engine_info *info; - /* - We need to save and reset thd->mem_root, otherwise it'll be freed - later in mysql_parse. - - We can't just change the thd->mem_root here as we want to keep the - things that are already allocated in thd->mem_root for Cursor::fetch() - */ - main_mem_root= *thd->mem_root; - state= thd->current_arena->state; - /* Allocate new memory root for thd */ - init_sql_alloc(thd->mem_root, - thd->variables.query_alloc_block_size, - thd->variables.query_prealloc_size); - - /* - The same is true for open tables and lock: save tables and zero THD - pointers to prevent table close in close_thread_tables (This is a part - of the temporary solution to make cursors work with minimal changes to - the current source base). - */ - derived_tables= thd->derived_tables; - open_tables= thd->open_tables; - lock= thd->lock; - query_id= thd->query_id; - free_list= thd->free_list; - change_list= thd->change_list; - reset_thd(thd); - /* Now we have an active cursor and can cause a deadlock */ - thd->lock_info.n_cursors++; - - close_at_commit= FALSE; /* reset in case we're reusing the cursor */ - info= &ht_info[0]; - for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++) - { - const handlerton *ht= *pht; - close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); - if (ht->create_cursor_read_view) - { - info->ht= ht; - info->read_view= (ht->create_cursor_read_view)(); - ++info; - } - } - /* - XXX: thd->locked_tables is not changed. - What problems can we have with it if cursor is open? - TODO: must be fixed because of the prelocked mode. - */ -} - - -void -Cursor::reset_thd(THD *thd) -{ - thd->derived_tables= 0; - thd->open_tables= 0; - thd->lock= 0; - thd->free_list= 0; - thd->change_list.empty(); -} - - -int -Cursor::open(JOIN *join_arg) -{ - join= join_arg; - THD *thd= join->thd; - /* First non-constant table */ - JOIN_TAB *join_tab= join->join_tab + join->const_tables; - DBUG_ENTER("Cursor::open"); - - /* - Send fields description to the client; server_status is sent - in 'EOF' packet, which ends send_fields(). - */ - thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; - join->result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS); - ::send_eof(thd); - thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; - - /* Prepare JOIN for reading rows. */ - join->tmp_table= 0; - join->join_tab[join->tables-1].next_select= setup_end_select_func(join); - join->send_records= 0; - join->fetch_limit= join->unit->offset_limit_cnt; - - /* Disable JOIN CACHE as it is not working with cursors yet */ - for (JOIN_TAB *tab= join_tab; - tab != join->join_tab + join->tables - 1; - tab++) - { - if (tab->next_select == sub_select_cache) - tab->next_select= sub_select; - } - - DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0); - DBUG_ASSERT(join_tab->not_used_in_distinct == 0); - /* - null_row is set only if row not found and it's outer join: should never - happen for the first table in join_tab list - */ - DBUG_ASSERT(join_tab->table->null_row == 0); - DBUG_RETURN(0); -} - - -/* - DESCRIPTION - Fetch next num_rows rows from the cursor and sent them to the client - PRECONDITION: - Cursor is open - RETURN VALUES: - none, this function will send error or OK to network if necessary. -*/ - -void -Cursor::fetch(ulong num_rows) -{ - THD *thd= join->thd; - JOIN_TAB *join_tab= join->join_tab + join->const_tables; - enum_nested_loop_state error= NESTED_LOOP_OK; - Query_arena backup_arena; - Engine_info *info; - DBUG_ENTER("Cursor::fetch"); - DBUG_PRINT("enter",("rows: %lu", num_rows)); - - DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 && - thd->lock == 0); - - thd->derived_tables= derived_tables; - thd->open_tables= open_tables; - thd->lock= lock; - thd->query_id= query_id; - thd->change_list= change_list; - /* save references to memory, allocated during fetch */ - thd->set_n_backup_item_arena(this, &backup_arena); - - for (info= ht_info; info->read_view ; info++) - (info->ht->set_cursor_read_view)(info->read_view); - - join->fetch_limit+= num_rows; - - error= sub_select(join, join_tab, 0); - if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) - error= sub_select(join,join_tab,1); - if (error == NESTED_LOOP_QUERY_LIMIT) - error= NESTED_LOOP_OK; /* select_limit used */ - if (error == NESTED_LOOP_CURSOR_LIMIT) - join->resume_nested_loop= TRUE; - -#ifdef USING_TRANSACTIONS - ha_release_temporary_latches(thd); -#endif - /* Grab free_list here to correctly free it in close */ - thd->restore_backup_item_arena(this, &backup_arena); - - for (info= ht_info; info->read_view; info++) - (info->ht->set_cursor_read_view)(0); - - if (error == NESTED_LOOP_CURSOR_LIMIT) - { - /* Fetch limit worked, possibly more rows are there */ - thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; - ::send_eof(thd); - thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; - change_list= thd->change_list; - reset_thd(thd); - } - else - { - close(TRUE); - if (error == NESTED_LOOP_OK) - { - thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; - ::send_eof(thd); - thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT; - } - else if (error != NESTED_LOOP_KILLED) - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - } - DBUG_VOID_RETURN; -} - - -void -Cursor::close(bool is_active) -{ - THD *thd= join->thd; - DBUG_ENTER("Cursor::close"); - - /* - In case of UNIONs JOIN is freed inside of unit->cleanup(), - otherwise in select_lex->cleanup(). - */ - if (unit) - (void) unit->cleanup(); - else - (void) join->select_lex->cleanup(); - - for (Engine_info *info= ht_info; info->read_view; info++) - { - (info->ht->close_cursor_read_view)(info->read_view); - info->read_view= 0; - info->ht= 0; - } - - if (is_active) - close_thread_tables(thd); - else - { - /* XXX: Another hack: closing tables used in the cursor */ - DBUG_ASSERT(lock || open_tables || derived_tables); - - TABLE *tmp_derived_tables= thd->derived_tables; - MYSQL_LOCK *tmp_lock= thd->lock; - - thd->open_tables= open_tables; - thd->derived_tables= derived_tables; - thd->lock= lock; - close_thread_tables(thd); - - thd->open_tables= tmp_derived_tables; - thd->derived_tables= tmp_derived_tables; - thd->lock= tmp_lock; - } - thd->lock_info.n_cursors--; /* Decrease the number of active cursors */ - join= 0; - unit= 0; - free_items(); - change_list.empty(); - DBUG_VOID_RETURN; -} - - -/*********************************************************************/ - /* An entry point to single-unit select (a select without UNION). @@ -2054,9 +1794,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array, } else { - if (join->prepare(rref_pointer_array, tables, wild_num, - conds, og_num, order, group, having, proc_param, - select_lex, unit)) + if (err= join->prepare(rref_pointer_array, tables, wild_num, + conds, og_num, order, group, having, proc_param, + select_lex, unit)) { goto err; } @@ -2071,9 +1811,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array, DBUG_RETURN(TRUE); thd->proc_info="init"; thd->used_tables=0; // Updated by setup_fields - if (join->prepare(rref_pointer_array, tables, wild_num, - conds, og_num, order, group, having, proc_param, - select_lex, unit)) + if (err= join->prepare(rref_pointer_array, tables, wild_num, + conds, og_num, order, group, having, proc_param, + select_lex, unit)) { goto err; } @@ -2115,7 +1855,7 @@ err: if (free_join) { thd->proc_info="end"; - err= select_lex->cleanup(); + err|= select_lex->cleanup(); DBUG_RETURN(err || thd->net.report_error); } DBUG_RETURN(join->error); @@ -2649,7 +2389,6 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, field Field used in comparision eq_func True if we used =, <=> or IS NULL value Value used for comparison with field - Is NULL for BETWEEN and IN usable_tables Tables which can be used for key optimization NOTES @@ -2673,6 +2412,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, !field->table->maybe_null || field->null_ptr) return; // Not a key. Skip it exists_optimize= KEY_OPTIMIZE_EXISTS; + DBUG_ASSERT(num_values == 1); } else { @@ -2724,7 +2464,26 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, eq_func is NEVER true when num_values > 1 */ if (!eq_func) - return; + { + /* + Additional optimization: if we're processing + "t.key BETWEEN c1 AND c1" then proceed as if we were processing + "t.key = c1". + TODO: This is a very limited fix. A more generic fix is possible. + There are 2 options: + A) Make equality propagation code be able to handle BETWEEN + (including cases like t1.key BETWEEN t2.key AND t3.key) + B) Make range optimizer to infer additional "t.key = c" equalities + and use them in equality propagation process (see details in + OptimizerKBAndTodo) + */ + if ((cond->functype() != Item_func::BETWEEN) || + ((Item_func_between*) cond)->negated || + !value[0]->eq(value[1], field->binary())) + return; + eq_func= TRUE; + } + if (field->result_type() == STRING_RESULT) { if ((*value)->result_type() != STRING_RESULT) @@ -2751,7 +2510,6 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, } } } - DBUG_ASSERT(num_values == 1); /* For the moment eq_func is always true. This slot is reserved for future extensions where we want to remembers other things than just eq comparisons @@ -2865,19 +2623,6 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level, if (cond->type() != Item::FUNC_ITEM) return; Item_func *cond_func= (Item_func*) cond; - if (cond_func->functype() == Item_func::NOT_FUNC) - { - Item *item= cond_func->arguments()[0]; - /* - At this moment all NOT before simple comparison predicates - are eliminated. NOT IN and NOT BETWEEN are treated similar - IN and BETWEEN respectively. - */ - if (item->type() == Item::FUNC_ITEM && - ((Item_func *) item)->select_optimize() == Item_func::OPTIMIZE_KEY) - add_key_fields(key_fields,and_level,item,usable_tables); - return; - } switch (cond_func->select_optimize()) { case Item_func::OPTIMIZE_NONE: break; @@ -5977,33 +5722,88 @@ void JOIN_TAB::cleanup() } -void JOIN::join_free(bool full) +/* + Partially cleanup JOIN after it has executed: close index or rnd read + (table cursors), free quick selects. + + DESCRIPTION + This function is called in the end of execution of a JOIN, before the used + tables are unlocked and closed. + + For a join that is resolved using a temporary table, the first sweep is + performed against actual tables and an intermediate result is inserted + into the temprorary table. + The last sweep is performed against the temporary table. Therefore, + the base tables and associated buffers used to fill the temporary table + are no longer needed, and this function is called to free them. + + For a join that is performed without a temporary table, this function + is called after all rows are sent, but before EOF packet is sent. + + For a simple SELECT with no subqueries this function performs a full + cleanup of the JOIN and calls mysql_unlock_read_tables to free used base + tables. + + If a JOIN is executed for a subquery or if it has a subquery, we can't + do the full cleanup and need to do a partial cleanup only. + o If a JOIN is not the top level join, we must not unlock the tables + because the outer select may not have been evaluated yet, and we + can't unlock only selected tables of a query. + + o Additionally, if this JOIN corresponds to a correlated subquery, we + should not free quick selects and join buffers because they will be + needed for the next execution of the correlated subquery. + + o However, if this is a JOIN for a [sub]select, which is not + a correlated subquery itself, but has subqueries, we can free it + fully and also free JOINs of all its subqueries. The exception + is a subquery in SELECT list, e.g: + SELECT a, (select max(b) from t1) group by c + This subquery will not be evaluated at first sweep and its value will + not be inserted into the temporary table. Instead, it's evaluated + when selecting from the temporary table. Therefore, it can't be freed + here even though it's not correlated. +*/ + +void JOIN::join_free() { SELECT_LEX_UNIT *unit; SELECT_LEX *sl; - DBUG_ENTER("JOIN::join_free"); - /* Optimization: if not EXPLAIN and we are done with the JOIN, free all tables. */ - full= full || (!select_lex->uncacheable && !thd->lex->describe); + bool full= (!select_lex->uncacheable && !thd->lex->describe); + bool can_unlock= full; + DBUG_ENTER("JOIN::join_free"); cleanup(full); for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit()) - for (sl= unit->first_select_in_union(); sl; sl= sl->next_select()) + for (sl= unit->first_select(); sl; sl= sl->next_select()) { - JOIN *join= sl->join; - if (join) - join->join_free(full); + Item_subselect *subselect= sl->master_unit()->item; + bool full_local= full && (!subselect || subselect->is_evaluated()); + /* + If this join is evaluated, we can fully clean it up and clean up all + its underlying joins even if they are correlated -- they will not be + used any more anyway. + If this join is not yet evaluated, we still must clean it up to + close its table cursors -- it may never get evaluated, as in case of + ... HAVING FALSE OR a IN (SELECT ...)) + but all table cursors must be closed before the unlock. + */ + sl->cleanup_all_joins(full_local); + /* Can't unlock if at least one JOIN is still needed */ + can_unlock= can_unlock && full_local; } /* We are not using tables anymore Unlock all tables. We may be in an INSERT .... SELECT statement. */ - if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) && + if (can_unlock && lock && thd->lock && + !(select_options & SELECT_NO_UNLOCK) && !select_lex->subquery_in_having && (select_lex == (thd->lex->unit.fake_select_lex ? thd->lex->unit.fake_select_lex : &thd->lex->select_lex))) @@ -6109,7 +5909,7 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab) tab->cached_eq_ref_table=1; if (tab->type == JT_CONST) // We can skip const tables return (tab->eq_ref_table=1); /* purecov: inspected */ - if (tab->type != JT_EQ_REF) + if (tab->type != JT_EQ_REF || tab->table->maybe_null) return (tab->eq_ref_table=0); // We must use this Item **ref_item=tab->ref.items; Item **end=ref_item+tab->ref.key_parts; @@ -6317,7 +6117,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, DBUG_RETURN(0); } - join->join_free(0); + join->join_free(); if (send_row) { @@ -6512,6 +6312,21 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal) { Item *left_item= ((Item_func*) item)->arguments()[0]; Item *right_item= ((Item_func*) item)->arguments()[1]; + + if (left_item->type() == Item::REF_ITEM && + ((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF) + { + if (((Item_ref*)left_item)->depended_from) + return FALSE; + left_item= left_item->real_item(); + } + if (right_item->type() == Item::REF_ITEM && + ((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF) + { + if (((Item_ref*)right_item)->depended_from) + return FALSE; + right_item= right_item->real_item(); + } if (left_item->type() == Item::FIELD_ITEM && right_item->type() == Item::FIELD_ITEM && !((Item_field*)left_item)->depended_from && @@ -8057,11 +7872,15 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, bool table_cant_handle_bit_fields, uint convert_blob_length) { + Item::Type orig_type= type; + Item *orig_item; + if (type != Item::FIELD_ITEM && item->real_item()->type() == Item::FIELD_ITEM && (item->type() != Item::REF_ITEM || !((Item_ref *) item)->depended_from)) { + orig_item= item; item= item->real_item(); type= Item::FIELD_ITEM; } @@ -8078,29 +7897,40 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::DEFAULT_VALUE_ITEM: { Item_field *field= (Item_field*) item; + bool orig_modify= modify_item; + Field *result; + if (orig_type == Item::REF_ITEM) + modify_item= 0; /* If item have to be able to store NULLs but underlaid field can't do it, create_tmp_field_from_field() can't be used for tmp field creation. */ if (field->maybe_null && !field->field->maybe_null()) { - Field *res= create_tmp_field_from_item(thd, item, table, NULL, - modify_item, convert_blob_length); + result= create_tmp_field_from_item(thd, item, table, NULL, + modify_item, convert_blob_length); *from_field= field->field; - if (res && modify_item) - ((Item_field*)item)->result_field= res; - return res; - } - - if (table_cant_handle_bit_fields && - field->field->type() == FIELD_TYPE_BIT) - return create_tmp_field_from_item(thd, item, table, copy_func, + if (result && modify_item) + field->result_field= result; + } + else if (table_cant_handle_bit_fields && field->field->type() == + FIELD_TYPE_BIT) + { + *from_field= field->field; + result= create_tmp_field_from_item(thd, item, table, copy_func, modify_item, convert_blob_length); - return create_tmp_field_from_field(thd, (*from_field= field->field), + if (result && modify_item) + field->result_field= result; + } + else + result= create_tmp_field_from_field(thd, (*from_field= field->field), item->name, table, - modify_item ? (Item_field*) item : + modify_item ? field : NULL, convert_blob_length); + if (orig_type == Item::REF_ITEM && orig_modify) + ((Item_ref*)orig_item)->set_result_field(result); + return result; } /* Fall through */ case Item::FUNC_ITEM: @@ -8129,9 +7959,31 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, /* Create a temp table according to a field list. - Set distinct if duplicates could be removed - Given fields field pointers are changed to point at tmp_table - for send_fields + + SYNOPSIS + create_tmp_table() + thd thread handle + param a description used as input to create the table + fields list of items that will be used to define + column types of the table (also see NOTES) + group TODO document + distinct should table rows be distinct + save_sum_fields see NOTES + select_options + rows_limit + table_alias possible name of the temporary table that can be used + for name resolving; can be "". + + DESCRIPTION + Given field pointers are changed to point at tmp_table for + send_fields. The table object is self contained: it's + allocated in its own memory root, as well as Field objects + created for table columns. + This function will replace Item_sum items in 'fields' list with + corresponding Item_field items, pointing at the fields in the + temporary table, unless this was prohibited by TRUE + value of argument save_sum_fields. The Item_field objects + are created in THD memory root. */ #define STRING_TOTAL_LENGTH_TO_PACK_ROWS 128 @@ -8145,6 +7997,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ulonglong select_options, ha_rows rows_limit, char *table_alias) { + MEM_ROOT *mem_root_save, own_root; TABLE *table; uint i,field_count,null_count,null_pack_length; uint hidden_null_count, hidden_null_pack_length, hidden_field_count; @@ -8209,29 +8062,33 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, field_count=param->field_count+param->func_count+param->sum_func_count; hidden_field_count=param->hidden_field_count; - if (!my_multi_malloc(MYF(MY_WME), - &table,sizeof(*table), - ®_field, sizeof(Field*)*(field_count+1), - &blob_field, sizeof(uint)*(field_count+1), - &from_field, sizeof(Field*)*field_count, - ©_func,sizeof(*copy_func)*(param->func_count+1), - ¶m->keyinfo,sizeof(*param->keyinfo), - &key_part_info, - sizeof(*key_part_info)*(param->group_parts+1), - ¶m->start_recinfo, - sizeof(*param->recinfo)*(field_count*2+4), - &tmpname,(uint) strlen(path)+1, - &group_buff,group && ! using_unique_constraint ? - param->group_length : 0, - NullS)) + + init_sql_alloc(&own_root, TABLE_ALLOC_BLOCK_SIZE, 0); + + if (!multi_alloc_root(&own_root, + &table, sizeof(*table), + ®_field, sizeof(Field*) * (field_count+1), + &blob_field, sizeof(uint)*(field_count+1), + &from_field, sizeof(Field*)*field_count, + ©_func, sizeof(*copy_func)*(param->func_count+1), + ¶m->keyinfo, sizeof(*param->keyinfo), + &key_part_info, + sizeof(*key_part_info)*(param->group_parts+1), + ¶m->start_recinfo, + sizeof(*param->recinfo)*(field_count*2+4), + &tmpname, (uint) strlen(path)+1, + &group_buff, group && ! using_unique_constraint ? + param->group_length : 0, + NullS)) { bitmap_clear_bit(&temp_pool, temp_pool_slot); DBUG_RETURN(NULL); /* purecov: inspected */ } - if (!(param->copy_field=copy=new Copy_field[field_count])) + /* Copy_field belongs to TMP_TABLE_PARAM, allocate it in THD mem_root */ + if (!(param->copy_field= copy= new (thd->mem_root) Copy_field[field_count])) { bitmap_clear_bit(&temp_pool, temp_pool_slot); - my_free((gptr) table,MYF(0)); /* purecov: inspected */ + free_root(&own_root, MYF(0)); /* purecov: inspected */ DBUG_RETURN(NULL); /* purecov: inspected */ } param->items_to_copy= copy_func; @@ -8241,6 +8098,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, bzero((char*) table,sizeof(*table)); bzero((char*) reg_field,sizeof(Field*)*(field_count+1)); bzero((char*) from_field,sizeof(Field*)*field_count); + + table->mem_root= own_root; + mem_root_save= thd->mem_root; + thd->mem_root= &table->mem_root; + table->field=reg_field; table->alias= table_alias; table->reginfo.lock_type=TL_WRITE; /* Will be updated */ @@ -8306,7 +8168,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, Field *new_field= create_tmp_field(thd, table, arg, arg->type(), ©_func, tmp_from_field, group != 0,not_all_columns, - group || distinct, + distinct, param->convert_blob_length); if (!new_field) goto err; // Should be OOM @@ -8317,6 +8179,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, *blob_field++= (uint) (reg_field - table->field); blob_count++; } + if (new_field->type() == FIELD_TYPE_BIT) + total_uneven_bit_length+= new_field->field_length & 7; new_field->field_index= (uint) (reg_field - table->field); *(reg_field++)= new_field; if (new_field->real_type() == MYSQL_TYPE_STRING || @@ -8325,7 +8189,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, string_count++; string_total_length+= new_field->pack_length(); } + thd->mem_root= mem_root_save; thd->change_item_tree(argp, new Item_field(new_field)); + thd->mem_root= &table->mem_root; if (!(new_field->flags & NOT_NULL_FLAG)) { null_count++; @@ -8350,12 +8216,16 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, write rows to the temporary table. We here distinguish between UNION and multi-table-updates by the fact that in the later case group is set to the row pointer. + + The test for item->marker == 4 is ensure we don't create a group-by + key over a bit field as heap tables can't handle that. */ Field *new_field= (param->schema_table) ? create_tmp_field_for_schema(thd, item, table) : create_tmp_field(thd, table, item, type, ©_func, tmp_from_field, group != 0, - not_all_columns || group != 0, 0, + not_all_columns || group != 0, + item->marker == 4, param->convert_blob_length); if (!new_field) @@ -8387,7 +8257,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, *(reg_field++) =new_field; } if (!--hidden_field_count) + { + /* + This was the last hidden field; Remember how many hidden fields could + have null + */ hidden_null_count=null_count; + null_count= 0; + } } DBUG_ASSERT(field_count >= (uint) (reg_field - table->field)); field_count= (uint) (reg_field - table->field); @@ -8422,8 +8299,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, null_count++; } hidden_null_pack_length=(hidden_null_count+7)/8; - null_pack_length= hidden_null_count + - (null_count + total_uneven_bit_length + 7) / 8; + null_pack_length= (hidden_null_pack_length + + (null_count + total_uneven_bit_length + 7) / 8); reclength+=null_pack_length; if (!reclength) reclength=1; // Dummy select @@ -8439,7 +8316,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, { uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1); table->s->rec_buff_length= alloc_length; - if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME)))) + if (!(table->record[0]= (byte*) + alloc_root(&table->mem_root, alloc_length*3))) goto err; table->record[1]= table->record[0]+alloc_length; table->s->default_values= table->record[1]+alloc_length; @@ -8625,8 +8503,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, table->s->uniques= 1; } if (!(key_part_info= (KEY_PART_INFO*) - sql_calloc((keyinfo->key_parts)*sizeof(KEY_PART_INFO)))) + alloc_root(&table->mem_root, + keyinfo->key_parts * sizeof(KEY_PART_INFO)))) goto err; + bzero((void*) key_part_info, keyinfo->key_parts * sizeof(KEY_PART_INFO)); table->key_info=keyinfo; keyinfo->key_part=key_part_info; keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL; @@ -8674,10 +8554,15 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, if (create_myisam_tmp_table(table,param,select_options)) goto err; } - if (!open_tmp_table(table)) - DBUG_RETURN(table); + if (open_tmp_table(table)) + goto err; - err: + thd->mem_root= mem_root_save; + + DBUG_RETURN(table); + +err: + thd->mem_root= mem_root_save; free_tmp_table(thd,table); /* purecov: inspected */ bitmap_clear_bit(&temp_pool, temp_pool_slot); DBUG_RETURN(NULL); /* purecov: inspected */ @@ -8822,11 +8707,12 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, if (table->s->keys) { // Get keys for ni_create bool using_unique_constraint=0; - HA_KEYSEG *seg= (HA_KEYSEG*) sql_calloc(sizeof(*seg) * - keyinfo->key_parts); + HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root, + sizeof(*seg) * keyinfo->key_parts); if (!seg) goto err; + bzero(seg, sizeof(*seg) * keyinfo->key_parts); if (keyinfo->key_length >= table->file->max_key_length() || keyinfo->key_parts > table->file->max_key_parts() || table->s->uniques) @@ -8923,13 +8809,14 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, void free_tmp_table(THD *thd, TABLE *entry) { + MEM_ROOT own_root= entry->mem_root; const char *save_proc_info; DBUG_ENTER("free_tmp_table"); DBUG_PRINT("enter",("table: %s",entry->alias)); save_proc_info=thd->proc_info; thd->proc_info="removing tmp table"; - free_blobs(entry); + if (entry->file) { if (entry->db_stat) @@ -8950,12 +8837,11 @@ free_tmp_table(THD *thd, TABLE *entry) /* free blobs */ for (Field **ptr=entry->field ; *ptr ; ptr++) (*ptr)->free(); - my_free((gptr) entry->record[0],MYF(0)); free_io_cache(entry); bitmap_clear_bit(&temp_pool, entry->temp_pool_slot); - my_free((gptr) entry,MYF(0)); + free_root(&own_root, MYF(0)); /* the table is allocated in its own root */ thd->proc_info=save_proc_info; DBUG_VOID_RETURN; @@ -9070,7 +8956,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, end_select function to use. This function can't fail. */ -static Next_select_func setup_end_select_func(JOIN *join) +Next_select_func setup_end_select_func(JOIN *join) { TABLE *table= join->tmp_table; Next_select_func end_select; @@ -9191,7 +9077,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) The following will unlock all cursors if the command wasn't an update command */ - join->join_free(0); // Unlock all cursors + join->join_free(); // Unlock all cursors if (join->result->send_eof()) rc= 1; // Don't send error } @@ -9225,7 +9111,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) } -static enum_nested_loop_state +enum_nested_loop_state sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) { enum_nested_loop_state rc; @@ -9366,7 +9252,7 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS. */ -static enum_nested_loop_state +enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) { join_tab->table->null_row=0; @@ -11527,7 +11413,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, ulong total_length= 0; for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++) { - uint length= (*ptr)->pack_length(); + uint length= (*ptr)->sort_length(); (*field_length++)= length; total_length+= length; } @@ -12067,11 +11953,16 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, We check order_item->fixed because Item_func_group_concat can put arguments for which fix_fields already was called. */ + thd->lex->current_select->is_item_list_lookup= 1; if (!order_item->fixed && (order_item->fix_fields(thd, order->item) || (order_item= *order->item)->check_cols(1) || thd->is_fatal_error)) + { + thd->lex->current_select->is_item_list_lookup= 0; return TRUE; /* Wrong field. */ + } + thd->lex->current_select->is_item_list_lookup= 0; uint el= all_fields.elements; all_fields.push_front(order_item); /* Add new field to field list. */ @@ -12385,6 +12276,11 @@ calc_group_buffer(JOIN *join,ORDER *group) key_length+=MAX_BLOB_WIDTH; // Can't be used as a key else if (field->type() == MYSQL_TYPE_VARCHAR) key_length+= field->field_length + HA_KEY_BLOB_LENGTH; + else if (field->type() == FIELD_TYPE_BIT) + { + /* Bit is usually stored as a longlong key for group fields */ + key_length+= 8; // Big enough + } else key_length+= field->pack_length(); } @@ -13049,6 +12945,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) The function replaces occurrences of group by fields in expr by ref objects for these fields unless they are under aggregate functions. + The function also corrects value of the the maybe_null attribute + for the items of all subexpressions containing group by fields. IMPLEMENTATION The function recursively traverses the tree of the expr expression, @@ -13059,6 +12957,9 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) This substitution is needed GROUP BY queries with ROLLUP if SELECT list contains expressions over group by attributes. + TODO: Some functions are not null-preserving. For those functions + updating of the maybe_null attribute is an overkill. + EXAMPLES SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP @@ -13075,6 +12976,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, { Name_resolution_context *context= &thd->lex->current_select->context; Item **arg,**arg_end; + bool arg_changed= FALSE; for (arg= expr->arguments(), arg_end= expr->arguments()+expr->arg_count; arg != arg_end; arg++) @@ -13092,16 +12994,21 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); - *changed= TRUE; + arg_changed= TRUE; } } } else if (item->type() == Item::FUNC_ITEM) { - if (change_group_ref(thd, (Item_func *) item, group_list, changed)) + if (change_group_ref(thd, (Item_func *) item, group_list, &arg_changed)) return 1; } } + if (arg_changed) + { + expr->maybe_null= 1; + *changed= TRUE; + } } return 0; } @@ -13163,7 +13070,7 @@ bool JOIN::rollup_init() } if (item->type() == Item::FUNC_ITEM) { - bool changed= 0; + bool changed= FALSE; if (change_group_ref(thd, (Item_func *) item, group_list, &changed)) return 1; /* @@ -13778,8 +13685,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization unit->fake_select_lex->type= "UNION RESULT"; unit->fake_select_lex->options|= SELECT_DESCRIBE; - if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE, - ""))) + if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE))) res= unit->exec(); res|= unit->cleanup(); } @@ -13871,13 +13777,20 @@ void st_table_list::print(THD *thd, String *str) const char *cmp_name; // Name to compare with alias if (view_name.str) { - append_identifier(thd, str, view_db.str, view_db.length); - str->append('.'); + // A view + + if (!(belong_to_view && + belong_to_view->compact_view_format)) + { + append_identifier(thd, str, view_db.str, view_db.length); + str->append('.'); + } append_identifier(thd, str, view_name.str, view_name.length); cmp_name= view_name.str; } else if (derived) { + // A derived table str->append('('); derived->print(str); str->append(')'); @@ -13885,8 +13798,14 @@ void st_table_list::print(THD *thd, String *str) } else { - append_identifier(thd, str, db, db_length); - str->append('.'); + // A normal table + + if (!(belong_to_view && + belong_to_view->compact_view_format)) + { + append_identifier(thd, str, db, db_length); + str->append('.'); + } if (schema_table) { append_identifier(thd, str, schema_table_name, diff --git a/sql/sql_select.h b/sql/sql_select.h index 78fa88801be..d6161eb6372 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -101,7 +101,7 @@ enum enum_nested_loop_state typedef enum_nested_loop_state (*Next_select_func)(JOIN *, struct st_join_table *, bool); typedef int (*Read_record_func)(struct st_join_table *tab); - +Next_select_func setup_end_select_func(JOIN *join); typedef struct st_join_table { TABLE *table; @@ -140,6 +140,11 @@ typedef struct st_join_table { void cleanup(); } JOIN_TAB; +enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool + end_of_records); +enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool + end_of_records); + typedef struct st_position /* Used in find_best */ { @@ -230,7 +235,7 @@ class JOIN :public Sql_alloc /* Is set if we have a GROUP BY and we have ORDER BY on a constant. */ bool skip_sort_order; - bool need_tmp, hidden_group_fields, buffer_result; + bool need_tmp, hidden_group_fields; DYNAMIC_ARRAY keyuse; Item::cond_result cond_value; List<Item> all_fields; // to store all fields that used in query @@ -299,8 +304,6 @@ class JOIN :public Sql_alloc skip_sort_order= 0; need_tmp= 0; hidden_group_fields= 0; /*safety*/ - buffer_result= test(select_options & OPTION_BUFFER_RESULT) && - !test(select_options & OPTION_FOUND_ROWS); error= 0; select= 0; return_tab= 0; @@ -355,7 +358,7 @@ class JOIN :public Sql_alloc the end of execution in order to increase concurrency and reduce memory consumption. */ - void join_free(bool full); + void join_free(); /* Cleanup this JOIN, possibly for reuse */ void cleanup(bool full); void clear(); @@ -374,58 +377,6 @@ class JOIN :public Sql_alloc }; -/* - Server-side cursor (now stands only for basic read-only cursor) - See class implementation in sql_select.cc - A cursor has its own runtime state - list of used items and memory root of - used memory - which is different from Prepared statement runtime: it must - be different at least for the purpose of reusing the same prepared - statement for many cursors. -*/ - -class Cursor: public Sql_alloc, public Query_arena -{ - MEM_ROOT main_mem_root; - JOIN *join; - SELECT_LEX_UNIT *unit; - - TABLE *open_tables; - MYSQL_LOCK *lock; - TABLE *derived_tables; - /* List of items created during execution */ - query_id_t query_id; - struct Engine_info - { - const handlerton *ht; - void *read_view; - }; - Engine_info ht_info[MAX_HA]; -public: - Protocol_prep protocol; - Item_change_list change_list; - select_send result; - THR_LOCK_OWNER lock_id; - my_bool close_at_commit; - - /* Temporary implementation as now we replace THD state by value */ - /* Save THD state into cursor */ - void init_from_thd(THD *thd); - /* bzero cursor state in THD */ - void reset_thd(THD *thd); - - int open(JOIN *join); - void fetch(ulong num_rows); - void reset() { join= 0; } - bool is_open() const { return join != 0; } - - void close(bool is_active); - - void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } - Cursor(THD *thd); - ~Cursor() {} -}; - - typedef struct st_select_check { uint const_ref,reg_ref; } SELECT_CHECK; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f75d035e46c..e1d3c7d6d33 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -42,7 +42,7 @@ static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), static int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet); static int -view_store_create_info(THD *thd, TABLE_LIST *table, String *packet); +view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); static bool schema_table_store_record(THD *thd, TABLE *table); @@ -67,18 +67,18 @@ bool mysqld_show_storage_engines(THD *thd) const char *default_type_name= ha_get_storage_engine((enum db_type)thd->variables.table_type); - show_table_type_st *types; - for (types= sys_table_types; types->type; types++) + handlerton **types; + for (types= sys_table_types; *types; types++) { protocol->prepare_for_resend(); - protocol->store(types->type, system_charset_info); - const char *option_name= show_comp_option_name[(int) *types->value]; + protocol->store((*types)->name, system_charset_info); + const char *option_name= show_comp_option_name[(int) (*types)->state]; - if (*types->value == SHOW_OPTION_YES && - !my_strcasecmp(system_charset_info, default_type_name, types->type)) + if ((*types)->state == SHOW_OPTION_YES && + !my_strcasecmp(system_charset_info, default_type_name, (*types)->name)) option_name= "DEFAULT"; protocol->store(option_name, system_charset_info); - protocol->store(types->comment, system_charset_info); + protocol->store((*types)->comment, system_charset_info); if (protocol->write()) DBUG_RETURN(TRUE); } @@ -347,7 +347,6 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, bool mysqld_show_create(THD *thd, TABLE_LIST *table_list) { - TABLE *table; Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); @@ -360,9 +359,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* Only one table for now, but VIEW can involve several tables */ if (open_normal_and_derived_tables(thd, table_list, 0)) - { DBUG_RETURN(TRUE); - } + /* TODO: add environment variables show when it become possible */ if (thd->lex->only_view && !table_list->view) { @@ -371,8 +369,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(TRUE); } - table= table_list->table; - + buffer.length(0); if ((table_list->view ? view_store_create_info(thd, table_list, &buffer) : store_create_info(thd, table_list, &buffer))) @@ -397,22 +394,15 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); protocol->prepare_for_resend(); - buffer.length(0); if (table_list->view) - { protocol->store(table_list->view_name.str, system_charset_info); - if (view_store_create_info(thd, table_list, &buffer)) - DBUG_RETURN(TRUE); - } else { if (table_list->schema_table) protocol->store(table_list->schema_table->table_name, system_charset_info); else - protocol->store(table->alias, system_charset_info); - if (store_create_info(thd, table_list, &buffer)) - DBUG_RETURN(TRUE); + protocol->store(table_list->table->alias, system_charset_info); } protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); @@ -425,8 +415,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create_info) { + Security_context *sctx= thd->security_ctx; int length; - char path[FN_REFLEN]; + char path[FN_REFLEN]; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -445,17 +436,17 @@ bool mysqld_show_create_db(THD *thd, char *dbname, } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (test_all_bits(thd->master_access,DB_ACLS)) + if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); + db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | + sctx->master_access); if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, thd->host_or_ip, dbname); + sctx->priv_user, sctx->host_or_ip, dbname); mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, thd->host_or_ip, dbname); + sctx->priv_user, sctx->host_or_ip, dbname); DBUG_RETURN(TRUE); } #endif @@ -803,7 +794,8 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) field->sql_type(type); packet->append(type.ptr(), type.length(), system_charset_info); - if (field->has_charset() && !limited_mysql_mode && !foreign_db_mode) + if (field->has_charset() && + !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))) { if (field->charset() != share->table_charset) { @@ -842,7 +834,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) has_default= (field->type() != FIELD_TYPE_BLOB && !(field->flags & NO_DEFAULT_VALUE_FLAG) && field->unireg_check != Field::NEXT_NUMBER && - !((foreign_db_mode || limited_mysql_mode) && + !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_now_default)); if (has_default) @@ -872,12 +864,13 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) packet->append(tmp); } - if (!foreign_db_mode && !limited_mysql_mode && + if (!(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS) && table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD) packet->append(" on update CURRENT_TIMESTAMP",28); - if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode) + if (field->unireg_check == Field::NEXT_NUMBER && + !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS)) packet->append(" auto_increment", 15 ); if (field->comment.length) @@ -1030,6 +1023,11 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) packet->append(" COMMENT=", 9); append_unescaped(packet, share->comment, strlen(share->comment)); } + if (share->connect_string.length) + { + packet->append(" CONNECTION=", 12); + append_unescaped(packet, share->connect_string.str, share->connect_string.length); + } if (file->raid_type) { uint length; @@ -1045,6 +1043,34 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) DBUG_RETURN(0); } +void +view_store_options(THD *thd, TABLE_LIST *table, String *buff) +{ + buff->append("ALGORITHM=", 10); + switch ((int8)table->algorithm) { + case VIEW_ALGORITHM_UNDEFINED: + buff->append("UNDEFINED ", 10); + break; + case VIEW_ALGORITHM_TMPTABLE: + buff->append("TEMPTABLE ", 10); + break; + case VIEW_ALGORITHM_MERGE: + buff->append("MERGE ", 6); + break; + default: + DBUG_ASSERT(0); // never should happen + } + buff->append("DEFINER=", 8); + append_identifier(thd, buff, + table->definer.user.str, table->definer.user.length); + buff->append('@'); + append_identifier(thd, buff, + table->definer.host.str, table->definer.host.length); + if (table->view_suid) + buff->append(" SQL SECURITY DEFINER ", 22); + else + buff->append(" SQL SECURITY INVOKER ", 22); +} static int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) @@ -1055,28 +1081,40 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) MODE_DB2 | MODE_MAXDB | MODE_ANSI)) != 0; - buff->append("CREATE ", 7); - if (!foreign_db_mode) + /* + Compact output format for view can be used + - if user has db of this view as current db + - if this view only references table inside it's own db + */ + if (!thd->db || strcmp(thd->db, table->view_db.str)) + table->compact_view_format= FALSE; + else { - buff->append("ALGORITHM=", 10); - switch((int8)table->algorithm) + TABLE_LIST *tbl; + table->compact_view_format= TRUE; + for (tbl= thd->lex->query_tables; + tbl; + tbl= tbl->next_global) { - case VIEW_ALGORITHM_UNDEFINED: - buff->append("UNDEFINED ", 10); - break; - case VIEW_ALGORITHM_TMPTABLE: - buff->append("TEMPTABLE ", 10); - break; - case VIEW_ALGORITHM_MERGE: - buff->append("MERGE ", 6); - break; - default: - DBUG_ASSERT(0); // never should happen + if (strcmp(table->view_db.str, tbl->view ? tbl->view_db.str :tbl->db)!= 0) + { + table->compact_view_format= FALSE; + break; + } } } + + buff->append("CREATE ", 7); + if (!foreign_db_mode) + { + view_store_options(thd, table, buff); + } buff->append("VIEW ", 5); - append_identifier(thd, buff, table->view_db.str, table->view_db.length); - buff->append('.'); + if (!table->compact_view_format) + { + append_identifier(thd, buff, table->view_db.str, table->view_db.length); + buff->append('.'); + } append_identifier(thd, buff, table->view_name.str, table->view_name.length); buff->append(" AS ", 4); @@ -1155,24 +1193,26 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) THD *tmp; while ((tmp=it++)) { + Security_context *tmp_sctx= tmp->security_ctx; struct st_my_thread_var *mysys_var; if ((tmp->vio_ok() || tmp->system_thread) && - (!user || (tmp->user && !strcmp(tmp->user,user)))) + (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user)))) { - thread_info *thd_info=new thread_info; + thread_info *thd_info= new thread_info; thd_info->thread_id=tmp->thread_id; - thd_info->user=thd->strdup(tmp->user ? tmp->user : - (tmp->system_thread ? - "system user" : "unauthenticated user")); - if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0]) + thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user : + (tmp->system_thread ? + "system user" : "unauthenticated user")); + if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) && + thd->security_ctx->host_or_ip[0]) { if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1))) my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN, - "%s:%u", tmp->host_or_ip, tmp->peer_port); + "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port); } else - thd_info->host= thd->strdup(tmp->host_or_ip); + thd_info->host= thd->strdup(tmp_sctx->host_or_ip); if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); thd_info->command=(int) tmp->command; @@ -1598,6 +1638,10 @@ static bool show_status_array(THD *thd, const char *wild, value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache; end= int10_to_str(*(long*) value, buff, 10); break; + case SHOW_KEY_CACHE_LONGLONG: + value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache; + end= longlong10_to_str(*(longlong*) value, buff, 10); + break; case SHOW_UNDEF: // Show never happen case SHOW_SYS: break; // Return empty string @@ -1955,7 +1999,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) enum enum_schema_tables schema_table_idx; List<char> bases; List_iterator_fast<char> it(bases); - COND *partial_cond; + COND *partial_cond; + Security_context *sctx= thd->security_ctx; uint derived_tables= lex->derived_tables; int error= 1; Open_tables_state open_tables_state_backup; @@ -1988,10 +2033,20 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) /* get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() + + We should use show_table_list->alias instead of + show_table_list->table_name because table_name + could be changed during opening of I_S tables. It's safe + to use alias because alias contains original table name + in this case(this part of code is used only for + 'show columns' & 'show statistics' commands). */ error= test(schema_table->process_table(thd, show_table_list, - table, res, show_table_list->db, - show_table_list->alias)); + table, res, + (show_table_list->view ? + show_table_list->view_db.str : + show_table_list->db), + show_table_list->alias)); close_thread_tables(thd); show_table_list->table= 0; goto err; @@ -2015,10 +2070,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) (base_name= select_lex->db) && !bases.elements)) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (with_i_schema || // don't check the rights if information schema db - !check_access(thd,SELECT_ACL, base_name, &thd->col_access,0,1) || - thd->master_access & (DB_ACLS | SHOW_DB_ACL) || - acl_get(thd->host, thd->ip, thd->priv_user, base_name,0) || + if (!check_access(thd,SELECT_ACL, base_name, + &thd->col_access, 0, 1, with_i_schema) || + sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || + acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) || (grant_option && !check_grant_db(thd, base_name))) #endif { @@ -2092,6 +2147,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) lex->derived_tables= 0; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); + /* + We should use show_table_list->alias instead of + show_table_list->table_name because table_name + could be changed during opening of I_S tables. It's safe + to use alias because alias contains original table name + in this case. + */ res= schema_table->process_table(thd, show_table_list, table, res, base_name, show_table_list->alias); @@ -2143,6 +2205,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) bool with_i_schema; HA_CREATE_INFO create; TABLE *table= tables->table; + Security_context *sctx= thd->security_ctx; DBUG_ENTER("fill_schema_shemata"); if (make_db_list(thd, &files, &idx_field_vals, @@ -2161,8 +2224,8 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) continue; } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) || - acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) || + if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || + acl_get(sctx->host, sctx->ip, sctx->priv_user, file_name,0) || (grant_option && !check_grant_db(thd, file_name))) #endif { @@ -2238,7 +2301,7 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, } tmp_buff= file->table_type(); table->field[4]->store(tmp_buff, strlen(tmp_buff), cs); - table->field[5]->store((longlong) share->frm_version); + table->field[5]->store((longlong) share->frm_version, TRUE); enum row_type row_type = file->get_row_type(); switch (row_type) { case ROW_TYPE_NOT_USED: @@ -2267,20 +2330,20 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, table->field[6]->store(tmp_buff, strlen(tmp_buff), cs); if (!tables->schema_table) { - table->field[7]->store((longlong) file->records); + table->field[7]->store((longlong) file->records, TRUE); table->field[7]->set_notnull(); } - table->field[8]->store((longlong) file->mean_rec_length); - table->field[9]->store((longlong) file->data_file_length); + table->field[8]->store((longlong) file->mean_rec_length, TRUE); + table->field[9]->store((longlong) file->data_file_length, TRUE); if (file->max_data_file_length) { - table->field[10]->store((longlong) file->max_data_file_length); + table->field[10]->store((longlong) file->max_data_file_length, TRUE); } - table->field[11]->store((longlong) file->index_file_length); - table->field[12]->store((longlong) file->delete_length); + table->field[11]->store((longlong) file->index_file_length, TRUE); + table->field[12]->store((longlong) file->delete_length, TRUE); if (show_table->found_next_number_field) { - table->field[13]->store((longlong) file->auto_increment_value); + table->field[13]->store((longlong) file->auto_increment_value, TRUE); table->field[13]->set_notnull(); } if (file->create_time) @@ -2308,7 +2371,7 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, table->field[17]->store(tmp_buff, strlen(tmp_buff), cs); if (file->table_flags() & (ulong) HA_HAS_CHECKSUM) { - table->field[18]->store((longlong) file->checksum()); + table->field[18]->store((longlong) file->checksum(), TRUE); table->field[18]->set_notnull(); } @@ -2431,7 +2494,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, #ifndef NO_EMBEDDED_ACCESS_CHECKS uint col_access; check_access(thd,SELECT_ACL | EXTRA_ACL, base_name, - &tables->grant.privilege, 0, 0); + &tables->grant.privilege, 0, 0, test(tables->schema_table)); col_access= get_column_grant(thd, &tables->grant, base_name, file_name, field->field_name) & COL_ACLS; @@ -2447,19 +2510,14 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, end=strmov(end,grant_types.type_names[bitnr]); } } - if (tables->schema_table) // any user has 'select' privilege on all - // I_S table columns - table->field[17]->store(grant_types.type_names[0], - strlen(grant_types.type_names[0]), cs); - else - table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs); + table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs); #endif table->field[1]->store(base_name, base_name_length, cs); table->field[2]->store(file_name, file_name_length, cs); table->field[3]->store(field->field_name, strlen(field->field_name), cs); - table->field[4]->store((longlong) count); + table->field[4]->store((longlong) count, TRUE); field->sql_type(type); table->field[14]->store(type.ptr(), type.length(), cs); tmp_buff= strchr(type.ptr(), '('); @@ -2503,9 +2561,9 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, { longlong c_octet_len= is_blob ? (longlong) field->max_length() : (longlong) field->max_length()/field->charset()->mbmaxlen; - table->field[8]->store(c_octet_len); + table->field[8]->store((longlong) field->max_length(), TRUE); table->field[8]->set_notnull(); - table->field[9]->store((longlong) field->max_length()); + table->field[9]->store(c_octet_len, TRUE); table->field[9]->set_notnull(); } @@ -2546,12 +2604,12 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, if (field_length >= 0) { - table->field[10]->store((longlong) field_length); + table->field[10]->store((longlong) field_length, TRUE); table->field[10]->set_notnull(); } if (decimals >= 0) { - table->field[11]->store((longlong) decimals); + table->field[11]->store((longlong) decimals, TRUE); table->field[11]->set_notnull(); } @@ -2607,7 +2665,7 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs); comment= tmp_cs->comment ? tmp_cs->comment : ""; table->field[2]->store(comment, strlen(comment), scs); - table->field[3]->store((longlong) tmp_cs->mbmaxlen); + table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE); if (schema_table_store_record(thd, table)) return 1; } @@ -2642,12 +2700,12 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) restore_record(table, s->default_values); table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs); table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs); - table->field[2]->store((longlong) tmp_cl->number); + table->field[2]->store((longlong) tmp_cl->number, TRUE); tmp_buff= (tmp_cl->state & MY_CS_PRIMARY) ? "Yes" : ""; table->field[3]->store(tmp_buff, strlen(tmp_buff), scs); tmp_buff= (tmp_cl->state & MY_CS_COMPILED)? "Yes" : ""; table->field[4]->store(tmp_buff, strlen(tmp_buff), scs); - table->field[5]->store((longlong) tmp_cl->strxfrm_multiply); + table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE); if (schema_table_store_record(thd, table)) return 1; } @@ -2768,7 +2826,8 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) Open_tables_state open_tables_state_backup; DBUG_ENTER("fill_schema_proc"); - strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS); + strxmov(definer, thd->security_ctx->priv_user, "@", + thd->security_ctx->priv_host, NullS); /* We use this TABLE_LIST instance only for checking of privileges. */ bzero((char*) &proc_tables,sizeof(proc_tables)); proc_tables.db= (char*) "mysql"; @@ -2848,10 +2907,10 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, table->field[1]->store(base_name, strlen(base_name), cs); table->field[2]->store(file_name, strlen(file_name), cs); table->field[3]->store((longlong) ((key_info->flags & - HA_NOSAME) ? 0 :1)); + HA_NOSAME) ? 0 : 1), TRUE); table->field[4]->store(base_name, strlen(base_name), cs); table->field[5]->store(key_info->name, strlen(key_info->name), cs); - table->field[6]->store((longlong) (j+1)); + table->field[6]->store((longlong) (j+1), TRUE); str=(key_part->field ? key_part->field->field_name : "?unknown field?"); table->field[7]->store(str, strlen(str), cs); @@ -2867,7 +2926,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, { ha_rows records=(show_table->file->records / key->rec_per_key[j]); - table->field[9]->store((longlong) records); + table->field[9]->store((longlong) records, TRUE); table->field[9]->set_notnull(); } if (!(key_info->flags & HA_FULLTEXT) && @@ -2905,6 +2964,8 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables, { CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("get_schema_views_record"); + char definer[HOSTNAME_LENGTH + USERNAME_LENGTH + 2]; + uint definer_len; if (!res) { if (tables->view) @@ -2918,17 +2979,24 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables, if (tables->with_check != VIEW_CHECK_NONE) { if (tables->with_check == VIEW_CHECK_LOCAL) - table->field[4]->store("LOCAL", 5, cs); + table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs); else - table->field[4]->store("CASCADED", 8, cs); + table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs); } else - table->field[4]->store("NONE", 4, cs); + table->field[4]->store(STRING_WITH_LEN("NONE"), cs); if (tables->updatable_view) - table->field[5]->store("YES", 3, cs); + table->field[5]->store(STRING_WITH_LEN("YES"), cs); + else + table->field[5]->store(STRING_WITH_LEN("NO"), cs); + definer_len= (strxmov(definer, tables->definer.user.str, "@", + tables->definer.host.str, NullS) - definer); + table->field[6]->store(definer, definer_len, cs); + if (tables->view_suid) + table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs); else - table->field[5]->store("NO", 2, cs); + table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs); DBUG_RETURN(schema_table_store_record(thd, table)); } } @@ -3106,7 +3174,7 @@ void store_key_column_usage(TABLE *table, const char*db, const char *tname, table->field[4]->store(db, strlen(db), cs); table->field[5]->store(tname, strlen(tname), cs); table->field[6]->store(con_type, con_len, cs); - table->field[7]->store((longlong) idx); + table->field[7]->store((longlong) idx, TRUE); } @@ -3178,7 +3246,7 @@ static int get_schema_key_column_usage_record(THD *thd, f_key_info->forein_id->length, f_info->str, f_info->length, (longlong) f_idx); - table->field[8]->store((longlong) f_idx); + table->field[8]->store((longlong) f_idx, TRUE); table->field[8]->set_notnull(); table->field[9]->store(f_key_info->referenced_db->str, f_key_info->referenced_db->length, @@ -3216,8 +3284,8 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) restore_record(table, s->default_values); table->field[0]->store(open_list->db, strlen(open_list->db), cs); table->field[1]->store(open_list->table, strlen(open_list->table), cs); - table->field[2]->store((longlong) open_list->in_use); - table->field[3]->store((longlong) open_list->locked); + table->field[2]->store((longlong) open_list->in_use, TRUE); + table->field[3]->store((longlong) open_list->locked, TRUE); if (schema_table_store_record(thd, table)) DBUG_RETURN(1); } @@ -3610,7 +3678,7 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) } List_iterator_fast<Item> it(sel->item_list); if (!(transl= - (Field_translator*)(thd->current_arena-> + (Field_translator*)(thd->stmt_arena-> alloc(sel->item_list.elements * sizeof(Field_translator))))) { @@ -3869,6 +3937,8 @@ ST_FIELD_INFO view_fields_info[]= {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0}, {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0}, {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0}, + {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0}, + {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index da10dcd3109..8f6f1e25264 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1562,25 +1562,24 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) { create_info->table_existed= 1; // Mark that table existed + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + alias); DBUG_RETURN(FALSE); } my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); DBUG_RETURN(TRUE); } if (wait_if_global_read_lock(thd, 0, 1)) - DBUG_RETURN(error); + DBUG_RETURN(TRUE); VOID(pthread_mutex_lock(&LOCK_open)); if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { if (!access(path,F_OK)) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - { - create_info->table_existed= 1; // Mark that table existed - error= FALSE; - } - else - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + goto warn; + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto end; } } @@ -1603,12 +1602,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, DBUG_PRINT("info", ("Table with same name already existed in handler")); if (create_if_not_exists) - { - create_info->table_existed= 1; // Mark that table existed - error= FALSE; - } - else - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + goto warn; + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto end; } } @@ -1647,6 +1642,14 @@ end: start_waiting_global_read_lock(thd); thd->proc_info="After create"; DBUG_RETURN(error); + +warn: + error= FALSE; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + alias); + create_info->table_existed= 1; // Mark that table existed + goto end; } /* @@ -1706,9 +1709,11 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, List_iterator_fast<Item> it(*items); Item *item; Field *tmp_field; + bool not_used; DBUG_ENTER("create_table_from_items"); tmp_table.alias= 0; + tmp_table.timestamp_field= 0; tmp_table.s= &tmp_table.share_not_to_be_used; tmp_table.s->db_create_options=0; tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr; @@ -1753,7 +1758,8 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, create_info, *extra_fields, *keys, 0, select_field_count)) { - if (!(table= open_table(thd, create_table, thd->mem_root, (bool*)0, 0))) + if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0, + MYSQL_LOCK_IGNORE_FLUSH))) quick_rm_table(create_info->db_type, create_table->db, table_case_name(create_info, create_table->table_name)); } @@ -1762,8 +1768,15 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(0); } + /* + FIXME: What happens if trigger manages to be created while we are + obtaining this lock ? May be it is sensible just to disable + trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH + save us from that ? + */ table->reginfo.lock_type=TL_WRITE; - if (! ((*lock)= mysql_lock_tables(thd, &table, 1, MYSQL_LOCK_IGNORE_FLUSH))) + if (! ((*lock)= mysql_lock_tables(thd, &table, 1, + MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) { VOID(pthread_mutex_lock(&LOCK_open)); hash_delete(&open_cache,(byte*) table); @@ -1937,8 +1950,8 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, { char* backup_dir= thd->lex->backup_dir; char src_path[FN_REFLEN], dst_path[FN_REFLEN]; - char* table_name = table->table_name; - char* db = thd->db ? thd->db : table->db; + char* table_name= table->table_name; + char* db= table->db; if (fn_format_relative_to_data_home(src_path, table_name, backup_dir, reg_ext)) @@ -1974,12 +1987,15 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, Now we should be able to open the partially restored table to finish the restore in the handler later on */ - if (!(table->table = reopen_name_locked_table(thd, table))) + pthread_mutex_lock(&LOCK_open); + if (reopen_name_locked_table(thd, table)) { - pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(send_check_errmsg(thd, table, "restore", + "Failed to open partially restored table")); } + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(0); } @@ -2076,12 +2092,16 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, Now we should be able to open the partially repaired table to finish the repair in the handler later on. */ - if (!(table_list->table = reopen_name_locked_table(thd, table_list))) + pthread_mutex_lock(&LOCK_open); + if (reopen_name_locked_table(thd, table_list)) { - pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table_list); pthread_mutex_unlock(&LOCK_open); + error= send_check_errmsg(thd, table_list, "repair", + "Failed to open partially repaired table"); + goto end; } + pthread_mutex_unlock(&LOCK_open); end: if (table == &tmp_table) @@ -3143,6 +3163,15 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (create_info->row_type == ROW_TYPE_NOT_USED) create_info->row_type= table->s->row_type; + DBUG_PRINT("info", ("old type: %d new type: %d", old_db_type, new_db_type)); + if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) || + ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED)) + { + DBUG_PRINT("info", ("doesn't support alter")); + my_error(ER_ILLEGAL_HA, MYF(0), table_name); + DBUG_RETURN(TRUE); + } + thd->proc_info="setup"; if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm @@ -3576,7 +3605,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, bzero((void*) &tbl, sizeof(tbl)); tbl.db= new_db; tbl.table_name= tbl.alias= tmp_name; - new_table= open_table(thd, &tbl, thd->mem_root, 0, 0); + new_table= open_table(thd, &tbl, thd->mem_root, (bool*) 0, + MYSQL_LOCK_IGNORE_FLUSH); } else { @@ -4060,7 +4090,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) strxmov(table_name, table->db ,".", table->table_name, NullS); - t= table->table= open_ltable(thd, table, TL_READ_NO_INSERT); + t= table->table= open_ltable(thd, table, TL_READ); thd->clear_error(); // these errors shouldn't get client protocol->prepare_for_resend(); @@ -4086,6 +4116,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) { /* calculating table's checksum */ ha_checksum crc= 0; + uchar null_mask=256 - (1 << t->s->last_null_bit_pos); /* InnoDB must be told explicitly to retrieve all columns, because this function does not set field->query_id in the columns to the @@ -4106,9 +4137,15 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) continue; break; } - if (t->record[0] != (byte*) t->field[0]->ptr) - row_crc= my_checksum(row_crc, t->record[0], - ((byte*) t->field[0]->ptr) - t->record[0]); + if (t->s->null_bytes) + { + /* fix undefined null bits */ + t->record[0][t->s->null_bytes-1] |= null_mask; + if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD)) + t->record[0][0] |= 1; + + row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes); + } for (uint i= 0; i < t->s->fields; i++ ) { @@ -4152,9 +4189,9 @@ static bool check_engine(THD *thd, const char *table_name, enum db_type *new_engine) { enum db_type req_engine= *new_engine; - bool no_substitution= + bool no_substitution= test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION); - if ((*new_engine= + if ((*new_engine= ha_checktype(thd, req_engine, no_substitution, 1)) == DB_TYPE_UNKNOWN) return TRUE; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index ddd0f3fe162..1bd298dda04 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -408,6 +408,11 @@ end: static int print_key_cache_status(const char *name, KEY_CACHE *key_cache) { + char llbuff1[22]; + char llbuff2[22]; + char llbuff3[22]; + char llbuff4[22]; + if (!key_cache->key_cache_inited) { printf("%s: Not in use\n", name); @@ -421,16 +426,18 @@ Division_limit: %10lu\n\ Age_limit: %10lu\n\ blocks used: %10lu\n\ not flushed: %10lu\n\ -w_requests: %10lu\n\ -writes: %10lu\n\ -r_requests: %10lu\n\ -reads: %10lu\n\n", +w_requests: %10s\n\ +writes: %10s\n\ +r_requests: %10s\n\ +reads: %10s\n\n", name, (ulong) key_cache->param_buff_size, key_cache->param_block_size, key_cache->param_division_limit, key_cache->param_age_threshold, key_cache->blocks_used,key_cache->global_blocks_changed, - key_cache->global_cache_w_requests,key_cache->global_cache_write, - key_cache->global_cache_r_requests,key_cache->global_cache_read); + llstr(key_cache->global_cache_w_requests,llbuff1), + llstr(key_cache->global_cache_write,llbuff2), + llstr(key_cache->global_cache_r_requests,llbuff3), + llstr(key_cache->global_cache_read,llbuff4)); } return 0; } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 053dfdfc990..dbad8dcffb5 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -103,8 +103,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) { TABLE *table; - bool result= 0; - + bool result= TRUE; DBUG_ENTER("mysql_create_or_drop_trigger"); /* @@ -119,9 +118,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) /* We should have only one table in table list. */ DBUG_ASSERT(tables->next_global == 0); - if (!(table= open_ltable(thd, tables, tables->lock_type))) - DBUG_RETURN(TRUE); - /* TODO: We should check if user has TRIGGER privilege for table here. Now we just require SUPER privilege for creating/dropping because @@ -131,28 +127,24 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) DBUG_RETURN(TRUE); /* - We do not allow creation of triggers on temporary tables. We also don't - allow creation of triggers on views but fulfilment of this restriction - is guaranteed by open_ltable(). It is better to have this check here - than do it in Table_triggers_list::create_trigger() and mess with table - cache. + There is no DETERMINISTIC clause for triggers, so can't check it. + But a trigger can in theory be used to do nasty things (if it supported + DROP for example) so we do the check for privileges. For now there is + already a stronger test right above; but when this stronger test will + be removed, the test below will hold. */ - if (table->s->tmp_table != NO_TMP_TABLE) + if (!trust_routine_creators && mysql_bin_log.is_open() && + !(thd->security_ctx->master_access & SUPER_ACL)) { - my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias); + my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); DBUG_RETURN(TRUE); } - if (!table->triggers) + /* We do not allow creation of triggers on temporary tables. */ + if (create && find_temporary_table(thd, tables->db, tables->table_name)) { - if (!create) - { - my_message(ER_TRG_DOES_NOT_EXIST, ER(ER_TRG_DOES_NOT_EXIST), MYF(0)); - DBUG_RETURN(TRUE); - } - - if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table))) - DBUG_RETURN(TRUE); + my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias); + DBUG_RETURN(TRUE); } /* @@ -161,31 +153,41 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) again until we are done. (Acquiring LOCK_open is not enough because global read lock is held without helding LOCK_open). */ - if (wait_if_global_read_lock(thd, 0, 0)) + if (wait_if_global_read_lock(thd, 0, 1)) DBUG_RETURN(TRUE); - /* - There is no DETERMINISTIC clause for triggers, so can't check it. - But a trigger can in theory be used to do nasty things (if it supported - DROP for example) so we do the check for privileges. For now there is - already a stronger test above (see start of the function); but when this - stronger test will be removed, the test below will hold. - */ - if (!trust_routine_creators && mysql_bin_log.is_open() && - !(thd->master_access & SUPER_ACL)) + VOID(pthread_mutex_lock(&LOCK_open)); + + if (lock_table_names(thd, tables)) + goto end; + + /* We also don't allow creation of triggers on views. */ + tables->required_type= FRMTYPE_TABLE; + + if (reopen_name_locked_table(thd, tables)) { - my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, - ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); - DBUG_RETURN(TRUE); + unlock_table_name(thd, tables); + goto end; + } + table= tables->table; + + if (!table->triggers) + { + if (!create) + { + my_error(ER_TRG_DOES_NOT_EXIST, MYF(0)); + goto end; + } + + if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table))) + goto end; } - VOID(pthread_mutex_lock(&LOCK_open)); result= (create ? table->triggers->create_trigger(thd, tables): table->triggers->drop_trigger(thd, tables)); - /* It is sensible to invalidate table in any case */ - close_cached_table(thd, table); +end: VOID(pthread_mutex_unlock(&LOCK_open)); start_waiting_global_read_lock(thd); @@ -511,6 +513,25 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) /* + Adjust Table_triggers_list with new TABLE pointer. + + SYNOPSIS + set_table() + new_table - new pointer to TABLE instance +*/ + +void Table_triggers_list::set_table(TABLE *new_table) +{ + table= new_table; + for (Field **field= table->triggers->record1_field ; *field ; field++) + { + (*field)->table= (*field)->orig_table= new_table; + (*field)->table_name= &new_table->alias; + } +} + + +/* Check whenever .TRG file for table exist and load all triggers it contains. SYNOPSIS diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index d9b39cc3034..c1d1f8d0e9e 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -98,6 +98,8 @@ public: return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]); } + void set_table(TABLE *new_table); + friend class Item_trigger_field; friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, Table_triggers_list *triggers); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index e0c3034a58a..ba3c598a784 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -472,10 +472,10 @@ int mysql_create_function(THD *thd,udf_func *udf) restore_record(table, s->default_values); // Default values for fields table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info); - table->field[1]->store((longlong) u_d->returns); + table->field[1]->store((longlong) u_d->returns, TRUE); table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info); if (table->s->fields >= 4) // If not old func format - table->field[3]->store((longlong) u_d->type); + table->field[3]->store((longlong) u_d->type, TRUE); error = table->file->write_row(table->record[0]); close_thread_tables(thd); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 72c96e81682..dee88af7d83 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -23,6 +23,7 @@ #include "mysql_priv.h" #include "sql_select.h" +#include "sql_cursor.h" bool mysql_union(THD *thd, LEX *lex, select_result *result, SELECT_LEX_UNIT *unit, ulong setup_tables_done_option) @@ -30,13 +31,9 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result, DBUG_ENTER("mysql_union"); bool res; if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | - setup_tables_done_option, ""))) + setup_tables_done_option))) res= unit->exec(); - if (!res && thd->cursor && thd->cursor->is_open()) - { - thd->cursor->set_unit(unit); - } - else + if (res || !thd->cursor || !thd->cursor->is_open()) res|= unit->cleanup(); DBUG_RETURN(res); } @@ -46,16 +43,6 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result, ** store records in temporary table for UNION ***************************************************************************/ -select_union::select_union(TABLE *table_par) - :table(table_par) -{ -} - -select_union::~select_union() -{ -} - - int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) { unit= u; @@ -103,6 +90,45 @@ bool select_union::flush() return 0; } +/* + Create a temporary table to store the result of select_union. + + SYNOPSIS + select_union::create_result_table() + thd thread handle + column_types a list of items used to define columns of the + temporary table + is_union_distinct if set, the temporary table will eliminate + duplicates on insert + options create options + + DESCRIPTION + Create a temporary table that is used to store the result of a UNION, + derived table, or a materialized cursor. + + RETURN VALUE + 0 The table has been created successfully. + 1 create_tmp_table failed. +*/ + +bool +select_union::create_result_table(THD *thd, List<Item> *column_types, + bool is_union_distinct, ulonglong options, + const char *alias) +{ + DBUG_ASSERT(table == 0); + tmp_table_param.init(); + tmp_table_param.field_count= column_types->elements; + + if (! (table= create_tmp_table(thd, &tmp_table_param, *column_types, + (ORDER*) 0, is_union_distinct, 1, + options, HA_POS_ERROR, (char*) alias))) + return TRUE; + table->file->extra(HA_EXTRA_WRITE_CACHE); + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + return FALSE; +} + /* initialization procedures before fake_select_lex preparation() @@ -133,11 +159,10 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd) bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, - ulong additional_options, - const char *tmp_table_alias) + ulong additional_options) { SELECT_LEX *lex_select_save= thd_arg->lex->current_select; - SELECT_LEX *sl, *first_select; + SELECT_LEX *sl, *first_sl= first_select(); select_result *tmp_result; bool is_union; TABLE *empty_table= 0; @@ -156,7 +181,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (describe) { /* fast reinit for EXPLAIN */ - for (sl= first_select_in_union(); sl; sl= sl->next_select()) + for (sl= first_sl; sl; sl= sl->next_select()) { sl->join->result= result; select_limit_cnt= HA_POS_ERROR; @@ -175,17 +200,16 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, prepared= 1; res= FALSE; - thd_arg->lex->current_select= sl= first_select= first_select_in_union(); - found_rows_for_union= first_select->options & OPTION_FOUND_ROWS; - is_union= test(first_select->next_select()); + thd_arg->lex->current_select= sl= first_sl; + found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS; + is_union= test(first_sl->next_select()); /* Global option */ if (is_union) { - if (!(tmp_result= union_result= new select_union(0))) + if (!(tmp_result= union_result= new select_union)) goto err; - union_result->tmp_table_param.init(); if (describe) tmp_result= sel_result; } @@ -238,8 +262,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, information about fields lengths and exact types */ if (!is_union) - types= first_select_in_union()->item_list; - else if (sl == first_select) + types= first_sl->item_list; + else if (sl == first_sl) { /* We need to create an empty table object. It is used @@ -287,7 +311,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, all collations together for UNION. */ List_iterator_fast<Item> tp(types); - Query_arena *arena= thd->current_arena; Item *type; ulonglong create_options; @@ -301,7 +324,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - create_options= (first_select_in_union()->options | thd_arg->options | + create_options= (first_sl->options | thd_arg->options | TMP_TABLE_ALL_COLUMNS); /* Force the temporary table to be a MyISAM table if we're going to use @@ -312,47 +335,35 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (global_parameters->ftfunc_list->elements) create_options= create_options | TMP_TABLE_FORCE_MYISAM; - union_result->tmp_table_param.field_count= types.elements; - if (!(table= create_tmp_table(thd_arg, - &union_result->tmp_table_param, types, - (ORDER*) 0, (bool) union_distinct, 1, - create_options, HA_POS_ERROR, - (char *) tmp_table_alias))) + if (union_result->create_result_table(thd, &types, test(union_distinct), + create_options, "")) goto err; - table->file->extra(HA_EXTRA_WRITE_CACHE); - table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); bzero((char*) &result_table_list, sizeof(result_table_list)); result_table_list.db= (char*) ""; result_table_list.table_name= result_table_list.alias= (char*) "union"; - result_table_list.table= table; - union_result->set_table(table); + result_table_list.table= table= union_result->table; thd_arg->lex->current_select= lex_select_save; if (!item_list.elements) { - Field **field; - Query_arena *tmp_arena,backup; - tmp_arena= thd->change_arena_if_needed(&backup); + Query_arena *arena, backup_arena; - for (field= table->field; *field; field++) - { - Item_field *item= new Item_field(*field); - if (!item || item_list.push_back(item)) - { - if (tmp_arena) - thd->restore_backup_item_arena(tmp_arena, &backup); - DBUG_RETURN(TRUE); - } - } - if (tmp_arena) - thd->restore_backup_item_arena(tmp_arena, &backup); - if (arena->is_stmt_prepare_or_first_sp_execute()) + arena= thd->activate_stmt_arena_if_needed(&backup_arena); + + res= table->fill_item_list(&item_list); + + if (arena) + thd->restore_active_arena(arena, &backup_arena); + + if (res) + goto err; + + if (thd->stmt_arena->is_stmt_prepare()) { - /* prepare fake select to initialize it correctly */ + /* Validate the global parameters of this union */ + init_prepare_fake_select_lex(thd); - /* - Should be done only once (the only item_list per statement). - */ + /* Should be done only once (the only item_list per statement) */ DBUG_ASSERT(fake_select_lex->join == 0); if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options, result))) @@ -375,19 +386,14 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, fake_select_lex->table_list.empty(); } } - else if (!arena->is_conventional()) + else { + DBUG_ASSERT(!thd->stmt_arena->is_conventional()); /* We're in execution of a prepared statement or stored procedure: reset field items to point at fields from the created temporary table. */ - List_iterator_fast<Item> it(item_list); - for (Field **field= table->field; *field; field++) - { - Item_field *item_field= (Item_field*) it++; - DBUG_ASSERT(item_field != 0); - item_field->reset_field(*field); - } + table->reset_item_list(&item_list); } } @@ -404,7 +410,7 @@ err: bool st_select_lex_unit::exec() { SELECT_LEX *lex_select_save= thd->lex->current_select; - SELECT_LEX *select_cursor=first_select_in_union(); + SELECT_LEX *select_cursor=first_select(); ulonglong add_rows=0; ha_rows examined_rows= 0; DBUG_ENTER("st_select_lex_unit::exec"); @@ -595,7 +601,7 @@ bool st_select_lex_unit::cleanup() table= 0; // Safety } - for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select()) + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) error|= sl->cleanup(); if (fake_select_lex) @@ -652,7 +658,7 @@ bool st_select_lex_unit::change_result(select_subselect *result, select_subselect *old_result) { bool res= FALSE; - for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select()) + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { if (sl->join && sl->join->result == old_result) if (sl->join->change_result(result)) @@ -663,6 +669,36 @@ bool st_select_lex_unit::change_result(select_subselect *result, return (res); } +/* + Get column type information for this unit. + + SYNOPSIS + st_select_lex_unit::get_unit_column_types() + + DESCRIPTION + For a single-select the column types are taken + from the list of selected items. For a union this function + assumes that st_select_lex_unit::prepare has been called + and returns the type holders that were created for unioned + column types of all selects. + + NOTES + The implementation of this function should be in sync with + st_select_lex_unit::prepare() +*/ + +List<Item> *st_select_lex_unit::get_unit_column_types() +{ + bool is_union= test(first_select()->next_select()); + + if (is_union) + { + DBUG_ASSERT(prepared); + /* Types are generated during prepare */ + return &types; + } + return &first_select()->item_list; +} bool st_select_lex::cleanup() { @@ -684,3 +720,17 @@ bool st_select_lex::cleanup() DBUG_RETURN(error); } + +void st_select_lex::cleanup_all_joins(bool full) +{ + SELECT_LEX_UNIT *unit; + SELECT_LEX *sl; + + if (join) + join->cleanup(full); + + for (unit= first_inner_unit(); unit; unit= unit->next_unit()) + for (sl= unit->first_select(); sl; sl= sl->next_select()) + sl->cleanup_all_joins(full); +} + diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b596420692a..a8e21177338 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -122,7 +122,8 @@ int mysql_update(THD *thd, bool used_key_is_modified, transactional_table; int res; int error=0; - uint used_index; + uint used_index= MAX_KEY; + bool need_sort= TRUE; #ifndef NO_EMBEDDED_ACCESS_CHECKS uint want_privilege; #endif @@ -134,25 +135,33 @@ int mysql_update(THD *thd, SQL_SELECT *select; READ_RECORD info; SELECT_LEX *select_lex= &thd->lex->select_lex; + bool need_reopen; DBUG_ENTER("mysql_update"); LINT_INIT(timestamp_query_id); - if (open_tables(thd, &table_list, &table_count, 0)) - DBUG_RETURN(1); - - if (table_list->multitable_view) + for ( ; ; ) { - DBUG_ASSERT(table_list->view != 0); - DBUG_PRINT("info", ("Switch to multi-update")); - /* pass counter value */ - thd->lex->table_count= table_count; - /* convert to multiupdate */ - return 2; + if (open_tables(thd, &table_list, &table_count, 0)) + DBUG_RETURN(1); + + if (table_list->multitable_view) + { + DBUG_ASSERT(table_list->view != 0); + DBUG_PRINT("info", ("Switch to multi-update")); + /* pass counter value */ + thd->lex->table_count= table_count; + /* convert to multiupdate */ + DBUG_RETURN(2); + } + if (!lock_tables(thd, table_list, table_count, &need_reopen)) + break; + if (!need_reopen) + DBUG_RETURN(1); + close_tables_for_reopen(thd, table_list); } - if (lock_tables(thd, table_list, table_count) || - mysql_handle_derived(thd->lex, &mysql_derived_prepare) || + if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || (thd->fill_derived_tables() && mysql_handle_derived(thd->lex, &mysql_derived_filling))) DBUG_RETURN(1); @@ -233,6 +242,11 @@ int mysql_update(THD *thd, send_ok(thd); // No matching records DBUG_RETURN(0); } + if (!select && limit != HA_POS_ERROR) + { + if (MAX_KEY != (used_index= get_index_for_order(table, order, limit))) + need_sort= FALSE; + } /* If running in safe sql mode, don't allow updates without keys */ if (table->quick_keys.is_clear_all()) { @@ -253,6 +267,10 @@ int mysql_update(THD *thd, used_key_is_modified= (!select->quick->unique_key_range() && select->quick->check_if_keys_used(&fields)); } + else if (used_index != MAX_KEY) + { + used_key_is_modified= check_if_key_used(table, used_index, fields); + } else if ((used_index=table->file->key_used_on_scan) < MAX_KEY) used_key_is_modified=check_if_key_used(table, used_index, fields); else @@ -268,10 +286,11 @@ int mysql_update(THD *thd, if (used_index < MAX_KEY && old_used_keys.is_set(used_index)) { table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); + table->file->extra(HA_EXTRA_KEYREAD); //todo: psergey: check } - if (order) + /* note: can actually avoid sorting below.. */ + if (order && need_sort) { /* Doing an ORDER BY; Let filesort find and sort the rows we are going @@ -315,7 +334,10 @@ int mysql_update(THD *thd, /* If quick select is used, initialize it before retrieving rows. */ if (select && select->quick && select->quick->reset()) goto err; - init_read_record(&info,thd,table,select,0,1); + if (used_index == MAX_KEY) + init_read_record(&info,thd,table,select,0,1); + else + init_read_record_idx(&info, thd, table, 1, used_index); thd->proc_info="Searching rows for update"; uint tmp_limit= limit; @@ -344,6 +366,10 @@ int mysql_update(THD *thd, error= 1; // Aborted limit= tmp_limit; end_read_record(&info); + + /* if we got here we must not use index in the main update loop below */ + used_index= MAX_KEY; + /* Change select to use tempfile */ if (select) { @@ -467,11 +493,20 @@ int mysql_update(THD *thd, query_cache_invalidate3(thd, table_list, 1); } - if ((updated || (error < 0)) && (error <= 0 || !transactional_table)) + /* + error < 0 means really no error at all: we processed all rows until the + last one without error. error > 0 means an error (e.g. unique key + violation and no IGNORE or REPLACE). error == 0 is also an error (if + preparing the record or invoking before triggers fails). See + ha_autocommit_or_rollback(error>=0) and DBUG_RETURN(error>=0) below. + Sometimes we want to binlog even if we updated no rows, in case user used + it to be sure master and slave are in same state. + */ + if ((error < 0) || (updated && !transactional_table)) { if (mysql_bin_log.is_open()) { - if (error <= 0) + if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_table, FALSE); @@ -554,6 +589,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, bzero((char*) &tables,sizeof(tables)); // For ORDER BY tables.table= table; tables.alias= table_list->alias; + thd->allow_sum_func= 0; if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, table_list, conds, &select_lex->leaf_tables, @@ -566,10 +602,14 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(TRUE); /* Check that we are not using table that we are updating in a sub select */ - if (unique_table(table_list, table_list->next_global)) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); - DBUG_RETURN(TRUE); + TABLE_LIST *duplicate; + if ((duplicate= unique_table(table_list, table_list->next_global))) + { + update_non_unique_table_error(table_list, "UPDATE", duplicate); + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); + DBUG_RETURN(TRUE); + } } select_lex->fix_prepare_information(thd, conds); DBUG_RETURN(FALSE); @@ -612,7 +652,6 @@ static table_map get_table_map(List<Item> *items) bool mysql_multi_update_prepare(THD *thd) { LEX *lex= thd->lex; - ulong opened_tables; TABLE_LIST *table_list= lex->query_tables; TABLE_LIST *tl, *leaves; List<Item> *fields= &lex->select_lex.item_list; @@ -626,13 +665,16 @@ bool mysql_multi_update_prepare(THD *thd) uint table_count= lex->table_count; const bool using_lock_tables= thd->locked_tables != 0; bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI); + bool need_reopen= FALSE; DBUG_ENTER("mysql_multi_update_prepare"); /* following need for prepared statements, to run next time multi-update */ thd->lex->sql_command= SQLCOM_UPDATE_MULTI; +reopen_tables: + /* open tables and create derived ones, but do not lock and fill them */ - if ((original_multiupdate && + if (((original_multiupdate || need_reopen) && open_tables(thd, &table_list, &table_count, 0)) || mysql_handle_derived(lex, &mysql_derived_prepare)) DBUG_RETURN(TRUE); @@ -716,7 +758,8 @@ bool mysql_multi_update_prepare(THD *thd) { uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL; if (check_access(thd, want_privilege, - tl->db, &tl->grant.privilege, 0, 0) || + tl->db, &tl->grant.privilege, 0, 0, + test(tl->schema_table)) || (grant_option && check_grant(thd, want_privilege, tl, 0, 1, 0))) DBUG_RETURN(TRUE); } @@ -737,20 +780,17 @@ bool mysql_multi_update_prepare(THD *thd) } } - opened_tables= thd->status_var.opened_tables; /* now lock and fill tables */ - if (lock_tables(thd, table_list, table_count)) - DBUG_RETURN(TRUE); - - /* - we have to re-call fixfields for fixed items, because lock maybe - reopened tables - */ - if (opened_tables != thd->status_var.opened_tables) + if (lock_tables(thd, table_list, table_count, &need_reopen)) { + if (!need_reopen) + DBUG_RETURN(TRUE); + /* - Fields items cleanup(). There are only Item_fields in the list, so we - do not do Item tree walking + We have to reopen tables since some of them were altered or dropped + during lock_tables() or something was done with their triggers. + Let us do some cleanups to be able do setup_table() and setup_fields() + once again. */ List_iterator_fast<Item> it(*fields); Item *item; @@ -761,12 +801,8 @@ bool mysql_multi_update_prepare(THD *thd) for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) tbl->cleanup_items(); - if (setup_tables(thd, &lex->select_lex.context, - &lex->select_lex.top_join_list, - table_list, &lex->select_lex.where, - &lex->select_lex.leaf_tables, FALSE) || - setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0)) - DBUG_RETURN(TRUE); + close_tables_for_reopen(thd, table_list); + goto reopen_tables; } /* @@ -779,7 +815,7 @@ bool mysql_multi_update_prepare(THD *thd) { TABLE *table= tl->table; TABLE_LIST *tlist; - if (!(tlist= tl->belong_to_view ? tl->belong_to_view : tl)->derived) + if (!(tlist= tl->top_table())->derived) { tlist->grant.want_privilege= (SELECT_ACL & ~tlist->grant.privilege); @@ -788,11 +824,14 @@ bool mysql_multi_update_prepare(THD *thd) DBUG_PRINT("info", ("table: %s want_privilege: %u", tl->alias, (uint) table->grant.want_privilege)); if (tl->lock_type != TL_READ && - tl->lock_type != TL_READ_NO_INSERT && - unique_table(tl, table_list)) + tl->lock_type != TL_READ_NO_INSERT) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); - DBUG_RETURN(TRUE); + TABLE_LIST *duplicate; + if ((duplicate= unique_table(tl, table_list))) + { + update_non_unique_table_error(table_list, "UPDATE", duplicate); + DBUG_RETURN(TRUE); + } } } @@ -820,9 +859,6 @@ bool mysql_multi_update(THD *thd, multi_update *result; DBUG_ENTER("mysql_multi_update"); - if (mysql_multi_update_prepare(thd)) - DBUG_RETURN(TRUE); - if (!(result= new multi_update(table_list, thd->lex->select_lex.leaf_tables, fields, values, @@ -1428,16 +1464,14 @@ bool multi_update::send_eof() /* Write the SQL statement to the binlog if we updated rows and we succeeded or if we updated some non - transacational tables. - Note that if we updated nothing we don't write to the binlog (TODO: - fix this). + transactional tables. */ - if (updated && (local_error <= 0 || !trans_safe)) + if ((local_error == 0) || (updated && !trans_safe)) { if (mysql_bin_log.is_open()) { - if (local_error <= 0) + if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 8269c16916a..5db08275735 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -210,6 +210,37 @@ bool mysql_create_view(THD *thd, #ifndef NO_EMBEDDED_ACCESS_CHECKS /* + check definer of view: + - same as current user + - current user has SUPER_ACL + */ + if (strcmp(lex->create_view_definer->user.str, + thd->security_ctx->priv_user) != 0 || + my_strcasecmp(system_charset_info, + lex->create_view_definer->host.str, + thd->security_ctx->priv_host) != 0) + { + if (!(thd->security_ctx->master_access & SUPER_ACL)) + { + my_error(ER_VIEW_OTHER_USER, MYF(0), lex->create_view_definer->user.str, + lex->create_view_definer->host.str); + res= TRUE; + goto err; + } + else + { + if (!is_acl_user(lex->create_view_definer->host.str, + lex->create_view_definer->user.str)) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_NO_SUCH_USER, + ER(ER_NO_SUCH_USER), + lex->create_view_definer->user.str, + lex->create_view_definer->host.str); + } + } + } + /* Privilege check for view creation: - user has CREATE VIEW privilege on view table - user has DROP privilege in case of ALTER VIEW or CREATE OR REPLACE @@ -224,11 +255,11 @@ bool mysql_create_view(THD *thd, table (i.e. user will not get some privileges by view creation) */ if ((check_access(thd, CREATE_VIEW_ACL, view->db, &view->grant.privilege, - 0, 0) || + 0, 0, is_schema_db(view->db)) || grant_option && check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) || (mode != VIEW_CREATE_NEW && (check_access(thd, DROP_ACL, view->db, &view->grant.privilege, - 0, 0) || + 0, 0, is_schema_db(view->db)) || grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0)))) { res= TRUE; @@ -245,7 +276,8 @@ bool mysql_create_view(THD *thd, if (check_some_access(thd, VIEW_ANY_ACL, tbl)) { my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), - "ANY", thd->priv_user, thd->host_or_ip, tbl->table_name); + "ANY", thd->security_ctx->priv_user, + thd->security_ctx->priv_host, tbl->table_name); res= TRUE; goto err; } @@ -280,7 +312,7 @@ bool mysql_create_view(THD *thd, if (!tbl->table_in_first_from_clause) { if (check_access(thd, SELECT_ACL, tbl->db, - &tbl->grant.privilege, 0, 0) || + &tbl->grant.privilege, 0, 0, test(tbl->schema_table)) || grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0)) { res= TRUE; @@ -348,7 +380,7 @@ bool mysql_create_view(THD *thd, /* prepare select to resolve all fields */ lex->view_prepare_mode= 1; - if (unit->prepare(thd, 0, 0, view->view_name.str)) + if (unit->prepare(thd, 0, 0)) { /* some errors from prepare are reported to user, if is not then @@ -369,6 +401,7 @@ bool mysql_create_view(THD *thd, if (lex->view_list.elements != select_lex->item_list.elements) { my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0)); + res= TRUE; goto err; } while ((item= it++, name= nm++)) @@ -410,7 +443,8 @@ bool mysql_create_view(THD *thd, { /* VIEW column has more privileges */ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - "create view", thd->priv_user, thd->host_or_ip, item->name, + "create view", thd->security_ctx->priv_user, + thd->security_ctx->priv_host, item->name, view->table_name); res= TRUE; goto err; @@ -447,9 +481,11 @@ err: /* index of revision number in following table */ -static const int revision_number_position= 5; +static const int revision_number_position= 8; /* index of last required parameter for making view */ -static const int required_view_parameters= 7; +static const int required_view_parameters= 10; +/* number of backups */ +static const int num_view_backups= 3; /* table of VIEW .frm field descriptors @@ -458,23 +494,41 @@ static const int required_view_parameters= 7; parse() */ static File_option view_parameters[]= -{{{(char*) "query", 5}, offsetof(TABLE_LIST, query), +{{{(char*) STRING_WITH_LEN("query")}, + offsetof(TABLE_LIST, query), FILE_OPTIONS_STRING}, - {{(char*) "md5", 3}, offsetof(TABLE_LIST, md5), + {{(char*) STRING_WITH_LEN("md5")}, + offsetof(TABLE_LIST, md5), FILE_OPTIONS_STRING}, - {{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable_view), + {{(char*) STRING_WITH_LEN("updatable")}, + offsetof(TABLE_LIST, updatable_view), FILE_OPTIONS_ULONGLONG}, - {{(char*) "algorithm", 9}, offsetof(TABLE_LIST, algorithm), + {{(char*) STRING_WITH_LEN("algorithm")}, + offsetof(TABLE_LIST, algorithm), FILE_OPTIONS_ULONGLONG}, - {{(char*) "with_check_option", 17}, offsetof(TABLE_LIST, with_check), - FILE_OPTIONS_ULONGLONG}, - {{(char*) "revision", 8}, offsetof(TABLE_LIST, revision), + {{(char*) STRING_WITH_LEN("definer_user")}, + offsetof(TABLE_LIST, definer.user), + FILE_OPTIONS_STRING}, + {{(char*) STRING_WITH_LEN("definer_host")}, + offsetof(TABLE_LIST, definer.host), + FILE_OPTIONS_STRING}, + {{(char*) STRING_WITH_LEN("suid")}, + offsetof(TABLE_LIST, view_suid), + FILE_OPTIONS_ULONGLONG}, + {{(char*) STRING_WITH_LEN("with_check_option")}, + offsetof(TABLE_LIST, with_check), + FILE_OPTIONS_ULONGLONG}, + {{(char*) STRING_WITH_LEN("revision")}, + offsetof(TABLE_LIST, revision), FILE_OPTIONS_REV}, - {{(char*) "timestamp", 9}, offsetof(TABLE_LIST, timestamp), + {{(char*) STRING_WITH_LEN("timestamp")}, + offsetof(TABLE_LIST, timestamp), FILE_OPTIONS_TIMESTAMP}, - {{(char*)"create-version", 14},offsetof(TABLE_LIST, file_version), + {{(char*)STRING_WITH_LEN("create-version")}, + offsetof(TABLE_LIST, file_version), FILE_OPTIONS_ULONGLONG}, - {{(char*) "source", 6}, offsetof(TABLE_LIST, source), + {{(char*) STRING_WITH_LEN("source")}, + offsetof(TABLE_LIST, source), FILE_OPTIONS_ESTRING}, {{NullS, 0}, 0, FILE_OPTIONS_STRING} @@ -587,8 +641,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, /* fill structure */ view->query.str= (char*)str.ptr(); view->query.length= str.length()-1; // we do not need last \0 - view->source.str= thd->query; - view->source.length= thd->query_length; + view->source.str= thd->lex->create_view_select_start; + view->source.length= (thd->query_length - + (thd->lex->create_view_select_start - thd->query)); view->file_version= 1; view->calc_md5(md5); view->md5.str= md5; @@ -602,6 +657,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; } view->algorithm= lex->create_view_algorithm; + view->definer.user= lex->create_view_definer->user; + view->definer.host= lex->create_view_definer->host; + view->view_suid= lex->create_view_suid; view->with_check= lex->create_view_check; if ((view->updatable_view= (can_be_merged && view->algorithm != VIEW_ALGORITHM_TMPTABLE))) @@ -655,7 +713,7 @@ loop_out: } if (sql_create_definition_file(&dir, &file, view_file_type, - (gptr)view, view_parameters, 3)) + (gptr)view, view_parameters, num_view_backups)) { DBUG_RETURN(thd->net.report_error? -1 : 1); } @@ -700,15 +758,20 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) For now we assume that tables will not be changed during PS life (it will be TRUE as far as we make new table cache). */ - Query_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->stmt_arena, backup; if (arena->is_conventional()) arena= 0; else - thd->set_n_backup_item_arena(arena, &backup); + thd->set_n_backup_active_arena(arena, &backup); /* init timestamp */ if (!table->timestamp.str) table->timestamp.str= table->timestamp_buffer; + /* prepare default values for old format */ + table->view_suid= 1; + table->definer.user.str= table->definer.host.str= 0; + table->definer.user.length= table->definer.host.length= 0; + /* TODO: when VIEWs will be stored in cache, table mem_root should be used here @@ -718,6 +781,21 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) goto err; /* + check old format view .frm + */ + if (!table->definer.user.str) + { + DBUG_ASSERT(!table->definer.host.str && + !table->definer.user.length && + !table->definer.host.length); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER), + table->db, table->table_name); + if (default_view_definer(thd->security_ctx, &table->definer)) + goto err; + } + + /* Save VIEW parameters, which will be wiped out by derived table processing */ @@ -774,9 +852,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) } if (!res && !thd->is_fatal_error) { - TABLE_LIST *top_view= (table->belong_to_view ? - table->belong_to_view : - table); + TABLE_LIST *top_view= table->top_table(); TABLE_LIST *view_tables= lex->query_tables; TABLE_LIST *view_tables_tail= 0; TABLE_LIST *tbl; @@ -997,13 +1073,15 @@ ok: ok2: if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); + if (!old_lex->time_zone_tables_used && thd->lex->time_zone_tables_used) + old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used; thd->lex= old_lex; DBUG_RETURN(0); err: if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); delete table->view; table->view= 0; // now it is not VIEW placeholder thd->lex= old_lex; @@ -1092,7 +1170,7 @@ frm_type_enum mysql_frm_type(char *path) int length; DBUG_ENTER("mysql_frm_type"); - if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0) + if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) { DBUG_RETURN(FRMTYPE_ERROR); } @@ -1145,8 +1223,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) thd->lex->select_lex.select_limit == 0) DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */ table= view->table; - if (view->belong_to_view) - view= view->belong_to_view; + view= view->top_table(); trans= view->field_translation; key_info_end= (key_info= table->key_info)+ table->s->keys; @@ -1165,7 +1242,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) { if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item)) { - thd->set_query_id= save_set_query_id; + thd->set_query_id= save_set_query_id; return TRUE; } } @@ -1297,3 +1374,94 @@ int view_checksum(THD *thd, TABLE_LIST *view) HA_ADMIN_WRONG_CHECKSUM : HA_ADMIN_OK); } + +/* + rename view + + Synopsis: + renames a view + + Parameters: + thd thread handler + new_name new name of view + view view + + Return values: + FALSE Ok + TRUE Error +*/ +bool +mysql_rename_view(THD *thd, + const char *new_name, + TABLE_LIST *view) +{ + LEX_STRING pathstr, file; + File_parser *parser; + char view_path[FN_REFLEN]; + bool error= TRUE; + + DBUG_ENTER("mysql_rename_view"); + + strxnmov(view_path, FN_REFLEN, mysql_data_home, "/", view->db, "/", + view->table_name, reg_ext, NullS); + (void) unpack_filename(view_path, view_path); + + pathstr.str= (char *)view_path; + pathstr.length= strlen(view_path); + + if ((parser= sql_parse_prepare(&pathstr, thd->mem_root, 1)) && + is_equal(&view_type, parser->type())) + { + TABLE_LIST view_def; + char dir_buff[FN_REFLEN], file_buff[FN_REFLEN]; + + /* + To be PS-friendly we should either to restore state of + TABLE_LIST object pointed by 'view' after using it for + view definition parsing or use temporary 'view_def' + object for it. + */ + bzero(&view_def, sizeof(view_def)); + view_def.timestamp.str= view_def.timestamp_buffer; + view_def.view_suid= TRUE; + + /* get view definition and source */ + if (parser->parse((gptr)&view_def, thd->mem_root, view_parameters, + array_elements(view_parameters)-1)) + goto err; + + /* rename view and it's backups */ + if (rename_in_schema_file(view->db, view->table_name, new_name, + view_def.revision - 1, num_view_backups)) + goto err; + + strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", view->db, "/", NullS); + (void) unpack_filename(dir_buff, dir_buff); + + pathstr.str= (char*)dir_buff; + pathstr.length= strlen(dir_buff); + + file.str= file_buff; + file.length= (strxnmov(file_buff, FN_REFLEN, new_name, reg_ext, NullS) + - file_buff); + + if (sql_create_definition_file(&pathstr, &file, view_file_type, + (gptr)&view_def, view_parameters, + num_view_backups)) + { + /* restore renamed view in case of error */ + rename_in_schema_file(view->db, new_name, view->table_name, + view_def.revision - 1, num_view_backups); + goto err; + } + } else + DBUG_RETURN(1); + + /* remove cache entries */ + query_cache_invalidate3(thd, view, 0); + sp_cache_invalidate(); + error= FALSE; + +err: + DBUG_RETURN(error); +} diff --git a/sql/sql_view.h b/sql/sql_view.h index 9d961feb143..4cc9eb454fb 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -34,6 +34,7 @@ int view_checksum(THD *thd, TABLE_LIST *view); extern TYPELIB updatable_views_with_limit_typelib; bool check_duplicate_names(List<Item>& item_list, bool gen_unique_view_names); +bool mysql_rename_view(THD *thd, const char *new_name, TABLE_LIST *view); #define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 90066318c60..94ce04fb5b1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -660,6 +660,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token YEAR_SYM %token ZEROFILL +%left JOIN_SYM +/* A dummy token to force the priority of table_ref production in a join. */ +%left TABLE_REF_PRIORITY %left SET_VAR %left OR_OR_SYM OR_SYM OR2_SYM XOR %left AND_SYM AND_AND_SYM @@ -823,10 +826,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); precision subselect_start opt_and charset subselect_end select_var_list select_var_list_init help opt_len opt_extended_describe - prepare prepare_src execute deallocate + prepare prepare_src execute deallocate statement sp_suid opt_view_list view_list or_replace algorithm sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec + view_user view_suid END_OF_INPUT %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -921,16 +925,11 @@ deallocate: { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_STMT_PREPARE) + if (lex->stmt_prepare_mode) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } - if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "DEALLOCATE"); - YYABORT; - } lex->sql_command= SQLCOM_DEALLOCATE_PREPARE; lex->prepared_stmt_name= $3; }; @@ -946,16 +945,11 @@ prepare: { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_STMT_PREPARE) + if (lex->stmt_prepare_mode) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } - if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "PREPARE"); - YYABORT; - } lex->sql_command= SQLCOM_PREPARE; lex->prepared_stmt_name= $2; }; @@ -981,16 +975,11 @@ execute: { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_STMT_PREPARE) + if (lex->stmt_prepare_mode) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } - if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "EXECUTE"); - YYABORT; - } lex->sql_command= SQLCOM_EXECUTE; lex->prepared_stmt_name= $2; } @@ -1269,16 +1258,16 @@ create: YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); } - | CREATE or_replace algorithm VIEW_SYM table_ident + | CREATE or_replace algorithm view_user view_suid VIEW_SYM table_ident { THD *thd= YYTHD; LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; /* first table in list is target VIEW name */ - if (!lex->select_lex.add_table_to_list(thd, $5, NULL, 0)) + if (!lex->select_lex.add_table_to_list(thd, $7, NULL, 0)) YYABORT; } - opt_view_list AS select_init check_option + opt_view_list AS select_view_init check_option {} | CREATE TRIGGER_SYM sp_name trg_action_time trg_event ON table_ident FOR_SYM EACH_SYM ROW_SYM @@ -1324,11 +1313,8 @@ create: YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); - if (sp->m_multi_results) - { - my_error(ER_SP_NO_RETSET, MYF(0), "trigger"); - YYABORT; - } + if (sp->is_not_allowed_in_function("trigger")) + YYABORT; /* We have to do it after parsing trigger body, because some of @@ -1481,11 +1467,9 @@ create_function_tail: LEX *lex= Lex; sp_head *sp= lex->sphead; - if (sp->m_multi_results) - { - my_error(ER_SP_NO_RETSET, MYF(0), "function"); - YYABORT; - } + if (sp->is_not_allowed_in_function("function")) + YYABORT; + if (sp->check_backpatch(YYTHD)) YYABORT; lex->sql_command= SQLCOM_CREATE_SPFUNCTION; @@ -1674,42 +1658,41 @@ sp_decls: ; sp_decl: - DECLARE_SYM sp_decl_idents type + DECLARE_SYM sp_decl_idents type { Lex->sphead->reset_lex(YYTHD); } sp_opt_default - { - LEX *lex= Lex; - sp_pcontext *ctx= lex->spcont; - uint max= ctx->context_pvars(); - enum enum_field_types type= (enum enum_field_types)$3; - Item *it= $5; + { + LEX *lex= Lex; + sp_pcontext *ctx= lex->spcont; + uint max= ctx->context_pvars(); + enum enum_field_types type= (enum enum_field_types)$3; + Item *it= $5; + bool has_default= (it != NULL); - for (uint i = max-$2 ; i < max ; i++) - { - ctx->set_type(i, type); - if (! it) - ctx->set_isset(i, FALSE); - else - { - sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(), - ctx, - ctx->pvar_context2index(i), - it, type, lex, - (i == max - 1)); - - /* - The last instruction is assigned to be responsible for - freeing LEX. - */ - lex->sphead->add_instr(in); - ctx->set_isset(i, TRUE); - ctx->set_default(i, it); - } - } + for (uint i = max-$2 ; i < max ; i++) + { + sp_instr_set *in; + + ctx->set_type(i, type); + if (! has_default) + it= new Item_null(); /* QQ Set to the type with null_value? */ + in = new sp_instr_set(lex->sphead->instructions(), + ctx, + ctx->pvar_context2index(i), + it, type, lex, + (i == max - 1)); + + /* + The last instruction is assigned to be responsible for + freeing LEX. + */ + lex->sphead->add_instr(in); + ctx->set_default(i, it); + } lex->sphead->restore_lex(YYTHD); - $$.vars= $2; - $$.conds= $$.hndlrs= $$.curs= 0; - } + $$.vars= $2; + $$.conds= $$.hndlrs= $$.curs= 0; + } | DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond { LEX *lex= Lex; @@ -1735,7 +1718,7 @@ sp_decl: sp->add_instr(i); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); - sp->m_in_handler= TRUE; + sp->m_flags|= sp_head::IN_HANDLER; } sp_hcond_list sp_proc_stmt { @@ -1759,7 +1742,7 @@ sp_decl: sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */ } lex->sphead->backpatch(hlab); - sp->m_in_handler= FALSE; + sp->m_flags&= ~sp_head::IN_HANDLER; $$.vars= $$.conds= $$.curs= 0; $$.hndlrs= $6; ctx->add_handlers($6); @@ -1971,12 +1954,7 @@ sp_proc_stmt: LEX *lex= Lex; sp_head *sp= lex->sphead; - if ((lex->sql_command == SQLCOM_SELECT && !lex->result) || - sp_multi_results_command(lex->sql_command)) - { - /* We maybe have one or more SELECT without INTO */ - sp->m_multi_results= TRUE; - } + sp->m_flags|= sp_get_flags_for_command(lex); if (lex->sql_command == SQLCOM_CHANGE_DB) { /* "USE db" doesn't work in a procedure */ my_error(ER_SP_BADSTATEMENT, MYF(0), "USE"); @@ -2026,14 +2004,14 @@ sp_proc_stmt: i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3, sp->m_returns, lex); sp->add_instr(i); - sp->m_has_return= TRUE; + sp->m_flags|= sp_head::HAS_RETURN; } sp->restore_lex(YYTHD); } | IF sp_if END IF {} | CASE_SYM WHEN_SYM { - Lex->sphead->m_simple_case= FALSE; + Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE; } sp_case END CASE_SYM {} | CASE_SYM @@ -2053,7 +2031,7 @@ sp_proc_stmt: lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in); lex->sphead->add_instr(i); - lex->sphead->m_simple_case= TRUE; + lex->sphead->m_flags|= sp_head::IN_SIMPLE_CASE; lex->sphead->restore_lex(YYTHD); } sp_case END CASE_SYM @@ -2290,7 +2268,6 @@ sp_fetch_list: sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); i->add_to_varlist(spv); - spv->isset= TRUE; } } | @@ -2312,7 +2289,6 @@ sp_fetch_list: sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); i->add_to_varlist(spv); - spv->isset= TRUE; } } ; @@ -2367,7 +2343,7 @@ sp_case: uint ip= sp->instructions(); sp_instr_jump_if_not *i; - if (! sp->m_simple_case) + if (! (sp->m_flags & sp_head::IN_SIMPLE_CASE)) i= new sp_instr_jump_if_not(ip, ctx, $2, lex); else { /* Simple case: <caseval> = <whenval> */ @@ -2716,6 +2692,7 @@ create_table_option: | INSERT_METHOD opt_equal merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;} | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.data_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_DATADIR; } | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR; } + | CONNECTION_SYM opt_equal TEXT_STRING_sys { Lex->create_info.connect_string.str= $3.str; Lex->create_info.connect_string.length= $3.length; Lex->create_info.used_fields|= HA_CREATE_USED_CONNECTION; } ; default_charset: @@ -3443,16 +3420,16 @@ alter: lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->spname= $3; } - | ALTER algorithm VIEW_SYM table_ident + | ALTER algorithm view_user view_suid VIEW_SYM table_ident { THD *thd= YYTHD; LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; lex->create_view_mode= VIEW_ALTER; /* first table in list is target VIEW name */ - lex->select_lex.add_table_to_list(thd, $4, NULL, 0); + lex->select_lex.add_table_to_list(thd, $6, NULL, 0); } - opt_view_list AS select_init check_option + opt_view_list AS select_view_init check_option {} ; @@ -3851,6 +3828,11 @@ optimize: OPTIMIZE opt_no_write_to_binlog table_or_tables { LEX *lex=Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "OPTIMIZE TABLE"); + YYABORT; + } lex->sql_command = SQLCOM_OPTIMIZE; lex->no_write_to_binlog= $2; lex->check_opt.init(); @@ -4015,6 +3997,18 @@ select_init: | '(' select_paren ')' union_opt; +select_view_init: + SELECT_SYM remember_name select_init2 + { + Lex->create_view_select_start= $2; + } + | + '(' remember_name select_paren ')' union_opt + { + Lex->create_view_select_start= $2; + } + ; + select_paren: SELECT_SYM select_part2 { @@ -4299,7 +4293,9 @@ predicate: else { $5->push_front($1); - $$= negate_expression(YYTHD, new Item_func_in(*$5)); + Item_func_in *item = new Item_func_in(*$5); + item->negate(); + $$= item; } } | bit_expr IN_SYM in_subselect @@ -4309,14 +4305,18 @@ predicate: | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate { $$= new Item_func_between($1,$3,$5); } | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate - { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | bit_expr SOUNDS_SYM LIKE bit_expr { $$= new Item_func_eq(new Item_func_soundex($1), new Item_func_soundex($4)); } | bit_expr LIKE simple_expr opt_escape - { $$= new Item_func_like($1,$3,$4); } + { $$= new Item_func_like($1,$3,$4,Lex->escape_used); } | bit_expr not LIKE simple_expr opt_escape - { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } + { $$= new Item_func_not(new Item_func_like($1,$4,$5, Lex->escape_used)); } | bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); } | bit_expr not REGEXP bit_expr { $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); } @@ -4536,6 +4536,8 @@ simple_expr: { $$= new Item_func_atan($3,$5); } | CHAR_SYM '(' expr_list ')' { $$= new Item_func_char(*$3); } + | CHAR_SYM '(' expr_list USING charset_name ')' + { $$= new Item_func_char(*$3, $5); } | CHARSET '(' expr ')' { $$= new Item_func_charset($3); } | COALESCE '(' expr_list ')' @@ -4779,27 +4781,48 @@ simple_expr: $$= new Item_func_sp(Lex->current_context(), name); lex->safe_to_cache_query=0; } - | IDENT_sys '(' udf_expr_list ')' + | IDENT_sys '(' + { +#ifdef HAVE_DLOPEN + udf_func *udf= 0; + if (using_udf_functions && + (udf= find_udf($1.str, $1.length)) && + udf->type == UDFTYPE_AGGREGATE) + { + LEX *lex= Lex; + if (lex->current_select->inc_in_sum_expr()) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + } + $<udf>$= udf; +#endif + } + udf_expr_list ')' { #ifdef HAVE_DLOPEN - udf_func *udf; + udf_func *udf= $<udf>3; SELECT_LEX *sel= Select; - if (using_udf_functions && (udf=find_udf($1.str, $1.length))) + if (udf) { + if (udf->type == UDFTYPE_AGGREGATE) + Select->in_sum_expr--; + switch (udf->returns) { case STRING_RESULT: if (udf->type == UDFTYPE_FUNCTION) { - if ($3 != NULL) - $$ = new Item_func_udf_str(udf, *$3); + if ($4 != NULL) + $$ = new Item_func_udf_str(udf, *$4); else $$ = new Item_func_udf_str(udf); } else { - if ($3 != NULL) - $$ = new Item_sum_udf_str(udf, *$3); + if ($4 != NULL) + $$ = new Item_sum_udf_str(udf, *$4); else $$ = new Item_sum_udf_str(udf); } @@ -4807,15 +4830,15 @@ simple_expr: case REAL_RESULT: if (udf->type == UDFTYPE_FUNCTION) { - if ($3 != NULL) - $$ = new Item_func_udf_float(udf, *$3); + if ($4 != NULL) + $$ = new Item_func_udf_float(udf, *$4); else $$ = new Item_func_udf_float(udf); } else { - if ($3 != NULL) - $$ = new Item_sum_udf_float(udf, *$3); + if ($4 != NULL) + $$ = new Item_sum_udf_float(udf, *$4); else $$ = new Item_sum_udf_float(udf); } @@ -4823,15 +4846,15 @@ simple_expr: case INT_RESULT: if (udf->type == UDFTYPE_FUNCTION) { - if ($3 != NULL) - $$ = new Item_func_udf_int(udf, *$3); + if ($4 != NULL) + $$ = new Item_func_udf_int(udf, *$4); else $$ = new Item_func_udf_int(udf); } else { - if ($3 != NULL) - $$ = new Item_sum_udf_int(udf, *$3); + if ($4 != NULL) + $$ = new Item_sum_udf_int(udf, *$4); else $$ = new Item_sum_udf_int(udf); } @@ -4839,15 +4862,15 @@ simple_expr: case DECIMAL_RESULT: if (udf->type == UDFTYPE_FUNCTION) { - if ($3 != NULL) - $$ = new Item_func_udf_decimal(udf, *$3); + if ($4 != NULL) + $$ = new Item_func_udf_decimal(udf, *$4); else $$ = new Item_func_udf_decimal(udf); } else { - if ($3 != NULL) - $$ = new Item_sum_udf_decimal(udf, *$3); + if ($4 != NULL) + $$ = new Item_sum_udf_decimal(udf, *$4); else $$ = new Item_sum_udf_decimal(udf); } @@ -4863,8 +4886,8 @@ simple_expr: sp_name *name= sp_name_current_db_new(YYTHD, $1); sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION); - if ($3) - $$= new Item_func_sp(Lex->current_context(), name, *$3); + if ($4) + $$= new Item_func_sp(Lex->current_context(), name, *$4); else $$= new Item_func_sp(Lex->current_context(), name); lex->safe_to_cache_query=0; @@ -5203,7 +5226,13 @@ derived_table_list: ; join_table: - table_ref normal_join table_ref { YYERROR_UNLESS($1 && ($$=$3)); } + /* + Evaluate production 'table_ref' before 'normal_join' so that + [INNER | CROSS] JOIN is properly nested as other left-associative + joins. + */ + table_ref %prec TABLE_REF_PRIORITY normal_join table_ref + { YYERROR_UNLESS($1 && ($$=$3)); } | table_ref STRAIGHT_JOIN table_factor { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; } | table_ref normal_join table_ref @@ -5649,10 +5678,14 @@ having_clause: ; opt_escape: - ESCAPE_SYM simple_expr { $$= $2; } + ESCAPE_SYM simple_expr + { + Lex->escape_used= TRUE; + $$= $2; + } | /* empty */ { - + Lex->escape_used= FALSE; $$= ((YYTHD->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ? new Item_string("", 0, &my_charset_latin1) : new Item_string("\\", 1, &my_charset_latin1)); @@ -5899,7 +5932,6 @@ select_var_ident: else { ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset,t->type)); - t->isset= TRUE; } } ; @@ -6549,15 +6581,16 @@ show_param: LEX *lex=Lex; lex->sql_command= SQLCOM_SHOW_GRANTS; THD *thd= lex->thd; + Security_context *sctx= thd->security_ctx; LEX_USER *curr_user; if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; - curr_user->user.str= thd->priv_user; - curr_user->user.length= strlen(thd->priv_user); - if (*thd->priv_host != 0) + curr_user->user.str= sctx->priv_user; + curr_user->user.length= strlen(sctx->priv_user); + if (*sctx->priv_host != 0) { - curr_user->host.str= thd->priv_host; - curr_user->host.length= strlen(thd->priv_host); + curr_user->host.str= sctx->priv_host; + curr_user->host.length= strlen(sctx->priv_host); } else { @@ -6643,6 +6676,9 @@ show_engine_param: STATUS_SYM { switch (Lex->create_info.db_type) { + case DB_TYPE_NDBCLUSTER: + Lex->sql_command = SQLCOM_SHOW_NDBCLUSTER_STATUS; + break; case DB_TYPE_INNODB: Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS; break; @@ -7458,14 +7494,15 @@ user: | CURRENT_USER optional_braces { THD *thd= YYTHD; + Security_context *sctx= thd->security_ctx; if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; - $$->user.str= thd->priv_user; - $$->user.length= strlen(thd->priv_user); - if (*thd->priv_host != 0) + $$->user.str= sctx->priv_user; + $$->user.length= strlen(sctx->priv_user); + if (*sctx->priv_host != 0) { - $$->host.str= thd->priv_host; - $$->host.length= strlen(thd->priv_host); + $$->host.str= sctx->priv_host; + $$->host.length= strlen(sctx->priv_host); } else { @@ -7930,7 +7967,6 @@ sys_option_value: sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, spv->offset, it, spv->type, lex, TRUE); lex->sphead->add_instr(sp_set); - spv->isset= TRUE; } } | option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types @@ -7962,6 +7998,18 @@ option_value: $2= $2 ? $2: global_system_variables.character_set_client; lex->var_list.push_back(new set_var_collation_client($2,thd->variables.collation_database,$2)); } + | NAMES_SYM equal expr + { + LEX *lex= Lex; + sp_pcontext *spc= lex->spcont; + LEX_STRING names; + + names.str= (char *)"names"; + names.length= 5; + if (spc && spc->find_pvar(&names)) + my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); + YYABORT; + } | NAMES_SYM charset_name_or_default opt_collate { LEX *lex= Lex; @@ -7979,10 +8027,21 @@ option_value: { THD *thd=YYTHD; LEX_USER *user; + LEX *lex= Lex; + sp_pcontext *spc= lex->spcont; + LEX_STRING pw; + + pw.str= (char *)"password"; + pw.length= 8; + if (spc && spc->find_pvar(&pw)) + { + my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str); + YYABORT; + } if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))) YYABORT; user->host=null_lex_str; - user->user.str=thd->priv_user; + user->user.str=thd->security_ctx->priv_user; thd->lex->var_list.push_back(new set_var_password(user, $3)); } | PASSWORD FOR_SYM user equal text_or_password @@ -8014,6 +8073,14 @@ internal_variable_name: if (tmp == &sys_time_zone && lex->add_time_zone_tables_to_query_tables(YYTHD)) YYABORT; + else if (spc && tmp == &sys_autocommit) + { + /* + We don't allow setting AUTOCOMMIT from a stored function + or trigger. + */ + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + } } else { @@ -8177,6 +8244,11 @@ handler: HANDLER_SYM table_ident OPEN_SYM opt_table_alias { LEX *lex= Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_OPEN; if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0)) YYABORT; @@ -8184,6 +8256,11 @@ handler: | HANDLER_SYM table_ident_nodb CLOSE_SYM { LEX *lex= Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_CLOSE; if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) YYABORT; @@ -8191,6 +8268,11 @@ handler: | HANDLER_SYM table_ident_nodb READ_SYM { LEX *lex=Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ lex->current_select->select_limit= new Item_int((int32) 1); @@ -8884,6 +8966,55 @@ algorithm: | ALGORITHM_SYM EQ TEMPTABLE_SYM { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; } ; + +view_user: + /* empty */ + { + THD *thd= YYTHD; + if (!(thd->lex->create_view_definer= + (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) + YYABORT; + if (default_view_definer(thd->security_ctx, + thd->lex->create_view_definer)) + YYABORT; + } + | CURRENT_USER optional_braces + { + THD *thd= YYTHD; + if (!(thd->lex->create_view_definer= + (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) + YYABORT; + if (default_view_definer(thd->security_ctx, + thd->lex->create_view_definer)) + YYABORT; + } + | DEFINER_SYM EQ ident_or_text '@' ident_or_text + { + THD *thd= YYTHD; + st_lex_user *view_user; + if (!(thd->lex->create_view_definer= view_user= + (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) + YYABORT; + view_user->user = $3; view_user->host=$5; + if (strchr(view_user->host.str, wild_many) || + strchr(view_user->host.str, wild_one)) + { + my_error(ER_NO_VIEW_USER, MYF(0)); + YYABORT; + } + } + ; + +view_suid: + /* empty */ + { Lex->create_view_suid= TRUE; } + | + SQL_SYM SECURITY_SYM DEFINER_SYM + { Lex->create_view_suid= TRUE; } + | SQL_SYM SECURITY_SYM INVOKER_SYM + { Lex->create_view_suid= FALSE; } + ; + check_option: /* empty */ { Lex->create_view_check= VIEW_CHECK_NONE; } diff --git a/sql/structs.h b/sql/structs.h index 03176b47360..92f09385d6e 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -20,7 +20,7 @@ struct st_table; class Field; -#define STRING_WITH_LEN(X) X, (sizeof(X)-1) +#define STRING_WITH_LEN(X) ((char*) X), (sizeof(X)-1) typedef struct st_lex_string { @@ -135,6 +135,7 @@ typedef struct st_read_record { /* Parameter to read_record */ byte *cache,*cache_pos,*cache_end,*read_positions; IO_CACHE *io_cache; bool print_error, ignore_not_found_rows; + bool first; /* used only with rr_index_read */ } READ_RECORD; @@ -186,7 +187,7 @@ enum SHOW_TYPE SHOW_SSL_GET_CIPHER_LIST, #endif /* HAVE_OPENSSL */ SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS, - SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG, + SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG, SHOW_KEY_CACHE_LONGLONG, SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS, SHOW_SLAVE_SKIP_ERRORS }; diff --git a/sql/table.cc b/sql/table.cc index 66fccec9c24..722e4e4df25 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -71,7 +71,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, uint rec_buff_length,n_length,int_length,records,key_parts,keys, interval_count,interval_parts,read_length,db_create_options; uint key_info_length, com_length; - ulong pos; + ulong pos, record_offset; char index_file[FN_REFLEN], *names, *keynames, *comment_pos; uchar head[288],*disk_buff,new_field_pack_flag; my_string record; @@ -300,6 +300,43 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, } #endif + record_offset= (ulong) (uint2korr(head+6)+ + ((uint2korr(head+14) == 0xffff ? + uint4korr(head+47) : uint2korr(head+14)))); + + if ((n_length= uint2korr(head+55))) + { + /* Read extra data segment */ + char *buff, *next_chunk, *buff_end; + if (!(next_chunk= buff= my_malloc(n_length, MYF(MY_WME)))) + goto err; + buff_end= buff + n_length; + if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength, + MYF(MY_NABP))) + { + my_free(buff, MYF(0)); + goto err; + } + share->connect_string.length= uint2korr(buff); + if (! (share->connect_string.str= strmake_root(&outparam->mem_root, + next_chunk + 2, share->connect_string.length))) + { + my_free(buff, MYF(0)); + goto err; + } + next_chunk+= share->connect_string.length + 2; + if (next_chunk + 2 < buff_end) + { + uint str_db_type_length= uint2korr(next_chunk); + share->db_type= ha_resolve_by_name(next_chunk + 2, str_db_type_length); + DBUG_PRINT("enter", ("Setting dbtype to: %d - %d - '%.*s'\n", + share->db_type, + str_db_type_length, str_db_type_length, + next_chunk + 2)); + next_chunk+= str_db_type_length + 2; + } + my_free(buff, MYF(0)); + } /* Allocate handler */ if (!(outparam->file= get_new_handler(outparam, share->db_type))) goto err; @@ -321,11 +358,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, rec_buff_length * records))) goto err; /* purecov: inspected */ share->default_values= (byte *) record; + if (my_pread(file,(byte*) record, (uint) share->reclength, - (ulong) (uint2korr(head+6)+ - ((uint2korr(head+14) == 0xffff ? - uint4korr(head+47) : uint2korr(head+14)))), - MYF(MY_NABP))) + record_offset, MYF(MY_NABP))) goto err; /* purecov: inspected */ if (records == 1) @@ -341,7 +376,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, else outparam->record[1]= outparam->record[0]; // Safety } - + #ifdef HAVE_purify /* We need this because when we read var-length rows, we are not updating @@ -443,6 +478,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, { outparam->null_flags=null_pos=(uchar*) record+1; null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1; + /* + null_bytes below is only correct under the condition that + there are no bit fields. Correct values is set below after the + table struct is initialized + */ share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8; } else @@ -855,6 +895,14 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, } } + /* + the correct null_bytes can now be set, since bitfields have been taken + into account + */ + share->null_bytes= (null_pos - (uchar*) outparam->null_flags + + (null_bit_pos + 7) / 8); + share->last_null_bit_pos= null_bit_pos; + /* The table struct is now initialized; Open the table */ error=2; if (db_stat) @@ -1381,7 +1429,8 @@ File create_frm(THD *thd, my_string name, const char *db, fileinfo[4]=1; int2store(fileinfo+6,IO_SIZE); /* Next block starts here */ key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16; - length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength)); + length= next_io_size((ulong) (IO_SIZE+key_length+reclength+ + create_info->extra_size)); int4store(fileinfo+10,length); tmp_key_length= (key_length < 0xffff) ? key_length : 0xffff; int2store(fileinfo+14,tmp_key_length); @@ -1403,6 +1452,7 @@ File create_frm(THD *thd, my_string name, const char *db, int4store(fileinfo+47, key_length); tmp= MYSQL_VERSION_ID; // Store to avoid warning from int4store int4store(fileinfo+51, tmp); + int2store(fileinfo+55, create_info->extra_size); bzero(fill,IO_SIZE); for (; length > IO_SIZE ; length-= IO_SIZE) { @@ -1665,6 +1715,63 @@ db_type get_table_type(THD *thd, const char *name) DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0)); } +/* + Create Item_field for each column in the table. + + SYNPOSIS + st_table::fill_item_list() + item_list a pointer to an empty list used to store items + + DESCRIPTION + Create Item_field object for each column in the table and + initialize it with the corresponding Field. New items are + created in the current THD memory root. + + RETURN VALUE + 0 success + 1 out of memory +*/ + +bool st_table::fill_item_list(List<Item> *item_list) const +{ + /* + All Item_field's created using a direct pointer to a field + are fixed in Item_field constructor. + */ + for (Field **ptr= field; *ptr; ptr++) + { + Item_field *item= new Item_field(*ptr); + if (!item || item_list->push_back(item)) + return TRUE; + } + return FALSE; +} + +/* + Reset an existing list of Item_field items to point to the + Fields of this table. + + SYNPOSIS + st_table::fill_item_list() + item_list a non-empty list with Item_fields + + DESCRIPTION + This is a counterpart of fill_item_list used to redirect + Item_fields to the fields of a newly created table. + The caller must ensure that number of items in the item_list + is the same as the number of columns in the table. +*/ + +void st_table::reset_item_list(List<Item> *item_list) const +{ + List_iterator_fast<Item> it(*item_list); + for (Field **ptr= field; *ptr; ptr++) + { + Item_field *item_field= (Item_field*) it++; + DBUG_ASSERT(item_field != 0); + item_field->reset_field(*ptr); + } +} /* calculate md5 of query @@ -1780,7 +1887,7 @@ bool st_table_list::setup_ancestor(THD *thd) /* Create view fields translation table */ if (!(transl= - (Field_translator*)(thd->current_arena-> + (Field_translator*)(thd->stmt_arena-> alloc(select->item_list.elements * sizeof(Field_translator))))) { @@ -1856,8 +1963,8 @@ bool st_table_list::prep_where(THD *thd, Item **conds, if (!no_where_clause && !where_processed) { TABLE_LIST *tbl= this; - Query_arena *arena= thd->current_arena, backup; - arena= thd->change_arena_if_needed(&backup); // For easier test + Query_arena *arena= thd->stmt_arena, backup; + arena= thd->activate_stmt_arena_if_needed(&backup); // For easier test /* Go up to join tree and try to find left join */ for (; tbl; tbl= tbl->embedding) @@ -1877,7 +1984,7 @@ bool st_table_list::prep_where(THD *thd, Item **conds, if (tbl == 0) *conds= and_conds(*conds, where); if (arena) - thd->restore_backup_item_arena(arena, &backup); + thd->restore_active_arena(arena, &backup); where_processed= TRUE; } } @@ -2056,7 +2163,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) { if (check_option && check_option->val_int() == 0) { - TABLE_LIST *view= (belong_to_view ? belong_to_view : this); + TABLE_LIST *view= top_table(); if (ignore_failure) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, @@ -2208,8 +2315,10 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution() List_iterator_fast<TABLE_LIST> it(cur_nested_join->join_list); cur_table_ref= it++; /* - If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse - order, thus the first operand is already at the front of the list. + If the current nested join is a RIGHT JOIN, the operands in + 'join_list' are in reverse order, thus the first operand is + already at the front of the list. Otherwise the first operand + is in the end of the list of join operands. */ if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT)) { @@ -2260,9 +2369,11 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution() cur_nested_join; cur_nested_join= cur_table_ref->nested_join) { + cur_table_ref= cur_nested_join->join_list.head(); /* - If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse - order, thus the last operand is in the end of the list. + If the current nested is a RIGHT JOIN, the operands in + 'join_list' are in reverse order, thus the last operand is in the + end of the list. */ if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT)) { @@ -2272,8 +2383,6 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution() while ((next= it++)) cur_table_ref= next; } - else - cur_table_ref= cur_nested_join->join_list.head(); if (cur_table_ref->is_leaf_for_name_resolution()) break; } @@ -2341,22 +2450,6 @@ Field *Natural_join_column::field() const char *Natural_join_column::table_name() { return table_ref->alias; - /* - TODO: - I think that it is sufficient to return just - table->alias, which is correctly set to either - the view name, the table name, or the alias to - the table reference (view or stored table). - */ -#ifdef NOT_YET - if (view_field) - return table_ref->view_name.str; - - DBUG_ASSERT(!strcmp(table_ref->table_name, - table_ref->table->s->table_name)); - return table_ref->table_name; -} -#endif } @@ -2492,7 +2585,7 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, DBUG_RETURN(field); } Item *item= new Item_direct_view_ref(&view->view->select_lex.context, - field_ref, view->view_name.str, + field_ref, view->alias, name); DBUG_RETURN(item); } diff --git a/sql/table.h b/sql/table.h index c9095ad48f6..e76d005f494 100644 --- a/sql/table.h +++ b/sql/table.h @@ -126,6 +126,7 @@ typedef struct st_table_share const char *db; /* Pointer to db */ const char *table_name; /* Table name (for open) */ const char *path; /* Path to .frm file (from datadir) */ + LEX_STRING connect_string; key_map keys_in_use; /* Keys in use for table */ key_map keys_for_keyread; ulong avg_row_length; /* create information */ @@ -140,7 +141,7 @@ typedef struct st_table_share enum tmp_table_type tmp_table; uint blob_ptr_size; /* 4 or 8 */ - uint null_bytes; + uint null_bytes, last_null_bit_pos; uint key_length; /* Length of table_cache_key */ uint fields; /* Number of fields */ uint rec_buff_length; /* Size of table->record[] buffer */ @@ -266,6 +267,9 @@ struct st_table { GRANT_INFO grant; FILESORT_INFO sort; TABLE_SHARE share_not_to_be_used; /* To be deleted when true shares */ + + bool fill_item_list(List<Item> *item_list) const; + void reset_item_list(List<Item> *item_list) const; }; @@ -539,10 +543,12 @@ typedef struct st_table_list LEX_STRING view_db; /* saved view database */ LEX_STRING view_name; /* saved view name */ LEX_STRING timestamp; /* GMT time stamp of last operation */ + st_lex_user definer; /* definer of view */ ulonglong file_version; /* version of file's field set */ ulonglong updatable_view; /* VIEW can be updated */ ulonglong revision; /* revision control number */ ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */ + ulonglong view_suid; /* view is suid (TRUE dy default) */ ulonglong with_check; /* WITH CHECK OPTION */ /* effective value of WITH CHECK OPTION (differ for temporary table @@ -576,6 +582,7 @@ typedef struct st_table_list /* TRUE if this merged view contain auto_increment field */ bool contain_auto_increment; bool multitable_view; /* TRUE iff this is multitable view */ + bool compact_view_format; /* Use compact format for SHOW CREATE VIEW */ /* view where processed */ bool where_processed; /* FRMTYPE_ERROR if any type is acceptable */ @@ -602,6 +609,8 @@ typedef struct st_table_list st_table_list *first_leaf_for_name_resolution(); st_table_list *last_leaf_for_name_resolution(); bool is_leaf_for_name_resolution(); + inline st_table_list *top_table() + { return belong_to_view ? belong_to_view : this; } inline bool prepare_check_option(THD *thd) { bool res= FALSE; diff --git a/sql/tztime.cc b/sql/tztime.cc index 5a907f0d170..537050e94db 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1826,7 +1826,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) */ table= tz_tables->table; tz_tables= tz_tables->next_local; - table->field[0]->store((longlong)tzid); + table->field[0]->store((longlong) tzid, TRUE); (void)table->file->ha_index_init(0); if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, @@ -1853,7 +1853,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) */ table= tz_tables->table; tz_tables= tz_tables->next_local; - table->field[0]->store((longlong)tzid); + table->field[0]->store((longlong) tzid, TRUE); (void)table->file->ha_index_init(0); // FIXME Is there any better approach than explicitly specifying 4 ??? @@ -1925,7 +1925,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) in ascending order by index scan also satisfies us. */ table= tz_tables->table; - table->field[0]->store((longlong)tzid); + table->field[0]->store((longlong) tzid, TRUE); (void)table->file->ha_index_init(0); // FIXME Is there any better approach than explicitly specifying 4 ??? diff --git a/sql/unireg.cc b/sql/unireg.cc index a89d89426a6..065f8583f71 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -75,6 +75,7 @@ bool mysql_create_frm(THD *thd, my_string file_name, uint keys, KEY *key_info, handler *db_file) { + LEX_STRING str_db_type; uint reclength,info_length,screens,key_info_length,maxlength; ulong key_buff_length; File file; @@ -82,6 +83,7 @@ bool mysql_create_frm(THD *thd, my_string file_name, uchar fileinfo[64],forminfo[288],*keybuff; TYPELIB formnames; uchar *screen_buff; + char buff[2]; DBUG_ENTER("mysql_create_frm"); formnames.type_names=0; @@ -116,6 +118,12 @@ bool mysql_create_frm(THD *thd, my_string file_name, } reclength=uint2korr(forminfo+266); + /* Calculate extra data segment length */ + str_db_type.str= (char *) ha_get_storage_engine(create_info->db_type); + str_db_type.length= strlen(str_db_type.str); + create_info->extra_size= (2 + str_db_type.length + + 2 + create_info->connect_string.length); + if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo, create_info, keys)) < 0) { @@ -150,6 +158,18 @@ bool mysql_create_frm(THD *thd, my_string file_name, create_fields,reclength, data_offset)) goto err; + int2store(buff, create_info->connect_string.length); + if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) || + my_write(file, (const byte*)create_info->connect_string.str, + create_info->connect_string.length, MYF(MY_NABP))) + goto err; + + int2store(buff, str_db_type.length); + if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) || + my_write(file, (const byte*)str_db_type.str, + str_db_type.length, MYF(MY_NABP))) + goto err; + VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0))); if (my_write(file,(byte*) forminfo,288,MYF_RW) || my_write(file,(byte*) screen_buff,info_length,MYF_RW) || @@ -465,16 +485,10 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, char *dst; uint length= field->interval->type_lengths[pos], hex_length; const char *src= field->interval->type_names[pos]; - const char *srcend= src + length; hex_length= length * 2; field->interval->type_lengths[pos]= hex_length; field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1); - for ( ; src < srcend; src++) - { - *dst++= _dig_vec_upper[((uchar) *src) >> 4]; - *dst++= _dig_vec_upper[((uchar) *src) & 15]; - } - *dst= '\0'; + octet2hex(dst, src, length); } } @@ -754,7 +768,7 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, (field->flags & NOT_NULL_FLAG)) { regfield->set_notnull(); - regfield->store((longlong) 1); + regfield->store((longlong) 1, TRUE); } else if (type == Field::YES) // Old unireg type regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)),system_charset_info); diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 5069a1dc082..460215418f8 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -401,16 +401,12 @@ static my_bool my_like_range_big5(CHARSET_INFO *cs __attribute__((unused)), uint res_length, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end; + const char *end= ptr + ptr_length; char *min_org=min_str; char *min_end=min_str+res_length; - uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + uint charlen= res_length / cs->mbmaxlen; - if (charlen < ptr_length) - ptr_length= charlen; - end= ptr + ptr_length; - - for (; ptr != end && min_str != min_end ; ptr++) + for (; ptr != end && min_str != min_end && charlen > 0; ptr++, charlen--) { if (ptr+1 != end && isbig5code(ptr[0],ptr[1])) { @@ -421,7 +417,10 @@ static my_bool my_like_range_big5(CHARSET_INFO *cs __attribute__((unused)), if (*ptr == escape && ptr+1 != end) { ptr++; /* Skip escape */ - *min_str++= *max_str++ = *ptr; + if (isbig5code(ptr[0], ptr[1])) + *min_str++= *max_str++ = *ptr++; + if (min_str < min_end) + *min_str++= *max_str++= *ptr; continue; } if (*ptr == w_one) /* '_' in SQL */ @@ -1712,7 +1711,7 @@ static uint16 tab_big5_uni0[]={ 0x2467,0x2468,0x2469,0x2474,0x2475,0x2476,0x2477,0x2478, 0x2479,0x247A,0x247B,0x247C,0x247D}; -/* page 1 0xC940-0xF9D5 */ +/* page 1 0xC940-0xF9DC */ static uint16 tab_big5_uni1[]={ 0x4E42,0x4E5C,0x51F5,0x531A,0x5382,0x4E07,0x4E0C,0x4E47, 0x4E8D,0x56D7,0xFA0C,0x5C6E,0x5F73,0x4E0F,0x5187,0x4E0E, @@ -3268,12 +3267,13 @@ static uint16 tab_big5_uni1[]={ 0x9E17,0x9F48,0x6207,0x6B1E,0x7227,0x864C,0x8EA8,0x9482, 0x9480,0x9481,0x9A69,0x9A68,0x9B2E,0x9E19,0x7229,0x864B, 0x8B9F,0x9483,0x9C79,0x9EB7,0x7675,0x9A6B,0x9C7A,0x9E1D, -0x7069,0x706A,0x9EA4,0x9F7E,0x9F49,0x9F98}; +0x7069,0x706A,0x9EA4,0x9F7E,0x9F49,0x9F98,0x7881,0x92B9, +0x88CF,0x58BB,0x6052,0x7CA7,0x5AFA}; static int func_big5_uni_onechar(int code){ if ((code>=0xA140)&&(code<=0xC7FC)) return(tab_big5_uni0[code-0xA140]); - if ((code>=0xC940)&&(code<=0xF9D5)) + if ((code>=0xC940)&&(code<=0xF9DC)) return(tab_big5_uni1[code-0xC940]); return(0); } @@ -3902,7 +3902,7 @@ static uint16 tab_uni_big57[]={ 0xE54D,0xE552, 0,0xE54E, 0,0xE551,0xBC5C, 0, 0xBEA5,0xBC5B, 0,0xE54A,0xE550, 0,0xBC5A,0xE54F, 0,0xE54C, 0,0xBC58, 0, 0, 0, 0, - 0, 0,0xE94D, 0,0xE94F,0xE94A,0xBEC1,0xE94C, + 0, 0,0xE94D,0xF9D9,0xE94F,0xE94A,0xBEC1,0xE94C, 0,0xBEC0,0xE94E, 0, 0,0xBEC3,0xE950,0xBEC2, 0xE949,0xE94B, 0, 0, 0, 0,0xC0A5,0xECCC, 0,0xC0A4,0xECCD,0xC0A3,0xECCB,0xC0A2,0xECCA, 0, @@ -3974,7 +3974,7 @@ static uint16 tab_uni_big57[]={ 0xE175,0xB9DE,0xE174,0xB9E4, 0,0xE16D,0xB9DF, 0, 0xE17B,0xB9E0,0xE16F,0xE172,0xE177,0xE171,0xE16C, 0, 0, 0, 0,0xE173,0xE555,0xBC61,0xE558,0xE557, -0xE55A,0xE55C, 0,0xBC5F, 0,0xE556, 0,0xE554, +0xE55A,0xE55C,0xF9DC,0xBC5F, 0,0xE556, 0,0xE554, 0,0xE55D,0xE55B,0xE559, 0,0xE55F, 0,0xE55E, 0xBC63,0xBC5E, 0,0xBC60,0xBC62, 0, 0,0xE560, 0xE957, 0, 0,0xE956,0xE955, 0,0xE958,0xE951, @@ -4145,7 +4145,7 @@ static uint16 tab_uni_big57[]={ 0,0xCEC0, 0, 0, 0, 0, 0, 0, 0xCECA,0xD1A1,0xCECB,0xABEE,0xCECE,0xCEC4,0xABED,0xCEC6, 0,0xCEC7, 0, 0,0xCEC9,0xABE9, 0, 0, -0xAEA3, 0, 0,0xCEC5,0xCEC1,0xAEA4, 0, 0, +0xAEA3, 0,0xF9DA,0xCEC5,0xCEC1,0xAEA4, 0, 0, 0xCECF,0xAE7E,0xD17D,0xCEC8, 0,0xD17C,0xCEC3,0xCECC, 0, 0,0xABEC,0xAEA1,0xABF2,0xAEA2,0xCED0,0xD17E, 0xABEB,0xAEA6,0xABF1,0xABF0,0xABEF,0xAEA5,0xCED1,0xAEA7, @@ -4919,7 +4919,7 @@ static uint16 tab_uni_big57[]={ 0xDACF,0xDACE,0xDACB,0xB2B8,0xB577,0xDAC9,0xDACC,0xB578, 0xDACD,0xDACA, 0, 0, 0, 0, 0, 0, 0,0xDEEE, 0,0xDEF2,0xB84E, 0,0xE2F0,0xB851, -0xDEF0, 0, 0,0xDEED,0xDEE8,0xDEEA,0xDEEB,0xDEE4, +0xDEF0,0xF9D6, 0,0xDEED,0xDEE8,0xDEEA,0xDEEB,0xDEE4, 0,0xB84D, 0, 0,0xB84C, 0,0xB848,0xDEE7, 0,0xB84F, 0,0xB850,0xDEE6,0xDEE9,0xDEF1,0xB84A, 0xB84B,0xDEEF,0xDEE5, 0, 0, 0,0xE2F2,0xBAD0, @@ -5051,7 +5051,7 @@ static uint16 tab_uni_big57[]={ 0xD34D,0xAFBB,0xD34B, 0,0xD34C,0xD34E, 0, 0, 0,0xD34A,0xB2C9, 0,0xD6DE,0xB2CB,0xD6E0,0xB2CA, 0xD6DF, 0, 0, 0, 0, 0,0xDAE8,0xB5AF, - 0,0xDAEA,0xDAE7,0xD6E1, 0,0xB5B0, 0, 0, + 0,0xDAEA,0xDAE7,0xD6E1, 0,0xB5B0, 0,0xF9DB, 0xDAE9, 0, 0, 0, 0, 0, 0,0xDF56, 0,0xB864,0xDF54,0xB865,0xDF55,0xB866, 0, 0, 0,0xBAE9,0xE361,0xE35E,0xE360,0xBAEA,0xBAEB,0xE35F, @@ -5440,7 +5440,7 @@ static uint16 tab_uni_big57[]={ 0,0xB5F6,0xDBCD, 0, 0, 0,0xDBC9,0xDBCB, 0xDBC6,0xDBC5,0xDBC3, 0,0xDBCA,0xDBCC,0xDBC8, 0, 0xDBC7,0xB5F4,0xB5F5, 0, 0, 0, 0, 0, - 0,0xDBCF,0xB8CD,0xDFF2,0xDFF8,0xDFF3,0xDFF4, 0, + 0,0xDBCF,0xB8CD,0xDFF2,0xDFF8,0xDFF3,0xDFF4,0xF9D8, 0xDFF9, 0,0xB8CF, 0,0xB8C7,0xB8CE,0xDFF1,0xDBC4, 0xB8CA,0xB8C8,0xDFF7,0xDFF6,0xB8C9,0xB8CB,0xDFF5,0xB8C6, 0,0xB8CC, 0, 0, 0, 0, 0,0xE3F6, @@ -5758,7 +5758,7 @@ static uint16 tab_uni_big57[]={ 0xE47B,0xE4AF,0xE4AC,0xE4A7,0xE477,0xE476,0xE4A1,0xE4B4, 0xBBCF,0xE4B7,0xE47D,0xE4A3,0xBE52, 0, 0, 0, 0, 0,0xBE5A,0xBE55,0xE8A4,0xE8A1,0xE867,0xBE50, - 0, 0, 0,0xBE4F,0xBE56, 0, 0, 0, + 0,0xF9D7, 0,0xBE4F,0xBE56, 0, 0, 0, 0xE865,0xBE54,0xE871,0xE863,0xE864,0xBE4E,0xE8A3,0xBE58, 0xE874,0xE879,0xE873,0xEBEE,0xE86F,0xE877,0xE875,0xE868, 0xE862,0xE87D,0xBE57,0xE87E, 0,0xE878, 0,0xE86D, @@ -6399,6 +6399,7 @@ CHARSET_INFO my_charset_big5_chinese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, &my_collation_big5_chinese_ci_handler @@ -6431,6 +6432,7 @@ CHARSET_INFO my_charset_big5_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 0fcd9021c4b..973a6ebf12a 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -86,6 +86,14 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)), } +uint my_lengthsp_binary(CHARSET_INFO *cs __attribute__((unused)), + const char *ptr __attribute__((unused)), + uint length) +{ + return length; +} + + /* Compare two strings. Result is sign(first_argument - second_argument) @@ -491,7 +499,7 @@ static MY_CHARSET_HANDLER my_charset_handler= my_numchars_8bit, my_charpos_8bit, my_well_formed_len_8bit, - my_lengthsp_8bit, + my_lengthsp_binary, my_numcells_8bit, my_mb_wc_bin, my_wc_mb_bin, @@ -516,7 +524,7 @@ static MY_CHARSET_HANDLER my_charset_handler= CHARSET_INFO my_charset_bin = { 63,0,0, /* number */ - MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_PRIMARY,/* state */ + MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_PRIMARY,/* state */ "binary", /* cs name */ "binary", /* name */ "", /* comment */ @@ -539,6 +547,7 @@ CHARSET_INFO my_charset_bin = 1, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + 0, /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_binary_handler diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c index b5f36c030bd..1e3126865f3 100644 --- a/strings/ctype-cp932.c +++ b/strings/ctype-cp932.c @@ -5417,7 +5417,7 @@ uint my_well_formed_len_cp932(CHARSET_INFO *cs __attribute__((unused)), { const char *b0= b; *error= 0; - while (pos && b < e) + while (pos-- && b < e) { /* Cast to int8 for extra safety. @@ -5522,6 +5522,7 @@ CHARSET_INFO my_charset_cp932_japanese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -5553,6 +5554,7 @@ CHARSET_INFO my_charset_cp932_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c index bdafc5c94b6..fa3a3bf53fe 100644 --- a/strings/ctype-czech.c +++ b/strings/ctype-czech.c @@ -628,6 +628,7 @@ CHARSET_INFO my_charset_latin2_czech_ci = 1, /* mbmaxlen */ 0, /* min_sort_char */ 0, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_8bit_handler, &my_collation_latin2_czech_ci_handler diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index b529bbb0308..97fea517c1b 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8706,6 +8706,7 @@ CHARSET_INFO my_charset_euckr_korean_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -8738,6 +8739,7 @@ CHARSET_INFO my_charset_euckr_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-eucjpms.c b/strings/ctype-eucjpms.c index ccdca2ba595..f9210fcb10e 100644 --- a/strings/ctype-eucjpms.c +++ b/strings/ctype-eucjpms.c @@ -8708,6 +8708,7 @@ CHARSET_INFO my_charset_eucjpms_japanese_ci= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad_char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -8740,6 +8741,7 @@ CHARSET_INFO my_charset_eucjpms_bin= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad_char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-extra.c b/strings/ctype-extra.c index e9a9598abdf..9fa4873c5d3 100644 --- a/strings/ctype-extra.c +++ b/strings/ctype-extra.c @@ -43,6 +43,7 @@ CHARSET_INFO compiled_charsets[] = { 0, /* mbmaxlen */ 0, /* min_sort_ord */ 0, /* max_sort_ord */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ NULL, /* cset handler */ NULL /* coll handler */ diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index 3d9a17205cd..f5d9b2627cd 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5757,6 +5757,7 @@ CHARSET_INFO my_charset_gb2312_chinese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -5788,6 +5789,7 @@ CHARSET_INFO my_charset_gb2312_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 5c220a285dd..edc595875d7 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -2714,16 +2714,12 @@ static my_bool my_like_range_gbk(CHARSET_INFO *cs __attribute__((unused)), uint res_length, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end; + const char *end= ptr + ptr_length; char *min_org=min_str; char *min_end=min_str+res_length; - uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + uint charlen= res_length / cs->mbmaxlen; - if (charlen < ptr_length) - ptr_length= charlen; - end= ptr + ptr_length; - - for (; ptr != end && min_str != min_end ; ptr++) + for (; ptr != end && min_str != min_end && charlen > 0; ptr++, charlen--) { if (ptr+1 != end && isgbkcode(ptr[0],ptr[1])) { @@ -2734,7 +2730,10 @@ static my_bool my_like_range_gbk(CHARSET_INFO *cs __attribute__((unused)), if (*ptr == escape && ptr+1 != end) { ptr++; /* Skip escape */ - *min_str++= *max_str++ = *ptr; + if (isgbkcode(ptr[0], ptr[1])) + *min_str++= *max_str++ = *ptr; + if (min_str < min_end) + *min_str++= *max_str++= *ptr; continue; } if (*ptr == w_one) /* '_' in SQL */ @@ -10046,6 +10045,7 @@ CHARSET_INFO my_charset_gbk_chinese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -10077,6 +10077,7 @@ CHARSET_INFO my_charset_gbk_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c index 9075710610b..746cb5a4003 100644 --- a/strings/ctype-latin1.c +++ b/strings/ctype-latin1.c @@ -28,8 +28,8 @@ static uchar ctype_latin1[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 16, 16,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 32, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 16, 2, 16, 16, 16, 16, 16, 16, 1, 16, 1, 0, 1, 0, + 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 2, 0, 2, 1, 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -441,6 +441,7 @@ CHARSET_INFO my_charset_latin1= 1, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_8bit_simple_ci_handler @@ -740,6 +741,7 @@ CHARSET_INFO my_charset_latin1_german2_ci= 1, /* mbmaxlen */ 0, /* min_sort_char */ 247, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_german2_ci_handler @@ -772,6 +774,7 @@ CHARSET_INFO my_charset_latin1_bin= 1, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_8bit_bin_handler diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 6f171c03845..a3e10ba7650 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -523,17 +523,13 @@ my_bool my_like_range_mb(CHARSET_INFO *cs, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end; + const char *end= ptr + ptr_length; char *min_org= min_str; char *min_end= min_str + res_length; char *max_end= max_str + res_length; - uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + uint charlen= res_length / cs->mbmaxlen; - if (charlen < ptr_length) - ptr_length= charlen; - end= ptr + ptr_length; - - for (; ptr != end && min_str != min_end ; ptr++) + for (; ptr != end && min_str != min_end && charlen > 0 ; ptr++, charlen--) { if (*ptr == escape && ptr+1 != end) { @@ -567,6 +563,7 @@ my_bool my_like_range_mb(CHARSET_INFO *cs, representation of the max_sort_char character, and copy it into max_str in a loop. */ + *max_length= res_length; pad_max_char(cs, max_str, max_end); return 0; } diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 208c38edd30..d6f2f0e5fe5 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -904,7 +904,7 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), while (long_val != 0) { long quo= long_val/10; - *--p = '0' + (char)(long_val - quo*10); + *--p = (char) ('0' + (long_val - quo*10)); long_val= quo; } @@ -1034,17 +1034,12 @@ my_bool my_like_range_simple(CHARSET_INFO *cs, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end; + const char *end= ptr + ptr_length; char *min_org=min_str; char *min_end=min_str+res_length; -#ifdef USE_MB - uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); - if (charlen < ptr_length) - ptr_length= charlen; -#endif - end= ptr + ptr_length; + uint charlen= res_length / cs->mbmaxlen; - for (; ptr != end && min_str != min_end ; ptr++) + for (; ptr != end && min_str != min_end && charlen > 0 ; ptr++, charlen--) { if (*ptr == escape && ptr+1 != end) { @@ -1321,6 +1316,7 @@ static my_bool my_cset_init_8bit(CHARSET_INFO *cs, void *(*alloc)(uint)) { cs->caseup_multiply= 1; cs->casedn_multiply= 1; + cs->pad_char= ' '; return create_fromuni(cs, alloc); } diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index c0a395b5792..398aea08b05 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -330,16 +330,13 @@ static my_bool my_like_range_sjis(CHARSET_INFO *cs __attribute__((unused)), uint res_length, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end; + const char *end= ptr + ptr_length; char *min_org=min_str; char *min_end=min_str+res_length; - uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + uint charlen= res_length / cs->mbmaxlen; - if (charlen < ptr_length) - ptr_length= charlen; - end= ptr + ptr_length; - - while (ptr < end && min_str < min_end) { + for ( ; ptr < end && min_str < min_end && charlen > 0 ; charlen--) + { if (ismbchar_sjis(cs, ptr, end)) { *min_str++ = *max_str++ = *ptr++; if (min_str < min_end) @@ -4696,6 +4693,7 @@ CHARSET_INFO my_charset_sjis_japanese_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -4727,6 +4725,7 @@ CHARSET_INFO my_charset_sjis_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 2003eaa0789..1200644de3c 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -498,7 +498,7 @@ static uint thai2sortable(uchar *tstr, uint len) l2bias use to control position weight of l2char example (*=l2char) XX*X must come before X*XX */ - memcpy_overlap((char*) p, (char*) (p+1), tlen-1); + memmove((char*) p, (char*) (p+1), tlen-1); tstr[len-1]= l2bias + t_ctype0[1]- L2_GARAN +1; p--; continue; @@ -648,77 +648,6 @@ int my_strnxfrm_tis620(CHARSET_INFO *cs __attribute__((unused)), } - -/* - Convert SQL LIKE string to C string - - Arg: String, its length, escape character, resource length, - minimal string and maximum string - Ret: Always 0 - - IMPLEMENTATION - We just copy this function from opt_range.cc. No need to convert to - thai2sortable string. min_str and max_str will be use for comparison and - converted there. - - RETURN VALUES - 0 -*/ - -#define max_sort_chr ((char) 255) - -static -my_bool my_like_range_tis620(CHARSET_INFO *cs __attribute__((unused)), - const char *ptr, uint ptr_length, - pbool escape, pbool w_one, pbool w_many, - uint res_length, char *min_str, char *max_str, - uint *min_length, uint *max_length) -{ - const char *end=ptr+ptr_length; - char *min_org=min_str; - char *min_end=min_str+res_length; - - for (; ptr != end && min_str != min_end ; ptr++) - { - if (*ptr == escape && ptr+1 != end) - { - ptr++; /* Skip escape */ - *min_str++ = *max_str++ = *ptr; - continue; - } - if (*ptr == w_one) /* '_' in SQL */ - { - *min_str++='\0'; /* This should be min char */ - *max_str++=max_sort_chr; - continue; - } - if (*ptr == w_many) /* '%' in SQL */ - { - /* - Calculate length of keys: - 'a\0\0... is the smallest possible string when we have space expand - a\ff\ff... is the biggest possible string - */ - *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) : - res_length); - *max_length= res_length; - do - { - *min_str++ = 0; - *max_str++ = max_sort_chr; - } while (min_str != min_end); - return 0; - } - *min_str++= *max_str++ = *ptr; - } - - *min_length= *max_length = (uint) (min_str - min_org); - while (min_str != min_end) - *min_str++= *max_str++ = ' '; /* Because of key compression */ - return 0; -} - - static unsigned short cs_to_uni[256]={ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F, @@ -928,7 +857,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler = my_strnncollsp_tis620, my_strnxfrm_tis620, my_strnxfrmlen_simple, - my_like_range_tis620, + my_like_range_simple, my_wildcmp_8bit, /* wildcmp */ my_strcasecmp_8bit, my_instr_simple, /* QQ: To be fixed */ @@ -992,7 +921,8 @@ CHARSET_INFO my_charset_tis620_thai_ci= 1, /* mbminlen */ 1, /* mbmaxlen */ 0, /* min_sort_char */ - 0, /* max_sort_char */ + 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -1023,7 +953,8 @@ CHARSET_INFO my_charset_tis620_bin= 1, /* mbminlen */ 1, /* mbmaxlen */ 0, /* min_sort_char */ - 0, /* max_sort_char */ + 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_8bit_bin_handler diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index dcf1c07113e..4768e42a0b0 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -6692,6 +6692,18 @@ static const char persian[]= " < \\uFEF5 < \\uFEF6 < \\uFEF7 < \\uFEF8 < \\uFEF9 < \\uFEFA" " < \\uFEFB < \\uFEFC"; +/* + Esperanto tailoring. + Contributed by Bertilo Wennergren <bertilow at gmail dot com> + September 1, 2005 +*/ +static const char esperanto[]= + "& C < \\u0109 <<< \\u0108" + "& G < \\u011D <<< \\u011C" + "& H < \\u0125 <<< \\u0124" + "& J < \\u0135 <<< \\u0134" + "& S < \\u015d <<< \\u015c" + "& U < \\u016d <<< \\u016c"; /* Unicode Collation Algorithm: @@ -7942,6 +7954,7 @@ static my_bool create_tailoring(CHARSET_INFO *cs, void *(*alloc)(uint)) static my_bool my_coll_init_uca(CHARSET_INFO *cs, void *(*alloc)(uint)) { + cs->pad_char= ' '; return create_tailoring(cs, alloc); } @@ -8059,6 +8072,7 @@ CHARSET_INFO my_charset_ucs2_general_uca= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8090,6 +8104,7 @@ CHARSET_INFO my_charset_ucs2_icelandic_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8121,6 +8136,7 @@ CHARSET_INFO my_charset_ucs2_latvian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8152,6 +8168,7 @@ CHARSET_INFO my_charset_ucs2_romanian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8183,6 +8200,7 @@ CHARSET_INFO my_charset_ucs2_slovenian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8214,6 +8232,7 @@ CHARSET_INFO my_charset_ucs2_polish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8245,6 +8264,7 @@ CHARSET_INFO my_charset_ucs2_estonian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8276,6 +8296,7 @@ CHARSET_INFO my_charset_ucs2_spanish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8307,6 +8328,7 @@ CHARSET_INFO my_charset_ucs2_swedish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8338,6 +8360,7 @@ CHARSET_INFO my_charset_ucs2_turkish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8369,6 +8392,7 @@ CHARSET_INFO my_charset_ucs2_czech_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8401,6 +8425,7 @@ CHARSET_INFO my_charset_ucs2_danish_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8432,6 +8457,7 @@ CHARSET_INFO my_charset_ucs2_lithuanian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8463,6 +8489,7 @@ CHARSET_INFO my_charset_ucs2_slovak_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8494,6 +8521,7 @@ CHARSET_INFO my_charset_ucs2_spanish2_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8526,6 +8554,7 @@ CHARSET_INFO my_charset_ucs2_roman_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8558,6 +8587,40 @@ CHARSET_INFO my_charset_ucs2_persian_uca_ci= 2, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_ucs2_handler, + &my_collation_ucs2_uca_handler +}; + + +CHARSET_INFO my_charset_ucs2_esperanto_uca_ci= +{ + 145,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "ucs2", /* cs name */ + "ucs2_esperanto_ci",/* name */ + "", /* comment */ + esperanto, /* tailoring */ + NULL, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 2, /* mbminlen */ + 2, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_uca_handler @@ -8637,6 +8700,7 @@ CHARSET_INFO my_charset_utf8_general_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8669,6 +8733,7 @@ CHARSET_INFO my_charset_utf8_icelandic_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8700,6 +8765,7 @@ CHARSET_INFO my_charset_utf8_latvian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8731,6 +8797,7 @@ CHARSET_INFO my_charset_utf8_romanian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8762,6 +8829,7 @@ CHARSET_INFO my_charset_utf8_slovenian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8793,6 +8861,7 @@ CHARSET_INFO my_charset_utf8_polish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8824,6 +8893,7 @@ CHARSET_INFO my_charset_utf8_estonian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8855,6 +8925,7 @@ CHARSET_INFO my_charset_utf8_spanish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8886,6 +8957,7 @@ CHARSET_INFO my_charset_utf8_swedish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8917,6 +8989,7 @@ CHARSET_INFO my_charset_utf8_turkish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8948,6 +9021,7 @@ CHARSET_INFO my_charset_utf8_czech_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -8980,6 +9054,7 @@ CHARSET_INFO my_charset_utf8_danish_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -9011,6 +9086,7 @@ CHARSET_INFO my_charset_utf8_lithuanian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -9042,6 +9118,7 @@ CHARSET_INFO my_charset_utf8_slovak_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -9073,6 +9150,7 @@ CHARSET_INFO my_charset_utf8_spanish2_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -9104,6 +9182,7 @@ CHARSET_INFO my_charset_utf8_roman_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler @@ -9135,6 +9214,39 @@ CHARSET_INFO my_charset_utf8_persian_uca_ci= 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_utf8_handler, + &my_collation_any_uca_handler +}; + +CHARSET_INFO my_charset_utf8_esperanto_uca_ci= +{ + 209,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "utf8", /* cs name */ + "utf8_esperanto_ci",/* name */ + "", /* comment */ + esperanto, /* tailoring */ + ctype_utf8, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 1, /* mbminlen */ + 3, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_any_uca_handler diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 41ab055d2de..80a7bd84601 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1063,7 +1063,7 @@ int my_ll10tostr_ucs2(CHARSET_INFO *cs __attribute__((unused)), while (long_val != 0) { long quo= long_val/10; - *--p = '0' + (char)(long_val - quo*10); + *--p = (char) ('0' + (long_val - quo*10)); long_val= quo; } @@ -1450,10 +1450,12 @@ my_bool my_like_range_ucs2(CHARSET_INFO *cs, const char *end=ptr+ptr_length; char *min_org=min_str; char *min_end=min_str+res_length; + uint charlen= res_length / cs->mbmaxlen; - for (; ptr + 1 < end && min_str + 1 < min_end ; ptr+=2) + for ( ; ptr + 1 < end && min_str + 1 < min_end && charlen > 0 + ; ptr+=2, charlen--) { - if (ptr[0] == '\0' && ptr[1] == escape && ptr+2 < end) + if (ptr[0] == '\0' && ptr[1] == escape && ptr + 1 < end) { ptr+=2; /* Skip escape */ *min_str++= *max_str++ = ptr[0]; @@ -1621,6 +1623,7 @@ CHARSET_INFO my_charset_ucs2_general_ci= 2, /* mbmaxlen */ 0, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_general_ci_handler @@ -1652,6 +1655,7 @@ CHARSET_INFO my_charset_ucs2_bin= 2, /* mbmaxlen */ 0, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_ucs2_handler, &my_collation_ucs2_bin_handler diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index 57ca2de2852..696eecaa794 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -8576,6 +8576,7 @@ CHARSET_INFO my_charset_ujis_japanese_ci= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler @@ -8608,6 +8609,7 @@ CHARSET_INFO my_charset_ujis_bin= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 88b6b7d5c86..e1bb746fd9a 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2579,6 +2579,7 @@ CHARSET_INFO my_charset_utf8_general_ci= 3, /* mbmaxlen */ 0, /* min_sort_char */ 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_ci_handler @@ -2611,6 +2612,7 @@ CHARSET_INFO my_charset_utf8_bin= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_mb_bin_handler @@ -2781,6 +2783,7 @@ CHARSET_INFO my_charset_utf8_general_cs= 3, /* mbmaxlen */ 0, /* min_sort_char */ 255, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_utf8_handler, &my_collation_cs_handler diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index c6b396658d4..16b8ce5aac4 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -662,6 +662,7 @@ CHARSET_INFO my_charset_cp1250_czech_ci = 1, /* mbmaxlen */ 0, /* min_sort_char */ 0, /* max_sort_char */ + ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_8bit_handler, &my_collation_czech_ci_handler diff --git a/strings/decimal.c b/strings/decimal.c index 4dc5fa91e0a..ea6ac2caf38 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1033,7 +1033,7 @@ int decimal2ulonglong(decimal_t *from, ulonglong *to) { ulonglong y=x; x=x*DIG_BASE + *buf++; - if (unlikely(y > (ULONGLONG_MAX/DIG_BASE) || x < y)) + if (unlikely(y > ((ulonglong) ULONGLONG_MAX/DIG_BASE) || x < y)) { *to=y; return E_DEC_OVERFLOW; @@ -1933,7 +1933,7 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), intg0=ROUND_UP(from1->intg+from2->intg), - frac0=frac1+frac2, error, i, j; + frac0=frac1+frac2, error, i, j, d_to_move; dec1 *buf1=from1->buf+intg1, *buf2=from2->buf+intg2, *buf0, *start2, *stop2, *stop1, *start0, carry; @@ -2007,6 +2007,20 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) } } } + buf1= to->buf; + d_to_move= intg0 + ROUND_UP(to->frac); + while (!*buf1 && (to->intg > DIG_PER_DEC1)) + { + buf1++; + to->intg-= DIG_PER_DEC1; + d_to_move--; + } + if (to->buf < buf1) + { + dec1 *cur_d= to->buf; + for (; d_to_move--; cur_d++, buf1++) + *cur_d= *buf1; + } return error; } diff --git a/strings/longlong2str-x86.s b/strings/longlong2str-x86.s index 1840bab3f47..168dab38a85 100644 --- a/strings/longlong2str-x86.s +++ b/strings/longlong2str-x86.s @@ -26,95 +26,88 @@ .type longlong2str_with_dig_vector,@function longlong2str_with_dig_vector: - subl $80,%esp + subl $80,%esp # Temporary buffer for up to 64 radix-2 digits pushl %ebp pushl %esi pushl %edi pushl %ebx - movl 100(%esp),%esi # Lower part of val - movl 112(%esp),%ebx # Radix - movl 104(%esp),%ebp # Higher part of val - movl %ebx,%eax - movl 108(%esp),%edi # get dst - testl %eax,%eax - jge .L144 + movl 100(%esp),%esi # esi = Lower part of val + movl 112(%esp),%ebx # ebx = Radix + movl 104(%esp),%ebp # ebp = Higher part of val + movl 108(%esp),%edi # edi = dst - addl $36,%eax - cmpl $34,%eax - ja .Lerror # Wrong radix - testl %ebp,%ebp - jge .L146 + testl %ebx,%ebx + jge .L144 # Radix was positive + negl %ebx # Change radix to positive + testl %ebp,%ebp # Test if given value is negative + jge .L144 movb $45,(%edi) # Add sign incl %edi # Change sign of val negl %esi adcl $0,%ebp negl %ebp -.L146: - negl %ebx # Change radix to positive - jmp .L148 - .align 4 -.L144: - addl $-2,%eax + +.L144: # Test that radix is between 2 and 36 + movl %ebx, %eax + addl $-2,%eax # Test that radix is between 2 and 36 cmpl $34,%eax - ja .Lerror # Radix in range - -.L148: - movl %esi,%eax # Test if zero (for easy loop) - orl %ebp,%eax - jne .L150 - movb $48,(%edi) - incl %edi - jmp .L10_end - .align 4 + ja .Lerror # Radix was not in range -.L150: leal 92(%esp),%ecx # End of buffer movl %edi, 108(%esp) # Store possible modified dest movl 116(%esp), %edi # dig_vec_upper - jmp .L155 - .align 4 - -.L153: - # val is stored in in ebp:esi + testl %ebp,%ebp # Test if value > 0xFFFFFFFF + jne .Llongdiv + cmpl %ebx, %esi # Test if <= radix, for easy loop + movl %esi, %eax # Value in eax (for Llow) + jae .Llow + + # Value is one digit (negative or positive) + movb (%eax,%edi),%bl + movl 108(%esp),%edi # get dst + movb %bl,(%edi) + incl %edi # End null here + jmp .L10_end - movl %ebp,%eax # High part of value +.Llongdiv: + # Value in ebp:esi. div the high part by the radix, + # then div remainder + low part by the radix. + movl %ebp,%eax # edx=0,eax=high(from ebp) xorl %edx,%edx + decl %ecx divl %ebx - movl %eax,%ebp + movl %eax,%ebp # edx=result of last, eax=low(from esi) movl %esi,%eax divl %ebx - decl %ecx - movl %eax,%esi # quotent in ebp:esi - movb (%edx,%edi),%al # al is faster than dl - movb %al,(%ecx) # store value in buff - .align 4 -.L155: + movl %eax,%esi # ebp:esi = quotient + movb (%edx,%edi),%dl # Store result number in temporary buffer testl %ebp,%ebp - ja .L153 - testl %esi,%esi # rest value - jl .L153 - je .L160 # Ready - movl %esi,%eax + movb %dl,(%ecx) # store value in buff + ja .Llongdiv # (Higher part of val still > 0) + .align 4 - -.L154: # Do rest with integer precision - cltd - divl %ebx +.Llow: # Do rest with integer precision + # Value in 0:eax. div 0 + low part by the radix. + xorl %edx,%edx decl %ecx + divl %ebx movb (%edx,%edi),%dl # bh is always zero as ebx=radix < 36 testl %eax,%eax movb %dl,(%ecx) - jne .L154 + jne .Llow .L160: movl 108(%esp),%edi # get dst - -.L10_mov: - movl %ecx,%esi - leal 92(%esp),%ecx # End of buffer - subl %esi,%ecx - rep - movsb + +.Lcopy_end: + leal 92(%esp),%esi # End of buffer +.Lmov: # mov temporary buffer to result (%ecx -> %edi) + movb (%ecx), %al + movb %al, (%edi) + incl %ecx + incl %edi + cmpl %ecx,%esi + jne .Lmov .L10_end: movl %edi,%eax # Pointer to end null @@ -166,21 +159,23 @@ longlong10_to_str: negl %esi # Change sign of val (ebp:esi) adcl $0,%ebp negl %ebp - .align 4 .L10_10: leal 92(%esp),%ecx # End of buffer - movl %esi,%eax # Test if zero (for easy loop) - orl %ebp,%eax - jne .L10_30 # Not zero - - # Here when value is zero - movb $48,(%edi) + testl %ebp,%ebp # Test if value > 0xFFFFFFFF + jne .L10_longdiv + cmpl $10, %esi # Test if <= radix, for easy loop + movl %esi, %ebx # Value in eax (for L10_low) + jae .L10_low + + # Value is one digit (negative or positive) + addb $48, %bl + movb %bl,(%edi) incl %edi jmp .L10_end .align 4 -.L10_20: +.L10_longdiv: # val is stored in in ebp:esi movl %ebp,%eax # High part of value xorl %edx,%edx @@ -195,17 +190,15 @@ longlong10_to_str: .L10_30: testl %ebp,%ebp - ja .L10_20 - testl %esi,%esi # rest value - jl .L10_20 # Unsigned, do ulonglong div once more - je .L10_mov # Ready + ja .L10_longdiv movl %esi,%ebx # Move val to %ebx +.L10_low: # The following code uses some tricks to change division by 10 to # multiplication and shifts movl $0xcccccccd,%esi -.L10_40: +.L10_40: # Divide %ebx with 10 movl %ebx,%eax mull %esi decl %ecx @@ -218,7 +211,7 @@ longlong10_to_str: movl %edx,%ebx testl %ebx,%ebx jne .L10_40 - jmp .L10_mov # Shared end with longlong10_to_str + jmp .Lcopy_end # Shared end with longlong2str .L10end: .size longlong10_to_str,.L10end-longlong10_to_str diff --git a/strings/my_strtoll10.c b/strings/my_strtoll10.c index cca7c8ab396..b9b09810c51 100644 --- a/strings/my_strtoll10.c +++ b/strings/my_strtoll10.c @@ -19,7 +19,16 @@ #include <m_string.h> #undef ULONGLONG_MAX +/* + Needed under MetroWerks Compiler, since MetroWerks compiler does not + properly handle a constant expression containing a mod operator +*/ +#if defined(__NETWARE__) && defined(__MWERKS__) +static ulonglong ulonglong_max= ~(ulonglong) 0; +#define ULONGLONG_MAX ulonglong_max +#else #define ULONGLONG_MAX (~(ulonglong) 0) +#endif /* __NETWARE__ && __MWERKS__ */ #define MAX_NEGATIVE_NUMBER ((ulonglong) LL(0x8000000000000000)) #define INIT_CNT 9 #define LFACTOR ULL(1000000000) diff --git a/strings/xml.c b/strings/xml.c index 02ca3932c39..767cb004d34 100644 --- a/strings/xml.c +++ b/strings/xml.c @@ -81,7 +81,7 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a) a->beg=p->cur; a->end=p->cur; - if (!bcmp(p->cur,"<!--",4)) + if ((p->end - p->cur > 3) && !bcmp(p->cur,"<!--",4)) { for( ; (p->cur < p->end) && bcmp(p->cur, "-->", 3); p->cur++) {} diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 6757a1052a8..6dbffdc9778 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -39,7 +39,8 @@ # If you want to affect other MySQL variables, you should make your changes # in the /etc/my.cnf, ~/.my.cnf or other MySQL configuration files. -# If you change base dir, you must also change datadir +# If you change base dir, you must also change datadir. These may get +# overwritten by settings in the MySQL configuration files. basedir= datadir= @@ -61,8 +62,8 @@ then else bindir="$basedir/bin" datadir="$basedir/data" - sbindir="$basedir/bin" - libexecdir="$basedir/bin" + sbindir="$basedir/sbin" + libexecdir="$basedir/libexec" fi # @@ -99,8 +100,8 @@ parse_server_arguments() { --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'` bindir="$basedir/bin" datadir="$basedir/data" - sbindir="$basedir/bin" - libexecdir="$basedir/bin" + sbindir="$basedir/sbin" + libexecdir="$basedir/libexec" ;; --datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; @@ -240,7 +241,7 @@ case "$mode" in if test -x $libexecdir/mysqlmanager then manager=$libexecdir/mysqlmanager - elif test -x $bindir/mysqlmanager + elif test -x $sbindir/mysqlmanager then manager=$sbindir/mysqlmanager fi diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 637a0402b8e..265f576cd86 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1,8 +1,15 @@ %define mysql_version @VERSION@ + # use "rpmbuild --with static" or "rpm --define '_with_static 1'" (for RPM 3.x) # to enable static linking (off by default) %{?_with_static:%define STATIC_BUILD 1} %{!?_with_static:%define STATIC_BUILD 0} + +# use "rpmbuild --with yassl" or "rpm --define '_with_yassl 1'" (for RPM 3.x) +# to build with yaSSL support (off by default) +%{?_with_yassl:%define YASSL_BUILD 1} +%{!?_with_yassl:%define YASSL_BUILD 0} + %if %{STATIC_BUILD} %define release 0 %else @@ -10,6 +17,7 @@ %endif %define license GPL %define mysqld_user mysql +%define mysqld_group mysql %define server_suffix -standard %define mysqldatadir /var/lib/mysql @@ -238,6 +246,9 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --with-unix-socket-path=/var/lib/mysql/mysql.sock \ --prefix=/ \ --with-extra-charsets=complex \ +%if %{YASSL_BUILD} + --with-yassl \ +%endif --exec-prefix=%{_exec_prefix} \ --libexecdir=%{_sbindir} \ --libdir=%{_libdir} \ @@ -248,11 +259,9 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --includedir=%{_includedir} \ --mandir=%{_mandir} \ --enable-thread-safe-client \ - --with-readline ; + --with-readline ; \ # Add this for more debugging support # --with-debug - # Add this for MyISAM RAID support: - # --with-raid " # benchdir does not fit in above model. Maybe a separate bench distribution @@ -295,7 +304,6 @@ then fi BuildMySQL "--enable-shared \ - --without-openssl \ --with-berkeley-db \ --with-innodb \ --with-ndbcluster \ @@ -304,24 +312,29 @@ BuildMySQL "--enable-shared \ --with-example-storage-engine \ --with-blackhole-storage-engine \ --with-federated-storage-engine \ - --with-embedded-server \ - --with-comment=\"MySQL Community Edition - Max (GPL)\" \ - --with-server-suffix='-Max'" + --with-big-tables \ + --with-comment=\"MySQL Community Edition - Experimental (GPL)\" \ + --with-server-suffix='-max'" + +# We might want to save the config log file +if test -n "$MYSQL_MAXCONFLOG_DEST" +then + cp -fp config.log "$MYSQL_MAXCONFLOG_DEST" +fi make test-force || true # Save mysqld-max mv sql/mysqld sql/mysqld-max nm --numeric-sort sql/mysqld-max > sql/mysqld-max.sym +# Save the perror binary so it supports the NDB error codes (BUG#13740) +mv extra/perror extra/perror.ndb # Install the ndb binaries (cd ndb; make install DESTDIR=$RBR) -# Install embedded server library in the build root -install -m 644 libmysqld/libmysqld.a $RBR%{_libdir}/mysql/ - # Include libgcc.a in the devel subpackage (BUG 4921) -if [ "$CC" = gcc ] +if expr "$CC" : ".*gcc.*" > /dev/null ; then libgcc=`$CC --print-libgcc-file` if [ -f $libgcc ] @@ -353,13 +366,17 @@ BuildMySQL "--disable-shared \ %endif --with-comment=\"MySQL Community Edition - Standard (GPL)\" \ --with-server-suffix='%{server_suffix}' \ - --without-embedded-server \ - --without-berkeley-db \ + --with-archive-storage-engine \ --with-innodb \ - --without-vio \ - --without-openssl" + --with-big-tables" nm --numeric-sort sql/mysqld > sql/mysqld.sym +# We might want to save the config log file +if test -n "$MYSQL_CONFLOG_DEST" +then + cp -fp config.log "$MYSQL_CONFLOG_DEST" +fi + make test-force || true %install @@ -383,15 +400,22 @@ make install-strip DESTDIR=$RBR benchdir_root=%{_datadir} (cd $RBR%{_libdir}; tar xf $RBR/shared-libs.tar; rm -f $RBR/shared-libs.tar) # install saved mysqld-max -install -s -m755 $MBD/sql/mysqld-max $RBR%{_sbindir}/mysqld-max +install -s -m 755 $MBD/sql/mysqld-max $RBR%{_sbindir}/mysqld-max + +# install saved perror binary with NDB support (BUG#13740) +install -s -m 755 $MBD/extra/perror.ndb $RBR%{_bindir}/perror # install symbol files ( for stack trace resolution) -install -m644 $MBD/sql/mysqld-max.sym $RBR%{_libdir}/mysql/mysqld-max.sym -install -m644 $MBD/sql/mysqld.sym $RBR%{_libdir}/mysql/mysqld.sym +install -m 644 $MBD/sql/mysqld-max.sym $RBR%{_libdir}/mysql/mysqld-max.sym +install -m 644 $MBD/sql/mysqld.sym $RBR%{_libdir}/mysql/mysqld.sym # Install logrotate and autostart -install -m644 $MBD/support-files/mysql-log-rotate $RBR%{_sysconfdir}/logrotate.d/mysql -install -m755 $MBD/support-files/mysql.server $RBR%{_sysconfdir}/init.d/mysql +install -m 644 $MBD/support-files/mysql-log-rotate $RBR%{_sysconfdir}/logrotate.d/mysql +install -m 755 $MBD/support-files/mysql.server $RBR%{_sysconfdir}/init.d/mysql + +# Install embedded server library in the build root +# FIXME No libmysqld on 5.0 yet +#install -m 644 libmysqld/libmysqld.a $RBR%{_libdir}/mysql/ # Create a symlink "rcmysql", pointing to the init.script. SuSE users # will appreciate that, as all services usually offer this. @@ -425,7 +449,7 @@ fi mysql_datadir=%{mysqldatadir} # Create data directory if needed -if test ! -d $mysql_datadir; then mkdir -m755 $mysql_datadir; fi +if test ! -d $mysql_datadir; then mkdir -m 755 $mysql_datadir; fi if test ! -d $mysql_datadir/mysql; then mkdir $mysql_datadir/mysql; fi if test ! -d $mysql_datadir/test; then mkdir $mysql_datadir/test; fi @@ -442,18 +466,20 @@ fi # Create a MySQL user and group. Do not report any problems if it already # exists. -groupadd -r %{mysqld_user} 2> /dev/null || true -useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" -g %{mysqld_user} %{mysqld_user} 2> /dev/null || true +groupadd -r %{mysqld_group} 2> /dev/null || true +useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" -g %{mysqld_group} %{mysqld_user} 2> /dev/null || true +# The user may already exist, make sure it has the proper group nevertheless (BUG#12823) +usermod -g %{mysqld_group} %{mysqld_user} 2> /dev/null || true # Change permissions so that the user that will run the MySQL daemon # owns all database files. -chown -R %{mysqld_user}:%{mysqld_user} $mysql_datadir +chown -R %{mysqld_user}:%{mysqld_group} $mysql_datadir # Initiate databases %{_bindir}/mysql_install_db --rpm --user=%{mysqld_user} # Change permissions again to fix any new files. -chown -R %{mysqld_user}:%{mysqld_user} $mysql_datadir +chown -R %{mysqld_user}:%{mysqld_group} $mysql_datadir # Fix permissions for the permission database so that only the user # can read them. @@ -470,7 +496,7 @@ sleep 2 mysql_clusterdir=/var/lib/mysql-cluster # Create cluster directory if needed -if test ! -d $mysql_clusterdir; then mkdir -m755 $mysql_clusterdir; fi +if test ! -d $mysql_clusterdir; then mkdir -m 755 $mysql_clusterdir; fi %post Max @@ -504,7 +530,7 @@ fi # Clean up the BuildRoot %clean -[ "$RBR" != "/" ] && [ -d $RBR ] && rm -rf $RBR; +[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; %files server %defattr(-,root,root,0755) @@ -650,7 +676,7 @@ fi %defattr(-, root, root, 0755) %attr(-, root, root) %{_datadir}/sql-bench %attr(-, root, root) %{_datadir}/mysql-test -%attr(755, rott, root) %{_bindir}/mysql_client_test +%attr(755, root, root) %{_bindir}/mysql_client_test %attr(755, root, root) %{_bindir}/mysqltestmanager %attr(755, root, root) %{_bindir}/mysqltestmanager-pwgen %attr(755, root, root) %{_bindir}/mysqltestmanagerc @@ -662,12 +688,54 @@ fi %files embedded %defattr(-, root, root, 0755) -%attr(644, root, root) %{_libdir}/mysql/libmysqld.a +# %attr(644, root, root) %{_libdir}/mysql/libmysqld.a # The spec file changelog only includes changes made to the spec file # itself - note that they must be ordered by date (important when # merging BK trees) %changelog +* Wed Oct 19 2005 Kent Boortz <kent@mysql.com> + +- Made yaSSL support an option (off by default) + +* Wed Oct 19 2005 Kent Boortz <kent@mysql.com> + +- Enabled yaSSL support + +* Sat Oct 15 2005 Kent Boortz <kent@mysql.com> + +- Give mode arguments the same way in all places +- Moved copy of mysqld.a to "standard" build, but + disabled it as we don't do embedded yet in 5.0 + +* Fri Oct 14 2005 Kent Boortz <kent@mysql.com> + +- For 5.x, always compile with --with-big-tables +- Copy the config.log file to location outside + the build tree + +* Fri Oct 14 2005 Kent Boortz <kent@mysql.com> + +- Removed unneeded/obsolte configure options +- Added archive engine to standard server +- Removed the embedded server from experimental server +- Changed suffix "-Max" => "-max" +- Changed comment string "Max" => "Experimental" + +* Thu Oct 13 2005 Lenz Grimmer <lenz@mysql.com> + +- added a usermod call to assign a potential existing mysql user to the + correct user group (BUG#12823) +- Save the perror binary built during Max build so it supports the NDB + error codes (BUG#13740) +- added a separate macro "mysqld_group" to be able to define the + user group of the mysql user seperately, if desired. + +* Thu Sep 29 2005 Lenz Grimmer <lenz@mysql.com> + +- fixed the removing of the RPM_BUILD_ROOT in the %clean section (the + $RBR variable did not get expanded, thus leaving old build roots behind) + * Thu Aug 04 2005 Lenz Grimmer <lenz@mysql.com> - Fixed the creation of the mysql user group account in the postinstall diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 84a32b52284..65a4617445c 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13828,8 +13828,11 @@ static void test_bug10760() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); rc= mysql_query(mysql, "update t1 set id=id+100"); - DIE_UNLESS(rc); - if (!opt_silent) + /* + If cursors are not materialized, the update will return an error; + we mainly test that it won't deadlock. + */ + if (rc && !opt_silent) printf("Got error (as expected): %s\n", mysql_error(mysql)); /* 2: check that MyISAM tables used in cursors survive diff --git a/tools/mysqlmanager.c b/tools/mysqlmanager.c index 4a5c08be50a..4d507fc3d32 100644 --- a/tools/mysqlmanager.c +++ b/tools/mysqlmanager.c @@ -332,8 +332,8 @@ static int client_msg_raw(NET* net,int err_code,int pre,const char* fmt, static int authenticate(struct manager_thd* thd); /* returns pointer to end of line */ static char* read_line(struct manager_thd* thd); -static pthread_handler_decl(process_connection, arg); -static pthread_handler_decl(process_launcher_messages, arg); +pthread_handler_t process_connection(void *arg); +pthread_handler_t process_launcher_messages(void *arg); static int exec_line(struct manager_thd* thd,char* buf,char* buf_end); #ifdef DO_STACKTRACE @@ -1089,8 +1089,7 @@ static void log_msg(const char* fmt, int msg_type, va_list args) pthread_mutex_unlock(&lock_log); } -static pthread_handler_decl(process_launcher_messages, - args __attribute__((unused))) +pthread_handler_t process_launcher_messages(void *arg __attribute__((unused))) { my_thread_init(); for (;!in_shutdown;) @@ -1146,7 +1145,7 @@ static pthread_handler_decl(process_launcher_messages, return 0; } -static pthread_handler_decl(process_connection,arg) +pthread_handler_t process_connection(void *arg) { struct manager_thd* thd = (struct manager_thd*)arg; my_thread_init(); diff --git a/vio/vio.c b/vio/vio.c index bcf0ac032c8..ff93cff959f 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -54,6 +54,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_fastsend; vio->viokeepalive =vio_keepalive; vio->should_retry =vio_should_retry; + vio->was_interrupted=vio_was_interrupted; vio->vioclose =vio_close_pipe; vio->peer_addr =vio_peer_addr; vio->in_addr =vio_in_addr; @@ -73,6 +74,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_fastsend; vio->viokeepalive =vio_keepalive; vio->should_retry =vio_should_retry; + vio->was_interrupted=vio_was_interrupted; vio->vioclose =vio_close_shared_memory; vio->peer_addr =vio_peer_addr; vio->in_addr =vio_in_addr; @@ -92,6 +94,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_ssl_fastsend; vio->viokeepalive =vio_ssl_keepalive; vio->should_retry =vio_ssl_should_retry; + vio->was_interrupted=vio_ssl_was_interrupted; vio->vioclose =vio_ssl_close; vio->peer_addr =vio_ssl_peer_addr; vio->in_addr =vio_ssl_in_addr; @@ -109,6 +112,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_fastsend; vio->viokeepalive =vio_keepalive; vio->should_retry =vio_should_retry; + vio->was_interrupted=vio_was_interrupted; vio->vioclose =vio_close; vio->peer_addr =vio_peer_addr; vio->in_addr =vio_in_addr; @@ -145,10 +149,18 @@ Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags) vio->sd); #if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) #if !defined(NO_FCNTL_NONBLOCK) -#if defined(__FreeBSD__) - fcntl(sd, F_SETFL, vio->fcntl_mode); /* Yahoo! FreeBSD patch */ -#endif - vio->fcntl_mode = fcntl(sd, F_GETFL); + /* + We call fcntl() to set the flags and then immediately read them back + to make sure that we and the system are in agreement on the state of + things. + + An example of why we need to do this is FreeBSD (and apparently some + other BSD-derived systems, like Mac OS X), where the system sometimes + reports that the socket is set for non-blocking when it really will + block. + */ + fcntl(sd, F_SETFL, 0); + vio->fcntl_mode= fcntl(sd, F_GETFL); #elif defined(HAVE_SYS_IOCTL_H) /* hpux */ /* Non blocking sockets doesn't work good on HPUX 11.0 */ (void) ioctl(sd,FIOSNBIO,0); diff --git a/vio/vio_priv.h b/vio/vio_priv.h index 3a75a08021d..c1c78cc6efa 100644 --- a/vio/vio_priv.h +++ b/vio/vio_priv.h @@ -39,6 +39,8 @@ int vio_ssl_fastsend(Vio *vio); int vio_ssl_keepalive(Vio *vio, my_bool onoff); /* Whenever we should retry the last read/write operation. */ my_bool vio_ssl_should_retry(Vio *vio); +/* Check that operation was timed out */ +my_bool vio_ssl_was_interrupted(Vio *vio); /* When the workday is over... */ int vio_ssl_close(Vio *vio); /* Return last error number */ diff --git a/vio/viosocket.c b/vio/viosocket.c index 3b4013f4089..5e0ed20b039 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -138,14 +138,21 @@ int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode, else vio->fcntl_mode |= O_NONBLOCK; /* set bit */ if (old_fcntl != vio->fcntl_mode) - r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode); + { + r= fcntl(vio->sd, F_SETFL, vio->fcntl_mode); + if (r == -1) + { + DBUG_PRINT("info", ("fcntl failed, errno %d", errno)); + vio->fcntl_mode= old_fcntl; + } + } } #else r= set_blocking_mode ? 0 : 1; #endif /* !defined(NO_FCNTL_NONBLOCK) */ #else /* !defined(__WIN__) && !defined(__EMX__) */ #ifndef __EMX__ - if (vio->type != VIO_TYPE_NAMEDPIPE) + if (vio->type != VIO_TYPE_NAMEDPIPE && vio->type != VIO_TYPE_SHARED_MEMORY) #endif { ulong arg; @@ -242,6 +249,15 @@ vio_should_retry(Vio * vio __attribute__((unused))) } +my_bool +vio_was_interrupted(Vio *vio __attribute__((unused))) +{ + int en= socket_errno; + return (en == SOCKET_EAGAIN || en == SOCKET_EINTR || + en == SOCKET_EWOULDBLOCK || en == SOCKET_ETIMEDOUT); +} + + int vio_close(Vio * vio) { int r=0; diff --git a/vio/viossl.c b/vio/viossl.c index 7528e9071cf..e6af07c4b0b 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -184,6 +184,15 @@ vio_ssl_should_retry(Vio * vio __attribute__((unused))) } +my_bool +vio_ssl_was_interrupted(Vio *vio __attribute__((unused))) +{ + int en= socket_errno; + return (en == SOCKET_EAGAIN || en == SOCKET_EINTR || + en == SOCKET_EWOULDBLOCK || en == SOCKET_ETIMEDOUT); +} + + int vio_ssl_close(Vio * vio) { int r; @@ -283,9 +292,10 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout) X509* client_cert; my_bool unused; my_bool net_blocking; - enum enum_vio_type old_type; + enum enum_vio_type old_type; DBUG_ENTER("sslaccept"); - DBUG_PRINT("enter", ("sd: %d ptr: Ox%p", vio->sd,ptr)); + DBUG_PRINT("enter", ("sd: %d ptr: Ox%p, timeout: %d", + vio->sd, ptr, timeout)); old_type= vio->type; net_blocking = vio_is_blocking(vio); @@ -379,7 +389,7 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout) (SSL*) vio->ssl_arg, timeout)); SSL_clear((SSL*) vio->ssl_arg); SSL_SESSION_set_timeout(SSL_get_session((SSL*) vio->ssl_arg), timeout); - SSL_set_fd ((SSL*) vio->ssl_arg, vio->sd); + SSL_set_fd ((SSL*) vio->ssl_arg, vio_ssl_fd(vio)); SSL_set_connect_state((SSL*) vio->ssl_arg); if (SSL_do_handshake((SSL*) vio->ssl_arg) < 1) { diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 44a077c33fc..766d835d2c0 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -219,9 +219,6 @@ new_VioSSLConnectorFd(const char* key_file, int result; DH *dh; DBUG_ENTER("new_VioSSLConnectorFd"); - DBUG_PRINT("enter", - ("key_file: %s, cert_file: %s, ca_path: %s, ca_file: %s, cipher: %s", - key_file, cert_file, ca_path, ca_file, cipher)); if (!(ptr=((struct st_VioSSLConnectorFd*) my_malloc(sizeof(struct st_VioSSLConnectorFd),MYF(0))))) @@ -314,9 +311,6 @@ new_VioSSLAcceptorFd(const char *key_file, int result; DH *dh; DBUG_ENTER("new_VioSSLAcceptorFd"); - DBUG_PRINT("enter", - ("key_file: %s, cert_file: %s, ca_path: %s, ca_file: %s, cipher: %s", - key_file, cert_file, ca_path, ca_file, cipher)); ptr= ((struct st_VioSSLAcceptorFd*) my_malloc(sizeof(struct st_VioSSLAcceptorFd),MYF(0))); diff --git a/zlib/ChangeLog b/zlib/ChangeLog index 1af7633d668..7f6869d3235 100644 --- a/zlib/ChangeLog +++ b/zlib/ChangeLog @@ -1,10 +1,96 @@ ChangeLog file for zlib -Changes in port for MySQL (19 July 2004) -- removed contrib, nt, os2, amiga, directories and some other files not used -in MySQL distribution. If you are working on porting MySQL to one of rare -platforms, you might find worth looking at the original zlib distribution -and using appropriate Makefiles/project files from it. + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Added zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] Changes in 1.2.2 (3 October 2004) - Update zlib.h comments on gzip in-memory processing @@ -454,7 +540,7 @@ Changes in 1.0.7 (20 Jan 1998) Changes in 1.0.6 (19 Jan 1998) - add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) -- Fix a deflate bug occuring only with compression level 0 (thanks to +- Fix a deflate bug occurring only with compression level 0 (thanks to Andy Buckler for finding this one). - In minigzip, pass transparently also the first byte for .Z files. - return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() @@ -148,13 +148,6 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html format using deflateInit2(). You can also request that inflate decode the gzip format using inflateInit2(). Read zlib.h for more details. - Note that you cannot specify special gzip header contents (e.g. a file - name or modification date), nor will inflate tell you what was in the - gzip header. If you need to customize the header or see what's in it, - you can use the raw deflate and inflate operations and the crc32() - function and roll your own gzip encoding and decoding. Read the gzip - RFC 1952 for details of the header and trailer format. - 21. Is zlib thread-safe? Yes. However any library routines that zlib uses and any application- @@ -295,20 +288,29 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html were downright silly. So now, we simply make sure that the code always works. -36. Will zlib read the (insert any ancient or arcane format here) compressed +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of + deflate is not affected. This only started showing up recently since + zlib 1.2.x uses malloc() by default for allocations, whereas earlier + versions used calloc(), which zeros out the allocated memory. + +37. Will zlib read the (insert any ancient or arcane format here) compressed data format? Probably not. Look in the comp.compression FAQ for pointers to various formats and associated software. -37. How can I encrypt/decrypt zip files with zlib? +38. How can I encrypt/decrypt zip files with zlib? zlib doesn't support encryption. The original PKZIP encryption is very weak and can be broken with freely available programs. To get strong encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib compression. For PKZIP compatible "encryption", look at http://www.info-zip.org/ -38. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? "gzip" is the gzip format, and "deflate" is the zlib format. They should probably have called the second one "zlib" instead to avoid confusion @@ -324,14 +326,14 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html Bottom line: use the gzip format for HTTP 1.1 encoding. -39. Does zlib support the new "Deflate64" format introduced by PKWare? +40. Does zlib support the new "Deflate64" format introduced by PKWare? No. PKWare has apparently decided to keep that format proprietary, since they have not documented it as they have previous compression formats. In any case, the compression improvements are so modest compared to other more modern approaches, that it's not worth the effort to implement. -40. Can you please sign these lengthy legal documents and fax them back to us +41. Can you please sign these lengthy legal documents and fax them back to us so that we can use your software in our product? No. Go away. Shoo. diff --git a/zlib/README b/zlib/README index df95ae13f54..758cc50020d 100644 --- a/zlib/README +++ b/zlib/README @@ -1,6 +1,6 @@ ZLIB DATA COMPRESSION LIBRARY -zlib 1.2.2 is a general purpose data compression library. All the code is +zlib 1.2.3 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) @@ -16,9 +16,8 @@ minigzip.c. To compile all files and run the test program, follow the instructions given at the top of Makefile. In short "make test; make install" should work for most -machines. For Unix: "./configure; make test; make install" For MSDOS, use one -of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or -descrip.mms. +machines. For Unix: "./configure; make test; make install". For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use make_vms.com. Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant <info@winimage.com> for the Windows DLL version. The zlib home page is @@ -34,7 +33,7 @@ Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available in http://dogma.net/markn/articles/zlibtool/zlibtool.htm -The changes made in version 1.2.2 are documented in the file ChangeLog. +The changes made in version 1.2.3 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory "contrib". diff --git a/zlib/README.MySQL b/zlib/README.MySQL new file mode 100644 index 00000000000..355dfb62d71 --- /dev/null +++ b/zlib/README.MySQL @@ -0,0 +1,7 @@ +This an incomplete version of the zlib library -- it excludes some of the +platform-specific project files, contributed code, and examples from the +original zlib distribution. You can find the original distribution at + + http://www.gzip.org/zlib/ + or + http://www.zlib.net/ diff --git a/zlib/adler32.c b/zlib/adler32.c index 624a1696eb0..007ba26277c 100644 --- a/zlib/adler32.c +++ b/zlib/adler32.c @@ -1,5 +1,5 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2004 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -12,12 +12,13 @@ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); +/* use NO_DIVIDE if your processor does not do division in hardware */ #ifdef NO_DIVIDE # define MOD(a) \ do { \ @@ -39,8 +40,17 @@ if (a >= (BASE << 1)) a -= (BASE << 1); \ if (a >= BASE) a -= BASE; \ } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) #else # define MOD(a) a %= BASE +# define MOD4(a) a %= BASE #endif /* ========================================================================= */ @@ -49,26 +59,91 @@ uLong ZEXPORT adler32(adler, buf, len) const Bytef *buf; uInt len; { - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } - if (buf == Z_NULL) return 1L; + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; - while (len > 0) { - k = len < NMAX ? (int)len : NMAX; - len -= k; - while (k >= 16) { + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; DO16(buf); buf += 16; - k -= 16; } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - MOD(s1); - MOD(s2); + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); } - return (s2 << 16) | s1; + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); } diff --git a/zlib/compress.c b/zlib/compress.c index 24ef0291911..df04f0148e6 100644 --- a/zlib/compress.c +++ b/zlib/compress.c @@ -1,5 +1,5 @@ /* compress.c -- compress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. + * Copyright (C) 1995-2003 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/crc32.c b/zlib/crc32.c index b39c7e1253e..f658a9ef55e 100644 --- a/zlib/crc32.c +++ b/zlib/crc32.c @@ -1,12 +1,12 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results about a factor - * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ @@ -64,6 +64,11 @@ # define TBLS 1 #endif /* BYFOUR */ +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; @@ -72,7 +77,6 @@ local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const unsigned long FAR *)); #endif /* MAKECRCH */ - /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. @@ -270,7 +274,7 @@ local unsigned long crc32_little(crc, buf, len) len--; } - buf4 = (const u4 FAR *)buf; + buf4 = (const u4 FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; @@ -310,7 +314,7 @@ local unsigned long crc32_big(crc, buf, len) len--; } - buf4 = (const u4 FAR *)buf; + buf4 = (const u4 FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32; @@ -331,3 +335,89 @@ local unsigned long crc32_big(crc, buf, len) } #endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/zlib/deflate.c b/zlib/deflate.c index 0fc53bc1e82..29ce1f64a57 100644 --- a/zlib/deflate.c +++ b/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2004 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.2 Copyright 1995-2004 Jean-loup Gailly "; + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -264,7 +264,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_RLE) { + strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ @@ -274,6 +274,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->strm = strm; s->wrap = wrap; + s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; @@ -333,9 +334,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) if (length < MIN_MATCH) return Z_OK; if (length > MAX_DIST(s)) { length = MAX_DIST(s); -#ifndef USE_DICT_HEAD dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif } zmemcpy(s->window, dictionary, length); s->strstart = length; @@ -391,6 +390,17 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; @@ -420,7 +430,7 @@ int ZEXPORT deflateParams(strm, level, strategy) #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; @@ -440,6 +450,25 @@ int ZEXPORT deflateParams(strm, level, strategy) return err; } +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. @@ -548,20 +577,47 @@ int ZEXPORT deflate (strm, flush) if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, 255); - s->status = BUSY_STATE; - strm->adler = crc32(0L, Z_NULL, 0); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } } else #endif @@ -592,6 +648,110 @@ int ZEXPORT deflate (strm, flush) strm->adler = adler32(0L, Z_NULL, 0); } } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif /* Flush as much pending output as possible */ if (s->pending != 0) { @@ -704,7 +864,12 @@ int ZEXPORT deflateEnd (strm) if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; - if (status != INIT_STATE && status != BUSY_STATE && + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } @@ -744,12 +909,12 @@ int ZEXPORT deflateCopy (dest, source) ss = source->state; - *dest = *source; + zmemcpy(dest, source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - *ds = *ss; + zmemcpy(ds, ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); @@ -838,9 +1003,11 @@ local void lm_init (s) s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; +#ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif +#endif } #ifndef FASTEST @@ -909,7 +1076,12 @@ local uInt longest_match(s, cur_match) match = s->window + cur_match; /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use @@ -1131,6 +1303,7 @@ local void fill_window(s) later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ + /* %%% avoid this when Z_RLE */ n = s->hash_size; p = &s->head[n]; do { @@ -1309,12 +1482,12 @@ local block_state deflate_fast(s, flush) * of the string with itself at the start of the input file). */ #ifdef FASTEST - if ((s->strategy < Z_HUFFMAN_ONLY) || + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { s->match_length = longest_match_fast (s, hash_head); } #else - if (s->strategy < Z_HUFFMAN_ONLY) { + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { s->match_length = longest_match (s, hash_head); } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { s->match_length = longest_match_fast (s, hash_head); @@ -1418,7 +1591,7 @@ local block_state deflate_slow(s, flush) * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ - if (s->strategy < Z_HUFFMAN_ONLY) { + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { s->match_length = longest_match (s, hash_head); } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { s->match_length = longest_match_fast (s, hash_head); @@ -1500,3 +1673,64 @@ local block_state deflate_slow(s, flush) return flush == Z_FINISH ? finish_done : block_done; } #endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/zlib/deflate.h b/zlib/deflate.h index 410681d18a4..05a5ab3a2c1 100644 --- a/zlib/deflate.h +++ b/zlib/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2002 Jean-loup Gailly + * Copyright (C) 1995-2004 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -49,6 +49,10 @@ /* All codes must not exceed MAX_BITS bits */ #define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ @@ -93,8 +97,10 @@ typedef struct internal_state { Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ + uInt pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ Byte method; /* STORED (for zip only) or DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ diff --git a/zlib/gzio.c b/zlib/gzio.c index 5e71b0ab3ae..7e90f4928fc 100644 --- a/zlib/gzio.c +++ b/zlib/gzio.c @@ -1,5 +1,5 @@ /* gzio.c -- IO on .gz files - * Copyright (C) 1995-2003 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h * * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. @@ -11,7 +11,7 @@ #include "zutil.h" -#ifdef NO_DEFLATE /* for compatiblity with old definition */ +#ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif @@ -220,7 +220,7 @@ gzFile ZEXPORT gzdopen (fd, mode) int fd; const char *mode; { - char name[20]; + char name[46]; /* allow for up to 128-bit integers */ if (fd < 0) return (gzFile)Z_NULL; sprintf(name, "<fd:%d>", fd); /* for debugging */ @@ -264,7 +264,7 @@ local int get_byte(s) if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { s->z_eof = 1; if (ferror(s->file)) s->z_err = Z_ERRNO; @@ -300,7 +300,7 @@ local void check_header(s) if (len < 2) { if (len) s->inbuf[0] = s->stream.next_in[0]; errno = 0; - len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; s->stream.avail_in += len; s->stream.next_in = s->inbuf; @@ -415,6 +415,7 @@ int ZEXPORT gzread (file, buf, len) s->stream.avail_out--; s->back = EOF; s->out++; + start++; if (s->last) { s->z_err = Z_STREAM_END; return 1; @@ -436,8 +437,8 @@ int ZEXPORT gzread (file, buf, len) s->stream.avail_in -= n; } if (s->stream.avail_out > 0) { - s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, - s->file); + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); } len -= s->stream.avail_out; s->in += len; @@ -448,17 +449,13 @@ int ZEXPORT gzread (file, buf, len) if (s->stream.avail_in == 0 && !s->z_eof) { errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { s->z_eof = 1; if (ferror(s->file)) { s->z_err = Z_ERRNO; break; } - if (feof(s->file)) { /* avoid error for empty file */ - s->z_err = Z_STREAM_END; - break; - } } s->stream.next_in = s->inbuf; } @@ -492,6 +489,9 @@ int ZEXPORT gzread (file, buf, len) } s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; return (int)(len - s->stream.avail_out); } @@ -903,6 +903,18 @@ int ZEXPORT gzeof (file) } /* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== Outputs a long in LSB order to the given file */ local void putLong (file, x) @@ -941,7 +953,6 @@ local uLong getLong (s) int ZEXPORT gzclose (file) gzFile file; { - int err; gz_stream *s = (gz_stream*)file; if (s == NULL) return Z_STREAM_ERROR; @@ -950,8 +961,8 @@ int ZEXPORT gzclose (file) #ifdef NO_GZCOMPRESS return Z_STREAM_ERROR; #else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); putLong (s->file, s->crc); putLong (s->file, (uLong)(s->in & 0xffffffff)); @@ -960,10 +971,16 @@ int ZEXPORT gzclose (file) return destroy((gz_stream*)file); } +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + /* =========================================================================== - Returns the error message for the last error which occured on the + Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an - error occured in the file system and not in the compression library, + error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. */ diff --git a/zlib/infback.c b/zlib/infback.c index 262f97c73ac..455dbc9ee84 100644 --- a/zlib/infback.c +++ b/zlib/infback.c @@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -26,7 +26,7 @@ local void fixedtables OF((struct inflate_state FAR *state)); window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_stream FAR *strm; +z_streamp strm; int windowBits; unsigned char FAR *window; const char *version; @@ -50,7 +50,8 @@ int stream_size; sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; state->wbits = windowBits; state->wsize = 1U << windowBits; state->window = window; @@ -238,7 +239,7 @@ struct inflate_state FAR *state; are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_stream FAR *strm; +z_streamp strm; in_func in; void FAR *in_desc; out_func out; @@ -611,7 +612,7 @@ void FAR *out_desc; } int ZEXPORT inflateBackEnd(strm) -z_stream FAR *strm; +z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; diff --git a/zlib/inffast.c b/zlib/inffast.c index 8c02a178d04..bbee92ed1e6 100644 --- a/zlib/inffast.c +++ b/zlib/inffast.c @@ -74,6 +74,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned write; /* window write index */ @@ -98,6 +101,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif wsize = state->wsize; whave = state->whave; write = state->write; @@ -167,6 +173,13 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ } } dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); diff --git a/zlib/inflate.c b/zlib/inflate.c index c6d38266d07..792fdee8e9c 100644 --- a/zlib/inflate.c +++ b/zlib/inflate.c @@ -1,5 +1,5 @@ /* inflate.c -- zlib decompression - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -113,8 +113,11 @@ z_streamp strm; state->mode = HEAD; state->last = 0; state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; state->wsize = 0; state->whave = 0; + state->write = 0; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; @@ -122,6 +125,22 @@ z_streamp strm; return Z_OK; } +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; @@ -144,7 +163,7 @@ int stream_size; ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; + strm->state = (struct internal_state FAR *)state; if (windowBits < 0) { state->wrap = 0; windowBits = -windowBits; @@ -582,6 +601,8 @@ int flush; break; } state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( @@ -597,11 +618,13 @@ int flush; break; } DROPBITS(4); - if (BITS(4) + 8 > state->wbits) { + len = BITS(4) + 8; + if (len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } + state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; @@ -621,16 +644,24 @@ int flush; state->mode = BAD; break; } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; @@ -638,15 +669,26 @@ int flush; if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; @@ -655,6 +697,7 @@ int flush; } if (state->length) goto inf_leave; } + state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { @@ -662,13 +705,20 @@ int flush; copy = 0; do { len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; } while (len && copy < have); - if (state->flags & 0x02000) + if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { @@ -676,13 +726,19 @@ int flush; copy = 0; do { len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; } while (len && copy < have); - if (state->flags & 0x02000) + if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { @@ -694,6 +750,10 @@ int flush; } INITBITS(); } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; @@ -969,6 +1029,13 @@ int flush; state->offset += BITS(state->extra); DROPBITS(state->extra); } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif if (state->offset > state->whave + out - left) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; @@ -1110,12 +1177,16 @@ uInt dictLength; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; - if (state->mode != DICT) return Z_STREAM_ERROR; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; /* check for correct dictionary id */ - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) return Z_DATA_ERROR; + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } /* copy dictionary to window */ if (updatewindow(strm, strm->avail_out)) { @@ -1137,6 +1208,23 @@ uInt dictLength; return Z_OK; } +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes @@ -1239,6 +1327,7 @@ z_streamp source; struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; + unsigned wsize; /* check input */ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || @@ -1261,14 +1350,19 @@ z_streamp source; } /* copy state */ - *dest = *source; - *copy = *state; - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) - zmemcpy(window, state->window, 1U << state->wbits); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } copy->window = window; - dest->state = (voidpf)copy; + dest->state = (struct internal_state FAR *)copy; return Z_OK; } diff --git a/zlib/inflate.h b/zlib/inflate.h index 9a12c8fd296..07bd3e78a7c 100644 --- a/zlib/inflate.h +++ b/zlib/inflate.h @@ -1,5 +1,5 @@ /* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2004 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -19,7 +19,6 @@ /* Possible inflate modes between inflate() calls */ typedef enum { HEAD, /* i: waiting for magic header */ -#ifdef GUNZIP FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ @@ -28,7 +27,6 @@ typedef enum { NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ -#endif DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ @@ -45,9 +43,7 @@ typedef enum { MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ -#ifdef GUNZIP LENGTH, /* i: waiting for 32-bit length (gzip) */ -#endif DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ @@ -84,8 +80,10 @@ struct inflate_state { int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ diff --git a/zlib/inftrees.c b/zlib/inftrees.c index 509461d9273..8a9c13ff03d 100644 --- a/zlib/inftrees.c +++ b/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2004 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.2 Copyright 1995-2004 Mark Adler "; + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 199, 198}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, @@ -232,6 +232,7 @@ unsigned short FAR *work; /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; + min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = this; @@ -262,7 +263,7 @@ unsigned short FAR *work; drop = root; /* increment past last table */ - next += 1U << curr; + next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; diff --git a/zlib/trees.c b/zlib/trees.c index 52c820fa2e9..395e4e16814 100644 --- a/zlib/trees.c +++ b/zlib/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2003 Jean-loup Gailly + * Copyright (C) 1995-2005 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -555,7 +555,7 @@ local void gen_bitlen(s, desc) while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { + if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; @@ -930,8 +930,9 @@ void _tr_flush_block(s, buf, stored_len, eof) /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { - /* Check if the file is ascii or binary */ - if (s->strm->data_type == Z_UNKNOWN) set_data_type(s); + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); @@ -982,7 +983,7 @@ void _tr_flush_block(s, buf, stored_len, eof) #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else - } else if (static_lenb == opt_lenb) { + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+eof, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); @@ -1117,21 +1118,24 @@ local void compress_block(s, ltree, dtree) } /* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. */ local void set_data_type(s) deflate_state *s; { - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->strm->data_type = bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII; + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; } /* =========================================================================== diff --git a/zlib/zconf.h b/zlib/zconf.h index 3c21403fce6..03a9431c8be 100644 --- a/zlib/zconf.h +++ b/zlib/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2004 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -43,6 +43,10 @@ # define get_crc_table z_get_crc_table # define zError z_zError +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func # define Byte z_Byte # define uInt z_uInt # define uLong z_uLong @@ -64,8 +68,10 @@ #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) diff --git a/zlib/zlib.3 b/zlib/zlib.3 index 3139e2467f2..90b8162870f 100644 --- a/zlib/zlib.3 +++ b/zlib/zlib.3 @@ -1,4 +1,4 @@ -.TH ZLIB 3 "3 October 2004" +.TH ZLIB 3 "18 July 2005" .SH NAME zlib \- compression/decompression library .SH SYNOPSIS @@ -133,8 +133,8 @@ before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS -Version 1.2.2 -Copyright (C) 1995-2004 Jean-loup Gailly (jloup@gzip.org) +Version 1.2.3 +Copyright (C) 1995-2005 Jean-loup Gailly (jloup@gzip.org) and Mark Adler (madler@alumni.caltech.edu). .LP This software is provided "as-is," diff --git a/zlib/zlib.h b/zlib/zlib.h index b4ddd34395c..022817927ce 100644 --- a/zlib/zlib.h +++ b/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.2, October 3rd, 2004 + version 1.2.3, July 18th, 2005 - Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,8 +37,8 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.2" -#define ZLIB_VERNUM 0x1220 +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 /* The 'zlib' compression library provides in-memory compression and @@ -95,7 +95,7 @@ typedef struct z_stream_s { free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ - int data_type; /* best guess about the data type: ascii or binary */ + int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; @@ -103,6 +103,29 @@ typedef struct z_stream_s { typedef z_stream FAR *z_streamp; /* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and @@ -166,11 +189,13 @@ typedef z_stream FAR *z_streamp; #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 +#define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 -#define Z_ASCII 1 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field (though see inflate()) */ @@ -244,6 +269,10 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular @@ -255,7 +284,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. + compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated @@ -280,8 +309,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. @@ -363,11 +392,11 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it get to the next deflate block boundary. When decoding the zlib - or gzip format, this will cause inflate() to return immediately after the - header and before the first block. When doing a raw inflate, inflate() will - go ahead and process the first block, and will return when it gets to the end - of that block, or when it runs out of data. + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the @@ -496,7 +525,9 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid @@ -525,7 +556,9 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size in deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine @@ -591,6 +624,23 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, if strm->avail_out was zero. */ +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* @@ -616,6 +666,30 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, stream state was inconsistent. */ +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); @@ -648,15 +722,15 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR. If a gzip stream is being decoded, strm->adler is + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, @@ -664,11 +738,14 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is @@ -719,8 +796,64 @@ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); stream state was inconsistent (such as zalloc or state being NULL). */ +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + /* -ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() @@ -744,7 +877,7 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); -ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* @@ -813,7 +946,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, that inflateBack() cannot return Z_OK. */ -ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. @@ -1087,6 +1220,12 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); input stream, otherwise zero. */ +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file @@ -1119,7 +1258,6 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); - /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is NULL, this function returns @@ -1135,12 +1273,21 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); @@ -1151,6 +1298,16 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + /* various hacks, don't look :) */ @@ -1167,7 +1324,7 @@ ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); diff --git a/zlib/zutil.c b/zlib/zutil.c index 0ef4f99f57e..d55f5948a37 100644 --- a/zlib/zutil.c +++ b/zlib/zutil.c @@ -1,5 +1,5 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -11,10 +11,6 @@ struct internal_state {int dummy;}; /* for buggy compilers */ #endif -#ifndef STDC -extern void exit OF((int)); -#endif - const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ @@ -78,38 +74,38 @@ uLong ZEXPORT zlibCompileFlags() flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS - flags += 1 << 16; + flags += 1L << 16; #endif #ifdef NO_GZIP - flags += 1 << 17; + flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND - flags += 1 << 20; + flags += 1L << 20; #endif #ifdef FASTEST - flags += 1 << 21; + flags += 1L << 21; #endif #ifdef STDC # ifdef NO_vsnprintf - flags += 1 << 25; + flags += 1L << 25; # ifdef HAS_vsprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # endif #else - flags += 1 << 24; + flags += 1L << 24; # ifdef NO_snprintf - flags += 1 << 25; + flags += 1L << 25; # ifdef HAS_sprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # endif #endif @@ -141,7 +137,10 @@ const char * ZEXPORT zError(err) } #if defined(_WIN32_WCE) - /* does not exist on WCE */ + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ int errno = 0; #endif diff --git a/zlib/zutil.h b/zlib/zutil.h index 7b42edcaa98..b7d5eff81b6 100644 --- a/zlib/zutil.h +++ b/zlib/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -17,14 +17,26 @@ #include "zlib.h" #ifdef STDC -# include <stddef.h> +# ifndef _WIN32_WCE +# include <stddef.h> +# endif # include <string.h> # include <stdlib.h> #endif #ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif extern int errno; #else -# include <errno.h> +# ifndef _WIN32_WCE +# include <errno.h> +# endif #endif #ifndef local @@ -105,6 +117,9 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #ifdef OS2 # define OS_CODE 0x06 +# ifdef M_I86 + #include <malloc.h> +# endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) @@ -193,15 +208,6 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define NO_vsnprintf #endif -#ifdef HAVE_STRERROR -# ifndef VMS - extern char *strerror OF((int)); -# endif -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - #if defined(pyr) # define NO_MEMCPY #endif |