diff --git a/.bzrignore b/.bzrignore index bb1cdb1c0c3..f3f7ce94449 100644 --- a/.bzrignore +++ b/.bzrignore @@ -254,11 +254,14 @@ bkpush.log bkpush.log* build.log build_tags.sh +client/decimal.c client/insert_test client/log_event.cc client/log_event.h client/mf_iocache.c client/mf_iocache.cc +client/my_decimal.cc +client/my_decimal.h client/mysql client/mysqladmin client/mysqladmin.c @@ -328,9 +331,12 @@ help.h include/my_config.h include/my_global.h include/mysql_version.h +include/mysqld_ername.h +include/mysqld_error.h include/readline include/readline/*.h include/readline/readline.h +include/sql_state.h include/widec.h innobase/autom4te-2.53.cache/* innobase/autom4te-2.53.cache/output.0 @@ -432,6 +438,7 @@ libmysqld/log_event.cc libmysqld/md5.c libmysqld/mf_iocache.cc libmysqld/mini_client.cc +libmysqld/my_decimal.cc libmysqld/my_time.c libmysqld/net_pkg.cc libmysqld/net_serv.cc @@ -985,6 +992,7 @@ support-files/mysql-3.23.29-gamma.spec support-files/mysql-log-rotate support-files/mysql.server support-files/mysql.spec +support-files/ndb-config-2-node.ini tags test/ndbapi/bank/bankCreator test/ndbapi/bank/bankMakeGL @@ -1052,6 +1060,3 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl -include/mysqld_ername.h -include/mysqld_error.h -include/sql_state.h diff --git a/BUILD/compile-ia64-debug-max b/BUILD/compile-ia64-debug-max index 9cd54de428d..56c36059ea9 100755 --- a/BUILD/compile-ia64-debug-max +++ b/BUILD/compile-ia64-debug-max @@ -9,5 +9,5 @@ then (cd gemini && aclocal && autoheader && aclocal && automake && autoconf) fi -CC=ecc CFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" CXX=ecc CXXFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static --with-debug --with-innodb --with-embedded-server +CC=ecc CFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" CXX=ecc CXXFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static --with-debug --with-innodb --with-embedded-server --with-archive-storage-engine gmake diff --git a/BUILD/compile-pentium-debug b/BUILD/compile-pentium-debug index 4a9d0e74599..7957caead29 100755 --- a/BUILD/compile-pentium-debug +++ b/BUILD/compile-pentium-debug @@ -1,7 +1,7 @@ #! /bin/sh path=`dirname $0` -. "$path/SETUP.sh" +. "$path/SETUP.sh" $@ --with-debug=full extra_flags="$pentium_cflags $debug_cflags" c_warnings="$c_warnings $debug_extra_warnings" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index 420657e0b73..7a11ad24c44 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -1,7 +1,7 @@ #! /bin/sh path=`dirname $0` -. "$path/SETUP.sh" +. "$path/SETUP.sh" $@ --with-debug=full extra_flags="$pentium_cflags $debug_cflags $max_cflags" c_warnings="$c_warnings $debug_extra_warnings" diff --git a/BUILD/compile-solaris-sparc-purify b/BUILD/compile-solaris-sparc-purify index c895d99c2cf..41ecd4ed530 100755 --- a/BUILD/compile-solaris-sparc-purify +++ b/BUILD/compile-solaris-sparc-purify @@ -1,29 +1,110 @@ #! /bin/sh +mode="" +cxxfilt="" + +# For g++ 3.X, the PurifyPlus tools needs a program named "cxxfilt", +# "c++file" or similar. It is part of libtool. If not found, you can +# specify the path to it. + while test $# -gt 0 do case "$1" in - --debug) EXTRA_CONFIG_FLAGS=--with-debug; shift ;; + --debug) EXTRA_CONFIG_FLAGS=--with-debug ;; + --purify) mode=purify ;; + --purecov*) mode=purecov ;; + --quantify) mode=quantify ;; + --cxxfilt) shift ; cxxfilt=$1 ;; -h | --help ) - echo "Usage: $0 [-h|-n] [configure-options]" - echo " --debug Compile with DBUG enabled" + echo "Usage: $0 [ options ]" + echo "Where the 'options' are" + echo " --help | -h Display this help" + echo " --debug Compile with DBUG enabled" + echo " --purify Only prepare for Purify" + echo " --purecov Only prepare for PureCover" + echo " --quantify Only prepare for Quantify" + echo " --cxxfilt Path to cxxfilt/c++filt program" + echo " This program is needed for gcc 3.X" exit 0 ;; - *) echo "No such option '$1'" ; exit ;; + *) echo "No such option '$1'" ; exit 1 ;; esac + shift done gmake -k clean || true /bin/rm -f */.deps/*.P config.cache aclocal && autoheader && aclocal && automake && autoconf -# (cd bdb/dist && sh s_all) +(cd bdb/dist && sh s_all) (cd innobase && aclocal && autoheader && aclocal && automake && autoconf) -CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --without-berkeley-db --with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS +CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db --with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS gmake -j 4 -cd sql ; mv mysqld mysqld-org ; -gmake CXXLD="purify -best-effort g++" mysqld ; mv mysqld mysqld-purify -gmake CXXLD="quantify -best-effort g++" mysqld ; mv mysqld mysqld-quantify -gmake CXXLD="purecov -best-effort g++" mysqld ; mv mysqld mysqld-purecov -mv mysqld-org mysqld +# ---------------------------------------------------------------------- + +#set -x + +purifying_binaries () +{ + while test $1 + do + dir=$1 + shift + target=$1 + shift + binary=$1 + shift + + opts="" + if [ -n "$cxxfilt" ] ; then + opts="$opts -demangle-program=$cxxfilt" + fi + opts="$opts -best-effort" + + back=`pwd` + cd $dir + + # Because of libtool magic, the target and binary + # created might not be the same. To trigger rebuild, + # we need to move them both. + + mv $binary $binary-old + if [ -f $target ] ; then + mv $target $target-old + fi + + if [ -n "$mode" -a $mode = purify ] ; then + gmake CCLD="purify $opts gcc" CXXLD="purify $opts g++" $target + mv $binary $binary-purify + fi + + if [ -n "$mode" -a $mode = quantify ] ; then + gmake CCLD="quantify $opts gcc" CXXLD="quantify $opts g++" $target + mv $binary $binary-quantify + fi + + if [ -n "$mode" -a $mode = purecov ] ; then + gmake CCLD="purecov $opts gcc" CXXLD="purecov $opts g++" $target + mv $binary $binary-purecov + fi + + mv $binary-old $binary + if [ -f $target-old ] ; then + mv $target-old $target + fi + + cd $back + done +} + + +purifying_binaries \ + sql mysqld mysqld \ + client mysqltest .libs/mysqltest \ + tests mysql_client_test mysql_client_test \ + libmysqld/examples mysqltest_embedded mysqltest_embedded \ + libmysqld/examples mysql_client_test_embedded mysql_client_test_embedded + +# ---------------------------------------------------------------------- + diff --git a/BitKeeper/etc/gone b/BitKeeper/etc/gone index 4cfffcc7d67..126bd4e38d3 100644 --- a/BitKeeper/etc/gone +++ b/BitKeeper/etc/gone @@ -457,6 +457,398 @@ ccarkner@nslinuxw10.bedford.progress.com|mysql-test/r/isolation.result|200103271 ccarkner@nslinuxw10.bedford.progress.com|mysql-test/t/isolation.test|20010327145543|39049|6a39e4138dd4a456 jani@hynda.mysql.fi|client/mysqlcheck|20010419221207|26716|363e3278166d84ec jcole@tetra.bedford.progress.com|BitKeeper/etc/logging_ok|20001004201211|30554 +magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 +magnus@neptunus.(none)|ndb/src/client/odbc/Extra.mk|20040414082358|47442|eabbb28986ca817d +magnus@neptunus.(none)|ndb/src/client/odbc/Makefile|20040414084435|33394|9bc928a18aa88d66 +magnus@neptunus.(none)|ndb/src/client/odbc/NdbOdbc.cpp|20040414082358|49599|aa491b06c9172d11 +magnus@neptunus.(none)|ndb/src/client/odbc/NdbOdbc.def|20040414082358|51708|cd3eed2c4a0121e9 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/CodeGen.cpp|20040414082358|53823|170c83c0765b9160 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/CodeGen.hpp|20040414082358|56074|738f834f80cceba8 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_base.cpp|20040414082358|58196|96f8ceaac8138bfe +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_base.hpp|20040414082358|60340|794baaed32588409 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_column.cpp|20040414082358|62566|5dd0e5c1215bd8bf +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_column.hpp|20040414082358|64739|5d5816d1c496e588 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_comp_op.cpp|20040414082358|01507|6ab02cc3b1e08985 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_comp_op.hpp|20040414082358|03757|37cf1e4cee3a6bf1 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_index.cpp|20040414082358|06374|d1f95c5917afab9 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_index.hpp|20040414082358|08625|12bcb33350fc35c1 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_row.cpp|20040414082358|11036|33f73454f8ddf2d5 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_row.hpp|20040414082358|13441|38cb00cc1baa9ee7 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_table.cpp|20040414082358|15724|c25e7cc06414a927 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_table.hpp|20040414082358|18032|9648f467f3f0418e +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_data_type.cpp|20040414082358|20759|9e46a7ef85345d4 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_data_type.hpp|20040414082358|23055|5e8928968d3c0107 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl.cpp|20040414082358|25484|c38ee5368efaf688 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl.hpp|20040414082358|27775|75482ddd87b65036 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_column.cpp|20040414082358|32443|c524862773dd9f38 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_column.hpp|20040414082358|33650|c9e534e381b21599 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_constr.cpp|20040414082359|02893|80ae32f83a6c2f00 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_constr.hpp|20040414082359|05185|bca16806c57bc97e +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_row.cpp|20040414082359|07481|ec2fbc3b8ab08a52 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_row.hpp|20040414082359|09844|c18a43b3770ad25a +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete.cpp|20040414082359|12149|feac77b440d04327 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete.hpp|20040414082359|14544|c852ee069a761aab +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_index.cpp|20040414082359|17020|17ed96eca90fe4e7 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_index.hpp|20040414082359|19336|18a9bb119b04636 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_lookup.cpp|20040414082359|23008|1a3728f8c896684 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_lookup.hpp|20040414082359|26530|1be71525ed9ee69 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_scan.cpp|20040414082359|29062|b040ad7670c24eb5 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_scan.hpp|20040414082359|31380|b9a11b4ec895d159 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml.cpp|20040414082359|33830|6826ad60f0f566e7 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml.hpp|20040414082359|36167|8fdbf19ad3174ca2 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_column.cpp|20040414082359|38509|b71ce6186edf1655 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_column.hpp|20040414082359|40901|a843b3418b30b7a3 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_row.cpp|20040414082359|43239|17c791507b36cc06 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_row.hpp|20040414082359|46942|33c4cffdd238728d +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_index.cpp|20040414082359|54231|fc5cab67ae58d9f6 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_index.hpp|20040414082359|55474|377c9eb280ec2ee2 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_table.cpp|20040414082359|57899|9637d93efa68996a +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_table.hpp|20040414082359|60249|d671379125e4bbbe +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr.cpp|20040414082359|64572|fafd271880c70cf3 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr.hpp|20040414082359|01410|9e8243e99e0ec84 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_column.cpp|20040414082359|03836|4c4fbcd5741cc8cf +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_column.hpp|20040414082359|06355|9c4cbbdf432dc475 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_const.cpp|20040414082359|08702|bdb29dcd94ac5e73 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_const.hpp|20040414082359|12473|9c8789cff376b832 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_conv.cpp|20040414082359|15160|d252fbfe8ef55fff +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_conv.hpp|20040414082359|18741|5cbea39eecb92a43 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_func.cpp|20040414082359|21099|5d3996f062fa3f52 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_func.hpp|20040414082359|23589|22aee1e4f92c49b9 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_op.cpp|20040414082359|25965|e1aaa0244f2efa4 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_op.hpp|20040414082359|28432|4eb8c02dd0602f +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_param.cpp|20040414082359|30810|a5e94ee7c5821611 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_param.hpp|20040414082359|33263|ec441ad8ef21aa2b +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_row.cpp|20040414082400|01179|bc73d8f9c681d418 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_row.hpp|20040414082400|03567|c541c49ea8c0c4f2 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_idx_column.cpp|20040414082400|06012|7d4d074ce5daea0a +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_idx_column.hpp|20040414082400|08377|caabaafa34722be7 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_insert.cpp|20040414082400|10799|7d0ef7cc8f657fd5 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_insert.hpp|20040414082400|14354|cc96fa9b81169471 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred.cpp|20040414082400|16798|56faa755aa42ddfa +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred.hpp|20040414082400|19159|eada43753e8b1e6c +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred_op.cpp|20040414082400|21533|47d693dde1a6d907 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred_op.hpp|20040414082400|23992|b42256983d2bda7b +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query.cpp|20040414082400|26355|4ac293821c9b4602 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query.hpp|20040414082400|28888|f86fbd9a108206c0 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_count.cpp|20040414082400|31247|9fa96a57d2dde660 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_count.hpp|20040414082400|33607|bdbe6e4734abc0c5 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_distinct.cpp|20040414082400|37150|3ba18528aa67b9dd +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_distinct.hpp|20040414082400|39517|c12b2b7ff6b2e7b3 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_filter.cpp|20040414082400|41984|a3d067d5d8fb40c +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_filter.hpp|20040414082400|44363|d0a341f2e40f0183 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_group.cpp|20040414082400|46860|4443c844308f9a98 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_group.hpp|20040414082400|49266|ba4691be942c6e2a +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_index.cpp|20040414082400|51663|f0312c9e2f22daf6 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_index.hpp|20040414082400|54471|6baaf1abbb704bb1 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_join.cpp|20040414082400|56943|36e07422c67d6838 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_join.hpp|20040414082400|59419|c4d17d18c4e3b4a0 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_lookup.cpp|20040414082400|61998|3d80e3ddbdae531d +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_lookup.hpp|20040414082400|00081|73332533e5196630 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_project.cpp|20040414082400|01373|ebc22f71bb7ec98c +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_project.hpp|20040414082400|03788|2734cdf1f907e0a4 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_range.cpp|20040414082400|06316|62ddafd2d17063cc +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_range.hpp|20040414082400|09865|81546843616efefa +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_repeat.cpp|20040414082400|11154|ce8f2a065897d6e3 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_repeat.hpp|20040414082400|13697|c20e10d0db9ad53c +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_scan.cpp|20040414082400|16320|855e56d6f56de938 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_scan.hpp|20040414082400|20784|b93c277da5b2509b +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sort.cpp|20040414082400|24684|c08fc07f739de097 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sort.hpp|20040414082400|25997|84edb5e128eda962 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sys.cpp|20040414082400|28427|1d6a4a1cec789001 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sys.hpp|20040414082400|31003|f5182823da25f097 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_root.cpp|20040414082400|33423|4c26a01ced583e41 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_root.hpp|20040414082401|01466|de1fd878505d9e26 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_select.cpp|20040414082401|04049|75b2a39f282d8ef5 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_select.hpp|20040414082401|06512|f9fadc322d78033a +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_set_row.cpp|20040414082401|08991|1bda7e6f86f18aef +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_set_row.hpp|20040414082401|12465|32ac3de384b91229 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_stmt.cpp|20040414082401|13817|c0e9903aa90df90b +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_stmt.hpp|20040414082401|17310|fab11fc487e74d05 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table.cpp|20040414082401|20990|c46b7a6e2ecf4f61 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table.hpp|20040414082401|22331|a48d57a0375a6d56 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table_list.cpp|20040414082402|33460|40948eccedfae7bb +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table_list.hpp|20040414082402|34739|c1e880e9949d3a +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update.cpp|20040414082402|37093|ed36f4a7a928a91b +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update.hpp|20040414082402|39546|c1de760c7b580b0c +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_index.cpp|20040414082402|42086|a0c6ad33ffbbc00e +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_index.hpp|20040414082402|44472|b57bbe5c8d927df9 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_lookup.cpp|20040414082402|46928|3491782088e97384 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_lookup.hpp|20040414082402|49343|ee335822c3496863 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_scan.cpp|20040414082402|51785|35e5b7d4619b3e09 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_scan.hpp|20040414082402|54180|287f193ad48fbefd +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Makefile|20040414084435|20906|420b8378d374f069 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleGram.ypp|20040414082402|57791|6301cedf92524710 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleParser.cpp|20040414082402|60351|549f93e2a7fd01b5 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleParser.hpp|20040414082402|62814|4fdff7ee3839efc4 +magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleScan.lpp|20040414082402|65230|e11862b97fe39faf +magnus@neptunus.(none)|ndb/src/client/odbc/common/AttrArea.cpp|20040414082402|03357|1570da617a1a6c4b +magnus@neptunus.(none)|ndb/src/client/odbc/common/AttrArea.hpp|20040414082402|06048|f3d78ccd37af4e6 +magnus@neptunus.(none)|ndb/src/client/odbc/common/CodeTree.cpp|20040414082402|08438|1a4912632b0a61ee +magnus@neptunus.(none)|ndb/src/client/odbc/common/CodeTree.hpp|20040414082402|10916|dcb603cce390eafa +magnus@neptunus.(none)|ndb/src/client/odbc/common/ConnArea.cpp|20040414082402|13287|103182cf445f0bc3 +magnus@neptunus.(none)|ndb/src/client/odbc/common/ConnArea.hpp|20040414082402|16782|ffe99deedf7dc1ee +magnus@neptunus.(none)|ndb/src/client/odbc/common/Ctx.cpp|20040414082402|18121|ce1c13ba8a312eba +magnus@neptunus.(none)|ndb/src/client/odbc/common/Ctx.hpp|20040414082402|20500|bc88aba55ab71063 +magnus@neptunus.(none)|ndb/src/client/odbc/common/DataField.cpp|20040414082402|22982|6bb1fe1cb971c8f9 +magnus@neptunus.(none)|ndb/src/client/odbc/common/DataField.hpp|20040414082402|25733|d324898a9a86463d +magnus@neptunus.(none)|ndb/src/client/odbc/common/DataRow.cpp|20040414082402|29367|8764a23cee4f9481 +magnus@neptunus.(none)|ndb/src/client/odbc/common/DataRow.hpp|20040414082402|31983|66a65eee1a1b2f23 +magnus@neptunus.(none)|ndb/src/client/odbc/common/DataType.cpp|20040414082402|34382|29b8ddd51fdd3a2f +magnus@neptunus.(none)|ndb/src/client/odbc/common/DataType.hpp|20040414082403|02299|adef26bc1dc940eb +magnus@neptunus.(none)|ndb/src/client/odbc/common/DescArea.cpp|20040414082403|04653|aab4edd7e336acdd +magnus@neptunus.(none)|ndb/src/client/odbc/common/DescArea.hpp|20040414082403|07055|20ba9b6484762f0f +magnus@neptunus.(none)|ndb/src/client/odbc/common/DiagArea.cpp|20040414082403|09406|e3662d8977947e67 +magnus@neptunus.(none)|ndb/src/client/odbc/common/DiagArea.hpp|20040414082403|11824|1c6595b5fac06eb2 +magnus@neptunus.(none)|ndb/src/client/odbc/common/Makefile|20040414084435|27122|8505f6b38fe5c219 +magnus@neptunus.(none)|ndb/src/client/odbc/common/OdbcData.cpp|20040414082403|16621|e557009c1ed1e017 +magnus@neptunus.(none)|ndb/src/client/odbc/common/OdbcData.hpp|20040414082403|19077|2125814c1293c0b3 +magnus@neptunus.(none)|ndb/src/client/odbc/common/ResultArea.cpp|20040414082403|21436|8bcc2a2d9a98b9b0 +magnus@neptunus.(none)|ndb/src/client/odbc/common/ResultArea.hpp|20040414082403|23832|8d4646b94be475d1 +magnus@neptunus.(none)|ndb/src/client/odbc/common/Sqlstate.cpp|20040414082403|26171|b844144af963c22c +magnus@neptunus.(none)|ndb/src/client/odbc/common/Sqlstate.hpp|20040414082403|29665|60006ee1c27c6e5 +magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtArea.cpp|20040414082403|32310|5c5f8613156e06b2 +magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtArea.hpp|20040414082403|34785|9662e56ae164eb7f +magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtInfo.cpp|20040414082403|37141|54ee4040e5807214 +magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtInfo.hpp|20040414082403|39465|6698d657391692fc +magnus@neptunus.(none)|ndb/src/client/odbc/common/common.cpp|20040414082403|41862|4792b9ecddd99482 +magnus@neptunus.(none)|ndb/src/client/odbc/common/common.hpp|20040414082403|45229|25369fa6c80eff53 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictCatalog.cpp|20040414082403|46524|9804b0ff3eac2f8 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictCatalog.hpp|20040414082403|50152|cace2fb2f6bb65e5 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictColumn.cpp|20040414082403|56647|b69d90c53e5b618 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictColumn.hpp|20040414082403|58973|c2da1b7bd0408bd1 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictIndex.cpp|20040414082403|62455|a456d3039e6a39e3 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictIndex.hpp|20040414082403|64865|f53b91a41bb96663 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSchema.cpp|20040414082403|01679|639403c84a47dfdd +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSchema.hpp|20040414082403|04043|5aa7dc8ade17e94c +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSys.cpp|20040414082403|06523|fb89465b10c32bb0 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSys.hpp|20040414082403|08917|76583ba8aa88fd6f +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictTable.cpp|20040414082403|11346|8f4a9ee5a8038f87 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictTable.hpp|20040414082403|13733|cf99a9ac3dd49206 +magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/Makefile|20040414084435|30267|4c1a6148787bdc2f +magnus@neptunus.(none)|ndb/src/client/odbc/docs/class.fig|20040414082403|16124|c0754ccad74d380a +magnus@neptunus.(none)|ndb/src/client/odbc/docs/descfield.pl|20040414082403|18935|e0bd59c2824824cc +magnus@neptunus.(none)|ndb/src/client/odbc/docs/diag.txt|20040414082403|21798|b66a7e227391335f +magnus@neptunus.(none)|ndb/src/client/odbc/docs/getinfo.pl|20040414082403|24266|2142ecf1567a66f6 +magnus@neptunus.(none)|ndb/src/client/odbc/docs/gettypeinfo.pl|20040414082403|27572|2ea4c0589eac4e73 +magnus@neptunus.(none)|ndb/src/client/odbc/docs/handleattr.pl|20040414082403|31383|b0c2a2901b68342e +magnus@neptunus.(none)|ndb/src/client/odbc/docs/main.hpp|20040414082404|00011|7b15eb7ffad488a0 +magnus@neptunus.(none)|ndb/src/client/odbc/docs/ndbodbc.html|20040414082404|02501|a2f14fdd978b62cc +magnus@neptunus.(none)|ndb/src/client/odbc/docs/select.fig|20040414082404|04967|34f5222b5012e1d7 +magnus@neptunus.(none)|ndb/src/client/odbc/docs/systables.pl|20040414082404|07386|1fa2191648bdb629 +magnus@neptunus.(none)|ndb/src/client/odbc/docs/type.txt|20040414082404|10311|feec700c81f5095f +magnus@neptunus.(none)|ndb/src/client/odbc/driver/Func.data|20040414082404|12860|9e75f15d921063f3 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/Func.pl|20040414082404|16530|aefb901bc3941d32 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/Makefile|20040414084435|24049|80d21270fc3ad931 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocConnect.cpp|20040414082404|18964|246af836b028d810 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocEnv.cpp|20040414082404|21279|eaf36cf2285ec2ac +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocHandle.cpp|20040414082404|23612|c0921921e84d1a10 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocHandleStd.cpp|20040414082404|27069|7d145f6e3640d913 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocStmt.cpp|20040414082404|29405|362331ef456ec879 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBindCol.cpp|20040414082404|31826|fec3a78088d4951d +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBindParam.cpp|20040414082404|34178|a50b619a23efaab +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBindParameter.cpp|20040414082404|36965|533b1992496e2775 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBrowseConnect.cpp|20040414082404|39327|120b61a1ff6edee3 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBulkOperations.cpp|20040414082404|41701|7a96be04250a388 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLCancel.cpp|20040414082404|45242|27eab683f6fa6ec6 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLCloseCursor.cpp|20040414082404|47634|6cbf193aadaf1058 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColAttribute.cpp|20040414082404|51528|f2c858b16a9360d +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColAttributes.cpp|20040414082404|53928|d4007908ee1309d +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColumnPrivileges.cpp|20040414082404|56456|39a3020da4c3485b +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColumns.cpp|20040414082404|58871|1c31107df60bb544 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLConnect.cpp|20040414082404|62974|868e02a519b72743 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLCopyDesc.cpp|20040414082404|64271|286522b25a029761 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDataSources.cpp|20040414082404|01136|12792108aac5b2ca +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDescribeCol.cpp|20040414082404|03611|1d1faafbcd3ecb3c +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDescribeParam.cpp|20040414082404|06014|70b016fa795ed275 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDisconnect.cpp|20040414082404|08470|9fb4c3d7a84db50a +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDriverConnect.cpp|20040414082404|10866|8dad42af7d17a9d9 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDrivers.cpp|20040414082404|13335|400e7453e70f6e99 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLEndTran.cpp|20040414082404|15741|c37cce04cc303c01 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLError.cpp|20040414082404|18143|593b81885c15187b +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLExecDirect.cpp|20040414082404|20664|5e6274e76315339d +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLExecute.cpp|20040414082404|24388|1692a85f8639f71 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLExtendedFetch.cpp|20040414082404|27134|8b9d604580a83cfd +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFetch.cpp|20040414082404|29534|fa1606aa2dd901db +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFetchScroll.cpp|20040414082404|31991|cdb16803511963a1 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLForeignKeys.cpp|20040414082405|00096|4b8a9af2f6bf92cb +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeConnect.cpp|20040414082405|02501|92359420501ebc5b +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeEnv.cpp|20040414082405|04956|64f1776817464807 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeHandle.cpp|20040414082405|07349|2dc029edf912c2d +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeStmt.cpp|20040414082405|09791|8f8cb0a43c02a67 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetConnectAttr.cpp|20040414082405|13307|b29ff18aeedd8966 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetConnectOption.cpp|20040414082405|15755|3e0bc4e1af95c682 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetCursorName.cpp|20040414082405|19268|8266b920671b6d01 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetData.cpp|20040414082405|21785|3d837348460c219d +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDescField.cpp|20040414082405|24186|62828192a7d1d954 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDescRec.cpp|20040414082405|26589|f54cc69bcd1238ad +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDiagField.cpp|20040414082405|29075|673e1ea0f9d5121f +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDiagRec.cpp|20040414082405|31498|bea0f68f5b940ab8 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetEnvAttr.cpp|20040414082405|33972|e742277d8bdf234d +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetFunctions.cpp|20040414082405|36391|72de050fbfb4a9bb +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetInfo.cpp|20040414082405|38935|e4e09d6bedbf02b1 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetStmtAttr.cpp|20040414082405|41363|de7dabc8c2acea7 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetStmtOption.cpp|20040414082405|43806|2ff900ebdd167077 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetTypeInfo.cpp|20040414082405|46378|333196b07473dff6 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLMoreResults.cpp|20040414082405|48899|483d94cb57379e81 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLNativeSql.cpp|20040414082405|51374|eeae6067f4a85c +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLNumParams.cpp|20040414082405|57810|8921304c3bcf4835 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLNumResultCols.cpp|20040414082405|59136|4d2b6527ffe81059 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLParamData.cpp|20040414082405|62648|163b046513f1e4ae +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLParamOptions.cpp|20040414082405|64040|bdcbccb961fff044 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLPrepare.cpp|20040414082405|00921|1d339fe24888087 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLPrimaryKeys.cpp|20040414082405|03420|5d7b2a0ae08a267 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLProcedureColumns.cpp|20040414082405|05843|c7a0535e9f50ff39 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLProcedures.cpp|20040414082405|08319|c59d025b22e2d1a6 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLPutData.cpp|20040414082405|11934|9dbf69ea9d369dbd +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLRowCount.cpp|20040414082405|14434|d4ac5b273afdb154 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetConnectAttr.cpp|20040414082405|16860|c2c520c34c41bd88 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetConnectOption.cpp|20040414082405|19298|dadc980d9f9cad1b +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetCursorName.cpp|20040414082405|21855|ccfc33dd2cf6abeb +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetDescField.cpp|20040414082405|24355|c4db694d1b9e8f77 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetDescRec.cpp|20040414082405|26866|f8dd72467d5012ab +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetEnvAttr.cpp|20040414082405|29480|7b50aeae6228c2db +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetParam.cpp|20040414082405|31915|e0dd2d5e8d3ec450 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetPos.cpp|20040414082405|34406|39a3e69960041aa7 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetScrollOptions.cpp|20040414082406|03524|6f8250379bb0cac8 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetStmtAttr.cpp|20040414082406|06008|e99b7e6025a1ae1f +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetStmtOption.cpp|20040414082406|10068|87af3125a48c27fa +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSpecialColumns.cpp|20040414082406|12486|1877b4c368825de5 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLStatistics.cpp|20040414082406|14949|87e0359f237aa66a +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLTablePrivileges.cpp|20040414082406|17508|fa16ea0fffa4edeb +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLTables.cpp|20040414082406|20645|c8b201068baec393 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLTransact.cpp|20040414082406|23280|eb33c2f66ee85738 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/driver.cpp|20040414082406|25724|f8f1eeec35b08f18 +magnus@neptunus.(none)|ndb/src/client/odbc/driver/driver.hpp|20040414082406|29359|f108f4eef34ec8ea +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_comp_op.cpp|20040414082406|31800|eacbd7512b32d68b +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_create_index.cpp|20040414082406|35482|c6b8e670198adfa9 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_create_table.cpp|20040414082406|37927|76904d417bc0a59a +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_delete_index.cpp|20040414082406|40489|1ffe5af6eb160a68 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_delete_lookup.cpp|20040414082406|43115|5d24028ce16b6623 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_delete_scan.cpp|20040414082406|46919|810aa4058f73c941 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_drop_index.cpp|20040414082406|49349|3a3871ec6ee48c28 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_drop_table.cpp|20040414082406|51862|639a2faba4da14f4 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_expr_conv.cpp|20040414082406|54314|b5452bd4fbd7c945 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_expr_func.cpp|20040414082406|56759|c78ab0e67d54f38c +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_expr_op.cpp|20040414082406|59381|5e341b2e63495ba4 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_insert.cpp|20040414082406|61884|71dd4bf2fb913f2e +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_pred_op.cpp|20040414082406|64460|ebe7b65ba81e5185 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_index.cpp|20040414082406|01584|4cada676fa178001 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_lookup.cpp|20040414082406|05431|79dfe29b088d832 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_range.cpp|20040414082406|06819|7c4e148e81a292d6 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_scan.cpp|20040414082406|09339|7c66194f7f93346f +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_sys.cpp|20040414082406|11968|d66abe07cd519163 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_update_index.cpp|20040414082406|14543|86140a945f790890 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_update_lookup.cpp|20040414082406|17085|b7a7387620cf42ab +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_update_scan.cpp|20040414082406|19743|2285c72106cffe0 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Executor.cpp|20040414082406|22273|ccb54cc8ffe18bae +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Executor.hpp|20040414082406|24762|c94d916ae5af2506 +magnus@neptunus.(none)|ndb/src/client/odbc/executor/Makefile|20040414084435|12419|a08f437558c2d3b4 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrDbc.cpp|20040414082406|27307|24a034fbb22cdb23 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrEnv.cpp|20040414082406|30042|7d74bcba78e149d0 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrRoot.cpp|20040414082406|32507|5def5d7e228eedf0 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrStmt.cpp|20040414082407|00551|5363ba63b35ff8f4 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/DescSpec.cpp|20040414082407|03310|cd50c1c855f1905 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/FuncTab.cpp|20040414082407|05927|e77abea11a532708 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleBase.cpp|20040414082407|08362|2ba63dce2dfec07b +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleBase.hpp|20040414082407|10820|8cf9a1e94d272328 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDbc.cpp|20040414082407|13361|2a79fea6477b2c63 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDbc.hpp|20040414082407|15852|9abc692ac6b0abb3 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDesc.cpp|20040414082407|18335|e77eb1d73d171a98 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDesc.hpp|20040414082407|20794|553aeb842b3da88e +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleEnv.cpp|20040414082407|23207|6b96fc6b188f252b +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleEnv.hpp|20040414082407|25666|572a7b4af6816f8b +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleRoot.cpp|20040414082407|28085|aa5044f74554fa9c +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleRoot.hpp|20040414082407|30587|2fcfca742c13cfb3 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleStmt.cpp|20040414082407|33024|782f96bda9eaf13c +magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleStmt.hpp|20040414082407|35570|6508fc97f3c772e1 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/InfoTab.cpp|20040414082407|38088|f89104b9c6fe7489 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/Makefile|20040414084435|15527|3d8d1529ad26ce76 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/PoolNdb.cpp|20040414082407|40567|793fa032699b7d98 +magnus@neptunus.(none)|ndb/src/client/odbc/handles/PoolNdb.hpp|20040414082407|43172|db9e1a04d2fe705d +magnus@neptunus.(none)|ndb/src/client/odbc/handles/handles.hpp|20040414082407|45564|bfe0b6a7a95ac142 +magnus@neptunus.(none)|ndb/src/ndbbaseclient/Makefile|20040414084439|01640|4b92d5e5b416dd0 +magnus@neptunus.(none)|ndb/src/ndbbaseclient/ndbbaseclient_dummy.cpp|20040414082426|08918|daee9eb6acbc94 +magnus@neptunus.(none)|ndb/src/ndbclient/Makefile|20040414084438|29978|f993f3afae0d4308 +magnus@neptunus.(none)|ndb/src/ndbclient/ndbclient_dummy.cpp|20040414082426|11587|73154070f5d0bfbf +magnus@neptunus.(none)|ndb/src/newtonapi/Makefile|20040414084438|17704|bcbd9a7282094cc +magnus@neptunus.(none)|ndb/src/newtonapi/dba_binding.cpp|20040414082426|14355|dcc4fb57f9ab6cba +magnus@neptunus.(none)|ndb/src/newtonapi/dba_bulkread.cpp|20040414082426|17142|4ddfe02a93d2ba11 +magnus@neptunus.(none)|ndb/src/newtonapi/dba_config.cpp|20040414082426|19935|38acf2ad3a932420 +magnus@neptunus.(none)|ndb/src/newtonapi/dba_dac.cpp|20040414082426|10457|4615e3d0d8a15bff +magnus@neptunus.(none)|ndb/src/newtonapi/dba_error.cpp|20040414082426|12319|a58b4a1628a2d4b9 +magnus@neptunus.(none)|ndb/src/newtonapi/dba_init.cpp|20040414082426|15064|80da7e3fa0775346 +magnus@neptunus.(none)|ndb/src/newtonapi/dba_internal.hpp|20040414082426|17987|54884404e30c8823 +magnus@neptunus.(none)|ndb/src/newtonapi/dba_process.cpp|20040414082426|22216|509e54294bc7efd2 +magnus@neptunus.(none)|ndb/src/newtonapi/dba_process.hpp|20040414082426|24005|f0ddefb3b2d6a662 +magnus@neptunus.(none)|ndb/src/newtonapi/dba_schema.cpp|20040414082426|26757|1c3b8399853c108 +magnus@neptunus.(none)|ndb/src/rep/ExtSender.cpp|20040414082426|29555|1851d559cfddae43 +magnus@neptunus.(none)|ndb/src/rep/ExtSender.hpp|20040414082426|32345|10ae62ec85ee6692 +magnus@neptunus.(none)|ndb/src/rep/Makefile|20040414084438|44449|954f853c2d812c2c +magnus@neptunus.(none)|ndb/src/rep/NodeConnectInfo.hpp|20040414082427|00605|9c4318dd55f3f84 +magnus@neptunus.(none)|ndb/src/rep/README|20040414082427|03407|6939b06d192a6b99 +magnus@neptunus.(none)|ndb/src/rep/RepApiInterpreter.cpp|20040414082427|06188|8ba561cb831ae353 +magnus@neptunus.(none)|ndb/src/rep/RepApiInterpreter.hpp|20040414082427|08968|31be5af2ba72d263 +magnus@neptunus.(none)|ndb/src/rep/RepApiService.cpp|20040414082427|11699|93d4005333167a0f +magnus@neptunus.(none)|ndb/src/rep/RepApiService.hpp|20040414082432|07265|42f5ffb7e3baa54e +magnus@neptunus.(none)|ndb/src/rep/RepCommandInterpreter.cpp|20040414082432|10009|f661a8ff312213f8 +magnus@neptunus.(none)|ndb/src/rep/RepCommandInterpreter.hpp|20040414082432|12750|fb6f22895e8c8679 +magnus@neptunus.(none)|ndb/src/rep/RepComponents.cpp|20040414082432|16488|fb067aee8e5a4a1f +magnus@neptunus.(none)|ndb/src/rep/RepComponents.hpp|20040414082432|19179|9e632beac4f8bbf8 +magnus@neptunus.(none)|ndb/src/rep/RepMain.cpp|20040414082432|21936|de79cb7b6f3acd18 +magnus@neptunus.(none)|ndb/src/rep/Requestor.cpp|20040414082432|24636|c653fa987f84ce43 +magnus@neptunus.(none)|ndb/src/rep/Requestor.hpp|20040414082432|27340|a499054c9a128dbd +magnus@neptunus.(none)|ndb/src/rep/RequestorSubscriptions.cpp|20040414082432|30099|f0643f7cc9aa9654 +magnus@neptunus.(none)|ndb/src/rep/SignalQueue.cpp|20040414082432|32849|6d32d876acc1a598 +magnus@neptunus.(none)|ndb/src/rep/SignalQueue.hpp|20040414082432|35536|b92204ff36f399d1 +magnus@neptunus.(none)|ndb/src/rep/TODO|20040414082432|38233|187896dd2e5dfd02 +magnus@neptunus.(none)|ndb/src/rep/adapters/AppNDB.cpp|20040414082432|46457|1db5eafacdeda3b7 +magnus@neptunus.(none)|ndb/src/rep/adapters/AppNDB.hpp|20040414082432|49233|2c3081224b4ff75f +magnus@neptunus.(none)|ndb/src/rep/adapters/ExtAPI.cpp|20040414082432|51989|d98f38669b10ca97 +magnus@neptunus.(none)|ndb/src/rep/adapters/ExtAPI.hpp|20040414082432|54656|32bcb96bcd2d60c +magnus@neptunus.(none)|ndb/src/rep/adapters/ExtNDB.cpp|20040414082432|57410|38cccb80529c02c6 +magnus@neptunus.(none)|ndb/src/rep/adapters/ExtNDB.hpp|20040414082432|60222|ee245e7e2c707685 +magnus@neptunus.(none)|ndb/src/rep/adapters/Makefile|20040414084438|21912|bcb9d87fd69a7911 +magnus@neptunus.(none)|ndb/src/rep/adapters/TableInfoPs.hpp|20040414082432|62988|56b1f8f75fe7cb1c +magnus@neptunus.(none)|ndb/src/rep/dbug_hack.cpp|20040414082432|40989|f090906a24103f0 +magnus@neptunus.(none)|ndb/src/rep/rep_version.hpp|20040414082432|43779|82a23fe4dbb13cab +magnus@neptunus.(none)|ndb/src/rep/repapi/Makefile|20040414084438|41386|25c4b35b84d945b4 +magnus@neptunus.(none)|ndb/src/rep/repapi/repapi.cpp|20040414082432|00155|82b9b00c67cfdcf7 +magnus@neptunus.(none)|ndb/src/rep/repapi/repapi.h|20040414082432|02987|6f8cf6b53a86a5ae +magnus@neptunus.(none)|ndb/src/rep/state/Channel.cpp|20040414082432|05711|1d5f62245962b839 +magnus@neptunus.(none)|ndb/src/rep/state/Channel.hpp|20040414082432|08527|71c1d63ef4b2cbfe +magnus@neptunus.(none)|ndb/src/rep/state/Interval.cpp|20040414082432|11324|3d079ca9cc21124d +magnus@neptunus.(none)|ndb/src/rep/state/Interval.hpp|20040414082432|14048|85aa46fc419bb109 +magnus@neptunus.(none)|ndb/src/rep/state/Makefile|20040414084438|33082|6a9cedaeedcc4650 +magnus@neptunus.(none)|ndb/src/rep/state/RepState.cpp|20040414082432|16760|3d60b0a46e9477c1 +magnus@neptunus.(none)|ndb/src/rep/state/RepState.hpp|20040414082432|19671|94d7c472c8a7367 +magnus@neptunus.(none)|ndb/src/rep/state/RepStateEvent.cpp|20040414082432|22494|f51d7eb7b7aca0b +magnus@neptunus.(none)|ndb/src/rep/state/RepStateRequests.cpp|20040414082432|25234|393882166df6929 +magnus@neptunus.(none)|ndb/src/rep/state/testInterval/Makefile|20040414084438|35164|e33e587a7947ac36 +magnus@neptunus.(none)|ndb/src/rep/state/testInterval/testInterval.cpp|20040414082432|27995|993f4118f616e80 +magnus@neptunus.(none)|ndb/src/rep/state/testRepState/Makefile|20040414084438|28225|f5a6d9415d7e0977 +magnus@neptunus.(none)|ndb/src/rep/state/testRepState/testRequestor.cpp|20040414082432|30850|4a943fae5be63c79 +magnus@neptunus.(none)|ndb/src/rep/state/testRepState/testRequestor.hpp|20040414082432|33580|583208c83ff5b554 +magnus@neptunus.(none)|ndb/src/rep/storage/GCIBuffer.cpp|20040414082433|01915|6e8c6f38ab63d1d6 +magnus@neptunus.(none)|ndb/src/rep/storage/GCIBuffer.hpp|20040414082433|04667|703e2016a7ec616f +magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainer.cpp|20040414082433|07490|9c53acd16fc5ac74 +magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainer.hpp|20040414082433|10275|ac28cea9114659fd +magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainerPS.cpp|20040414082433|13103|116168903a2c617a +magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainerPS.hpp|20040414082433|15896|9a801ffe939e192e +magnus@neptunus.(none)|ndb/src/rep/storage/GCIPage.cpp|20040414082433|18724|42fa918fbf36828a +magnus@neptunus.(none)|ndb/src/rep/storage/GCIPage.hpp|20040414082433|22604|4197e2278326515e +magnus@neptunus.(none)|ndb/src/rep/storage/LogRecord.hpp|20040414082433|25752|11644fe7c5f5d36 +magnus@neptunus.(none)|ndb/src/rep/storage/Makefile|20040414084438|25055|a955d34726662aba +magnus@neptunus.(none)|ndb/src/rep/storage/NodeConnectInfo.hpp|20040414082433|28517|35a7682fd9dba464 +magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroup.cpp|20040414082433|31343|adebbefb11cd1670 +magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroup.hpp|20040414082433|34127|3fcddc2da5d10e45 +magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroupInfo.cpp|20040414082433|36945|b1130e3c42777658 +magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroupInfo.hpp|20040414082433|39718|7fd3b74f4b59a503 +magnus@neptunus.(none)|ndb/src/rep/transfer/Makefile|20040414084438|38260|6b43df78ea480db1 +magnus@neptunus.(none)|ndb/src/rep/transfer/TransPS.cpp|20040414082433|43592|7a88ca746987ac10 +magnus@neptunus.(none)|ndb/src/rep/transfer/TransPS.hpp|20040414082433|46546|846b26eaa80632a1 +magnus@neptunus.(none)|ndb/src/rep/transfer/TransSS.cpp|20040414082433|49370|8f12a062b240eecf +magnus@neptunus.(none)|ndb/src/rep/transfer/TransSS.hpp|20040414082433|52255|7718b5e4ce9a4007 +magnus@neptunus.(none)|ndb/src/rep/transfer/TransSSSubscriptions.cpp|20040414082433|55067|6bc55e474f33e023 magnus@neptunus.(none)|ndb/tools/ndbnet/Makefile.PL|20040414082442|56473|81be90388548652f magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net.pm|20040414082442|02828|425c84165071d5f6 magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Base.pm|20040414082442|11671|50a6f0d38fa1a57c @@ -789,26 +1181,15 @@ sasha@mysql.sashanet.com|build-tags|20011125054855|05181|7afb7e785b80f97 sasha@mysql.sashanet.com|build-tags|20011201050944|25384|b6f6fff142121618 sasha@mysql.sashanet.com|libmysql_r/acconfig.h|20001128060846|51084|65f1202b3b5c345f sasha@mysql.sashanet.com|mysql-test/README.gcov|20001012045950|28177|5a6da067a30780ce -sasha@mysql.sashanet.com|mysql-test/README.gcov|20001214012355|41825|2de7575ca81155e5 sasha@mysql.sashanet.com|mysql-test/README|20001010001022|12739|108667adaeabe3f5 sasha@mysql.sashanet.com|mysql-test/r/3.23/alt000001.result|20001122072330|24729|393103dbf15f35c9 sasha@mysql.sashanet.com|mysql-test/r/3.23/ins000001.result|20001018175743|49824|f45c599efdf8352b sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000001.a.result|20001118063528|39426|2987b17db06808c3 sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000001.b.result|20001118063528|44057|62e1fa91167cacc3 -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000002.result|20001118063528|46039|109f5ceed1e0d64 sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000003.result|20001118063528|48148|68d6ee00beaa011 sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000004.a.result|20001118063528|50132|3415f066cb91c460 sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000004.b.result|20001118063528|52094|352b35351551485 -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000005.result|20001118063528|54071|a50962bc2340ab9a -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000006.result|20001118063528|56081|5653051e8ce6b4aa -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000007.result|20001121063807|21606|e0c3b6134e0884da -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000008.result|20001121063807|23636|c5cfee19ca5a7da9 -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000009.result|20001121063807|25633|ed8042446ab97926 -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000010.result|20001122072330|29430|3228109b8965b0f8 -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000011.result|20001125024912|48851|c29dce30aa97f265 -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000012.result|20001126062901|05938|35d6596da7b90fc5 sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000012.status.result|20001126062901|09395|bbbd650b5beea32f -sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000013.result|20001202171150|03876|ac5024e6cf6daac6 sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000013.status.result|20001202171150|06069|6bee190c298cc9fd sasha@mysql.sashanet.com|mysql-test/r/3.23/sel000003.result|20001011230020|64653|d7b657b1e3a286a7 sasha@mysql.sashanet.com|mysql-test/r/3.23/sel000100.res|20001205131218|23520|84ed46856cb3a69f @@ -817,7 +1198,6 @@ sasha@mysql.sashanet.com|mysql-test/r/binlog-backup-restore.result|2001042423392 sasha@mysql.sashanet.com|mysql-test/r/df_crash.result|20010406010433|59989|4a3dbee64843953d sasha@mysql.sashanet.com|mysql-test/r/identity.result|20010910233028|16331|e41453a364242503 sasha@mysql.sashanet.com|mysql-test/r/mrg000002.result|20001212152450|11492|745be0854aaaaf5e -sasha@mysql.sashanet.com|mysql-test/r/slave-running.result|20001208141122|24303|f73e49462cf59e1f sasha@mysql.sashanet.com|mysql-test/r/slave-stopped.result|20001208141122|28916|25c134b1a4f1993a sasha@mysql.sashanet.com|mysql-test/std_data/m.MRG|20001212152450|17736|3f5632c37af00f18 sasha@mysql.sashanet.com|mysql-test/std_data/m.frm|20001212152450|13897|e351dfe0b6824c0c diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 6f99987bd9b..e519dbb1de2 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -128,6 +128,7 @@ miguel@light. miguel@light.local miguel@sartre.local mikael@mc04.(none) +mikael@orca.ndb.mysql.com mikron@c-fb0ae253.1238-1-64736c10.cust.bredbandsbolaget.se mikron@mikael-ronstr-ms-dator.local mleich@mysql.com @@ -150,8 +151,10 @@ monty@tramp.mysql.fi monty@work.mysql.com mronstrom@build.mysql.com mronstrom@mysql.com +mskold@bk-internal.mysql.com mskold@mysql.com msvensson@build.mysql.com +msvensson@neptunus.homeip.net mwagner@cash.mwagner.org mwagner@evoq.mwagner.org mwagner@here.mwagner.org @@ -160,6 +163,7 @@ mwagner@work.mysql.com mydev@mysql.com mysql@home.(none) mysql@mc04.(none) +mysqldev@bk-internal.mysql.com mysqldev@build.mysql2.com mysqldev@melody.local mysqldev@mysql.com @@ -196,6 +200,7 @@ ram@gw.mysql.r18.ru ram@gw.udmsearch.izhnet.ru ram@mysql.r18.ru ram@ram.(none) +ramil@mysql.com ranger@regul.home.lan rburnett@build.mysql.com reggie@bob.(none) diff --git a/Build-tools/Bootstrap b/Build-tools/Bootstrap index 10ebc5c2dd1..8b769dca3c4 100755 --- a/Build-tools/Bootstrap +++ b/Build-tools/Bootstrap @@ -210,10 +210,16 @@ if (-d $target_dir) } else { - &logger("Renaming $target_dir to $target_dir.old." . $$); + # Get the time stamp of "configure.in" + @stat= stat("$target_dir/configure.in"); + my $mtime= $stat[9]; + my ($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime); + my $mtime= sprintf("%04d-%02d-%02d-%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min); + + &logger("Renaming $target_dir to $target_dir-$mtime"); $command= "mv "; $command.= "-v " if ($opt_verbose || defined $opt_log); - $command.= "$target_dir $target_dir.old." . $$; + $command.= "$target_dir $target_dir-$mtime"; &run_command($command, "Could not rename $target_dir!"); } } diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index 03fad4d0f51..8f1e5a6a8ef 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -7,7 +7,7 @@ use Sys::Hostname; @config_options= (); @make_options= (); -$opt_distribution=$opt_user=$opt_config_env=$opt_config_extra_env=""; +$opt_comment=$opt_distribution=$opt_user=$opt_config_env=$opt_config_extra_env=""; $opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_suffix=""; $opt_tmp=$opt_version_suffix=""; $opt_bundled_zlib=$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_one_error=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_archive=$opt_with_cluster=$opt_with_csv=$opt_with_example=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=$opt_readline=0; @@ -17,6 +17,7 @@ GetOptions( "bdb", "build-thread=i", "bundled-zlib", + "comment=s", "config-env=s" => \@config_env, "config-extra-env=s" => \@config_extra_env, "config-options=s" => \@config_options, @@ -111,6 +112,7 @@ $log="$pwd/Logs/$host-$major.$minor$opt_version_suffix.log"; $opt_distribution =~ /(mysql[^\/]*)\.tar/; $ver=$1; $gcc_version=which("gcc"); +$opt_comment= "Official MySQL$opt_version_suffix binary" unless $opt_comment; if (defined($gcc_version) && ! $opt_config_env) { $tmp=`$gcc_version -v 2>&1`; @@ -305,7 +307,7 @@ if ($opt_stage <= 1) } $prefix="/usr/local/mysql"; - check_system("$opt_config_env ./configure --prefix=$prefix --localstatedir=$prefix/data --libexecdir=$prefix/bin --with-comment=\"Official MySQL$opt_version_suffix binary\" --with-extra-charsets=complex --with-server-suffix=\"$opt_version_suffix\" --enable-thread-safe-client --enable-local-infile $opt_config_options","Thank you for choosing MySQL"); + check_system("$opt_config_env ./configure --prefix=$prefix --localstatedir=$prefix/data --libexecdir=$prefix/bin --with-comment=\"$opt_comment\" --with-extra-charsets=complex --with-server-suffix=\"$opt_version_suffix\" --enable-thread-safe-client --enable-local-infile $opt_config_options","Thank you for choosing MySQL"); if (-d "$pwd/$host/include-mysql") { safe_system("cp -r $pwd/$host/include-mysql/* $pwd/$host/$ver/include"); @@ -532,6 +534,10 @@ When running several Do-compile runs in parallel, each build should have its own thread ID, so running the test suites does not cause conflicts with duplicate TCP port numbers. +--comment= +Replace the default compilation comment that is embedded into +the mysqld binary. + --config-env= To set up the environment, like 'CC=cc CXX=gcc CXXFLAGS=-O3' @@ -689,16 +695,20 @@ sub abort if ($opt_user) { - $mail_header_file="$opt_tmp/do-command.$$"; - open(TMP,">$mail_header_file"); + # Take the last 40 lines of the build log + open(LOG, "$log") or die $!; + my @log= ; + close LOG; + splice @log => 0, -40; + my $mail_file="$opt_tmp/do-command.$$"; + open(TMP,">$mail_file") or die $!; print TMP "From: mysqldev\@$full_host_name\n"; print TMP "To: $email\n"; print TMP "Subject: $host($uname): $ver$opt_version_suffix compilation failed\n\n"; + print TMP @log; close TMP; - system("tail -n 40 $log > $log.mail"); - system("cat $mail_header_file $log.mail | $sendmail -t -f $email"); - unlink($mail_header_file); - unlink("$log.mail"); + system("$sendmail -t -f $email < $mail_file"); + unlink($mail_file); } exit 1; } diff --git a/Build-tools/Do-solaris-pkg b/Build-tools/Do-solaris-pkg new file mode 100644 index 00000000000..685a1f0923b --- /dev/null +++ b/Build-tools/Do-solaris-pkg @@ -0,0 +1,183 @@ +#!/usr/bin/perl +# +# Script to create Solaris packages +# +$INTERACTIVE= 0; +chomp ($hostname= `hostname`); +$find = "/usr/bin/find"; +$pkgproto = "/usr/bin/pkgproto"; +$pkgmk = "/usr/bin/pkgmk -o"; +$pkgtrans = "/usr/bin/pkgtrans"; +$temp = "/tmp/prototype$$"; +$prototype = "prototype"; +$pkginfo = "pkginfo"; +($gid ,$pkg ,$uid ,$userInfo ,$email ,$quota ,$group ,$passwd +,$category ,$userHome ,$vendor ,$loginShell ,$pstamp ,$basedir)=(); + +$fullname = shift @ARGV; +$fullname or die "No package name was specified"; +-d $fullname or die "That directory is not present!"; + +$fullname =~ s,/+$,,; # Remove ending slash if any + +$pkgdir= `cd ../$hostname; pwd`; +$pwd = `pwd`; +if ($pwd =~ '\/usr\/local') { + $pwd = $`; +} +die "Wrong location, please cd to /usr/local/ and run again.\n" + if ($pwd eq ""); + +system ("$find . -print | $pkgproto > $temp"); +open (PREPROTO,"<$temp") or die "Unable to read prototype information ($!)\n"; +open (PROTO,">$prototype") or die "Unable to write file prototype ($!)\n"; +print PROTO "i pkginfo=./$pkginfo\n"; +while () { + # Read the prototype information from /tmp/prototype$$ + chomp; + $thisline = $_; + if ($thisline =~ " prototype " + or $thisline =~ " pkginfo ") { + # We don't need that line + } elsif ($thisline =~ "^[fd] ") { + # Change the ownership for files and directories + ($dir, $none, $file, $mode, $user, $group) = split / /,$thisline; + print PROTO "$dir $none $file $mode bin bin\n"; + } else { + # Symlinks and other stuff should be printed as well ofcourse + print PROTO "$thisline\n"; + } +} +close PROTO; +close PREPROTO; + +# Clean up +unlink $temp or warn "Unable to remove tempfile ($!)\n"; + +# Now we can start building the package +# +# First get some info + +$fullname =~ /^((mysql)-.+)-([\d\.]+)-.+$/ + or die "This name is not what I expected - \"$fullname\""; + +$default{"name"}= $2; +$default{"version"}= $3; +$default{"pkg"}= $1; +$default{"arch"} = `uname -m`; +chomp $default{"arch"}; +$default{"category"}= "application"; +$default{"vendor"}= "MySQL AB"; +$default{"email"}= "build\@mysql.com"; +$default{"pstamp"}= "MySQL AB Build Engineers"; +$os = `uname -r`; +$os =~ '\.'; +$os = "sol$'"; +chomp $os; +$default{"basedir"}= "/usr/local"; +$default{"packagename"}= "${fullname}.pkg"; + +# Check for correctness of guessed values by userinput + +%questions = ( + pkg => "Please give the name for this package", + name => "Now enter the real name for this package", + arch => "What architecture did you build the package on?", + version => "Enter the version number of the package", + category => "What category does this package belong to?", + vendor => "Who is the vendor of this package?", + email => "Enter the email adress for contact", + pstamp => "Enter your own name", + basedir => "What is the basedir this package will install into?", + packagename => "How should I call the packagefile?", +); + +@vars = qw(pkg name arch version category vendor email pstamp basedir + packagename); +foreach $varname (@vars) { + getvar_noq($varname); +} + +if ($INTERACTIVE) { + while (!&chkvar()) { + print "\n"; + foreach $varname (@vars) { + getvar($varname); + } + @vars = qw(pkg name arch version category vendor email pstamp basedir + packagename); + } +} +$classes = "none"; + +# Create the pkginfo file + +print "\nNow creating $pkginfo file\n"; +open (PKGINFO,">$pkginfo") || die "Unable to open $pkginfo for writing ($!)\n"; +print PKGINFO "PKG=\"$pkg\"\n"; +print PKGINFO "NAME=\"$name\"\n"; +print PKGINFO "ARCH=\"$arch\"\n"; +print PKGINFO "VERSION=\"$version\"\n"; +print PKGINFO "CATEGORY=\"$category\"\n"; +print PKGINFO "VENDOR=\"$vendor\"\n"; +print PKGINFO "EMAIL=\"$email\"\n"; +print PKGINFO "PSTAMP=\"$pstamp\"\n"; +print PKGINFO "BASEDIR=\"$basedir\"\n"; +print PKGINFO "CLASSES=\"$classes\"\n"; +close PKGINFO; +print "Done.\n"; + +# Build and zip the package + +print "Building package\n"; +system ("$pkgmk -r `pwd`"); +system ("(cd /var/spool/pkg; $pkgtrans -s -o `pwd` /tmp/$packagename $pkg)"); +system ("gzip /tmp/$packagename"); + +# Clean-up the spool area +system ("(cd /var/spool/pkg; rm -rf $pkg)"); +# Clean-up the ~/packaging/ area +system ("(rm -rf mysql*)"); +unlink $pkginfo; +unlink $prototype; +system ("mv /tmp/${packagename}.gz $pkgdir"); +print "Done. (~/$hostname/$packagename.gz)\n"; +# The subroutines +sub chkvar { + print "\n"; + + print "PKG=$pkg\n"; + print "NAME=$name\n"; + print "ARCH=$arch\n"; + print "VERSION=$version\n"; + print "CATEGORY=$category\n"; + print "VENDOR=$vendor\n"; + print "EMAIL=$email\n"; + print "PSTAMP=$pstamp\n"; + print "BASEDIR=$basedir\n"; + print "PACKAGENAME=$packagename\n"; + + + print "\nIs this information correct? [Y/n]: "; + my $answer= ; + chomp $answer; + $answer= 'Y' if ($answer eq ""); + $answer= uc $answer; + my $res= ($answer eq 'Y')? 1 : 0; + return($res); +} + +sub getvar_noq { + my $questionname = "@_"; + $$questionname = $default{$questionname}; +} + +sub getvar { + my $questionname = "@_"; + my $ucquestionname= uc $questionname; + print "$ucquestionname: $questions{$questionname} [$default{\"$questionname\"}]: "; + my $answer = ; + chomp $answer; + $$questionname = $answer; + $$questionname = $default{$questionname} if ($$questionname eq ""); +} diff --git a/Build-tools/mysql-copyright-2 b/Build-tools/mysql-copyright-2 index 2ea2e8ef441..972d5483d54 100755 --- a/Build-tools/mysql-copyright-2 +++ b/Build-tools/mysql-copyright-2 @@ -109,6 +109,12 @@ sub add_copyright $line_copyright= "! "; $end_copyright= ""; } + elsif ($ARGV =~ /\.sql$/) + { + $start_copyright="-- "; + $line_copyright= "-- "; + $end_copyright= ""; + } elsif ($ARGV =~ /\.asm$/) { $start_copyright="; "; diff --git a/VC++Files/mysql.dsw b/VC++Files/mysql.dsw index b0a36f1bd24..43cfab4b915 100644 --- a/VC++Files/mysql.dsw +++ b/VC++Files/mysql.dsw @@ -735,15 +735,15 @@ Package=<4> ############################################################################### -Project: "mysqltest"=.\client\mysqltest.dsp - Package Owner=<4> - -Package=<5> +Project: "mysqltest"=.\client\mysqltest.dsp - Package Owner=<4> + +Package=<5> {{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency + }}} + + +Package=<4> +{{{ Begin Project Dependency Project_Dep_Name libmysql End Project Dependency Begin Project Dependency @@ -754,24 +754,40 @@ Package=<4> End Project Dependency }}} -############################################################################### +############################################################################### + +Project: "mysql_client_test"=.\tests\mysql_client_test.dsp - Package Owner=<4> + + Package=<5> +{{{ + }}} + + Package=<4> + {{{ + }}} -Project: "mysql_test_run_new"=".\mysql-test\mysql_test_run_new.dsp" - Package Owner=<4> + ############################################################################### -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency + +Project: "mysql_test_run_new"=".\mysql-test\mysql_test_run_new.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ Begin Project Dependency Project_Dep_Name mysqltest End Project Dependency Begin Project Dependency Project_Dep_Name mysqladmin End Project Dependency + Begin Project Dependency + Project_Dep_Name mysql_client_test + End Project Dependency }}} + ############################################################################### Global: diff --git a/VC++Files/tests/mysql_client_test.dsp b/VC++Files/tests/mysql_client_test.dsp new file mode 100644 index 00000000000..07014487bd1 --- /dev/null +++ b/VC++Files/tests/mysql_client_test.dsp @@ -0,0 +1,94 @@ +# Microsoft Developer Studio Project File - Name="mysql_client_test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mysql_client_test - 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 "mysql_client_test.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 "mysql_client_test.mak" CFG="mysql_client_test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mysql_client_test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "mysql_client_test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mysql_client_test - 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 /MTd /I "../include" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /Fp".\Debug/mysql_client_test.pch" /Fo".\Debug/" /Fd".\Debug/" /GZ /c /GX +# ADD CPP /nologo /MTd /I "../include" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /Fp".\Debug/mysql_client_test.pch" /Fo".\Debug/" /Fd".\Debug/" /GZ /c /GX +# ADD BASE MTL /nologo /tlb".\Debug\mysql_client_test.tlb" /win32 +# ADD MTL /nologo /tlb".\Debug\mysql_client_test.tlb" /win32 +# ADD BASE RSC /l 1033 +# ADD RSC /l 1033 +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 odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib /nologo /out:"..\tests\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console +# ADD 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 odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib /nologo /out:"..\tests\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console + +!ELSEIF "$(CFG)" == "mysql_client_test - 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 /MTd /I "../include" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /GF /Gy /Fp".\Release/client_test.pch" /Fo".\Release/" /Fd".\Release/" /c /GX +# ADD CPP /nologo /MTd /I "../include" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /D "MYSQL_CLIENT" /D "__WIN__" /D "_WIN32" /GF /Gy /Fp".\Release/client_test.pch" /Fo".\Release/" /Fd".\Release/" /c /GX +# ADD BASE MTL /nologo /tlb".\Release\client_test.tlb" /win32 +# ADD MTL /nologo /tlb".\Release\client_test.tlb" /win32 +# ADD BASE RSC /l 1033 +# ADD RSC /l 1033 +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 odbc32.lib odbccp32.lib Ws2_32.lib /nologo /out:"..\tests\client_test.exe" /incremental:no /pdb:".\Release\client_test.pdb" /pdbtype:sept /subsystem:console +# ADD 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 odbc32.lib odbccp32.lib Ws2_32.lib /nologo /out:"..\tests\client_test.exe" /incremental:no /pdb:".\Release\client_test.pdb" /pdbtype:sept /subsystem:console + +!ENDIF + +# Begin Target + +# Name "mysql_client_test - Win32 Debug" +# Name "mysql_client_test - Win32 Release" +# Begin Source File + +SOURCE=tests\mysql_client_test.c +# End Source File +# End Target +# End Project + diff --git a/client/Makefile.am b/client/Makefile.am index 2721953629e..d3307f9da42 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -34,7 +34,8 @@ mysqltest_SOURCES= mysqltest.c $(top_srcdir)/mysys/my_getsystime.c mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) mysqlbinlog_SOURCES = mysqlbinlog.cc $(top_srcdir)/mysys/mf_tempdir.c mysqlmanagerc_SOURCES = mysqlmanagerc.c -sql_src=log_event.h mysql_priv.h log_event.cc +sql_src=log_event.h mysql_priv.h log_event.cc my_decimal.h my_decimal.cc +strings_src=decimal.c # Fix for mit-threads DEFS = -DUNDEF_THREADS_HACK @@ -43,7 +44,11 @@ link_sources: for f in $(sql_src) ; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(top_srcdir)/sql/$$f $(srcdir)/$$f; \ - done; + done; \ + for f in $(strings_src) ; do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ $(top_srcdir)/strings/$$f $(srcdir)/$$f; \ + done; # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/client/mysql.cc b/client/mysql.cc index 046cba536be..e387bb26063 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -155,6 +155,8 @@ static char mysql_charsets_dir[FN_REFLEN+1]; static const char *xmlmeta[] = { "&", "&", "<", "<", + ">", ">", + "\"", """, 0, 0 }; static const char *day_names[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; @@ -2126,13 +2128,11 @@ print_table_data_xml(MYSQL_RES *result) (void) tee_fputs("\n \n", PAGER); for (uint i=0; i < mysql_num_fields(result); i++) { - tee_fprintf(PAGER, "\t<%s>", (fields[i].name ? - (fields[i].name[0] ? fields[i].name : - "   ") : "NULL")); + tee_fprintf(PAGER, "\t"); xmlencode_print(cur[i], lengths[i]); - tee_fprintf(PAGER, "\n", (fields[i].name ? - (fields[i].name[0] ? fields[i].name : - "   ") : "NULL")); + tee_fprintf(PAGER, "\n"); } (void) tee_fputs(" \n", PAGER); } diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 3bef8fb0452..24fe14b6675 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -1009,6 +1009,7 @@ static void usage(void) print_defaults("my",load_default_groups); puts("\nWhere command is a one or more of: (Commands may be shortened)\n\ create databasename Create a new database\n\ + debug Instruct server to write debug information to log\n\ drop databasename Delete a database and all its tables\n\ extended-status Gives an extended status message from the server\n\ flush-hosts Flush all cached hosts\n\ diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index caf126f2830..dc1c1e6fc02 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -488,6 +488,15 @@ end: static struct my_option my_long_options[] = { + /* + mysqlbinlog needs charsets knowledge, to be able to convert a charset + number found in binlog to a charset name (to be able to print things + like this: + SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`; + */ + {"character-sets-dir", OPT_CHARSETS_DIR, + "Directory where character sets are.", (gptr*) &charsets_dir, + (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF {"debug", '#', "Output debug log.", (gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -1271,8 +1280,14 @@ int main(int argc, char** argv) */ #ifdef __WIN__ +#include "my_decimal.h" +#include "decimal.c" +#include "my_decimal.cpp" #include "log_event.cpp" #else +#include "my_decimal.h" +#include "decimal.c" +#include "my_decimal.cc" #include "log_event.cc" #endif diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 980046fe6e6..15be51853cd 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -195,7 +195,7 @@ static void usage(void) puts("and you are welcome to modify and redistribute it under the GPL license.\n"); puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)"); puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be"); - puts("used at the same time. It works on MyISAM and in some cases on BDB tables."); + puts("used at the same time. Not all options are supported by all storage engines."); puts("Please consult the MySQL manual for latest information about the"); puts("above. The options -c,-r,-a and -o are exclusive to each other, which"); puts("means that the last option will be used, if several was specified.\n"); diff --git a/client/mysqldump.c b/client/mysqldump.c index 70310737164..c2b07e2ec20 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -493,7 +493,7 @@ static void write_header(FILE *sql_file, char *db_name) "); } fprintf(sql_file, - "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=\"%s%s%s\" */;\n", + "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n", path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",", compatible_mode_normal_str); check_io(sql_file); @@ -867,7 +867,7 @@ static int dbConnect(char *host, char *user,char *passwd) cannot reconnect. */ sock->reconnect= 0; - sprintf(buff, "/*!40100 SET @@SQL_MODE=\"%s\" */", + sprintf(buff, "/*!40100 SET @@SQL_MODE='%s' */", compatible_mode_normal_str); if (mysql_query_with_error_report(sock, 0, buff)) { @@ -2195,27 +2195,27 @@ static my_bool dump_all_views_in_db(char *database) RETURN void */ -static void get_actual_table_name( const char *old_table_name, - char *new_table_name, - int buf_size ) + +static void get_actual_table_name(const char *old_table_name, + char *new_table_name, + int buf_size) { - MYSQL_RES *tableRes; - MYSQL_ROW row; - char query[ NAME_LEN + 50 ]; + MYSQL_RES *tableRes; + MYSQL_ROW row; + char query[ NAME_LEN + 50 ]; + DBUG_ENTER("get_actual_table_name"); - DBUG_ENTER("get_actual_table_name"); + sprintf( query, "SHOW TABLES LIKE '%s'", old_table_name); + if (mysql_query_with_error_report(sock, 0, query)) + { + safe_exit(EX_MYSQLERR); + } - sprintf( query, "SHOW TABLES LIKE '%s'", old_table_name ); - if (mysql_query_with_error_report(sock, 0, query)) - { - safe_exit(EX_MYSQLERR); - } - - tableRes = mysql_store_result( sock ); - row = mysql_fetch_row( tableRes ); - strncpy( new_table_name, row[0], buf_size ); - mysql_free_result(tableRes); -} /* get_actual_table_name */ + tableRes= mysql_store_result( sock ); + row= mysql_fetch_row( tableRes ); + strmake(new_table_name, row[0], buf_size-1); + mysql_free_result(tableRes); +} static int dump_selected_tables(char *db, char **table_names, int tables) diff --git a/config/ac-macros/character_sets.m4 b/config/ac-macros/character_sets.m4 index c83cc63a8aa..6efd31fdb05 100644 --- a/config/ac-macros/character_sets.m4 +++ b/config/ac-macros/character_sets.m4 @@ -405,3 +405,20 @@ AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_CHARSET_NAME], ["$default_charset"], [Define the default charset name]) AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_COLLATION_NAME], ["$default_collation"], [Define the default charset name]) + +# Shall we build the UCA-based Unicode collations +AC_ARG_WITH(uca, + [ --without-uca Skip building of the national Unicode collations.], + [with_uca=$withval], + [with_uca=yes] +) + +AC_MSG_CHECKING([whether to compile national Unicode collations]) + +if test "$with_uca" = "yes" +then + AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_UCA_COLLATIONS], [1], [national Unicode collations]) +else + AC_MSG_RESULT(no) +fi diff --git a/config/ac-macros/zlib.m4 b/config/ac-macros/zlib.m4 index 6c92d561e5a..94a26f33dd3 100644 --- a/config/ac-macros/zlib.m4 +++ b/config/ac-macros/zlib.m4 @@ -3,6 +3,8 @@ dnl Define zlib paths to point at bundled zlib AC_DEFUN([MYSQL_USE_BUNDLED_ZLIB], [ ZLIB_INCLUDES="-I\$(top_srcdir)/zlib" ZLIB_LIBS="\$(top_builddir)/zlib/libz.la" +dnl Omit -L$pkglibdir as it's always in the list of mysql_config deps. +ZLIB_DEPS="-lz" zlib_dir="zlib" AC_SUBST([zlib_dir]) mysql_cv_compress="yes" @@ -44,8 +46,13 @@ dnl $prefix/lib. If zlib headers or binaries weren't found at $prefix, the dnl macro bails out with error. dnl dnl If the library was found, this function #defines HAVE_COMPRESS -dnl and configure variables ZLIB_INCLUDES (i.e. -I/path/to/zlib/include) and -dnl ZLIB_LIBS (i. e. -L/path/to/zlib/lib -lz). +dnl and configure variables ZLIB_INCLUDES (i.e. -I/path/to/zlib/include), +dnl ZLIB_LIBS (i. e. -L/path/to/zlib/lib -lz) and ZLIB_DEPS which is +dnl used in mysql_config and is always the same as ZLIB_LIBS except to +dnl when we use the bundled zlib. In the latter case ZLIB_LIBS points to the +dnl build dir ($top_builddir/zlib), while mysql_config must point to the +dnl installation dir ($pkglibdir), so ZLIB_DEPS is set to point to +dnl $pkglibdir. AC_DEFUN([MYSQL_CHECK_ZLIB_WITH_COMPRESS], [ AC_MSG_CHECKING([for zlib compression library]) @@ -94,7 +101,11 @@ case $SYSTEM_TYPE in ;; esac if test "$mysql_cv_compress" = "yes"; then + if test "x$ZLIB_DEPS" = "x"; then + ZLIB_DEPS="$ZLIB_LIBS" + fi AC_SUBST([ZLIB_LIBS]) + AC_SUBST([ZLIB_DEPS]) AC_SUBST([ZLIB_INCLUDES]) AC_DEFINE([HAVE_COMPRESS], [1], [Define to enable compression support]) fi diff --git a/configure.in b/configure.in index b2d8d65439d..e6ae8f8f70b 100644 --- a/configure.in +++ b/configure.in @@ -918,9 +918,11 @@ if test "$ac_cv_header_termio_h" = "no" -a "$ac_cv_header_termios_h" = "no" then AC_CHECK_FUNC(gtty, , AC_CHECK_LIB(compat, gtty)) fi -# We make a special variable for client library's to avoid including -# thread libs in the client. -NON_THREADED_CLIENT_LIBS="$LIBS $ZLIB_LIBS" + +# We make a special variable for non-threaded version of LIBS to avoid +# including thread libs into non-threaded version of MySQL client library. +# Later in this script LIBS will be augmented with a threads library. +NON_THREADED_LIBS="$LIBS" AC_MSG_CHECKING([for int8]) case $SYSTEM_TYPE in @@ -1497,7 +1499,7 @@ then if test -f /usr/lib/libxnet.so -a "$SYSTEM_TYPE" = "sni-sysv4" then LIBS="-lxnet $LIBS" - NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS -lxnet" + NON_THREADED_LIBS="-lxnet $NON_THREADED_LIBS" with_named_thread="-Kthread $LDFLAGS -lxnet" LD_FLAGS="" CFLAGS="-Kthread $CFLAGS" @@ -2444,7 +2446,7 @@ dnl This probably should be cleaned up more - for now the threaded dnl client is just using plain-old libs. sql_client_dirs="libmysql strings regex client" linked_client_targets="linked_libmysql_sources" -CLIENT_LIBS=$NON_THREADED_CLIENT_LIBS + if test "$THREAD_SAFE_CLIENT" != "no" then sql_client_dirs="libmysql_r $sql_client_dirs" @@ -2452,9 +2454,11 @@ then AC_DEFINE([THREAD_SAFE_CLIENT], [1], [Should be client be thread safe]) fi -CLIENT_LIBS="$CLIENT_LIBS $STATIC_NSS_FLAGS" +CLIENT_LIBS="$NON_THREADED_LIBS $openssl_libs $ZLIB_LIBS $STATIC_NSS_FLAGS" AC_SUBST(CLIENT_LIBS) +AC_SUBST(NON_THREADED_LIBS) +AC_SUBST(STATIC_NSS_FLAGS) AC_SUBST(sql_client_dirs) AC_SUBST(linked_client_targets) diff --git a/extra/perror.c b/extra/perror.c index e667ea723b8..b377b360b5c 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -189,6 +189,7 @@ int main(int argc,char *argv[]) { int error,code,found; const char *msg; + char *unknown_error = 0; MY_INIT(argv[0]); if (get_options(&argc,&argv)) @@ -217,7 +218,14 @@ int main(int argc,char *argv[]) string 'Unknown Error'. To avoid printing it we try to find the error string by asking for an impossible big error message. */ - const char *unknown_error= strerror(10000); + msg= strerror(10000); + + /* + Allocate a buffer for unknown_error since strerror always returns + the same pointer on some platforms such as Windows + */ + unknown_error= malloc(strlen(msg)+1); + strmov(unknown_error, msg); for ( ; argc-- > 0 ; argv++) { @@ -267,6 +275,11 @@ int main(int argc,char *argv[]) } } } + + /* if we allocated a buffer for unknown_error, free it now */ + if (unknown_error) + free(unknown_error); + exit(error); return error; } diff --git a/include/decimal.h b/include/decimal.h index 4d1fbfddc01..1e0ee97c267 100644 --- a/include/decimal.h +++ b/include/decimal.h @@ -26,7 +26,9 @@ typedef struct st_decimal { decimal_digit *buf; } decimal; -int decimal2string(decimal *from, char *to, int *to_len); +int decimal2string(decimal *from, char *to, int *to_len, + int fixed_precision, int fixed_decimals, + char filler); int string2decimal(char *from, decimal *to, char **end); int string2decimal_fixed(char *from, decimal *to, char **end); int decimal2ulonglong(decimal *from, ulonglong *to); @@ -35,6 +37,7 @@ int decimal2longlong(decimal *from, longlong *to); int longlong2decimal(longlong from, decimal *to); int decimal2double(decimal *from, double *to); int double2decimal(double from, decimal *to); +void decimal_optimize_fraction(decimal *from); int decimal2bin(decimal *from, char *to, int precision, int scale); int bin2decimal(char *from, decimal *to, int precision, int scale); @@ -50,6 +53,7 @@ int decimal_div(decimal *from1, decimal *from2, decimal *to, int scale_incr); int decimal_mod(decimal *from1, decimal *from2, decimal *to); int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode mode); int decimal_is_zero(decimal *from); +void max_decimal(int precision, int frac, decimal *to); /* set a decimal to zero */ @@ -65,7 +69,8 @@ int decimal_is_zero(decimal *from); of the decimal (including decimal dot, possible sign and \0) */ -#define decimal_string_size(dec) ((dec)->intg + (dec)->frac + ((dec)->frac > 0) + 2) +#define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \ + (dec)->frac + ((dec)->frac > 0) + 2) /* negate a decimal */ #define decimal_neg(dec) do { (dec)->sign^=1; } while(0) diff --git a/include/ft_global.h b/include/ft_global.h index 94f6ad9ef51..c3f60d13a7a 100644 --- a/include/ft_global.h +++ b/include/ft_global.h @@ -62,7 +62,7 @@ void ft_free_stopwords(void); #define FT_SORTED 2 #define FT_EXPAND 4 /* query expansion */ -FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, byte *); +FT_INFO *ft_init_search(uint,void *, uint, byte *, uint,CHARSET_INFO *, byte *); my_bool ft_boolean_check_syntax_string(const byte *); #ifdef __cplusplus diff --git a/include/my_global.h b/include/my_global.h index f27eb4733bd..f5cd8edeab9 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -135,7 +135,13 @@ #ifdef HAVE_UNIXWARE7_THREADS #include #else +#if defined(HPUX10) || defined(HPUX11) +C_MODE_START /* HPUX needs this, signal.h bug */ +#include +C_MODE_END +#else #include /* AIX must have this included first */ +#endif #endif /* HAVE_UNIXWARE7_THREADS */ #endif /* HAVE_mit_thread */ #if !defined(SCO) && !defined(_REENTRANT) diff --git a/include/mysql.h b/include/mysql.h index 58c314207c1..b87b865608e 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -337,6 +337,17 @@ typedef struct st_mysql_parameters */ int STDCALL mysql_server_init(int argc, char **argv, char **groups); void STDCALL mysql_server_end(void); +/* + mysql_server_init/end need to be called when using libmysqld or + libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so + you don't need to call it explicitely; but you need to call + mysql_server_end() to free memory). The names are a bit misleading + (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general + names which suit well whether you're using libmysqld or libmysqlclient. We + intend to promote these aliases over the mysql_server* ones. +*/ +#define mysql_library_init mysql_server_init +#define mysql_library_end mysql_server_end MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); diff --git a/include/mysql_com.h b/include/mysql_com.h index 78d71bde1cf..3165ca4c4c3 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -216,6 +216,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, MYSQL_TYPE_BIT, + MYSQL_TYPE_NEWDECIMAL=246, MYSQL_TYPE_ENUM=247, MYSQL_TYPE_SET=248, MYSQL_TYPE_TINY_BLOB=249, @@ -231,6 +232,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, /* For backward compatibility */ #define CLIENT_MULTI_QUERIES CLIENT_MULTI_STATEMENTS #define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL +#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL #define FIELD_TYPE_TINY MYSQL_TYPE_TINY #define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT #define FIELD_TYPE_LONG MYSQL_TYPE_LONG @@ -346,7 +348,8 @@ struct rand_struct { /* The following is for user defined functions */ -enum Item_result {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}; +enum Item_result {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, + DECIMAL_RESULT}; typedef struct st_udf_args { diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c index 1ce52c8ee31..d9dc2ca93f5 100644 --- a/innobase/buf/buf0rea.c +++ b/innobase/buf/buf0rea.c @@ -686,7 +686,9 @@ buf_read_recv_pages( fprintf(stderr, "InnoDB: Error: InnoDB has waited for 50 seconds for pending\n" "InnoDB: reads to the buffer pool to be finished.\n" -"InnoDB: Number of pending reads %lu\n", (ulong) buf_pool->n_pend_reads); +"InnoDB: Number of pending reads %lu, pending pread calls %lu\n", + (ulong) buf_pool->n_pend_reads, + (ulong)os_file_n_pending_preads); os_aio_print_debug = TRUE; } diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c index 00048bf6fbb..b1297fe7a5b 100644 --- a/innobase/data/data0type.c +++ b/innobase/data/data0type.c @@ -81,6 +81,7 @@ dtype_get_at_most_n_mbchars( ulint data_len, const char* str) { +#ifndef UNIV_HOTBACKUP ut_a(data_len != UNIV_SQL_NULL); if (dtype_str_needs_mysql_cmp(dtype)) { @@ -99,6 +100,12 @@ dtype_get_at_most_n_mbchars( } return(data_len); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /************************************************************************* diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 800d7dcd9e9..6ec4809790e 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -53,6 +53,7 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve /* Identifies generated InnoDB foreign key names */ static char dict_ibfk[] = "_ibfk_"; +#ifndef UNIV_HOTBACKUP /********************************************************************** Compares NUL-terminated UTF-8 strings case insensitively. @@ -76,6 +77,7 @@ void innobase_casedn_str( /*================*/ char* a); /* in/out: string to put in lower case */ +#endif /* !UNIV_HOTBACKUP */ /************************************************************************** Adds a column to the data dictionary hash table. */ @@ -2095,6 +2097,7 @@ dict_foreign_find_index( dict_index_t* types_idx)/* in: NULL or an index to whose types the column types must match */ { +#ifndef UNIV_HOTBACKUP dict_index_t* index; const char* col_name; ulint i; @@ -2139,6 +2142,12 @@ dict_foreign_find_index( } return(NULL); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /************************************************************************** @@ -2492,6 +2501,7 @@ dict_scan_col( const char** name) /* out,own: the column name; NULL if no name was scannable */ { +#ifndef UNIV_HOTBACKUP dict_col_t* col; ulint i; @@ -2525,6 +2535,12 @@ dict_scan_col( } return(ptr); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /************************************************************************* @@ -2542,6 +2558,7 @@ dict_scan_table_name( const char** ref_name)/* out,own: the table name; NULL if no name was scannable */ { +#ifndef UNIV_HOTBACKUP const char* database_name = NULL; ulint database_name_len = 0; const char* table_name = NULL; @@ -2623,6 +2640,12 @@ dict_scan_table_name( *table = dict_table_get_low(ref); return(ptr); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /************************************************************************* diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 17b53a7a140..7fd1ca08c04 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -8,7 +8,9 @@ Created 4/24/1996 Heikki Tuuri *******************************************************/ #include "dict0load.h" +#ifndef UNIV_HOTBACKUP #include "mysql_version.h" +#endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_NONINL #include "dict0load.ic" @@ -792,6 +794,7 @@ dict_load_table( name, (ulong)mix_len); } +#ifndef UNIV_HOTBACKUP #if MYSQL_VERSION_ID < 50003 /* Starting from MySQL 5.0.3, the high-order bit of MIX_LEN is the "compact format" flag. */ @@ -807,6 +810,7 @@ dict_load_table( return(NULL); } #endif /* MYSQL_VERSION_ID < 50300 */ +#endif /* !UNIV_HOTBACKUP */ ut_a(0 == ut_strcmp("SPACE", dict_field_get_col( diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 9b2f7ffe575..8da6ad08538 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -3013,8 +3013,8 @@ fil_load_single_table_tablespaces(void) /* printf( " Looking at file %s\n", fileinfo.name); */ - if (fileinfo.type == OS_FILE_TYPE_DIR - || dbinfo.type == OS_FILE_TYPE_UNKNOWN) { + if (fileinfo.type == OS_FILE_TYPE_DIR) { + goto next_file_item; } diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic index 0b92ffbe7f1..15833905761 100644 --- a/innobase/include/data0type.ic +++ b/innobase/include/data0type.ic @@ -273,6 +273,7 @@ dtype_get_fixed_size( /* out: fixed size, or 0 */ dtype_t* type) /* in: type */ { +#ifndef UNIV_HOTBACKUP ulint mtype; mtype = dtype_get_mtype(type); @@ -321,6 +322,12 @@ dtype_get_fixed_size( } return(0); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /*************************************************************************** diff --git a/innobase/include/rem0rec.ic b/innobase/include/rem0rec.ic index 366f1c3f77d..2593fb8edeb 100644 --- a/innobase/include/rem0rec.ic +++ b/innobase/include/rem0rec.ic @@ -279,7 +279,15 @@ rec_get_next_offs( /* Note that for 64 KiB pages, field_value can 'wrap around' and the debug assertion is not valid */ - ut_ad((int16_t)field_value + /* In the following assertion, field_value is interpreted + as signed 16-bit integer in 2's complement arithmetics. + If all platforms defined int16_t in the standard headers, + the expression could be written simpler as + (int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE + */ + ut_ad((field_value >= 32768 + ? field_value - 65536 + : field_value) + ut_align_offset(rec, UNIV_PAGE_SIZE) < UNIV_PAGE_SIZE); #endif diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index c5374fd00fa..27cdaf2e505 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -294,6 +294,12 @@ srv_boot(void); /*==========*/ /* out: DB_SUCCESS or error code */ /************************************************************************* +Initializes the server. */ + +void +srv_init(void); +/*==========*/ +/************************************************************************* Frees the OS fast mutex created in srv_boot(). */ void diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h index 8df0f97c4ff..d24f119c0b0 100644 --- a/innobase/include/srv0start.h +++ b/innobase/include/srv0start.h @@ -53,6 +53,16 @@ srv_parse_log_group_home_dirs( error */ char* str, /* in: character string */ char*** log_group_home_dirs); /* out, own: log group home dirs */ +/************************************************************************* +Adds a slash or a backslash to the end of a string if it is missing +and the string is not empty. */ + +char* +srv_add_path_separator_if_needed( +/*=============================*/ + /* out: string which has the separator if the + string is not empty */ + char* str); /* in: null-terminated character string */ /******************************************************************** Starts Innobase and creates a new database if database files are not found and the user wants. Server parameters are diff --git a/innobase/include/sync0sync.h b/innobase/include/sync0sync.h index 5046a960bcf..c798c047fa3 100644 --- a/innobase/include/sync0sync.h +++ b/innobase/include/sync0sync.h @@ -17,7 +17,9 @@ Created 9/5/1995 Heikki Tuuri #include "os0sync.h" #include "sync0arr.h" +#ifndef UNIV_HOTBACKUP extern my_bool timed_mutexes; +#endif /* UNIV_HOTBACKUP */ /********************************************************************** Initializes the synchronization data structures. */ @@ -475,6 +477,7 @@ struct mutex_struct { const char* cfile_name;/* File name where mutex created */ ulint cline; /* Line where created */ ulint magic_n; +#ifndef UNIV_HOTBACKUP ulong count_using; /* count of times mutex used */ ulong count_spin_loop; /* count of spin loops */ ulong count_spin_rounds; /* count of spin rounds */ @@ -484,6 +487,7 @@ struct mutex_struct { ulonglong lmax_spent_time; /* mutex os_wait timer msec */ const char* cmutex_name;/* mutex name */ ulint mutex_type;/* 0 - usual mutex 1 - rw_lock mutex */ +#endif /* !UNIV_HOTBACKUP */ }; #define MUTEX_MAGIC_N (ulint)979585 diff --git a/innobase/include/sync0sync.ic b/innobase/include/sync0sync.ic index f26f3788dc3..b3fde61db5e 100644 --- a/innobase/include/sync0sync.ic +++ b/innobase/include/sync0sync.ic @@ -250,7 +250,9 @@ mutex_enter_func( /* Note that we do not peek at the value of lock_word before trying the atomic test_and_set; we could peek, and possibly save time. */ +#ifndef UNIV_HOTBACKUP mutex->count_using++; +#endif /* UNIV_HOTBACKUP */ if (!mutex_test_and_set(mutex)) { diff --git a/innobase/include/trx0roll.h b/innobase/include/trx0roll.h index 9d025da4a5f..944142a299d 100644 --- a/innobase/include/trx0roll.h +++ b/innobase/include/trx0roll.h @@ -225,6 +225,21 @@ trx_savepoint_for_mysql( position corresponding to this connection at the time of the savepoint */ + +/*********************************************************************** +Releases a named savepoint. Savepoints which +were set after this savepoint are deleted. */ + +ulint +trx_release_savepoint_for_mysql( +/*================================*/ + /* out: if no savepoint + of the name found then + DB_NO_SAVEPOINT, + otherwise DB_SUCCESS */ + trx_t* trx, /* in: transaction handle */ + const char* savepoint_name); /* in: savepoint name */ + /*********************************************************************** Frees savepoint structs. */ diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index b63afdd526c..8ac18241e32 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -173,10 +173,10 @@ their transaction objects for a recovery. */ int trx_recover_for_mysql( -/*=================*/ +/*==================*/ /* out: number of prepared transactions */ XID* xid_list, /* in/out: prepared transactions */ - uint len); /* in: number of slots in xid_list */ + ulint len); /* in: number of slots in xid_list */ /*********************************************************************** This function is used to commit one X/Open XA distributed transaction diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 5d1e8e208cd..8158c198e21 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -80,10 +80,6 @@ memory is read outside the allocated blocks. */ /* Make a non-inline debug version */ -#ifdef DBUG_ON -#define UNIV_DEBUG -#endif /* DBUG_ON */ - /* #define UNIV_DEBUG #define UNIV_MEM_DEBUG diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 05466764063..a2560c1faae 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -694,7 +694,7 @@ lock_is_table_exclusive( trx_t* trx) /* in: transaction */ { lock_t* lock; - bool ok = FALSE; + ibool ok = FALSE; ut_ad(table && trx); @@ -4219,7 +4219,8 @@ lock_get_n_rec_locks(void) return(n_locks); } - + +#ifndef UNIV_HOTBACKUP /************************************************************************* Prints info of locks for all transactions. */ @@ -4743,7 +4744,7 @@ lock_validate(void) return(TRUE); } - +#endif /* !UNIV_HOTBACKUP */ /*============ RECORD LOCK CHECKS FOR ROW OPERATIONS ====================*/ /************************************************************************* diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index a2c5365993c..969f7aee859 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -711,12 +711,12 @@ http://www.mysql.com/doc/en/Windows_symbolic_links.html */ } else if (lpFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { info->type = OS_FILE_TYPE_DIR; - } else if (lpFindFileData->dwFileAttributes - & FILE_ATTRIBUTE_NORMAL) { -/* TODO: are FILE_ATTRIBUTE_NORMAL files really all normal files? */ - info->type = OS_FILE_TYPE_FILE; } else { - info->type = OS_FILE_TYPE_UNKNOWN; + /* It is probably safest to assume that all other + file types are normal. Better to check them rather + than blindly skip them. */ + + info->type = OS_FILE_TYPE_FILE; } } @@ -834,7 +834,7 @@ os_file_create_directory( rcode = CreateDirectory(pathname, NULL); if (!(rcode != 0 || - (GetLastError() == ERROR_FILE_EXISTS && !fail_if_exists))) { + (GetLastError() == ERROR_ALREADY_EXISTS && !fail_if_exists))) { /* failure */ os_file_handle_error(pathname, "CreateDirectory"); @@ -918,8 +918,9 @@ try_again: file = CreateFile(name, access, - FILE_SHARE_READ,/* file can be read also by other - processes */ + FILE_SHARE_READ | FILE_SHARE_WRITE, + /* file can be read ansd written also + by other processes */ NULL, /* default security attributes */ create_flag, attributes, @@ -1024,7 +1025,7 @@ os_file_create_simple_no_error_handling( DWORD create_flag; DWORD access; DWORD attributes = 0; - DWORD share_mode = FILE_SHARE_READ; + DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE; ut_a(name); @@ -1347,7 +1348,7 @@ loop: return(TRUE); } - if (GetLastError() == ERROR_PATH_NOT_FOUND) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) { /* the file does not exist, this not an error */ return(TRUE); @@ -1408,7 +1409,7 @@ loop: return(TRUE); } - if (GetLastError() == ERROR_PATH_NOT_FOUND) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) { /* If the file does not exist, we classify this as a 'mild' error and return */ diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c index fc94fc4b1e0..488d2757115 100644 --- a/innobase/page/page0cur.c +++ b/innobase/page/page0cur.c @@ -311,9 +311,6 @@ page_cur_search_with_match( low_matched_bytes = cur_matched_bytes; } else if (cmp == -1) { - offsets = rec_get_offsets(mid_rec, index, offsets, - dtuple_get_n_fields_cmp(tuple), &heap); - if (mode == PAGE_CUR_LE_OR_EXTENDS && page_cur_rec_field_extends(tuple, mid_rec, offsets, cur_matched_fields)) { @@ -366,9 +363,6 @@ page_cur_search_with_match( low_matched_bytes = cur_matched_bytes; } else if (cmp == -1) { - offsets = rec_get_offsets(mid_rec, index, offsets, - dtuple_get_n_fields_cmp(tuple), &heap); - if (mode == PAGE_CUR_LE_OR_EXTENDS && page_cur_rec_field_extends(tuple, mid_rec, offsets, cur_matched_fields)) { diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index aab0f5affa7..87ed497ba1e 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -51,14 +51,19 @@ innobase_invalidate_query_cache( chars count */ /********************************************************************** -This function returns true if SQL-query in the current thread +This function returns true if + +1) SQL-query in the current thread is either REPLACE or LOAD DATA INFILE REPLACE. + +2) SQL-query in the current thread +is INSERT ON DUPLICATE KEY UPDATE. + NOTE that /mysql/innobase/row/row0ins.c must contain the prototype for this function ! */ ibool -innobase_query_is_replace(void); -/*===========================*/ +innobase_query_is_update(void); /************************************************************************* Creates an insert node struct. */ @@ -1541,6 +1546,7 @@ row_ins_scan_sec_index_for_duplicate( dtuple_t* entry, /* in: index entry */ que_thr_t* thr) /* in: query thread */ { +#ifndef UNIV_HOTBACKUP ulint n_unique; ulint i; int cmp; @@ -1597,12 +1603,12 @@ row_ins_scan_sec_index_for_duplicate( offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); - if (innobase_query_is_replace()) { + if (innobase_query_is_update()) { - /* The manual defines the REPLACE semantics that it - is either an INSERT or DELETE(s) for duplicate key - + INSERT. Therefore, we should take X-lock for - duplicates */ + /* If the SQL-query will update or replace + duplicate key we will take X-lock for + duplicates ( REPLACE, LOAD DATAFILE REPLACE, + INSERT ON DUPLICATE KEY UPDATE). */ err = row_ins_set_exclusive_rec_lock(LOCK_ORDINARY, rec, index, offsets, thr); @@ -1657,6 +1663,12 @@ next_rec: dtuple_set_n_fields_cmp(entry, n_fields_cmp); return(err); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /******************************************************************* @@ -1676,6 +1688,7 @@ row_ins_duplicate_error_in_clust( que_thr_t* thr, /* in: query thread */ mtr_t* mtr) /* in: mtr */ { +#ifndef UNIV_HOTBACKUP ulint err; rec_t* rec; page_t* page; @@ -1720,12 +1733,12 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - if (innobase_query_is_replace()) { + if (innobase_query_is_update()) { - /* The manual defines the REPLACE semantics - that it is either an INSERT or DELETE(s) - for duplicate key + INSERT. Therefore, we - should take X-lock for duplicates */ + /* If the SQL-query will update or replace + duplicate key we will take X-lock for + duplicates ( REPLACE, LOAD DATAFILE REPLACE, + INSERT ON DUPLICATE KEY UPDATE). */ err = row_ins_set_exclusive_rec_lock( LOCK_REC_NOT_GAP,rec,cursor->index, @@ -1759,12 +1772,12 @@ row_ins_duplicate_error_in_clust( offsets = rec_get_offsets(rec, cursor->index, offsets, ULINT_UNDEFINED, &heap); - /* The manual defines the REPLACE semantics that it - is either an INSERT or DELETE(s) for duplicate key - + INSERT. Therefore, we should take X-lock for - duplicates. */ + if (innobase_query_is_update()) { - if (innobase_query_is_replace()) { + /* If the SQL-query will update or replace + duplicate key we will take X-lock for + duplicates ( REPLACE, LOAD DATAFILE REPLACE, + INSERT ON DUPLICATE KEY UPDATE). */ err = row_ins_set_exclusive_rec_lock( LOCK_REC_NOT_GAP, rec, @@ -1796,6 +1809,12 @@ row_ins_duplicate_error_in_clust( err = DB_SUCCESS; func_exit: return(err); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /******************************************************************* diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 2c4eebedaf7..f1673aa6fa5 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -260,6 +260,7 @@ row_mysql_handle_errors( que_thr_t* thr, /* in: query thread */ trx_savept_t* savept) /* in: savepoint or NULL */ { +#ifndef UNIV_HOTBACKUP ulint err; handle_new_error: @@ -359,6 +360,12 @@ handle_new_error: trx->error_state = DB_SUCCESS; return(FALSE); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /************************************************************************ @@ -2072,6 +2079,7 @@ row_add_table_to_background_drop_list( return(TRUE); } +#ifndef UNIV_HOTBACKUP /************************************************************************* Discards the tablespace of a table which stored in an .ibd file. Discarding means that this function deletes the .ibd file and assigns a new table id for @@ -2433,7 +2441,6 @@ row_truncate_table_for_mysql( { dict_foreign_t* foreign; ulint err; - ibool locked_dictionary = FALSE; mem_heap_t* heap; byte* buf; dtuple_t* tuple; @@ -2451,13 +2458,15 @@ operations could try to access non-existent pages. 1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock on the table before we can do TRUNCATE TABLE. Then there are no running -queries on the table. +queries on the table. This is guaranteed, because in +ha_innobase::store_lock(), we do not weaken the TL_WRITE lock requested +by MySQL when executing SQLCOM_TRUNCATE. 2) Purge and rollback: we assign a new table id for the table. Since purge and rollback look for the table based on the table id, they see the table as 'dropped' and discard their operations. 3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE, so we do not have to remove insert buffer records, as the insert buffer works at a low -level. If a freed page is later reallocated, the allocator will remove +level. If a freed page is later reallocated, the allocator will remove the ibuf entries for it. TODO: when we truncate *.ibd files (analogous to DISCARD TABLESPACE), we @@ -2465,10 +2474,10 @@ will have to remove we remove all entries for the table in the insert buffer tree! 4) Linear readahead and random readahead: we use the same method as in 3) to -discard ongoing operations. (This will only be relevant for TRUNCATE TABLE +discard ongoing operations. (This will only be relevant for TRUNCATE TABLE by DISCARD TABLESPACE.) 5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we -do not allow the TRUNCATE. We also reserve the data dictionary latch. */ +do not allow the TRUNCATE. We also reserve the data dictionary latch. */ static const char renumber_tablespace_proc[] = "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n" @@ -2516,14 +2525,11 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ /* Serialize data dictionary operations with dictionary mutex: no deadlocks can occur then in these operations */ - if (trx->dict_operation_lock_mode != RW_X_LATCH) { - /* Prevent foreign key checks etc. while we are truncating the - table */ + ut_a(trx->dict_operation_lock_mode == 0); + /* Prevent foreign key checks etc. while we are truncating the + table */ - row_mysql_lock_data_dictionary(trx); - - locked_dictionary = TRUE; - } + row_mysql_lock_data_dictionary(trx); #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex))); @@ -2551,8 +2557,8 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ fputs(" Cannot truncate table ", ef); ut_print_name(ef, trx, table->name); - fputs("\n" - "because it is referenced by ", ef); + fputs(" by DROP+CREATE\n" + "InnoDB: because it is referenced by ", ef); ut_print_name(ef, trx, foreign->foreign_table_name); putc('\n', ef); mutex_exit(&dict_foreign_err_mutex); @@ -2569,10 +2575,10 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ if (table->n_foreign_key_checks_running > 0) { ut_print_timestamp(stderr); - fputs(" InnoDB: You are trying to truncate table ", stderr); + fputs(" InnoDB: Cannot truncate table ", stderr); ut_print_name(stderr, trx, table->name); - fputs("\n" -"InnoDB: though there is a foreign key check running on it.\n", + fputs(" by DROP+CREATE\n" +"InnoDB: because there is a foreign key check running on it.\n", stderr); err = DB_ERROR; @@ -2686,9 +2692,7 @@ fputs(" InnoDB: Unable to assign a new identifier to table ", stderr); funct_exit: - if (locked_dictionary) { - row_mysql_unlock_data_dictionary(trx); - } + row_mysql_unlock_data_dictionary(trx); trx->op_info = ""; @@ -2696,6 +2700,7 @@ funct_exit: return((int) err); } +#endif /* !UNIV_HOTBACKUP */ /************************************************************************* Drops a table for MySQL. If the name of the table to be dropped is equal @@ -3092,7 +3097,9 @@ funct_exit: trx->op_info = ""; +#ifndef UNIV_HOTBACKUP srv_wake_master_thread(); +#endif /* !UNIV_HOTBACKUP */ return((int) err); } diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 7da2ee10d27..55ce452772d 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -848,7 +848,7 @@ srv_get_thread_type(void) /************************************************************************* Initializes the server. */ -static + void srv_init(void) /*==========*/ @@ -1310,6 +1310,7 @@ srv_boot(void) return(DB_SUCCESS); } +#ifndef UNIV_HOTBACKUP /************************************************************************* Reserves a slot in the thread table for the current MySQL OS thread. NOTE! The kernel mutex has to be reserved by the caller! */ @@ -1368,6 +1369,7 @@ srv_table_reserve_slot_for_mysql(void) return(slot); } +#endif /* !UNIV_HOTBACKUP */ /******************************************************************* Puts a MySQL OS thread to wait for a lock to be released. If an error @@ -1382,6 +1384,7 @@ srv_suspend_mysql_thread( que_thr_t* thr) /* in: query thread associated with the MySQL OS thread */ { +#ifndef UNIV_HOTBACKUP srv_slot_t* slot; os_event_t event; double wait_time; @@ -1520,6 +1523,12 @@ srv_suspend_mysql_thread( trx->error_state = DB_LOCK_WAIT_TIMEOUT; } +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /************************************************************************ @@ -1532,6 +1541,7 @@ srv_release_mysql_thread_if_suspended( que_thr_t* thr) /* in: query thread associated with the MySQL OS thread */ { +#ifndef UNIV_HOTBACKUP srv_slot_t* slot; ulint i; @@ -1553,8 +1563,15 @@ srv_release_mysql_thread_if_suspended( } /* not found */ +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } +#ifndef UNIV_HOTBACKUP /********************************************************************** Refreshes the values used to calculate per-second averages. */ static @@ -2576,3 +2593,4 @@ suspend_thread: return(0); #endif } +#endif /* !UNIV_HOTBACKUP */ diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 983a8306773..b2f97492e70 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -479,7 +479,6 @@ srv_normalize_path_for_win( Adds a slash or a backslash to the end of a string if it is missing and the string is not empty. */ -static char* srv_add_path_separator_if_needed( /*=============================*/ @@ -531,6 +530,7 @@ srv_calc_high32( return(file_size >> (32 - UNIV_PAGE_SIZE_SHIFT)); } +#ifndef UNIV_HOTBACKUP /************************************************************************* Creates or opens the log files and closes them. */ static @@ -1834,4 +1834,5 @@ void set_panic_flag_for_netware() extern ibool panic_shutdown; panic_shutdown = TRUE; } -#endif +#endif /* __NETWARE__ */ +#endif /* !UNIV_HOTBACKUP */ diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c index 359945594be..973b46fdd50 100644 --- a/innobase/sync/sync0rw.c +++ b/innobase/sync/sync0rw.c @@ -102,8 +102,10 @@ rw_lock_create_func( lock->mutex.cfile_name = cfile_name; lock->mutex.cline = cline; +#ifndef UNIV_HOTBACKUP lock->mutex.cmutex_name = cmutex_name; lock->mutex.mutex_type = 1; +#endif /* !UNIV_HOTBACKUP */ rw_lock_set_waiters(lock, 0); rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 788965f82ef..98b91ed5211 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -215,6 +215,7 @@ mutex_create_func( mutex->level = SYNC_LEVEL_NONE; mutex->cfile_name = cfile_name; mutex->cline = cline; +#ifndef UNIV_HOTBACKUP mutex->cmutex_name= cmutex_name; mutex->count_using= 0; mutex->mutex_type= 0; @@ -224,7 +225,7 @@ mutex_create_func( mutex->count_spin_rounds= 0; mutex->count_os_wait= 0; mutex->count_os_yield= 0; - +#endif /* !UNIV_HOTBACKUP */ /* Check that lock_word is aligned; this is important on Intel */ ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0); @@ -372,9 +373,9 @@ mutex_spin_wait( ulint ltime_diff; ulint sec; ulint ms; - +#ifndef UNIV_HOTBACKUP uint timer_started = 0; - +#endif /* !UNIV_HOTBACKUP */ ut_ad(mutex); mutex_loop: @@ -388,8 +389,10 @@ mutex_loop: memory word. */ spin_loop: +#ifndef UNIV_HOTBACKUP mutex_spin_wait_count++; mutex->count_spin_loop++; +#endif /* !UNIV_HOTBACKUP */ while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS) { @@ -403,6 +406,7 @@ spin_loop: if (i == SYNC_SPIN_ROUNDS) { +#ifndef UNIV_HOTBACKUP mutex->count_os_yield++; if (timed_mutexes == 1 && timer_started==0) { @@ -410,6 +414,7 @@ spin_loop: lstart_time= (ib_longlong)sec * 1000000 + ms; timer_started = 1; } +#endif /* !UNIV_HOTBACKUP */ os_thread_yield(); } @@ -422,7 +427,9 @@ spin_loop: mutex_spin_round_count += i; +#ifndef UNIV_HOTBACKUP mutex->count_spin_rounds += i; +#endif /* !UNIV_HOTBACKUP */ if (mutex_test_and_set(mutex) == 0) { @@ -504,8 +511,8 @@ Now there is no risk of infinite wait on the event. */ mutex_system_call_count++; mutex_os_wait_count++; +#ifndef UNIV_HOTBACKUP mutex->count_os_wait++; - /* !!!!! Sometimes os_wait can be called without os_thread_yield */ @@ -516,12 +523,13 @@ Now there is no risk of infinite wait on the event. */ lstart_time= (ib_longlong)sec * 1000000 + ms; timer_started = 1; } - +#endif /* !UNIV_HOTBACKUP */ sync_array_wait_event(sync_primary_wait_array, index); goto mutex_loop; finish_timing: +#ifndef UNIV_HOTBACKUP if (timed_mutexes == 1 && timer_started==1) { ut_usectime(&sec, &ms); @@ -534,6 +542,7 @@ finish_timing: mutex->lmax_spent_time= ltime_diff; } } +#endif /* !UNIV_HOTBACKUP */ return; } diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index e5cffd2a4f3..e57057de7ff 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -52,6 +52,7 @@ trx_general_rollback_for_mysql( trx_savept_t* savept) /* in: pointer to savepoint undo number, if partial rollback requested */ { +#ifndef UNIV_HOTBACKUP mem_heap_t* heap; que_thr_t* thr; roll_node_t* roll_node; @@ -103,6 +104,12 @@ trx_general_rollback_for_mysql( srv_active_wake_master_thread(); return((int) trx->error_state); +#else /* UNIV_HOTBACKUP */ + /* This function depends on MySQL code that is not included in + InnoDB Hot Backup builds. Besides, this function should never + be called in InnoDB Hot Backup. */ + ut_error; +#endif /* UNIV_HOTBACKUP */ } /*********************************************************************** @@ -316,6 +323,51 @@ trx_savepoint_for_mysql( return(DB_SUCCESS); } +/*********************************************************************** +Releases a named savepoint. Savepoints which +were set after this savepoint are deleted. */ + +ulint +trx_release_savepoint_for_mysql( +/*============================*/ + /* out: if no savepoint + of the name found then + DB_NO_SAVEPOINT, + otherwise DB_SUCCESS */ + trx_t* trx, /* in: transaction handle */ + const char* savepoint_name) /* in: savepoint name */ +{ + trx_named_savept_t* savep; + + savep = UT_LIST_GET_FIRST(trx->trx_savepoints); + + while (savep != NULL) { + if (0 == ut_strcmp(savep->name, savepoint_name)) { + /* Found */ + break; + } + savep = UT_LIST_GET_NEXT(trx_savepoints, savep); + } + + if (savep == NULL) { + + return(DB_NO_SAVEPOINT); + } + + /* We can now free all savepoints strictly later than this one */ + + trx_roll_savepoints_free(trx, savep); + + /* Now we can free this savepoint too */ + + UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); + + mem_free(savep->name); + mem_free(savep); + + return(DB_SUCCESS); +} + /*********************************************************************** Returns a transaction savepoint taken at this point in time. */ diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 6619286ee71..f254f3ff904 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -1844,7 +1844,7 @@ trx_recover_for_mysql( /* out: number of prepared transactions stored in xid_list */ XID* xid_list, /* in/out: prepared transactions */ - uint len) /* in: number of slots in xid_list */ + ulint len) /* in: number of slots in xid_list */ { trx_t* trx; int num_of_transactions = 0; diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c index 6f2aa0957d8..1fffd08c718 100644 --- a/innobase/ut/ut0ut.c +++ b/innobase/ut/ut0ut.c @@ -44,13 +44,13 @@ ut_get_high32( /* out: a >> 32 */ ulint a) /* in: ulint */ { -#if SIZEOF_LONG == 4 - UT_NOT_USED(a); + ib_longlong i; - return 0; -#else - return(a >> 32); -#endif + i = (ib_longlong)a; + + i = i >> 32; + + return((ulint)i); } /************************************************************ @@ -416,7 +416,11 @@ ut_print_namel( { const char* s = name; const char* e = s + namelen; +#ifdef UNIV_HOTBACKUP + int q = '"'; +#else int q = mysql_get_identifier_quote_char(trx, name, namelen); +#endif if (q == EOF) { fwrite(name, 1, namelen, f); return; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 258391ac899..a1e13be8e25 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3186,6 +3186,8 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind) case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: param->store_param_func= store_param_str; /* For variable length types user must set either length or @@ -3512,6 +3514,8 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value, case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: default: { /* @@ -4249,6 +4253,8 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) break; case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: DBUG_ASSERT(param->buffer_length != 0); param->fetch_result= fetch_result_str; break; @@ -4308,6 +4314,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) field->max_length= MAX_DATE_STRING_REP_LENGTH; break; case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: case MYSQL_TYPE_GEOMETRY: diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 2f90d22f990..3c33b56ba1c 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -62,7 +62,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.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 \ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ - parse_file.cc sql_view.cc sql_trigger.cc + parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources) libmysqld_a_SOURCES= diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 4e66bd92a94..a5b4439a57f 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -366,6 +366,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) reset_tree(& ftb->no_dupes); } + ftbw->off=0; /* in case of reinit */ if (_ft2_search(ftb, ftbw, 1)) return; } @@ -374,7 +375,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, - uint query_len) + uint query_len, CHARSET_INFO *cs) { FTB *ftb; FTB_EXPR *ftbe; @@ -386,8 +387,8 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftb->state=UNINITIALIZED; ftb->info=info; ftb->keynr=keynr; - ftb->charset= ((keynr==NO_SUCH_KEY) ? - default_charset_info : info->s->keyinfo[keynr].seg->charset); + ftb->charset=cs; + DBUG_ASSERT(keynr==NO_SUCH_KEY || cs == info->s->keyinfo[keynr].seg->charset); ftb->with_scan=0; ftb->lastpos=HA_OFFSET_ERROR; bzero(& ftb->no_dupes, sizeof(TREE)); diff --git a/myisam/ft_static.c b/myisam/ft_static.c index cf4a8dd2a73..e221950f445 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -57,11 +57,12 @@ const struct _ft_vft _ft_vft_boolean = { FT_INFO *ft_init_search(uint flags, void *info, uint keynr, - byte *query, uint query_len, byte *record) + byte *query, uint query_len, CHARSET_INFO *cs, + byte *record) { FT_INFO *res; if (flags & FT_BOOL) - res= ft_init_boolean_search((MI_INFO *)info, keynr, query, query_len); + res= ft_init_boolean_search((MI_INFO *)info, keynr, query, query_len,cs); else res= ft_init_nlq_search((MI_INFO *)info, keynr, query, query_len, flags, record); diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index e7a0829e140..ddb9fbfead2 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -131,7 +131,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *); uint _mi_ft_parse(TREE *, MI_INFO *, uint, const byte *, my_bool); FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, uint, byte *); -FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint); +FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, CHARSET_INFO *); extern const struct _ft_vft _ft_vft_nlq; int ft_nlq_read_next(FT_INFO *, char *); diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 3d5833c47be..8735c4c1fff 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -47,7 +47,7 @@ dist-hook: $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/t/*.test $(srcdir)/t/*.opt $(srcdir)/t/*.sh $(srcdir)/t/*.slave-mi $(distdir)/t $(INSTALL_DATA) $(srcdir)/include/*.inc $(distdir)/include - $(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r + $(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.result.es $(srcdir)/r/*.require $(distdir)/r $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.000001 $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data @@ -65,7 +65,7 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/t/*.opt $(DESTDIR)$(testdir)/t $(INSTALL_DATA) $(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/*.result $(srcdir)/r/*.result.es $(DESTDIR)$(testdir)/r $(INSTALL_DATA) $(srcdir)/r/*.require $(DESTDIR)$(testdir)/r $(INSTALL_DATA) $(srcdir)/include/*.inc $(DESTDIR)$(testdir)/include $(INSTALL_DATA) $(srcdir)/std_data/*.dat $(DESTDIR)$(testdir)/std_data diff --git a/mysql-test/include/have_cp932.inc b/mysql-test/include/have_cp932.inc new file mode 100644 index 00000000000..b500dac0bbe --- /dev/null +++ b/mysql-test/include/have_cp932.inc @@ -0,0 +1,4 @@ +-- require r/have_cp932.require +disable_query_log; +show collation like "cp932_japanese_ci"; +enable_query_log; diff --git a/mysql-test/include/have_eucjpms.inc b/mysql-test/include/have_eucjpms.inc new file mode 100644 index 00000000000..a5e1a5ac547 --- /dev/null +++ b/mysql-test/include/have_eucjpms.inc @@ -0,0 +1,4 @@ +-- require r/have_eucjpms.require +disable_query_log; +show collation like "eucjpms_japanese_ci"; +enable_query_log; diff --git a/mysql-test/include/have_multi_ndb.inc b/mysql-test/include/have_multi_ndb.inc new file mode 100644 index 00000000000..d0c083cab86 --- /dev/null +++ b/mysql-test/include/have_multi_ndb.inc @@ -0,0 +1,28 @@ +# Setup connections to both MySQL Servers connected to the cluster +connect (server1,127.0.0.1,root,,test,$MASTER_MYPORT,); +connect (server2,127.0.0.1,root,,test,$MASTER_MYPORT1,); + +# Check that server1 has NDB support +connection server1; +disable_query_log; +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +flush tables; +@r/have_ndb.require show variables like "have_ndbcluster"; +@r/server_id.require show variables like "server_id"; +enable_query_log; + +# Check that server2 has NDB support +connection server2; +disable_query_log; +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +flush tables; +@r/have_ndb.require show variables like "have_ndbcluster"; +@r/server_id1.require show variables like "server_id"; +enable_query_log; + +# Set the default connection to 'server1' +connection server1; diff --git a/mysql-test/include/have_ndb.inc b/mysql-test/include/have_ndb.inc index 84e60657876..28fcf18cb16 100644 --- a/mysql-test/include/have_ndb.inc +++ b/mysql-test/include/have_ndb.inc @@ -1,7 +1,6 @@ +--exec test x$NDB_STATUS_OK = x1 -- require r/have_ndb.require disable_query_log; show variables like "have_ndbcluster"; enable_query_log; -#connect (server1,127.0.0.1,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); -#connect (server2,127.0.0.1,root,,test,$MASTER_MYPORT1,$MASTER_MYSOCK1); -#connection server1; + diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl new file mode 100644 index 00000000000..5977bb380cf --- /dev/null +++ b/mysql-test/lib/mtr_cases.pl @@ -0,0 +1,270 @@ +# -*- cperl -*- + +# This is a library file used by the Perl version of mysql-test-run, +# and is part of the translation of the Bourne shell script with the +# same name. + +use strict; + +sub collect_test_cases ($); +sub collect_one_test_case ($$$$$); + +############################################################################## +# +# Collect information about test cases we are to run +# +############################################################################## + +sub collect_test_cases ($) { + my $suite= shift; # Test suite name + + my $testdir; + my $resdir; + + if ( $suite eq "main" ) + { + $testdir= "$::glob_mysql_test_dir/t"; + $resdir= "$::glob_mysql_test_dir/r"; + } + else + { + $testdir= "$::glob_mysql_test_dir/suite/$suite/t"; + $resdir= "$::glob_mysql_test_dir/suite/$suite/r"; + } + + my $cases = []; # Array of hash, will be array of C struct + + opendir(TESTDIR, $testdir) or mtr_error("Can't open dir \"$testdir\": $!"); + + if ( @::opt_cases ) + { + foreach my $tname ( @::opt_cases ) { # Run in specified order, no sort + my $elem= "$tname.test"; + if ( ! -f "$testdir/$elem") + { + mtr_error("Test case $tname ($testdir/$elem) is not found"); + } + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases); + } + closedir TESTDIR; + } + else + { + foreach my $elem ( sort readdir(TESTDIR) ) { + my $tname= mtr_match_extension($elem,"test"); + next if ! defined $tname; + next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test); + + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases); + } + closedir TESTDIR; + } + + # To speed things up, we sort first in if the test require a restart + # or not, second in alphanumeric order. + +# @$cases = sort { +# if ( $a->{'master_restart'} and $b->{'master_restart'} or +# ! $a->{'master_restart'} and ! $b->{'master_restart'} ) +# { +# return $a->{'name'} cmp $b->{'name'}; +# } +# if ( $a->{'master_restart'} ) +# { +# return 1; # Is greater +# } +# else +# { +# return -1; # Is less +# } +# } @$cases; + + return $cases; +} + + +############################################################################## +# +# Collect information about a single test case +# +############################################################################## + + +sub collect_one_test_case($$$$$) { + my $testdir= shift; + my $resdir= shift; + my $tname= shift; + my $elem= shift; + my $cases= shift; + + my $path= "$testdir/$elem"; + + # ---------------------------------------------------------------------- + # Skip some tests silently + # ---------------------------------------------------------------------- + + if ( $::opt_start_from and $tname lt $::opt_start_from ) + { + return; + } + + # ---------------------------------------------------------------------- + # Skip some tests but include in list, just mark them to skip + # ---------------------------------------------------------------------- + + my $tinfo= {}; + $tinfo->{'name'}= $tname; + $tinfo->{'result_file'}= "$resdir/$tname.result"; + push(@$cases, $tinfo); + + if ( $::opt_skip_test and defined mtr_match_prefix($tname,$::opt_skip_test) ) + { + $tinfo->{'skip'}= 1; + return; + } + + # FIXME temporary solution, we have a hard coded list of test cases to + # skip if we are using the embedded server + + if ( $::glob_use_embedded_server and + mtr_match_any_exact($tname,\@::skip_if_embedded_server) ) + { + $tinfo->{'skip'}= 1; + return; + } + + # ---------------------------------------------------------------------- + # Collect information about test case + # ---------------------------------------------------------------------- + + $tinfo->{'path'}= $path; + $tinfo->{'timezone'}= "GMT-3"; # for UNIX_TIMESTAMP tests to work + + if ( defined mtr_match_prefix($tname,"rpl") ) + { + if ( $::opt_skip_rpl ) + { + $tinfo->{'skip'}= 1; + return; + } + + $tinfo->{'slave_num'}= 1; # Default, use one slave + + # FIXME currently we always restart slaves + $tinfo->{'slave_restart'}= 1; + + if ( $tname eq 'rpl_failsafe' or $tname eq 'rpl_chain_temp_table' ) + { +# $tinfo->{'slave_num'}= 3; # Not 3 ? Check old code, strange + } + } + + # FIXME what about embedded_server + ndbcluster, skip ?! + + my $master_opt_file= "$testdir/$tname-master.opt"; + my $slave_opt_file= "$testdir/$tname-slave.opt"; + my $slave_mi_file= "$testdir/$tname.slave-mi"; + my $master_sh= "$testdir/$tname-master.sh"; + my $slave_sh= "$testdir/$tname-slave.sh"; + my $disabled= "$testdir/$tname.disabled"; + + $tinfo->{'master_opt'}= []; + $tinfo->{'slave_opt'}= []; + $tinfo->{'slave_mi'}= []; + + if ( -f $master_opt_file ) + { + $tinfo->{'master_restart'}= 1; # We think so for now + # This is a dirty hack from old mysql-test-run, we use the opt file + # to flag other things as well, it is not a opt list at all + my $extra_master_opt= mtr_get_opts_from_file($master_opt_file); + + foreach my $opt (@$extra_master_opt) + { + my $value; + + $value= mtr_match_prefix($opt, "--timezone="); + + if ( defined $value ) + { + $tinfo->{'timezone'}= $value; + $extra_master_opt= []; + $tinfo->{'master_restart'}= 0; + last; + } + + $value= mtr_match_prefix($opt, "--result-file="); + + if ( defined $value ) + { + $tinfo->{'result_file'}= "r/$value.result"; + if ( $::opt_result_ext and $::opt_record or + -f "$tinfo->{'result_file'}$::opt_result_ext") + { + $tinfo->{'result_file'}.= $::opt_result_ext; + } + $extra_master_opt= []; + $tinfo->{'master_restart'}= 0; + last; + } + } + + $tinfo->{'master_opt'}= $extra_master_opt; + } + + if ( -f $slave_opt_file ) + { + $tinfo->{'slave_opt'}= mtr_get_opts_from_file($slave_opt_file); + $tinfo->{'slave_restart'}= 1; + } + + if ( -f $slave_mi_file ) + { + $tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file); + $tinfo->{'slave_restart'}= 1; + } + + if ( -f $master_sh ) + { + if ( $::glob_win32_perl ) + { + $tinfo->{'skip'}= 1; + } + else + { + $tinfo->{'master_sh'}= $master_sh; + $tinfo->{'master_restart'}= 1; + } + } + + if ( -f $slave_sh ) + { + if ( $::glob_win32_perl ) + { + $tinfo->{'skip'}= 1; + } + else + { + $tinfo->{'slave_sh'}= $slave_sh; + $tinfo->{'slave_restart'}= 1; + } + } + + if ( -f $disabled ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'disable'}= 1; # Sub type of 'skip' + $tinfo->{'comment'}= mtr_fromfile($disabled); + } + + # We can't restart a running server that may be in use + + if ( $::glob_use_running_server and + ( $tinfo->{'master_restart'} or $tinfo->{'slave_restart'} ) ) + { + $tinfo->{'skip'}= 1; + } +} + + +1; diff --git a/mysql-test/lib/mtr_io.pl b/mysql-test/lib/mtr_io.pl index 017ba11645b..b3da6d97664 100644 --- a/mysql-test/lib/mtr_io.pl +++ b/mysql-test/lib/mtr_io.pl @@ -8,6 +8,7 @@ use strict; sub mtr_get_pid_from_file ($); sub mtr_get_opts_from_file ($); +sub mtr_fromfile ($); sub mtr_tofile ($@); sub mtr_tonewfile($@); @@ -107,6 +108,8 @@ sub mtr_fromfile ($) { open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!"); my $text= join('', ); close FILE; + $text =~ s/^\s+//; # Remove starting space, incl newlines + $text =~ s/\s+$//; # Remove ending space, incl newlines return $text; } diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index e832468d0cb..e1461a9730c 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -5,14 +5,19 @@ # same name. #use Carp qw(cluck); +use Socket; +use Errno; use strict; -use POSIX ":sys_wait_h"; +#use POSIX ":sys_wait_h"; +use POSIX 'WNOHANG'; sub mtr_run ($$$$$$); sub mtr_spawn ($$$$$$); -sub mtr_stop_mysqld_servers ($$); +sub mtr_stop_mysqld_servers ($); sub mtr_kill_leftovers (); +sub mtr_record_dead_children (); +sub sleep_until_file_created ($$$); # static in C sub spawn_impl ($$$$$$$); @@ -34,7 +39,18 @@ sub mtr_run ($$$$$$) { my $error= shift; my $pid_file= shift; - return spawn_impl($path,$arg_list_t,1,$input,$output,$error,$pid_file); + return spawn_impl($path,$arg_list_t,'run',$input,$output,$error,$pid_file); +} + +sub mtr_run_test ($$$$$$) { + my $path= shift; + my $arg_list_t= shift; + my $input= shift; + my $output= shift; + my $error= shift; + my $pid_file= shift; + + return spawn_impl($path,$arg_list_t,'test',$input,$output,$error,$pid_file); } sub mtr_spawn ($$$$$$) { @@ -45,7 +61,7 @@ sub mtr_spawn ($$$$$$) { my $error= shift; my $pid_file= shift; - return spawn_impl($path,$arg_list_t,0,$input,$output,$error,$pid_file); + return spawn_impl($path,$arg_list_t,'spawn',$input,$output,$error,$pid_file); } @@ -58,7 +74,7 @@ sub mtr_spawn ($$$$$$) { sub spawn_impl ($$$$$$$) { my $path= shift; my $arg_list_t= shift; - my $join= shift; + my $mode= shift; my $input= shift; my $output= shift; my $error= shift; @@ -71,107 +87,203 @@ sub spawn_impl ($$$$$$$) { print STDERR "#### ", "STDIN $input\n" if $input; print STDERR "#### ", "STDOUT $output\n" if $output; print STDERR "#### ", "STDERR $error\n" if $error; - if ( $join ) - { - print STDERR "#### ", "RUN "; - } - else - { - print STDERR "#### ", "SPAWN "; - } - print STDERR "$path ", join(" ",@$arg_list_t), "\n"; + print STDERR "#### ", "$mode : $path ", join(" ",@$arg_list_t), "\n"; print STDERR "#### ", "-" x 78, "\n"; } - my $pid= fork(); - if ( ! defined $pid ) + FORK: { - mtr_error("$path ($pid) can't be forked"); - } + my $pid= fork(); - if ( $pid ) - { - # Parent, i.e. the main script - if ( $join ) + if ( ! defined $pid ) { - # We run a command and wait for the result - # FIXME this need to be improved - my $res= waitpid($pid,0); + if ( $! == $!{EAGAIN} ) # See "perldoc Errno" + { + mtr_debug("Got EAGAIN from fork(), sleep 1 second and redo"); + sleep(1); + redo FORK; + } + else + { + mtr_error("$path ($pid) can't be forked"); + } + } - if ( $res == -1 ) + if ( $pid ) + { + spawn_parent_impl($pid,$mode,$path); + } + else + { + # Child, redirect output and exec + # FIXME I tried POSIX::setsid() here to detach and, I hoped, + # avoid zombies. But everything went wild, somehow the parent + # became a deamon as well, and was hard to kill ;-) + # Need to catch SIGCHLD and do waitpid or something instead...... + + $SIG{INT}= 'DEFAULT'; # Parent do some stuff, we don't + + if ( $output ) + { + if ( ! open(STDOUT,">",$output) ) + { + mtr_error("can't redirect STDOUT to \"$output\": $!"); + } + } + if ( $error ) + { + if ( $output eq $error ) + { + if ( ! open(STDERR,">&STDOUT") ) + { + mtr_error("can't dup STDOUT: $!"); + } + } + else + { + if ( ! open(STDERR,">",$error) ) + { + mtr_error("can't redirect STDERR to \"$output\": $!"); + } + } + } + if ( $input ) + { + if ( ! open(STDIN,"<",$input) ) + { + mtr_error("can't redirect STDIN to \"$input\": $!"); + } + } + exec($path,@$arg_list_t); + } + } +} + + +sub spawn_parent_impl { + my $pid= shift; + my $mode= shift; + my $path= shift; + + if ( $mode eq 'run' or $mode eq 'test' ) + { + my $exit_value= -1; + my $signal_num= 0; + my $dumped_core= 0; + + if ( $mode eq 'run' ) + { + # Simple run of command, we wait for it to return + my $ret_pid= waitpid($pid,0); + + if ( $ret_pid <= 0 ) { mtr_error("$path ($pid) got lost somehow"); } - my $exit_value= $? >> 8; - my $signal_num= $? & 127; - my $dumped_core= $? & 128; - if ( $signal_num ) - { - mtr_error("$path ($pid) got signal $signal_num"); - } - if ( $dumped_core ) - { - mtr_error("$path ($pid) dumped core"); - } + + $exit_value= $? >> 8; + $signal_num= $? & 127; + $dumped_core= $? & 128; + return $exit_value; } else { - # We spawned a process we don't wait for - return $pid; + # We run mysqltest and wait for it to return. But we try to + # catch dying mysqld processes as well. + # + # We do blocking waitpid() until we get the return from the + # "mysqltest" call. But if a mysqld process dies that we + # started, we take this as an error, and kill mysqltest. + # + # FIXME is this as it should be? Can't mysqld terminate + # normally from running a test case? + + my $ret_pid; # What waitpid() returns + + while ( ($ret_pid= waitpid(-1,0)) != -1 ) + { + # Someone terminated, don't know who. Collect + # status info first before $? is lost, + # but not $exit_value, this is flagged from + # + + if ( $ret_pid == $pid ) + { + # We got termination of mysqltest, we are done + $exit_value= $? >> 8; + $signal_num= $? & 127; + $dumped_core= $? & 128; + last; + } + + # If one of the mysqld processes died, we want to + # mark this, and kill the mysqltest process. + + foreach my $idx (0..1) + { + if ( $::master->[$idx]->{'pid'} eq $ret_pid ) + { + mtr_debug("child $ret_pid was master[$idx], " . + "exit during mysqltest run"); + $::master->[$idx]->{'pid'}= 0; + last; + } + } + + foreach my $idx (0..2) + { + if ( $::slave->[$idx]->{'pid'} eq $ret_pid ) + { + mtr_debug("child $ret_pid was slave[$idx], " . + "exit during mysqltest run"); + $::slave->[$idx]->{'pid'}= 0; + last; + } + } + + mtr_debug("waitpid() catched exit of unknown child $ret_pid, " . + "exit during mysqltest run"); + } + + if ( $ret_pid != $pid ) + { + # We terminated the waiting because a "mysqld" process died. + # Kill the mysqltest process. + + kill(9,$pid); + + $ret_pid= waitpid($pid,0); + + if ( $ret_pid == -1 ) + { + mtr_error("$path ($pid) got lost somehow"); + } + } + + return $exit_value; } } else { - # Child, redirect output and exec - # FIXME I tried POSIX::setsid() here to detach and, I hoped, - # avoid zombies. But everything went wild, somehow the parent - # became a deamon as well, and was hard to kill ;-) - # Need to catch SIGCHLD and do waitpid or something instead...... - - $SIG{INT}= 'DEFAULT'; # Parent do some stuff, we don't - - if ( $output ) - { - if ( ! open(STDOUT,">",$output) ) - { - mtr_error("can't redirect STDOUT to \"$output\": $!"); - } - } - if ( $error ) - { - if ( $output eq $error ) - { - if ( ! open(STDERR,">&STDOUT") ) - { - mtr_error("can't dup STDOUT: $!"); - } - } - else - { - if ( ! open(STDERR,">",$error) ) - { - mtr_error("can't redirect STDERR to \"$output\": $!"); - } - } - } - if ( $input ) - { - if ( ! open(STDIN,"<",$input) ) - { - mtr_error("can't redirect STDIN to \"$input\": $!"); - } - } - exec($path,@$arg_list_t); + # We spawned a process we don't wait for + return $pid; } } + + ############################################################################## # # Kill processes left from previous runs # ############################################################################## +# We just "ping" on the ports, and if we can't do a socket connect +# we assume the server is dead. So we don't *really* know a server +# is dead, we just hope that it after letting the listen port go, +# it is dead enough for us to start a new server. + sub mtr_kill_leftovers () { # First, kill all masters and slaves that would conflict with @@ -199,10 +311,23 @@ sub mtr_kill_leftovers () { }); } - mtr_stop_mysqld_servers(\@args, 1); + mtr_mysqladmin_shutdown(\@args); + + # We now have tried to terminate nice. We have waited for the listen + # port to be free, but can't really tell if the mysqld process died + # or not. We now try to find the process PID from the PID file, and + # send a kill to that process. Note that Perl let kill(0,@pids) be + # a way to just return the numer of processes the kernel can send + # signals to. So this can be used (except on Cygwin) to determine + # if there are processes left running that we cound out might exists. + # + # But still after all this work, all we know is that we have + # the ports free. # We scan the "var/run/" directory for other process id's to kill - my $rundir= "$::glob_mysql_test_dir/var/run"; # FIXME $path_run_dir or something + + # FIXME $path_run_dir or something + my $rundir= "$::glob_mysql_test_dir/var/run"; if ( -d $rundir ) { @@ -218,193 +343,157 @@ sub mtr_kill_leftovers () { if ( -f $pidfile ) { my $pid= mtr_get_pid_from_file($pidfile); - if ( ! unlink($pidfile) ) + + # Race, could have been removed between I tested with -f + # and the unlink() below, so I better check again with -f + + if ( ! unlink($pidfile) and -f $pidfile ) { mtr_error("can't remove $pidfile"); } - push(@pids, $pid); + + if ( $::glob_cygwin_perl or kill(0, $pid) ) + { + push(@pids, $pid); # We know (cygwin guess) it exists + } } } closedir(RUNDIR); - start_reap_all(); - - if ( $::glob_cygwin_perl ) + if ( @pids ) { - # We have no (easy) way of knowing the Cygwin controlling - # process, in the PID file we only have the Windows process id. - system("kill -f " . join(" ",@pids)); # Hope for the best.... - } - else - { - my $retries= 10; # 10 seconds - do + if ( $::glob_cygwin_perl ) { - kill(9, @pids); - } while ( $retries-- and kill(0, @pids) ); + # We have no (easy) way of knowing the Cygwin controlling + # process, in the PID file we only have the Windows process id. + system("kill -f " . join(" ",@pids)); # Hope for the best.... + mtr_debug("Sleep 5 seconds waiting for processes to die"); + sleep(5); + } + else + { + my $retries= 10; # 10 seconds + do + { + kill(9, @pids); + mtr_debug("Sleep 1 second waiting for processes to die"); + sleep(1) # Wait one second + } while ( $retries-- and kill(0, @pids) ); - if ( kill(0, @pids) ) - { - mtr_error("can't kill processes " . join(" ", @pids)); + if ( kill(0, @pids) ) # Check if some left + { + # FIXME maybe just mtr_warning() ? + mtr_error("can't kill process(es) " . join(" ", @pids)); + } } } + } - stop_reap_all(); + # We may have failed everything, bug we now check again if we have + # the listen ports free to use, and if they are free, just go for it. + + foreach my $srv ( @args ) + { + if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) ) + { + mtr_error("can't kill old mysqld holding port $srv->{'port'}"); + } } } ############################################################################## # -# Shut down mysqld servers +# Shut down mysqld servers we have started from this run of this script # ############################################################################## -# To speed things we kill servers in parallel. -# The argument is a list of 'pidfiles' and 'socketfiles'. -# We use the pidfiles and socketfiles to try to terminate the servers. -# This is not perfect, there could still be other server processes -# left. +# To speed things we kill servers in parallel. The argument is a list +# of 'ports', 'pids', 'pidfiles' and 'socketfiles'. -# Force flag is to be set only for killing mysqld servers this script -# didn't create in this run, i.e. initial cleanup before we start working. -# If force flag is set, we try to kill all with mysqladmin, and -# give up if we have no PIDs. +# FIXME On Cygwin, and maybe some other platforms, $srv->{'pid'} and +# $srv->{'pidfile'} will not be the same PID. We need to try to kill +# both I think. -# FIXME On some operating systems, $srv->{'pid'} and $srv->{'pidfile'} -# will not be the same PID. We need to try to kill both I think. - -sub mtr_stop_mysqld_servers ($$) { +sub mtr_stop_mysqld_servers ($) { my $spec= shift; - my $force= shift; # ---------------------------------------------------------------------- - # If the process was not started from this file, we got no PID, - # we try to find it in the PID file. + # First try nice normal shutdown using 'mysqladmin' # ---------------------------------------------------------------------- - my $any_pid= 0; # If we have any PIDs + mtr_mysqladmin_shutdown($spec); + + # ---------------------------------------------------------------------- + # We loop with waitpid() nonblocking to see how many of the ones we + # are to kill, actually got killed by mtr_mysqladmin_shutdown(). + # Note that we don't rely on this, the mysqld server might have stop + # listening to the port, but still be alive. But it is a start. + # ---------------------------------------------------------------------- foreach my $srv ( @$spec ) { - if ( ! $srv->{'pid'} and -f $srv->{'pidfile'} ) + if ( $srv->{'pid'} and (waitpid($srv->{'pid'},&WNOHANG) == $srv->{'pid'}) ) { - $srv->{'pid'}= mtr_get_pid_from_file($srv->{'pidfile'}); - } - if ( $srv->{'pid'} ) - { - $any_pid= 1; + $srv->{'pid'}= 0; } } - # If the processes where started from this script, and we know - # no PIDs, then we don't have to do anything. + # ---------------------------------------------------------------------- + # We know the process was started from this file, so there is a PID + # saved, or else we have nothing to do. + # Might be that is is recorded to be missing, but we failed to + # take away the PID file earlier, then we do it now. + # ---------------------------------------------------------------------- - if ( ! $any_pid and ! $force ) + my %mysqld_pids; + + foreach my $srv ( @$spec ) + { + if ( $srv->{'pid'} ) + { + $mysqld_pids{$srv->{'pid'}}= 1; + } + else + { + # Race, could have been removed between I tested with -f + # and the unlink() below, so I better check again with -f + + if ( -f $srv->{'pidfile'} and ! unlink($srv->{'pidfile'}) and + -f $srv->{'pidfile'} ) + { + mtr_error("can't remove $srv->{'pidfile'}"); + } + } + } + + # ---------------------------------------------------------------------- + # If the processes where started from this script, and we had no PIDS + # then we don't have to do anything. + # ---------------------------------------------------------------------- + + if ( ! keys %mysqld_pids ) { # cluck "This is how we got here!"; return; } # ---------------------------------------------------------------------- - # First try nice normal shutdown using 'mysqladmin' - # ---------------------------------------------------------------------- - - start_reap_all(); # Don't require waitpid() of children - - foreach my $srv ( @$spec ) - { - if ( -e $srv->{'sockfile'} or $srv->{'port'} ) - { - # FIXME wrong log..... - # FIXME, stderr..... - # Shutdown time must be high as slave may be in reconnect - my $args; - - mtr_init_args(\$args); - - mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--user=%s", $::opt_user); - mtr_add_arg($args, "--password="); - if ( -e $srv->{'sockfile'} ) - { - mtr_add_arg($args, "--socket=%s", $srv->{'sockfile'}); - } - if ( $srv->{'port'} ) - { - mtr_add_arg($args, "--port=%s", $srv->{'port'}); - } - mtr_add_arg($args, "--connect_timeout=5"); - mtr_add_arg($args, "--shutdown_timeout=20"); - mtr_add_arg($args, "--protocol=tcp"); # FIXME new thing, will it help?! - mtr_add_arg($args, "shutdown"); - # We don't wait for termination of mysqladmin - mtr_spawn($::exe_mysqladmin, $args, - "", $::path_manager_log, $::path_manager_log, ""); - } - } - - # Wait for them all to remove their pid and socket file - - PIDSOCKFILEREMOVED: - for (my $loop= $::opt_sleep_time_for_delete; $loop; $loop--) - { - my $pidsockfiles_left= 0; - foreach my $srv ( @$spec ) - { - if ( -e $srv->{'sockfile'} or -f $srv->{'pidfile'} ) - { - $pidsockfiles_left++; # Could be that pidfile is left - } - } - if ( ! $pidsockfiles_left ) - { - last PIDSOCKFILEREMOVED; - } - if ( $loop % 20 == 1 ) - { - mtr_warning("Still processes alive after 10 seconds, retrying for $loop seconds..."); - } - mtr_debug("Sleep for 1 second waiting for pid and socket file removal"); - sleep(1); # One second - } - - # ---------------------------------------------------------------------- - # If no known PIDs, we have nothing more to try - # ---------------------------------------------------------------------- - - if ( ! $any_pid ) - { - stop_reap_all(); - return; - } - - # ---------------------------------------------------------------------- - # We may have killed all that left a socket, but we are not sure we got - # them all killed. If we suspect it lives, try nice kill with SIG_TERM. - # Note that for true Win32 processes, kill(0,$pid) will not return 1. + # In mtr_mysqladmin_shutdown() we only waited for the mysqld servers + # not to listen to the port. But we are not sure we got them all + # killed. If we suspect it lives, try nice kill with SIG_TERM. Note + # that for true Win32 processes, kill(0,$pid) will not return 1. # ---------------------------------------------------------------------- SIGNAL: foreach my $sig (15,9) { - my $process_left= 0; - foreach my $srv ( @$spec ) + my $retries= 10; # 10 seconds + kill($sig, keys %mysqld_pids); + while ( $retries-- and kill(0, keys %mysqld_pids) ) { - if ( $srv->{'pid'} and - ( -f $srv->{'pidfile'} or kill(0,$srv->{'pid'}) ) ) - { - $process_left++; - mtr_warning("process $srv->{'pid'} not cooperating, " . - "will send signal $sig to process"); - kill($sig,$srv->{'pid'}); # SIG_TERM - } - if ( ! $process_left ) - { - last SIGNAL; - } + mtr_debug("Sleep 1 second waiting for processes to die"); + sleep(1) # Wait one second } - mtr_debug("Sleep for 5 seconds waiting for processes to die"); - sleep(5); # We wait longer than usual } # ---------------------------------------------------------------------- @@ -437,8 +526,8 @@ sub mtr_stop_mysqld_servers ($$) { foreach my $file ($srv->{'pidfile'}, $srv->{'sockfile'}) { - unlink($file); - if ( -e $file ) + # Know it is dead so should be no race, careful anyway + if ( -f $file and ! unlink($file) and -f $file ) { $errors++; mtr_warning("couldn't delete $file"); @@ -454,9 +543,147 @@ sub mtr_stop_mysqld_servers ($$) { } } - stop_reap_all(); + # FIXME We just assume they are all dead, for Cygwin we are not + # really sure + +} - # FIXME We just assume they are all dead, we don't know.... + +############################################################################## +# +# Shut down mysqld servers using "mysqladmin ... shutdown". +# To speed this up, we start them in parallel and use waitpid() to +# catch their termination. Note that this doesn't say the servers +# are terminated, just that 'mysqladmin' is terminated. +# +# Note that mysqladmin will ask the server about what PID file it uses, +# and mysqladmin will wait for it to be removed before it terminates +# (unless passes timeout). +# +# This function will take at most about 20 seconds, and we still are not +# sure we killed them all. If none is responding to ping, we return 1, +# else we return 0. +# +############################################################################## + +sub mtr_mysqladmin_shutdown () { + my $spec= shift; + + my @mysql_admin_pids; + my @to_kill_specs; + + foreach my $srv ( @$spec ) + { + if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) ) + { + push(@to_kill_specs, $srv); + } + } + + + foreach my $srv ( @to_kill_specs ) + { + # FIXME wrong log..... + # FIXME, stderr..... + # Shutdown time must be high as slave may be in reconnect + my $args; + + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--user=%s", $::opt_user); + mtr_add_arg($args, "--password="); + if ( -e $srv->{'sockfile'} ) + { + mtr_add_arg($args, "--socket=%s", $srv->{'sockfile'}); + } + if ( $srv->{'port'} ) + { + mtr_add_arg($args, "--port=%s", $srv->{'port'}); + } + if ( $srv->{'port'} and ! -e $srv->{'sockfile'} ) + { + mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket + } + mtr_add_arg($args, "--connect_timeout=5"); + mtr_add_arg($args, "--shutdown_timeout=20"); + 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, ""); + push(@mysql_admin_pids, $pid); + } + + # We wait blocking, we wait for the last one anyway + foreach my $pid (@mysql_admin_pids) + { + waitpid($pid,0); # FIXME no need to check -1 or 0? + } + + # If we trusted "mysqladmin --shutdown_timeout= ..." we could just + # terminate now, but we don't (FIXME should be debugged). + # So we try again to ping and at least wait the same amount of time + # mysqladmin would for all to die. + + my $timeout= 20; # 20 seconds max + my $res= 1; # If we just fall through, we are done + + TIME: + while ( $timeout-- ) + { + foreach my $srv ( @to_kill_specs ) + { + $res= 1; # We are optimistic + if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) ) + { + mtr_debug("Sleep 1 second waiting for processes to stop using port"); + sleep(1); # One second + $res= 0; + next TIME; + } + } + last; # If we got here, we are done + } + + return $res; +} + +############################################################################## +# +# The operating system will keep information about dead children, +# we read this information here, and if we have records the process +# is alive, we mark it as dead. +# +############################################################################## + +sub mtr_record_dead_children () { + + my $ret_pid; + + # FIXME the man page says to wait for -1 to terminate, + # but on OS X we get '0' all the time... + while ( ($ret_pid= waitpid(-1,&WNOHANG)) > 0 ) + { + mtr_debug("waitpid() catched exit of child $ret_pid"); + foreach my $idx (0..1) + { + if ( $::master->[$idx]->{'pid'} eq $ret_pid ) + { + mtr_debug("child $ret_pid was master[$idx]"); + $::master->[$idx]->{'pid'}= 0; + } + } + + foreach my $idx (0..2) + { + if ( $::slave->[$idx]->{'pid'} eq $ret_pid ) + { + mtr_debug("child $ret_pid was slave[$idx]"); + $::slave->[$idx]->{'pid'}= 0; + last; + } + } + } } sub start_reap_all { @@ -467,6 +694,32 @@ sub stop_reap_all { $SIG{CHLD}= 'DEFAULT'; } +sub mtr_ping_mysqld_server () { + my $port= shift; + + my $remote= "localhost"; + my $iaddr= inet_aton($remote); + if ( ! $iaddr ) + { + mtr_error("can't find IP number for $remote"); + } + my $paddr= sockaddr_in($port, $iaddr); + my $proto= getprotobyname('tcp'); + if ( ! socket(SOCK, PF_INET, SOCK_STREAM, $proto) ) + { + mtr_error("can't create socket: $!"); + } + if ( connect(SOCK, $paddr) ) + { + close(SOCK); # FIXME check error? + return 1; + } + else + { + return 0; + } +} + ############################################################################## # # Wait for a file to be created @@ -474,33 +727,38 @@ sub stop_reap_all { ############################################################################## -sub sleep_until_file_created ($$) { +sub sleep_until_file_created ($$$) { my $pidfile= shift; my $timeout= shift; + my $pid= shift; - my $loop= $timeout; - while ( $loop-- ) + for ( my $loop= 1; $loop <= $timeout; $loop++ ) { if ( -r $pidfile ) { - return; + return 1; } - mtr_debug("Sleep for 1 second waiting for creation of $pidfile"); - if ( $loop % 20 == 1 ) + # Check if it died after the fork() was successful + if ( waitpid($pid,&WNOHANG) == $pid ) { - mtr_warning("Waiting for $pidfile to be created, still trying for $loop seconds..."); + return 0; + } + + mtr_debug("Sleep 1 second waiting for creation of $pidfile"); + + if ( $loop % 60 == 0 ) + { + my $left= $timeout - $loop; + mtr_warning("Waited $loop seconds for $pidfile to be created, " . + "still waiting for $left seconds..."); } sleep(1); } - if ( ! -r $pidfile ) - { - mtr_error("No $pidfile was created"); - } + return 0; } - 1; diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 0f75fc1341a..c45bb1601ce 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -10,6 +10,7 @@ sub mtr_report_test_name($); sub mtr_report_test_passed($); sub mtr_report_test_failed($); sub mtr_report_test_skipped($); +sub mtr_report_test_disabled($); sub mtr_show_failed_diff ($); sub mtr_report_stats ($); @@ -72,7 +73,14 @@ sub mtr_report_test_skipped ($) { my $tinfo= shift; $tinfo->{'result'}= 'MTR_RES_SKIPPED'; - print "[ skipped ]\n"; + if ( $tinfo->{'disable'} ) + { + print "[ disabled ] $tinfo->{'comment'}\n"; + } + else + { + print "[ skipped ]\n"; + } } sub mtr_report_test_passed ($) { @@ -95,9 +103,18 @@ sub mtr_report_test_failed ($) { $tinfo->{'result'}= 'MTR_RES_FAILED'; print "[ fail ]\n"; - print "Errors 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"; + # FIXME Instead of this test, and meaningless error message in 'else' + # we should write out into $::path_timefile when the error occurs. + if ( -f $::path_timefile ) + { + print "Errors 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"; + } } sub mtr_report_stats ($) { diff --git a/mysql-test/my_create_tables.c b/mysql-test/my_create_tables.c index 405f66dc8df..06a6fabf022 100644 --- a/mysql-test/my_create_tables.c +++ b/mysql-test/my_create_tables.c @@ -96,6 +96,8 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Lock_tables_priv enum('N','Y') DEFAULT 'N' NOT NULL," "PRIMARY KEY Host (Host,Db,User)," "KEY User (User))" + "engine=MyISAM " + "CHARACTER SET utf8 COLLATE utf8_bin " "comment='Database privileges';\n"); if (test) @@ -126,10 +128,12 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Create_tmp_table_priv enum('N','Y') DEFAULT 'N' NOT NULL," "Lock_tables_priv enum('N','Y') DEFAULT 'N' NOT NULL," "PRIMARY KEY Host (Host,Db))" - "comment='Host privileges;" - " Merged with database privileges';\n"); + "engine=MyISAM " + "CHARACTER SET utf8 COLLATE utf8_bin " + "comment='Host privileges; Merged with database privileges';\n"); } + if (test_sys_file(mdata,"mysql/user.frm")) { #ifdef __WIN__ @@ -184,7 +188,10 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "max_updates int(11) unsigned DEFAULT 0 NOT NULL," "max_connections int(11) unsigned DEFAULT 0 NOT NULL," "PRIMARY KEY Host (Host,User)" - ") comment='Users and global privileges';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 COLLATE utf8_bin " + "comment='Users and global privileges';\n"); + if (test) { @@ -238,7 +245,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "dl char(128) DEFAULT '' NOT NULL," "type enum ('function','aggregate') NOT NULL," "PRIMARY KEY (name)" - ") comment='User defined functions';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 COLLATE utf8_bin " + "comment='User defined functions';\n"); } if (test_sys_file(mdata,"mysql/tables_priv.frm")) @@ -258,7 +267,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) " DEFAULT '' NOT NULL," "PRIMARY KEY (Host,Db,User,Table_name)," "KEY Grantor (Grantor)" - ") comment='Table privileges';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 COLLATE utf8_bin " + "comment='Table privileges';\n"); } if (test_sys_file(mdata,"mysql/columns_priv.frm")) @@ -274,7 +285,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Column_priv set('Select','Insert','Update','References')" " DEFAULT '' NOT NULL," "PRIMARY KEY (Host,Db,User,Table_name,Column_name)" - ") comment='Column privileges';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 COLLATE utf8_bin " + "comment='Column privileges';\n"); } if (test_sys_file(mdata,"mysql/help_topic.frm")) @@ -289,7 +302,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "url varchar(128) not null," "primary key (help_topic_id)," "unique index (name)" - ") comment='help topics';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 " + "comment='help topics';\n"); } if (test_sys_file(mdata,"mysql/help_category.frm")) @@ -302,7 +317,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "url varchar(128) not null," "primary key (help_category_id)," "unique index (name)" - ") comment='help categories';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 " + "comment='help categories';\n"); } if (test_sys_file(mdata,"mysql/help_keyword.frm")) @@ -313,7 +330,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "name varchar(64) not null," "primary key (help_keyword_id)," "unique index (name)" - ") comment='help keywords';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 " + "comment='help keywords';\n"); } if (test_sys_file(mdata,"mysql/help_relation.frm")) @@ -323,7 +342,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "help_topic_id int unsigned not null references help_topic," "help_keyword_id int unsigned not null references help_keyword," "primary key (help_keyword_id, help_topic_id)" - ") comment='keyword-topic relation';\n"); + ") engine=MyISAM " + "CHARACTER SET utf8 " + "comment='keyword-topic relation';\n"); } if (test_sys_file(mdata,"mysql/time_zone_name.frm")) @@ -333,7 +354,7 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Name char(64) NOT NULL," "Time_zone_id int unsigned NOT NULL," "PRIMARY KEY Name (Name)" - ") DEFAULT CHARACTER SET latin1 " + ") engine=MyISAM CHARACTER SET utf8 " "comment='Time zone names';\n"); if (test) @@ -341,7 +362,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) fprintf(out, "INSERT INTO time_zone_name (Name, Time_Zone_id) VALUES" "('MET', 1), ('UTC', 2), ('Universal', 2), " - "('Europe/Moscow',3), ('leap/Europe/Moscow',4);\n"); + "('Europe/Moscow',3), ('leap/Europe/Moscow',4)," + "('Japan', 5);\n"); + } } @@ -353,13 +376,13 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Time_zone_id int unsigned NOT NULL auto_increment," "Use_leap_seconds enum('Y','N') DEFAULT 'N' NOT NULL," "PRIMARY KEY TzId (Time_zone_id)" - ") DEFAULT CHARACTER SET latin1 " + ") engine=MyISAM CHARACTER SET utf8 " "comment='Time zones';\n"); if (test) { fprintf(out,"INSERT INTO time_zone (Time_zone_id, Use_leap_seconds)" - "VALUES (1,'N'), (2,'N'), (3,'N'), (4,'Y');\n"); + "VALUES (1,'N'), (2,'N'), (3,'N'), (4,'Y'), (5,'N');\n"); } } @@ -371,7 +394,7 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Transition_time bigint signed NOT NULL," "Transition_type_id int unsigned NOT NULL," "PRIMARY KEY TzIdTranTime (Time_zone_id, Transition_time)" - ") DEFAULT CHARACTER SET latin1 " + ") engine=MyISAM CHARACTER SET utf8 " "comment='Time zone transitions';\n"); if (test) @@ -576,7 +599,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) ",(4, 2045689222, 8) ,(4, 2058390022, 9)" ",(4, 2077138822, 8) ,(4, 2090444422, 9)" ",(4, 2108588422, 8) ,(4, 2121894022, 9)" - ",(4, 2140038022, 8);\n"); + ",(4, 2140038022, 8), (5, -1009875600, 1);\n"); + + } } @@ -590,7 +615,7 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Is_DST tinyint unsigned DEFAULT 0 NOT NULL," "Abbreviation char(8) DEFAULT '' NOT NULL," "PRIMARY KEY TzIdTrTId (Time_zone_id, Transition_type_id)" - ") DEFAULT CHARACTER SET latin1 " + ") engine=MyISAM CHARACTER SET utf8 " "comment='Time zone transition types';\n"); if (test) @@ -612,7 +637,9 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) ",(4, 4, 10800, 0, 'MSK') ,(4, 5, 14400, 1, 'MSD')" ",(4, 6, 18000, 1, 'MSD') ,(4, 7, 7200, 0, 'EET')" ",(4, 8, 10800, 0, 'MSK') ,(4, 9, 14400, 1, 'MSD')" - ",(4, 10, 10800, 1, 'EEST') ,(4, 11, 7200, 0, 'EET');\n"); + ",(4, 10, 10800, 1, 'EEST') ,(4, 11, 7200, 0, 'EET')" + ",(5, 0, 32400, 0, 'CJT') ,(5, 1, 32400, 0, 'JST');\n"); + } } @@ -623,7 +650,7 @@ bool create_system_files(const char *mdata,const char *output_file, bool test) "Transition_time bigint signed NOT NULL," "Correction int signed NOT NULL," "PRIMARY KEY TranTime (Transition_time)" - ") DEFAULT CHARACTER SET latin1 " + ") engine=MyISAM CHARACTER SET utf8 " "comment='Leap seconds information for time zones';\n"); if (test) diff --git a/mysql-test/my_manage.c b/mysql-test/my_manage.c index 1f006f7ab90..88e68dfc27e 100644 --- a/mysql-test/my_manage.c +++ b/mysql-test/my_manage.c @@ -122,7 +122,7 @@ void add_arg(arg_list_t *al, const char *format, ...) al->argv[al->argc]= malloc(strlen(temp)+1); ASSERT(al->argv[al->argc] != NULL); strcpy(al->argv[al->argc], temp); - + ++(al->argc); } else @@ -644,7 +644,7 @@ void del_tree(char *dir) if (lstat(entry->d_name, &st) == -1) { /* FIXME error */ - return; + return; } if (S_ISDIR(st.st_mode)) #else @@ -800,9 +800,12 @@ int removef(const char *format, ...) #ifndef STRUCT_DIRENT_HAS_D_TYPE struct stat st; - if (lstat(entry->d_name, &st) == -1) + /* create long name */ + snprintf(temp, FN_REFLEN, "%s/%s", path, entry->d_name); + + if (lstat(temp, &st) == -1) { - return 1; + return 1; /* Error couldn't lstat file */ } if (!S_ISDIR(st.st_mode) && !fnmatch(p, entry->d_name,0)) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 3bbdb48d98a..f204fee50ed 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -84,10 +84,11 @@ use Sys::Hostname; #use Carp; use IO::Socket; use IO::Socket::INET; -use Data::Dumper; +#use Data::Dumper; use strict; #use diagnostics; +require "lib/mtr_cases.pl"; require "lib/mtr_process.pl"; require "lib/mtr_io.pl"; require "lib/mtr_gcov.pl"; @@ -165,14 +166,12 @@ our $glob_user= 'test'; our $glob_use_embedded_server= 0; our $glob_basedir; -our $glob_do_test; # The total result our $path_charsetsdir; our $path_client_bindir; our $path_language; -our $path_tests_bindir; our $path_timefile; our $path_manager_log; # Used by mysqldadmin our $path_slave_load_tmpdir; # What is this?! @@ -192,8 +191,10 @@ our $exe_master_mysqld; our $exe_mysql; our $exe_mysqladmin; our $exe_mysqlbinlog; +our $exe_mysql_client_test; our $exe_mysqld; our $exe_mysqldump; # Called from test case +our $exe_mysql_fix_system_tables; our $exe_mysqltest; our $exe_slave_mysqld; @@ -208,6 +209,7 @@ our $opt_current_test; our $opt_ddd; our $opt_debug; our $opt_do_test; +our @opt_cases; # The test cases names in argv our $opt_embedded_server; our $opt_extern; our $opt_fast; @@ -232,8 +234,6 @@ our $opt_local_master; our $master; # Will be struct in C our $slave; -our $opt_master_myport; -our $opt_slave_myport; our $opt_ndbcluster_port; our $opt_ndbconnectstring; @@ -284,6 +284,11 @@ our $opt_warnings; our $opt_with_ndbcluster; our $opt_with_openssl; +our $exe_ndb_mgm; +our $path_ndb_tools_dir; +our $path_ndb_backup_dir; +our $file_ndb_testrun_log; +our $flag_ndb_status_ok= 1; ###################################################################### # @@ -297,8 +302,7 @@ sub command_line_setup (); sub executable_setup (); sub environment_setup (); sub kill_and_cleanup (); -sub collect_test_cases ($); -sub sleep_until_file_created ($$); +sub ndbcluster_install (); sub ndbcluster_start (); sub ndbcluster_stop (); sub run_benchmarks ($); @@ -306,6 +310,7 @@ sub run_tests (); sub mysql_install_db (); sub install_db ($$); sub run_testcase ($); +sub report_failure_and_restart ($); sub do_before_start_master ($$); sub do_before_start_slave ($$); sub mysqld_start ($$$$); @@ -347,18 +352,20 @@ sub main () { kill_and_cleanup(); mysql_install_db(); - if ( $opt_with_ndbcluster and ! $glob_use_running_ndbcluster ) - { - ndbcluster_start(); # We start the cluster storage engine - } - # mysql_loadstd(); FIXME copying from "std_data" .frm and # .MGR but there are none?! } if ( $opt_start_and_exit ) { - mtr_report("Servers started, exiting"); + if ( mysqld_start('master',0,[],[]) ) + { + mtr_report("Servers started, exiting"); + } + else + { + mtr_error("Can't start the mysqld server"); + } } else { @@ -447,8 +454,8 @@ sub command_line_setup () { $path_manager_log= "$glob_mysql_test_dir/var/log/manager.log"; $opt_current_test= "$glob_mysql_test_dir/var/log/current_test"; - $opt_master_myport= 9306; - $opt_slave_myport= 9308; + my $opt_master_myport= 9306; + my $opt_slave_myport= 9308; $opt_ndbcluster_port= 9350; # Read the command line @@ -532,6 +539,8 @@ sub command_line_setup () { usage(""); } + @opt_cases= @ARGV; + # Put this into a hash, will be a C struct $master->[0]->{'path_myddir'}= "$glob_mysql_test_dir/var/master-data"; @@ -542,6 +551,8 @@ sub command_line_setup () { $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'}= "$glob_mysql_test_dir/var/master1-data"; $master->[1]->{'path_myerr'}= "$glob_mysql_test_dir/var/log/master1.err"; $master->[1]->{'path_mylog'}= "$glob_mysql_test_dir/var/log/master1.log"; @@ -598,7 +609,7 @@ sub command_line_setup () { # Look at the command line options and set script flags # -------------------------------------------------------------------------- - if ( $opt_record and ! @ARGV) + if ( $opt_record and ! @opt_cases ) { mtr_error("Will not run in record mode without a specific test case"); } @@ -672,6 +683,10 @@ sub command_line_setup () { $glob_use_running_ndbcluster= 1; $opt_with_ndbcluster= 1; } + else + { + $opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port"; + } # FIXME @@ -733,7 +748,8 @@ sub executable_setup () { { mtr_error("Can't find embedded server 'mysqltest'"); } - $path_tests_bindir= "$glob_basedir/libmysqld/examples"; + $exe_mysql_client_test= + "$glob_basedir/libmysqld/examples/mysql_client_test_embedded"; } else { @@ -749,7 +765,8 @@ sub executable_setup () { { $exe_mysqltest= "$glob_basedir/client/mysqltest"; } - $path_tests_bindir= "$glob_basedir/tests"; + $exe_mysql_client_test= + "$glob_basedir/tests/mysql_client_test"; } if ( -f "$glob_basedir/client/.libs/mysqldump" ) { @@ -768,22 +785,29 @@ sub executable_setup () { $exe_mysqlbinlog= "$glob_basedir/client/mysqlbinlog"; } - $exe_mysqld= "$glob_basedir/sql/mysqld"; - $path_client_bindir= "$glob_basedir/client"; - $exe_mysqladmin= "$path_client_bindir/mysqladmin"; - $exe_mysql= "$path_client_bindir/mysql"; - $path_language= "$glob_basedir/sql/share/english/"; - $path_charsetsdir= "$glob_basedir/sql/share/charsets"; + $path_client_bindir= "$glob_basedir/client"; + $exe_mysqld= "$glob_basedir/sql/mysqld"; + $exe_mysqladmin= "$path_client_bindir/mysqladmin"; + $exe_mysql= "$path_client_bindir/mysql"; + $exe_mysql_fix_system_tables= "$glob_basedir/scripts/mysql_fix_privilege_tables"; + $path_language= "$glob_basedir/sql/share/english/"; + $path_charsetsdir= "$glob_basedir/sql/share/charsets"; + + $path_ndb_tools_dir= "$glob_basedir/ndb/tools"; + $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm"; } else { - $path_client_bindir= "$glob_basedir/bin"; - $path_tests_bindir= "$glob_basedir/tests"; - $exe_mysqltest= "$path_client_bindir/mysqltest"; - $exe_mysqldump= "$path_client_bindir/mysqldump"; - $exe_mysqlbinlog= "$path_client_bindir/mysqlbinlog"; - $exe_mysqladmin= "$path_client_bindir/mysqladmin"; - $exe_mysql= "$path_client_bindir/mysql"; + my $path_tests_bindir= "$glob_basedir/tests"; + + $path_client_bindir= "$glob_basedir/bin"; + $exe_mysqltest= "$path_client_bindir/mysqltest"; + $exe_mysqldump= "$path_client_bindir/mysqldump"; + $exe_mysqlbinlog= "$path_client_bindir/mysqlbinlog"; + $exe_mysqladmin= "$path_client_bindir/mysqladmin"; + $exe_mysql= "$path_client_bindir/mysql"; + $exe_mysql_fix_system_tables= "$path_client_bindir/scripts/mysql_fix_privilege_tables"; + if ( -d "$glob_basedir/share/mysql/english" ) { $path_language ="$glob_basedir/share/mysql/english/"; @@ -804,6 +828,36 @@ sub executable_setup () { $exe_mysqld= "$glob_basedir/bin/mysqld"; } + if ( $glob_use_embedded_server ) + { + if ( -f "$path_client_bindir/mysqltest_embedded" ) + { + # FIXME valgrind? + $exe_mysqltest="$path_client_bindir/mysqltest_embedded"; + } + else + { + error("Cannot find embedded server 'mysqltest_embedded'"); + } + if ( -d "$path_tests_bindir/mysql_client_test_embedded" ) + { + $exe_mysql_client_test= + "$path_tests_bindir/mysql_client_test_embedded"; + } + else + { + $exe_mysql_client_test= + "$path_client_bindir/mysql_client_test_embedded"; + } + } + else + { + $exe_mysqltest="$path_client_bindir/mysqltest"; + $exe_mysql_client_test="$path_client_bindir/mysql_client_test"; + } + + $path_ndb_tools_dir= "$glob_basedir/bin"; + $exe_ndb_mgm= "$glob_basedir/bin/ndb_mgm"; } # FIXME special $exe_master_mysqld and $exe_slave_mysqld @@ -818,6 +872,10 @@ sub executable_setup () { { $exe_slave_mysqld= $exe_mysqld; } + + $path_ndb_backup_dir= + "$glob_mysql_test_dir/var/ndbcluster-$opt_ndbcluster_port"; + $file_ndb_testrun_log= "$glob_mysql_test_dir/var/log/ndb_testrun.log"; } @@ -846,13 +904,18 @@ sub environment_setup () { # Also command lines in .opt files may contain env vars # -------------------------------------------------------------------------- - $ENV{'LC_COLLATE'}= "C"; - $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; - $ENV{'MASTER_MYPORT'}= $opt_master_myport; - $ENV{'SLAVE_MYPORT'}= $opt_slave_myport; -# $ENV{'MYSQL_TCP_PORT'}= '@MYSQL_TCP_PORT@'; # FIXME - $ENV{'MYSQL_TCP_PORT'}= 3306; - $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'}; + $ENV{'UMASK'}= "0660"; # The octal *string* + $ENV{'UMASK_DIR'}= "0770"; # The octal *string* + $ENV{'LC_COLLATE'}= "C"; + $ENV{'USE_RUNNING_SERVER'}= $glob_use_running_server; + $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; + $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'}; + $ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'}; + $ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'}; + $ENV{'MASTER_MYPORT1'}= $master->[1]->{'path_myport'}; + $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'path_myport'}; +# $ENV{'MYSQL_TCP_PORT'}= '@MYSQL_TCP_PORT@'; # FIXME + $ENV{'MYSQL_TCP_PORT'}= 3306; } @@ -875,203 +938,6 @@ sub handle_int_signal () { } -############################################################################## -# -# Collect information about test cases we are to run -# -############################################################################## - -sub collect_test_cases ($) { - my $suite= shift; # Test suite name - - my $testdir; - my $resdir; - - if ( $suite eq "main" ) - { - $testdir= "$glob_mysql_test_dir/t"; - $resdir= "$glob_mysql_test_dir/r"; - } - else - { - $testdir= "$glob_mysql_test_dir/suite/$suite/t"; - $resdir= "$glob_mysql_test_dir/suite/$suite/r"; - } - - my @tests; # Array of hash, will be array of C struct - - opendir(TESTDIR, $testdir) or mtr_error("Can't open dir \"$testdir\": $!"); - - foreach my $elem ( sort readdir(TESTDIR) ) { - my $tname= mtr_match_extension($elem,"test"); - next if ! defined $tname; - next if $opt_do_test and ! defined mtr_match_prefix($elem,$opt_do_test); - my $path= "$testdir/$elem"; - - # ---------------------------------------------------------------------- - # Skip some tests silently - # ---------------------------------------------------------------------- - - if ( $opt_start_from and $tname lt $opt_start_from ) - { - next; - } - - # ---------------------------------------------------------------------- - # Skip some tests but include in list, just mark them to skip - # ---------------------------------------------------------------------- - - my $tinfo= {}; - $tinfo->{'name'}= $tname; - $tinfo->{'result_file'}= "$resdir/$tname.result"; - push(@tests, $tinfo); - - if ( $opt_skip_test and defined mtr_match_prefix($tname,$opt_skip_test) ) - { - $tinfo->{'skip'}= 1; - next; - } - - # FIXME temporary solution, we have a hard coded list of test cases to - # skip if we are using the embedded server - - if ( $glob_use_embedded_server and - mtr_match_any_exact($tname,\@skip_if_embedded_server) ) - { - $tinfo->{'skip'}= 1; - next; - } - - # ---------------------------------------------------------------------- - # Collect information about test case - # ---------------------------------------------------------------------- - - $tinfo->{'path'}= $path; - $tinfo->{'timezone'}= "GMT-3"; # for UNIX_TIMESTAMP tests to work - - if ( defined mtr_match_prefix($tname,"rpl") ) - { - if ( $opt_skip_rpl ) - { - $tinfo->{'skip'}= 1; - next; - } - - # FIXME currently we always restart slaves - $tinfo->{'slave_restart'}= 1; - - if ( $tname eq 'rpl_failsafe' or $tname eq 'rpl_chain_temp_table' ) - { - $tinfo->{'slave_num'}= 3; - } - else - { - $tinfo->{'slave_num'}= 1; - } - } - - # FIXME what about embedded_server + ndbcluster, skip ?! - - my $master_opt_file= "$testdir/$tname-master.opt"; - my $slave_opt_file= "$testdir/$tname-slave.opt"; - my $slave_mi_file= "$testdir/$tname.slave-mi"; - my $master_sh= "$testdir/$tname-master.sh"; - my $slave_sh= "$testdir/$tname-slave.sh"; - - if ( -f $master_opt_file ) - { - $tinfo->{'master_restart'}= 1; # We think so for now - # This is a dirty hack from old mysql-test-run, we use the opt file - # to flag other things as well, it is not a opt list at all - my $extra_master_opt= mtr_get_opts_from_file($master_opt_file); - - foreach my $opt (@$extra_master_opt) - { - my $value; - - $value= mtr_match_prefix($opt, "--timezone="); - - if ( defined $value ) - { - $tinfo->{'timezone'}= $value; - $extra_master_opt= []; - $tinfo->{'master_restart'}= 0; - last; - } - - $value= mtr_match_prefix($opt, "--result-file="); - - if ( defined $value ) - { - $tinfo->{'result_file'}= "r/$value.result"; - if ( $opt_result_ext and $opt_record or - -f "$tinfo->{'result_file'}$opt_result_ext") - { - $tinfo->{'result_file'}.= $opt_result_ext; - } - $extra_master_opt= []; - $tinfo->{'master_restart'}= 0; - last; - } - } - - $tinfo->{'master_opt'}= $extra_master_opt; - } - - if ( -f $slave_opt_file ) - { - $tinfo->{'slave_opt'}= mtr_get_opts_from_file($slave_opt_file); - $tinfo->{'slave_restart'}= 1; - } - - if ( -f $slave_mi_file ) - { - $tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file); - $tinfo->{'slave_restart'}= 1; - } - - if ( -f $master_sh ) - { - if ( $glob_win32_perl ) - { - $tinfo->{'skip'}= 1; - } - else - { - $tinfo->{'master_sh'}= $master_sh; - $tinfo->{'master_restart'}= 1; - } - } - - if ( -f $slave_sh ) - { - if ( $glob_win32_perl ) - { - $tinfo->{'skip'}= 1; - } - else - { - $tinfo->{'slave_sh'}= $slave_sh; - $tinfo->{'slave_restart'}= 1; - } - } - - # We can't restart a running server that may be in use - - if ( $glob_use_running_server and - ( $tinfo->{'master_restart'} or $tinfo->{'slave_restart'} ) ) - { - $tinfo->{'skip'}= 1; - } - - } - - closedir TESTDIR; - - return \@tests; -} - - ############################################################################## # # Handle left overs from previous runs @@ -1099,22 +965,19 @@ sub kill_and_cleanup () { mtr_report("Killing Possible Leftover Processes"); mkpath("$glob_mysql_test_dir/var/log"); # Needed for mysqladmin log mtr_kill_leftovers(); - } - if ( $opt_with_ndbcluster and ! $glob_use_running_ndbcluster ) - { ndbcluster_stop(); + $master->[0]->{'ndbcluster'}= 1; } mtr_report("Removing Stale Files"); rmtree("$glob_mysql_test_dir/var/log"); - rmtree("$glob_mysql_test_dir/var/ndbcluster"); + rmtree("$glob_mysql_test_dir/var/ndbcluster-$opt_ndbcluster_port"); rmtree("$glob_mysql_test_dir/var/run"); rmtree("$glob_mysql_test_dir/var/tmp"); mkpath("$glob_mysql_test_dir/var/log"); - mkpath("$glob_mysql_test_dir/var/ndbcluster"); mkpath("$glob_mysql_test_dir/var/run"); mkpath("$glob_mysql_test_dir/var/tmp"); mkpath($opt_tmpdir); @@ -1152,26 +1015,67 @@ sub kill_and_cleanup () { # FIXME why is there a different start below?! +sub ndbcluster_install () { + + if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) + { + return 0; + } + mtr_report("Install ndbcluster"); + my $ndbcluster_opts= $opt_bench ? "" : "--small"; + my $ndbcluster_port_base= $opt_ndbcluster_port + 2; + if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", + ["--port=$opt_ndbcluster_port", + "--port-base=$ndbcluster_port_base", + "--data-dir=$glob_mysql_test_dir/var", + $ndbcluster_opts, + "--initial"], + "", "", "", "") ) + { + mtr_error("Error ndbcluster_install"); + return 1; + } + + ndbcluster_stop(); + $master->[0]->{'ndbcluster'}= 1; + + return 0; +} + sub ndbcluster_start () { - mtr_report("Starting ndbcluster"); - my $ndbcluster_opts= $opt_bench ? "" : "--small"; - # FIXME check result code?! - mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--port-base=$opt_ndbcluster_port", - $ndbcluster_opts, - "--diskless", - "--initial", - "--data-dir=$glob_mysql_test_dir/var"], - "", "", "", ""); + if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) + { + return 0; + } + # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null + if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", + ["--port=$opt_ndbcluster_port", + "--data-dir=$glob_mysql_test_dir/var"], + "", "/dev/null", "", "") ) + { + mtr_error("Error ndbcluster_install"); + return 1; + } + + return 0; } sub ndbcluster_stop () { + + if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) + { + return; + } + my $ndbcluster_port_base= $opt_ndbcluster_port + 2; + # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--data-dir=$glob_mysql_test_dir/var", - "--port-base=$opt_ndbcluster_port", + ["--port=$opt_ndbcluster_port", + "--data-dir=$glob_mysql_test_dir/var", "--stop"], - "", "", "", ""); + "", "/dev/null", "", ""); + + return; } @@ -1189,6 +1093,10 @@ sub run_benchmarks ($) { if ( ! $glob_use_embedded_server and ! $opt_local_master ) { $master->[0]->{'pid'}= mysqld_start('master',0,[],[]); + if ( ! $master->[0]->{'pid'} ) + { + mtr_error("Can't start the mysqld server"); + } } mtr_init_args(\$args); @@ -1254,7 +1162,7 @@ sub run_suite () { mtr_print_thick_line(); - mtr_report("Finding Tests in the '$suite' suite"); + mtr_report("Finding Tests in the '$suite' suite"); my $tests= collect_test_cases($suite); @@ -1275,11 +1183,6 @@ sub run_suite () { stop_masters_slaves(); } - if ( $opt_with_ndbcluster and ! $glob_use_running_ndbcluster ) - { - ndbcluster_stop(); - } - if ( $opt_gcov ) { gcov_collect(); # collect coverage information @@ -1301,10 +1204,19 @@ sub run_suite () { sub mysql_install_db () { - mtr_report("Installing Test Databases"); - + # FIXME not exactly true I think, needs improvements install_db('master', $master->[0]->{'path_myddir'}); + install_db('master', $master->[1]->{'path_myddir'}); install_db('slave', $slave->[0]->{'path_myddir'}); + install_db('slave', $slave->[1]->{'path_myddir'}); + install_db('slave', $slave->[2]->{'path_myddir'}); + + if ( ndbcluster_install() ) + { + # failed to install, disable usage but flag that its no ok + $opt_with_ndbcluster= 0; + $flag_ndb_status_ok= 0; + } return 0; } @@ -1368,6 +1280,9 @@ sub run_testcase ($) { mtr_tonewfile($opt_current_test,"$tname\n"); # Always tell where we are + # output current test to ndbcluster log file to enable diagnostics + mtr_tofile($file_ndb_testrun_log,"CURRENT TEST $tname\n"); + # ---------------------------------------------------------------------- # If marked to skip, just print out and return. # Note that a test case not marked as 'skip' can still be @@ -1422,6 +1337,12 @@ sub run_testcase ($) { mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); do_before_start_master($tname,$tinfo->{'master_sh'}); + # ---------------------------------------------------------------------- + # If any mysqld servers running died, we have to know + # ---------------------------------------------------------------------- + + mtr_record_dead_children(); + # ---------------------------------------------------------------------- # Start masters # ---------------------------------------------------------------------- @@ -1435,18 +1356,37 @@ sub run_testcase ($) { if ( ! $opt_local_master ) { + if ( $master->[0]->{'ndbcluster'} ) + { + $master->[0]->{'ndbcluster'}= ndbcluster_start(); + if ( $master->[0]->{'ndbcluster'} ) + { + report_failure_and_restart($tinfo); + return; + } + } if ( ! $master->[0]->{'pid'} ) { $master->[0]->{'pid'}= mysqld_start('master',0,$tinfo->{'master_opt'},[]); + if ( ! $master->[0]->{'pid'} ) + { + report_failure_and_restart($tinfo); + return; + } } if ( $opt_with_ndbcluster and ! $master->[1]->{'pid'} ) { $master->[1]->{'pid'}= mysqld_start('master',1,$tinfo->{'master_opt'},[]); + if ( ! $master->[1]->{'pid'} ) + { + report_failure_and_restart($tinfo); + return; + } } - if ( $tinfo->{'master_opt'} ) + if ( @{$tinfo->{'master_opt'}} ) { $master->[0]->{'uses_special_flags'}= 1; } @@ -1469,6 +1409,11 @@ sub run_testcase ($) { $slave->[$idx]->{'pid'}= mysqld_start('slave',$idx, $tinfo->{'slave_opt'}, $tinfo->{'slave_mi'}); + if ( ! $slave->[$idx]->{'pid'} ) + { + report_failure_and_restart($tinfo); + return; + } } } } @@ -1502,33 +1447,40 @@ sub run_testcase ($) { "mysqltest returned unexpected code $res, " . "it has probably crashed"); } - mtr_report_test_failed($tinfo); - mtr_show_failed_diff($tname); - print "\n"; - if ( ! $opt_force ) - { - print "Aborting: $tname failed. To continue, re-run with '--force'."; - print "\n"; - if ( ! $opt_gdb and ! $glob_use_running_server and - ! $opt_ddd and ! $glob_use_embedded_server ) - { - stop_masters_slaves(); - } - exit(1); - } - - # FIXME always terminate on failure?! - if ( ! $opt_gdb and ! $glob_use_running_server and - ! $opt_ddd and ! $glob_use_embedded_server ) - { - stop_masters_slaves(); - } - print "Resuming Tests\n\n"; + report_failure_and_restart($tinfo); } } } +sub report_failure_and_restart ($) { + my $tinfo= shift; + + mtr_report_test_failed($tinfo); + mtr_show_failed_diff($tinfo->{'name'}); + print "\n"; + if ( ! $opt_force ) + { + print "Aborting: $tinfo->{'name'} failed. To continue, re-run with '--force'."; + print "\n"; + if ( ! $opt_gdb and ! $glob_use_running_server and + ! $opt_ddd and ! $glob_use_embedded_server ) + { + stop_masters_slaves(); + } + exit(1); + } + + # FIXME always terminate on failure?! + if ( ! $opt_gdb and ! $glob_use_running_server and + ! $opt_ddd and ! $glob_use_embedded_server ) + { + stop_masters_slaves(); + } + print "Resuming Tests\n\n"; +} + + ############################################################################## # # Start and stop servers @@ -1603,11 +1555,13 @@ sub do_before_start_slave ($$) { } sub mysqld_arguments ($$$$$) { - my $args= shift; - my $type= shift; # master/slave/bootstrap - my $idx= shift; - my $extra_opt= shift; - my $slave_master_info= shift; + my $args= shift; + my $type= shift; # master/slave/bootstrap + my $idx= shift; + my $extra_opt= shift; + my $slave_master_info= shift; + +# print STDERR Dumper($extra_opt); my $sidx= ""; # Index as string, 0 is empty string if ( $idx > 0 ) @@ -1728,17 +1682,8 @@ sub mysqld_arguments ($$$$$) { if ( $opt_with_ndbcluster ) { mtr_add_arg($args, "%s--ndbcluster", $prefix); - - if ( $glob_use_running_ndbcluster ) - { - mtr_add_arg($args,"--ndb-connectstring=%s", $prefix, - $opt_ndbconnectstring); - } - else - { - mtr_add_arg($args,"--ndb-connectstring=host=localhost:%d", - $prefix, $opt_ndbcluster_port); - } + mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, + $opt_ndbconnectstring); } # FIXME always set nowdays??? SMALL_SERVER @@ -1835,10 +1780,10 @@ sub mysqld_arguments ($$$$$) { ############################################################################## sub mysqld_start ($$$$) { - my $type= shift; # master/slave/bootstrap - my $idx= shift; - my $extra_opt= shift; - my $slave_master_info= shift; + my $type= shift; # master/slave/bootstrap + my $idx= shift; + my $extra_opt= shift; + my $slave_master_info= shift; my $args; # Arg vector my $exe; @@ -1893,9 +1838,8 @@ sub mysqld_start ($$$$) { $master->[$idx]->{'path_myerr'}, $master->[$idx]->{'path_myerr'}, "") ) { - sleep_until_file_created($master->[$idx]->{'path_mypid'}, - $master->[$idx]->{'start_timeout'}); - return $pid; + return sleep_until_file_created($master->[$idx]->{'path_mypid'}, + $master->[$idx]->{'start_timeout'}, $pid); } } @@ -1905,13 +1849,12 @@ sub mysqld_start ($$$$) { $slave->[$idx]->{'path_myerr'}, $slave->[$idx]->{'path_myerr'}, "") ) { - sleep_until_file_created($slave->[$idx]->{'path_mypid'}, - $master->[$idx]->{'start_timeout'}); - return $pid; + return sleep_until_file_created($slave->[$idx]->{'path_mypid'}, + $master->[$idx]->{'start_timeout'}, $pid); } } - mtr_error("Can't start mysqld FIXME"); + return 0; } sub stop_masters_slaves () { @@ -1944,7 +1887,13 @@ sub stop_masters () { } } - mtr_stop_mysqld_servers(\@args, 0); + if ( ! $master->[0]->{'ndbcluster'} ) + { + ndbcluster_stop(); + $master->[0]->{'ndbcluster'}= 1; + } + + mtr_stop_mysqld_servers(\@args); } sub stop_slaves () { @@ -1966,7 +1915,7 @@ sub stop_slaves () { } } - mtr_stop_mysqld_servers(\@args, 0); + mtr_stop_mysqld_servers(\@args); } @@ -1992,17 +1941,39 @@ sub run_mysqltest ($$) { } my $cmdline_mysql= - "$exe_mysql --host=localhost --port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --user=root --password="; + "$exe_mysql --host=localhost --user=root --password= " . + "--port=$master->[0]->{'path_myport'} " . + "--socket=$master->[0]->{'path_mysock'}"; + + my $cmdline_mysql_client_test= + "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . + "--port=$master->[0]->{'path_myport'} " . + "--socket=$master->[0]->{'path_mysock'}"; + + my $cmdline_mysql_fix_system_tables= + "$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " . + "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . + "--port=$master->[0]->{'path_myport'} " . + "--socket=$master->[0]->{'path_mysock'}"; + + # FIXME really needing a PATH??? # $ENV{'PATH'}= "/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11:$ENV{'PATH'}"; - $ENV{'MYSQL'}= $exe_mysql; + $ENV{'MYSQL'}= $cmdline_mysql; $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; - $ENV{'MYSQL_BINLOG'}= $exe_mysqlbinlog; - $ENV{'CLIENT_BINDIR'}= $path_client_bindir; - $ENV{'TESTS_BINDIR'}= $path_tests_bindir; + $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{'NDB_STATUS_OK'}= $flag_ndb_status_ok; + $ENV{'NDB_MGM'}= $exe_ndb_mgm; + $ENV{'NDB_BACKUP_DIR'}= $path_ndb_backup_dir; + $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; + $ENV{'NDB_TOOLS_OUTPUT'}= $file_ndb_testrun_log; + $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; my $exe= $exe_mysqltest; my $args; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 24ea7a53046..c3b27dd9af2 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -227,6 +227,8 @@ EXTRA_MYSQLBINLOG_OPT="" USE_RUNNING_SERVER=0 USE_NDBCLUSTER="" USE_RUNNING_NDBCLUSTER="" +USE_PURIFY="" +PURIFY_LOGS="" DO_GCOV="" DO_GDB="" MANUAL_GDB="" @@ -246,7 +248,7 @@ MYSQL_TEST_SSL_OPTS="" USE_TIMER="" USE_EMBEDDED_SERVER="" RESULT_EXT="" -TEST_MODE="default" +TEST_MODE="" NDB_MGM_EXTRA_OPTS= NDB_MGMD_EXTRA_OPTS= @@ -254,8 +256,17 @@ NDBD_EXTRA_OPTS= while test $# -gt 0; do case "$1" in - --embedded-server) USE_EMBEDDED_SERVER=1 USE_MANAGER=0 NO_SLAVE=1 ; \ - USE_RUNNING_SERVER=0 RESULT_EXT=".es" TEST_MODE="embedded" ;; + --embedded-server) + USE_EMBEDDED_SERVER=1 + USE_MANAGER=0 NO_SLAVE=1 + USE_RUNNING_SERVER=0 + RESULT_EXT=".es" + TEST_MODE="$TEST_MODE embedded" ;; + --purify) + USE_PURIFY=1 + USE_MANAGER=0 + USE_RUNNING_SERVER=0 + TEST_MODE="$TEST_MODE purify" ;; --user=*) DBUSER=`$ECHO "$1" | $SED -e "s;--user=;;"` ;; --force) FORCE=1 ;; --timer) USE_TIMER=1 ;; @@ -341,7 +352,7 @@ while test $# -gt 0; do SLEEP_TIME_AFTER_RESTART=`$ECHO "$1" | $SED -e "s;--sleep=;;"` ;; --ps-protocol) - TEST_MODE="ps-protocol" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; + TEST_MODE="$TEST_MODE ps-protocol" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; --user-test=*) USER_TEST=`$ECHO "$1" | $SED -e "s;--user-test=;;"` ;; @@ -430,7 +441,7 @@ while test $# -gt 0; do STRACE_CLIENT=1 ;; --debug) - EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \ + EXTRA_MASTER_MYSQLD_TRACE=" \ --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/master.trace" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \ --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/slave.trace" @@ -454,6 +465,13 @@ while test $# -gt 0; do shift done +if [ -z "$TEST_MODE" ] ; then + TEST_MODE="default" +else + # Remove the leading space if any + TEST_MODE=`echo $TEST_MODE | sed 's/^ *//'` +fi + #++ # mysqld Environment Parameters #-- @@ -482,6 +500,7 @@ export MASTER_MYPORT MASTER_MYPORT1 SLAVE_MYPORT MYSQL_TCP_PORT MASTER_MYSOCK MA NDBCLUSTER_BASE_PORT=`expr $NDBCLUSTER_PORT + 2` NDBCLUSTER_OPTS="--port=$NDBCLUSTER_PORT --port-base=$NDBCLUSTER_BASE_PORT --data-dir=$MYSQL_TEST_DIR/var --ndb_mgm-extra-opts=$NDB_MGM_EXTRA_OPTS --ndb_mgmd-extra-opts=$NDB_MGMD_EXTRA_OPTS --ndbd-extra-opts=$NDBD_EXTRA_OPTS" NDB_BACKUP_DIR=$MYSQL_TEST_DIR/var/ndbcluster-$NDBCLUSTER_PORT +NDB_TOOLS_OUTPUT=$MYSQL_TEST_DIR/var/log/ndb_tools.log if [ x$SOURCE_DIST = x1 ] ; then MY_BASEDIR=$MYSQL_TEST_DIR @@ -515,7 +534,10 @@ if [ x$SOURCE_DIST = x1 ] ; then fi MYSQL_CLIENT_TEST="$BASEDIR/libmysqld/examples/mysql_client_test_embedded" else - MYSQLD="$VALGRIND $BASEDIR/sql/mysqld" + MYSQLD="$BASEDIR/sql/mysqld" + if [ -n "$VALGRIND" ] ; then + MYSQLD="$VALGRIND $MYSQLD" + fi if [ -f "$BASEDIR/client/.libs/lt-mysqltest" ] ; then MYSQL_TEST="$BASEDIR/client/.libs/lt-mysqltest" elif [ -f "$BASEDIR/client/.libs/mysqltest" ] ; then @@ -552,6 +574,31 @@ if [ x$SOURCE_DIST = x1 ] ; then MYSQL_FIX_SYSTEM_TABLES="$BASEDIR/scripts/mysql_fix_privilege_tables" NDB_TOOLS_DIR="$BASEDIR/ndb/tools" NDB_MGM="$BASEDIR/ndb/src/mgmclient/ndb_mgm" + + if [ -n "$USE_PURIFY" ] ; then + PSUP="$MYSQL_TEST_DIR/purify.suppress" + echo "suppress UMR rw_read_held; mi_open; ha_myisam::open64; handler::ha_open; openfrm" > $PSUP + echo "suppress UMR my_end; main" >> $PSUP + echo "suppress UMR _doprnt; fprintf; my_end; main" >> $PSUP + PURIFYOPTIONS="-windows=no -log-file=%v.purifylog -append-logfile -add-suppression-files=$PSUP" + if [ -f "${MYSQL_TEST}-purify" ] ; then + MYSQL_TEST="${MYSQL_TEST}-purify" + PLOG="$MYSQL_TEST.purifylog" + if [ -f $PLOG ]; then + mv $PLOG $PLOG.$$ + fi + PURIFY_LOGS="$PLOG" + fi + if [ -f "${MYSQLD}-purify" ] ; then + MYSQLD="${MYSQLD}-purify" + PLOG="$MYSQLD.purifylog" + if [ -f $PLOG ]; then + mv $PLOG $PLOG.$$ + fi + PURIFY_LOGS="$PURIFY_LOGS $PLOG" + fi + fi + else # We have a binary installation. Note that this can be both from @@ -645,8 +692,7 @@ then fi MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --socket=$MASTER_MYSOCK --port=$MYSQL_TCP_PORT --silent" -MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT" -MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR $EXTRA_MYSQLBINLOG_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 --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD" export MYSQL MYSQL_DUMP MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES @@ -654,6 +700,10 @@ export CLIENT_BINDIR MYSQL_CLIENT_TEST CHARSETSDIR export NDB_TOOLS_DIR export NDB_MGM export NDB_BACKUP_DIR +export NDB_TOOLS_OUTPUT +export PURIFYOPTIONS +NDB_STATUS_OK=1 +export NDB_STATUS_OK MYSQL_TEST_ARGS="--no-defaults --socket=$MASTER_MYSOCK --database=$DB \ --user=$DBUSER --password=$DBPASSWD --silent -v --skip-safemalloc \ @@ -783,6 +833,19 @@ disable_test() { $ECHO "$RES$RES_SPACE [ disabled ] $2" } + +report_current_test () { + tname=$1 + echo "CURRENT_TEST: $tname" >> $MASTER_MYERR + if [ -n "$PURIFY_LOGS" ] ; then + for log in $PURIFY_LOGS + do + echo "CURRENT_TEST: $tname" >> $log + done + fi +} + + report_stats () { if [ $TOT_FAIL = 0 ]; then $ECHO "All $TOT_TEST tests were successful." @@ -1011,6 +1074,7 @@ start_ndbcluster() { if [ ! -z "$USE_NDBCLUSTER" ] then + rm -f $NDB_TOOLS_OUTPUT if [ -z "$USE_RUNNING_NDBCLUSTER" ] then echo "Starting ndbcluster" @@ -1020,13 +1084,15 @@ start_ndbcluster() else NDBCLUSTER_EXTRA_OPTS="--small" fi - NDB_STARTED=1 - ./ndb/ndbcluster $NDBCLUSTER_OPTS $NDBCLUSTER_EXTRA_OPTS --initial || NDB_STARTED=0 - if [ x$NDB_STARTED != x1 ] ; then + ./ndb/ndbcluster $NDBCLUSTER_OPTS $NDBCLUSTER_EXTRA_OPTS --initial || NDB_STATUS_OK=0 + if [ x$NDB_STATUS_OK != x1 ] ; then if [ x$FORCE != x1 ] ; then exit 1 fi + USE_NDBCLUSTER= + return fi + NDB_CONNECTSTRING="host=localhost:$NDBCLUSTER_PORT" else NDB_CONNECTSTRING="$USE_RUNNING_NDBCLUSTER" @@ -1083,6 +1149,11 @@ start_master() this_master_myport=$MASTER_MYPORT NOT_FIRST_MASTER_EXTRA_OPTS="" fi + if [ -n "$EXTRA_MASTER_MYSQLD_TRACE" ] + then + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \ + $EXTRA_MASTER_MYSQLD_TRACE$1" + fi if [ -z "$DO_BENCH" ] then master_args="--no-defaults --log-bin=$MYSQL_TEST_DIR/var/log/master-bin$1 \ @@ -1535,7 +1606,7 @@ run_testcase () esac stop_master stop_master 1 - echo "CURRENT_TEST: $tname" >> $MASTER_MYERR + report_current_test $tname start_master if [ -n "$USE_NDBCLUSTER" -a -z "$DO_BENCH" ] ; then start_master 1 @@ -1551,13 +1622,13 @@ run_testcase () EXTRA_MASTER_OPT="" stop_master stop_master 1 - echo "CURRENT_TEST: $tname" >> $MASTER_MYERR + report_current_test $tname start_master if [ -n "$USE_NDBCLUSTER" -a -z "$DO_BENCH" ] ; then start_master 1 fi else - echo "CURRENT_TEST: $tname" >> $MASTER_MYERR + report_current_test $tname fi fi @@ -1741,7 +1812,6 @@ then mysql_loadstd fi - $ECHO "Starting Tests" # Some test cases need USE_RUNNING_SERVER diff --git a/mysql-test/mysql_test_run_new.c b/mysql-test/mysql_test_run_new.c index bdebe912b97..41cd4706e0b 100644 --- a/mysql-test/mysql_test_run_new.c +++ b/mysql-test/mysql_test_run_new.c @@ -132,7 +132,13 @@ static char skip_test[FN_REFLEN]= " repair ," " rpl_trunc_binlog ," " mysqldump ," -" rpl000001 "; +" rpl000001 ," + +" derived ," +" group_by ," +" select ," +" rpl000015 ," +" subselect "; #endif static char ignore_test[FN_REFLEN]= ""; @@ -143,6 +149,8 @@ static char mysql_tmp_dir[FN_REFLEN]; static char result_dir[FN_REFLEN]; static char master_dir[FN_REFLEN]; static char slave_dir[FN_REFLEN]; +static char slave1_dir[FN_REFLEN]; +static char slave2_dir[FN_REFLEN]; static char lang_dir[FN_REFLEN]; static char char_dir[FN_REFLEN]; @@ -190,6 +198,8 @@ int restarts= 0; FILE *log_fd= NULL; +static char argument[FN_REFLEN]; + /****************************************************************************** functions @@ -221,7 +231,7 @@ void log_info(const char *, ...); void log_error(const char *, ...); void log_errno(const char *, ...); void die(const char *); -char *str_tok(char *string, const char *delim); +char *str_tok(char* dest, char *string, const char *delim); #ifndef __WIN__ void run_init_script(const char *script_name); #endif @@ -289,11 +299,15 @@ void install_db(char *datadir) add_arg(&al, "--basedir=%s", base_dir); add_arg(&al, "--datadir=%s", datadir); add_arg(&al, "--skip-innodb"); + add_arg(&al, "--skip-ndbcluster"); add_arg(&al, "--skip-bdb"); #ifndef __NETWARE__ add_arg(&al, "--character-sets-dir=%s", char_dir); add_arg(&al, "--language=%s", lang_dir); #endif +// added + add_arg(&al, "--default-character-set=latin1"); + add_arg(&al, "--innodb_data_file_path=ibdata1:50M"); /* spawn */ if ((err= spawn(mysqld_file, &al, TRUE, input, output, error, NULL)) != 0) @@ -335,12 +349,27 @@ void mysql_install_db() mkdir(temp, S_IRWXU); snprintf(temp, FN_REFLEN, "%s/var/master-data/test", mysql_test_dir); mkdir(temp, S_IRWXU); + snprintf(temp, FN_REFLEN, "%s/var/slave-data", mysql_test_dir); mkdir(temp, S_IRWXU); snprintf(temp, FN_REFLEN, "%s/var/slave-data/mysql", mysql_test_dir); mkdir(temp, S_IRWXU); snprintf(temp, FN_REFLEN, "%s/var/slave-data/test", mysql_test_dir); mkdir(temp, S_IRWXU); + + snprintf(temp, FN_REFLEN, "%s/var/slave1-data", mysql_test_dir); + mkdir(temp, S_IRWXU); + snprintf(temp, FN_REFLEN, "%s/var/slave1-data/mysql", mysql_test_dir); + mkdir(temp, S_IRWXU); + snprintf(temp, FN_REFLEN, "%s/var/slave1-data/test", mysql_test_dir); + mkdir(temp, S_IRWXU); + + snprintf(temp, FN_REFLEN, "%s/var/slave2-data", mysql_test_dir); + mkdir(temp, S_IRWXU); + snprintf(temp, FN_REFLEN, "%s/var/slave2-data/mysql", mysql_test_dir); + mkdir(temp, S_IRWXU); + snprintf(temp, FN_REFLEN, "%s/var/slave2-data/test", mysql_test_dir); + mkdir(temp, S_IRWXU); #else mkdir(temp); /* create subdirectories */ @@ -368,6 +397,8 @@ void mysql_install_db() install_db(master_dir); mlog("Creating test databases for slave... \n"); install_db(slave_dir); + install_db(slave1_dir); + install_db(slave2_dir); } /****************************************************************************** @@ -384,7 +415,6 @@ void start_master() int err; char master_out[FN_REFLEN]; char master_err[FN_REFLEN]; -/* char temp[FN_REFLEN]; */ char temp2[FN_REFLEN]; /* remove old berkeley db log files that can confuse the server */ @@ -463,6 +493,11 @@ void start_master() add_arg(&al, "--character-sets-dir=%s", char_dir); add_arg(&al, "--tmpdir=%s", mysql_tmp_dir); add_arg(&al, "--language=%s", lang_dir); + + add_arg(&al, "--rpl-recovery-rank=1"); + add_arg(&al, "--init-rpl-role=master"); + add_arg(&al, "--default-character-set=latin1"); +// add_arg(&al, "--innodb_data_file_path=ibdata1:50M"); #ifdef DEBUG /* only for debug builds */ add_arg(&al, "--debug"); #endif @@ -491,13 +526,13 @@ void start_master() { char *p; - p= (char *)str_tok(master_opt, " \t"); + p= (char *)str_tok(argument, master_opt, " \t"); if (!strstr(master_opt, "timezone")) { while (p) { add_arg(&al, "%s", p); - p= (char *)str_tok(NULL, " \t"); + p= (char *)str_tok(argument, NULL, " \t"); } } } @@ -624,10 +659,10 @@ void start_slave() add_arg(&al, "--log-bin=slave-bin"); add_arg(&al, "--relay_log=slave-relay-bin"); add_arg(&al, "--basedir=%s", base_dir); - add_arg(&al, "--port=%u", slave_port); #if !defined(__NETWARE__) && !defined(__WIN__) add_arg(&al, "--socket=%s",slave_socket); #endif + add_arg(&al, "--port=%u", slave_port); add_arg(&al, "--datadir=%s", slave_dir); #ifndef __WIN__ add_arg(&al, "--pid-file=%s", slave_pid); @@ -651,10 +686,15 @@ void start_slave() add_arg(&al, "--master-retry-count=10"); add_arg(&al, "-O"); add_arg(&al, "slave_net_timeout=10"); + add_arg(&al, "--log-slave-updates"); + add_arg(&al, "--log=%s/var/log/slave.log", mysql_test_dir); + add_arg(&al, "--default-character-set=latin1"); + add_arg(&al, "--skip-ndbcluster"); + #ifdef DEBUG /* only for debug builds */ add_arg(&al, "--debug"); -#endif - +#endif + if (use_openssl) { add_arg(&al, "--ssl-ca=%s", ca_cert); @@ -667,12 +707,12 @@ void start_slave() { char *p; - p= (char *)str_tok(slave_master_info, " \t"); + p= (char *)str_tok(argument, slave_master_info, " \t"); while (p) { add_arg(&al, "%s", p); - p= (char *)str_tok(NULL, " \t"); + p= (char *)str_tok(argument, NULL, " \t"); } } else @@ -700,13 +740,13 @@ void start_slave() { char *p; - p= (char *)str_tok(slave_opt, " \t"); + p= (char *)str_tok(argument, slave_opt, " \t"); while (p) { add_arg(&al, "%s", p); - p= (char *)str_tok(NULL, " \t"); - } + p= (char *)str_tok(argument, NULL, " \t"); + } } /* remove the pid file if it exists */ @@ -753,9 +793,12 @@ void start_slave() void mysql_start() { -/* log_info("Starting the MySQL server(s): %u", ++restarts); */ + + + printf("loading master...\r"); start_master(); + printf("loading slave...\r"); start_slave(); /* activate the test screen */ @@ -853,6 +896,7 @@ void mysql_restart() mysql_stop(); mlog(DASH); + sleep(1); mysql_start(); } @@ -912,7 +956,7 @@ int read_option(char *opt_file, char *opt) if ((p= strstr(opt, "\\\\")) != NULL) { /* bmove is guranteed to work byte by byte */ - bmove(p, p+1, strlen(p+1)); + bmove(p, p+1, strlen(p)+1); } } else @@ -977,14 +1021,6 @@ void run_test(char *test) char err_file[FN_REFLEN]; int err; arg_list_t al; -#ifdef __WIN__ - /* Clean test database */ - removef("%s/test/*.*", master_dir); - removef("%s/test/*.*", slave_dir); - removef("%s/mysqltest/*.*", master_dir); - removef("%s/mysqltest/*.*", slave_dir); - -#endif /* skip slave? */ flag= skip_slave; skip_slave= (strncmp(test, "rpl", 3) != 0); @@ -1045,9 +1081,6 @@ void run_test(char *test) if (!master_running) mysql_start(); else if (restart) mysql_restart(); - /* let the system stabalize */ - sleep(1); - /* show test */ mlog("%-46s ", test); @@ -1066,10 +1099,12 @@ void run_test(char *test) add_arg(&al, "--silent"); add_arg(&al, "--basedir=%s/", mysql_test_dir); add_arg(&al, "--host=127.0.0.1"); + add_arg(&al, "--skip-safemalloc"); add_arg(&al, "-v"); add_arg(&al, "-R"); add_arg(&al, "%s", result_file); - + + if (use_openssl) { add_arg(&al, "--ssl-ca=%s", ca_cert); @@ -1079,7 +1114,6 @@ void run_test(char *test) /* spawn */ err= spawn(mysqltest_file, &al, TRUE, test_file, out_file, err_file, NULL); - /* free args */ free_args(&al); @@ -1259,7 +1293,9 @@ void die(const char *msg) void setup(char *file __attribute__((unused))) { char temp[FN_REFLEN]; +#if defined(__WIN__) || defined(__NETWARE__) char file_path[FN_REFLEN*2]; +#endif char *p; int position; @@ -1349,7 +1385,11 @@ void setup(char *file __attribute__((unused))) snprintf(client_key, FN_REFLEN, "%s/SSL/client-key.pem", base_dir); /* setup files */ +#ifdef _DEBUG + snprintf(mysqld_file, FN_REFLEN, "%s/mysqld-debug.exe", bin_dir); +#else snprintf(mysqld_file, FN_REFLEN, "%s/mysqld.exe", bin_dir); +#endif snprintf(mysqltest_file, FN_REFLEN, "%s/mysqltest.exe", bin_dir); snprintf(mysqladmin_file, FN_REFLEN, "%s/mysqladmin.exe", bin_dir); #else @@ -1361,6 +1401,8 @@ void setup(char *file __attribute__((unused))) snprintf(result_dir, FN_REFLEN, "%s/r", mysql_test_dir); snprintf(master_dir, FN_REFLEN, "%s/var/master-data", mysql_test_dir); snprintf(slave_dir, FN_REFLEN, "%s/var/slave-data", mysql_test_dir); + snprintf(slave1_dir, FN_REFLEN, "%s/var/slave1-data", mysql_test_dir); + snprintf(slave2_dir, FN_REFLEN, "%s/var/slave2-data", mysql_test_dir); snprintf(lang_dir, FN_REFLEN, "%s/sql/share/english", base_dir); snprintf(char_dir, FN_REFLEN, "%s/sql/share/charsets", base_dir); @@ -1413,30 +1455,147 @@ void setup(char *file __attribute__((unused))) snprintf(file_path,FN_REFLEN,"MYSQL_TEST_DIR=%s",mysql_test_dir); _putenv(file_path); snprintf(file_path, FN_REFLEN*2, - "MYSQL_DUMP=%s/mysqldump.exe --no-defaults -u root --port=%u", + "MYSQL_DUMP=%s/mysqldump.exe --no-defaults -uroot --port=%u", bin_dir, master_port); _putenv(file_path); snprintf(file_path, FN_REFLEN*2, - "MYSQL_BINLOG=%s/mysqlbinlog.exe --no-defaults --local-load=%s", + "MYSQL_BINLOG=%s/mysqlbinlog.exe --no-defaults --local-load=%s", bin_dir, mysql_tmp_dir); _putenv(file_path); + + snprintf(file_path, FN_REFLEN*2, + "TESTS_BINDIR=%s/tests", base_dir); + _putenv(file_path); + + snprintf(file_path, FN_REFLEN*2, + "CHARSETSDIR=%s/sql/share/charsets", base_dir); + _putenv(file_path); + + snprintf(file_path, FN_REFLEN*2, + "MYSQL=%s/mysql --port=%u ", + bin_dir, master_port); + _putenv(file_path); + + snprintf(file_path, FN_REFLEN*2, + "MYSQL_FIX_SYSTEM_TABLES=%s/scripts/mysql_fix_privilege_tables --no-defaults " + "--host=localhost --port=%u " + "--basedir=%s --bindir=%s --verbose", + base_dir,master_port, base_dir, bin_dir); + _putenv(file_path); + + snprintf(file_path, FN_REFLEN*2, + "NDB_TOOLS_DIR=%s/ndb/tools", base_dir); + _putenv(file_path); + + snprintf(file_path, FN_REFLEN*2, + "CLIENT_BINDIR=%s", bin_dir); + _putenv(file_path); + + snprintf(file_path, FN_REFLEN*2, + "MYSQL_CLIENT_TEST=%s/tests/mysql_client_test --no-defaults --testcase " + "--user=root --port=%u --silent", + base_dir, master_port); + _putenv(file_path); + #else - snprintf(file_path,FN_REFLEN,"MYSQL_TEST_DIR=%s",mysql_test_dir); - putenv(file_path); - snprintf(file_path, FN_REFLEN*2, - "MYSQL_DUMP=%s/mysqldump --no-defaults -u root --port=%u --socket=%s", - bin_dir, master_port, master_socket); - putenv(file_path); - snprintf(file_path, FN_REFLEN*2, - "MYSQL_BINLOG=%s/mysqlbinlog --no-defaults --local-load=%s", - bin_dir, mysql_tmp_dir); - putenv(file_path); + { + static char env_MYSQL_TEST_DIR[FN_REFLEN*2]; + static char env_MYSQL_DUMP[FN_REFLEN*2]; + static char env_MYSQL_BINLOG[FN_REFLEN*2]; + static char env_MASTER_MYSOCK[FN_REFLEN*2]; + static char env_TESTS_BINDIR[FN_REFLEN*2]; + static char env_CHARSETSDIR[FN_REFLEN*2]; + static char env_MYSQL[FN_REFLEN*2]; + static char env_MYSQL_FIX_SYSTEM_TABLES[FN_REFLEN*2]; + static char env_CLIENT_BINDIR[FN_REFLEN*2]; + static char env_MYSQL_CLIENT_TEST[FN_REFLEN*2]; + static char env_NDB_TOOLS_DIR[FN_REFLEN*2]; + static char env_NDB_MGM[FN_REFLEN*2]; + static char env_NDB_BACKUP_DIR[FN_REFLEN*2]; + static char env_NDB_TOOLS_OUTPUT[FN_REFLEN*2]; + + snprintf(env_MYSQL_TEST_DIR,FN_REFLEN*2, + "MYSQL_TEST_DIR=%s",mysql_test_dir); + putenv(env_MYSQL_TEST_DIR); + + snprintf(env_MYSQL_DUMP, FN_REFLEN*2,"MYSQL_DUMP=%s/mysqldump --no-defaults " + "-uroot --port=%u --socket=%s ", + bin_dir, master_port, master_socket); + putenv(env_MYSQL_DUMP); + + snprintf(env_MYSQL_BINLOG, FN_REFLEN*2, + "MYSQL_BINLOG=%s/mysqlbinlog --no-defaults --local-load=%s -uroot ", + bin_dir, mysql_tmp_dir); + putenv(env_MYSQL_BINLOG); + + snprintf(env_MASTER_MYSOCK, FN_REFLEN*2, + "MASTER_MYSOCK=%s", master_socket); + putenv(env_MASTER_MYSOCK); + + snprintf(env_TESTS_BINDIR, FN_REFLEN*2, + "TESTS_BINDIR=%s/tests", base_dir); + putenv(env_TESTS_BINDIR); + + snprintf(env_CHARSETSDIR, FN_REFLEN*2, + "CHARSETSDIR=%s/sql/share/charsets", base_dir); + putenv(env_CHARSETSDIR); + + snprintf(env_MYSQL, FN_REFLEN*2, + "MYSQL=%s/mysql --port=%u --socket=%s -uroot ", + bin_dir, master_port, master_socket); + putenv(env_MYSQL); + + snprintf(env_MYSQL_FIX_SYSTEM_TABLES, FN_REFLEN*2, + "MYSQL_FIX_SYSTEM_TABLES=%s/scripts/mysql_fix_privilege_tables --no-defaults " + "--host=localhost --port=%u --socket=%s " + "--basedir=%s --bindir=%s --verbose -uroot ", + base_dir,master_port, master_socket, base_dir, bin_dir); + putenv(env_MYSQL_FIX_SYSTEM_TABLES); + + + snprintf(env_CLIENT_BINDIR, FN_REFLEN*2, + "CLIENT_BINDIR=%s", bin_dir); + putenv(env_CLIENT_BINDIR); + + snprintf(env_MYSQL_CLIENT_TEST, FN_REFLEN*2, + "MYSQL_CLIENT_TEST=%s/tests/mysql_client_test --no-defaults --testcase " + "--user=root --socket=%s --port=%u --silent", + base_dir, master_socket, master_port); + putenv(env_MYSQL_CLIENT_TEST); + + // NDB + + snprintf(env_NDB_TOOLS_DIR, FN_REFLEN*2, + "NDB_TOOLS_DIR=%s/ndb/tools", base_dir); + putenv(env_NDB_TOOLS_DIR); + + snprintf(env_NDB_MGM, FN_REFLEN*2, + "NDB_MGM=%s/ndb/src/mgmclient/ndb_mgm", base_dir); + putenv(env_NDB_MGM); + + //NDBCLUSTER_PORT=9350 + snprintf(env_NDB_BACKUP_DIR, FN_REFLEN*2, + "NDB_BACKUP_DIR=%s/var/ndbcluster-%i", mysql_test_dir, 9350); + putenv(env_NDB_BACKUP_DIR); + + snprintf(env_NDB_TOOLS_OUTPUT, FN_REFLEN*2, + "NDB_TOOLS_OUTPUT=%s/var/log/ndb_tools.log", mysql_test_dir); + putenv(env_NDB_TOOLS_OUTPUT); + + putenv((char *)"NDB_STATUS_OK=1"); + +// NDB_MGM="$BASEDIR/ndb/src/mgmclient/ndb_mgm" +// NDB_BACKUP_DIR=$MYSQL_TEST_DIR/var/ndbcluster-$NDBCLUSTER_PORT +// NDB_TOOLS_OUTPUT=$MYSQL_TEST_DIR/var/log/ndb_tools.log + } + #endif #ifndef __WIN__ putenv((char *)"MASTER_MYPORT=9306"); putenv((char *)"SLAVE_MYPORT=9307"); putenv((char *)"MYSQL_TCP_PORT=3306"); + #else _putenv("MASTER_MYPORT=9306"); _putenv("SLAVE_MYPORT=9307"); @@ -1468,8 +1627,13 @@ int main(int argc, char **argv) char **testes= 0; int name_index; int index; + char var_dir[FN_REFLEN]; /* setup */ setup(argv[0]); + + /* delete all file in var */ + snprintf(var_dir,FN_REFLEN,"%s/var",mysql_test_dir); + del_tree(var_dir); /* The --ignore option is comma saperated list of test cases to skip and @@ -1484,7 +1648,8 @@ int main(int argc, char **argv) { char *temp, *token; temp= strdup(strchr(argv[1],'=') + 1); - for (token=str_tok(temp, ","); token != NULL; token=str_tok(NULL, ",")) + for (token=str_tok(argument, temp, ","); token != NULL; + token=str_tok(argument, NULL, ",")) { if (strlen(ignore_test) + strlen(token) + 2 <= FN_REFLEN-1) sprintf(ignore_test+strlen(ignore_test), " %s ", token); @@ -1508,7 +1673,7 @@ int main(int argc, char **argv) /* install test databases */ mysql_install_db(); - + mlog("Starting Tests...\n"); mlog("\n"); @@ -1671,105 +1836,70 @@ Arguments: Output: return the null terminated token of NULL. */ - -char *str_tok(char *string, const char *delim) +char *str_tok(char* dest, char *string, const char *delim) { - char *token; /* current token received from strtok */ - char *qt_token; /* token delimeted by the matching pair of quote */ - /* - if there are any quote chars found in the token then this variable - will hold the concatenated string to return to the caller - */ - char *ptr_token=NULL; - /* pointer to the quote character in the token from strtok */ - char *ptr_quote=NULL; + char *token; + char *ptr_end_token= NULL; + char *ptr_quote= NULL; + char *ptr_token= NULL; + int count_quotes= 0; - /* See if the delimeter contains any quote character */ + *dest = '\0'; if (strchr(delim,'\'') || strchr(delim,'\"')) return NULL; - /* repeate till we are getting some token from strtok */ - while ((token= (char*)strtok(string, delim) ) != NULL) + token= (char*)strtok(string, delim); + if (token) { - /* - make the input string NULL so that next time onward strtok can - be called with NULL input string. - */ - string= NULL; - /* We don't need to remove any quote character for Windows version */ + /* double quote is found */ + if (strchr(token,'\"')) + { + do + { + if (count_quotes & 1) + { + if (*dest == '\0') + sprintf(dest,"%s", ptr_token); + else + sprintf(dest,"%s %s", dest, ptr_token); + ptr_token= (char*)strtok(NULL, delim); + if (!ptr_token) + break; + } + else + { + ptr_token= token; + } + if (ptr_quote = strchr(ptr_token,'\"')) + { + ptr_end_token= ptr_token + strlen(ptr_token); + do + { #ifndef __WIN__ - /* check if the current token contain double quote character*/ - if ((ptr_quote= (char*)strchr(token,'\"')) != NULL) - { - /* - get the matching the matching double quote in the remaining - input string - */ - qt_token= (char*)strtok(NULL,"\""); - } - /* check if the current token contain single quote character*/ - else if ((ptr_quote= (char*)strchr(token,'\'')) != NULL) - { - /* - get the matching the matching single quote in the remaining - input string - */ - qt_token= (char*)strtok(NULL,"\'"); - } + bmove(ptr_quote, ptr_quote+1, ptr_end_token - ptr_quote); #endif - /* - if the current token does not contains any quote character then - return to the caller. - */ - if (ptr_quote == NULL) - { - /* - if there is any earlier token i.e. ptr_token then append the - current token in it and return it else return the current - token directly - */ - return ptr_token ? strcat(ptr_token,token) : token; - } - - /* - remove the quote character i.e. make NULL so that the token will - be devided in two part and later both part can be concatenated - and hence quote will be removed - */ - *ptr_quote= 0; - - /* check if ptr_token has been initialized or not */ - if (ptr_token == NULL) - { - /* initialize the ptr_token with current token */ - ptr_token= token; - /* copy entire string between matching pair of quote*/ - sprintf(ptr_token+strlen(ptr_token),"%s %s", ptr_quote+1, qt_token); + count_quotes++; + } while (ptr_quote != NULL && (ptr_quote = strchr(ptr_quote+1,'\"'))); + } + /* there are unpair quotes we have to search next quote*/ + } while (count_quotes & 1); + if (ptr_token != NULL) + { + if (*dest == '\0') + sprintf(dest,"%s", ptr_token); + else + sprintf(dest,"%s %s",dest,ptr_token); + } } else { - /* - copy the current token and entire string between matching pair - of quote - */ - if (qt_token == NULL) - { - sprintf(ptr_token+strlen(ptr_token),"%s%s", token, ptr_quote+1); - } - else - { - sprintf(ptr_token+strlen(ptr_token),"%s%s %s", token, ptr_quote+1, - qt_token ); - } + sprintf(dest,"%s",token); } } - - /* return the concatenated token */ - return ptr_token; + return token ? dest : NULL; } #ifndef __WIN__ - /* Synopsis: This function run scripts files on Linux and Netware diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 4c70e72bdfb..4268b121b1d 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -7,7 +7,7 @@ select 9223372036854775807,-009223372036854775808; 9223372036854775807 -9223372036854775808 select +9999999999999999999,-9999999999999999999; 9999999999999999999 -9999999999999999999 -9999999999999999999 -10000000000000000000 +9999999999999999999 -9999999999999999999 select cast(9223372036854775808 as unsigned)+1; cast(9223372036854775808 as unsigned)+1 9223372036854775809 @@ -16,7 +16,7 @@ select 9223372036854775808+1; 9223372036854775809 select -(0-3),round(-(0-3)), round(9999999999999999999); -(0-3) round(-(0-3)) round(9999999999999999999) -3 3 10000000000000000000 +3 3 9999999999999999999 create table t1 (a bigint unsigned not null, primary key(a)); insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612); select * from t1; diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 1f2d60fb79a..1ca913e1259 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -91,7 +91,10 @@ CASE WHEN 1 THEN 'a' ELSE 1.0 END AS c5, CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6, CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7, CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8, -CASE WHEN 1 THEN 1.0 END AS c9 +CASE WHEN 1 THEN 1.0 END AS c9, +CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10, +CASE WHEN 1 THEN 0.1e1 else 1 END AS c11, +CASE WHEN 1 THEN 0.1e1 else '1' END AS c12 ; SHOW CREATE TABLE t1; Table Create Table @@ -100,11 +103,14 @@ 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(3) NOT NULL default '', - `c6` varbinary(3) NOT NULL default '', - `c7` double(3,1) NOT NULL default '0.0', - `c8` double(3,1) NOT NULL default '0.0', - `c9` double(3,1) default NULL + `c5` varbinary(4) NOT NULL default '', + `c6` varbinary(4) NOT NULL default '', + `c7` decimal(5,1) NOT NULL default '0.0', + `c8` decimal(5,1) NOT NULL default '0.0', + `c9` decimal(5,1) default NULL, + `c10` double NOT NULL default '0', + `c11` double NOT NULL default '0', + `c12` varbinary(5) NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; SELECT CASE @@ -146,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)` double(3,1) NOT NULL default '0.0', + `COALESCE(1.0)` decimal(5,1) NOT NULL default '0.0', `COALESCE('a')` varchar(1) NOT NULL default '', - `COALESCE(1,1.0)` double(3,1) NOT NULL default '0.0', + `COALESCE(1,1.0)` decimal(5,1) NOT NULL default '0.0', `COALESCE(1,'1')` varbinary(1) NOT NULL default '', - `COALESCE(1.1,'1')` varbinary(3) NOT NULL default '', + `COALESCE(1.1,'1')` varbinary(4) 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/client_xml.result b/mysql-test/r/client_xml.result new file mode 100644 index 00000000000..a4164148159 --- /dev/null +++ b/mysql-test/r/client_xml.result @@ -0,0 +1,74 @@ +create table t1 ( +`a&b` int, +`ab` text +); +insert into t1 values (1, 2, 'a&b ab'); + + + + + 1 + 2 + a&b a<b a>b + + + + + + + + + + + + + 1 + 2 + a&b a<b a>b + + + + + + + + + 1 + + + + + + + 1 + + + + + + + 0 + + + + + + + 1 + + + + + + + NULL + + +drop table t1; diff --git a/mysql-test/r/compare.result b/mysql-test/r/compare.result index bf8a5106044..6f667aabac0 100644 --- a/mysql-test/r/compare.result +++ b/mysql-test/r/compare.result @@ -36,3 +36,9 @@ hex(a) STRCMP(a,'a') STRCMP(a,'a ') 6109 -1 -1 61 0 0 DROP TABLE t1; +SELECT CHAR(31) = '', '' = CHAR(31); +CHAR(31) = '' '' = CHAR(31) +0 0 +SELECT CHAR(30) = '', '' = CHAR(30); +CHAR(30) = '' '' = CHAR(30) +0 0 diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 05d1ba026ba..1c378f88e5c 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -103,9 +103,9 @@ Field Type Null Key Default Extra a datetime NO 0000-00-00 00:00:00 b time NO 00:00:00 c date NO 0000-00-00 -d bigint(17) NO 0 -e double(18,1) NO 0.0 -f bigint(17) NO 0 +d int(2) NO 0 +e decimal(6,1) NO 0.0 +f bigint(18) NO 0 drop table t2; create table t2 select CAST("2001-12-29" AS DATE) as d, CAST("20:45:11" AS TIME) as t, CAST("2001-12-29 20:45:11" AS DATETIME) as dt; describe t2; @@ -418,7 +418,7 @@ d date YES NULL e varchar(1) NO f datetime YES NULL g time YES NULL -h longblob NO +h varbinary(23) NO dd time YES NULL select * from t2; a b c d e f g h dd @@ -437,7 +437,7 @@ t2 CREATE TABLE `t2` ( `ifnull(e,e)` bigint(20) default NULL, `ifnull(f,f)` float(3,2) default NULL, `ifnull(g,g)` double(4,3) default NULL, - `ifnull(h,h)` decimal(5,4) default NULL, + `ifnull(h,h)` decimal(6,4) default NULL, `ifnull(i,i)` year(4) default NULL, `ifnull(j,j)` date default NULL, `ifnull(k,k)` datetime NOT NULL default '0000-00-00 00:00:00', diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index a6ca59fc62b..fe2d76c8ab3 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -526,13 +526,14 @@ insert into t2 values (@v); show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 User var 1 135 @`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci -master-bin.000001 135 Query 1 218 use `test`; insert into t2 values (@v) +master-bin.000001 135 Query 1 225 use `test`; insert into t2 values (@v) /*!40019 SET @@session.max_insert_delayed_threads=0*/; SET @`v`:=_ucs2 0x006100620063 COLLATE `ucs2_general_ci`; use test; SET TIMESTAMP=10000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t2 values (@v); drop table t2; set names latin1; diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index da2bb9081de..071cb673501 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -330,6 +330,15 @@ SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MA min max avg 10.00 10.00 10 DROP TABLE t1; +create table t1 (a integer, b integer); +insert into t1 values (1,4), (2,2),(2,2), (4,1),(4,1),(4,1),(4,1); +select distinct sum(b) from t1 group by a; +sum(b) +4 +select distinct sum(b) from (select a,b from t1) y group by a; +sum(b) +4 +drop table t1; CREATE TABLE t1 (a char(10), b char(10)); INSERT INTO t1 VALUES ('root','localhost'), ('root','%'); SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 1e1d6f96eb7..177994b488d 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -462,5 +462,5 @@ rout int(11) default '0' INSERT INTO t1 VALUES ('1',1,0); SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; html prod -1 0.00 +1 0.00000 drop table t1; diff --git a/mysql-test/r/drop_temp_table.result b/mysql-test/r/drop_temp_table.result index 34c08f08788..163fc845e88 100644 --- a/mysql-test/r/drop_temp_table.result +++ b/mysql-test/r/drop_temp_table.result @@ -1,7 +1,9 @@ reset master; create database `drop-temp+table-test`; use `drop-temp+table-test`; +create temporary table shortn1 (a int); create temporary table `table:name` (a int); +create temporary table shortn2 (a int); select get_lock("a",10); get_lock("a",10) 1 @@ -10,9 +12,13 @@ get_lock("a",10) 1 show binlog events; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 206 create database `drop-temp+table-test` -master-bin.000001 206 Query 1 322 use `drop-temp+table-test`; create temporary table `table:name` (a int) -master-bin.000001 322 Query 1 473 use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`table:name` -master-bin.000001 473 Query 1 566 use `drop-temp+table-test`; DO RELEASE_LOCK("a") +master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4 +master-bin.000001 # Query 1 # create database `drop-temp+table-test` +master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn1 (a int) +master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table `table:name` (a int) +master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn2 (a int) +master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2` +master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`table:name` +master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn1` +master-bin.000001 # Query 1 # use `drop-temp+table-test`; DO RELEASE_LOCK("a") drop database `drop-temp+table-test`; diff --git a/mysql-test/r/func_equal.result b/mysql-test/r/func_equal.result index 352b76f2744..fe5e5b1b371 100644 --- a/mysql-test/r/func_equal.result +++ b/mysql-test/r/func_equal.result @@ -1,7 +1,7 @@ drop table if exists t1,t2; -select 0<=>0,0.0<=>0.0,"A"<=>"A",NULL<=>NULL; -0<=>0 0.0<=>0.0 "A"<=>"A" NULL<=>NULL -1 1 1 1 +select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL; +0<=>0 0.0<=>0.0 0E0=0E0 "A"<=>"A" NULL<=>NULL +1 1 1 1 1 select 1<=>0,0<=>NULL,NULL<=>0; 1<=>0 0<=>NULL NULL<=>0 0 0 0 @@ -11,6 +11,12 @@ select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0; select "A"<=>"B","A"<=>NULL,NULL<=>"A"; "A"<=>"B" "A"<=>NULL NULL<=>"A" 0 0 0 +select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1; +0<=>0.0 0.0<=>0E0 0E0<=>"0" 10.0<=>1E1 10<=>10.0 10<=>1E1 +1 1 1 1 1 1 +select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0; +1.0<=>0E1 10<=>NULL NULL<=>0.0 NULL<=>0E0 +0 0 0 0 create table t1 (id int, value int); create table t2 (id int, value int); insert into t1 values (1,null); diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index df95193043e..fdadd378ceb 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -737,3 +737,15 @@ one 2 two 2 three 1 drop table t1; +create table t1(f1 datetime); +insert into t1 values (now()); +create table t2 select f2 from (select max(now()) f2 from t1) a; +show columns from t2; +Field Type Null Key Default Extra +f2 datetime NO 0000-00-00 00:00:00 +drop table t2; +create table t2 select f2 from (select now() f2 from t1) a; +show columns from t2; +Field Type Null Key Default Extra +f2 datetime NO 0000-00-00 00:00:00 +drop table t2, t1; diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 5a9f0f68228..2d464c891bf 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -28,3 +28,24 @@ length(format('nan', 2)) > 0 select concat("$",format(2500,2)); concat("$",format(2500,2)) $2,500.00 +create table t1 ( a timestamp ); +insert into t1 values ( '2004-01-06 12:34' ); +select a from t1 where left(a+0,6) in ( left(20040106,6) ); +a +2004-01-06 12:34:00 +select a from t1 where left(a+0,6) = ( left(20040106,6) ); +a +2004-01-06 12:34:00 +select a from t1 where right(a+0,6) in ( right(20040106123400,6) ); +a +2004-01-06 12:34:00 +select a from t1 where right(a+0,6) = ( right(20040106123400,6) ); +a +2004-01-06 12:34:00 +select a from t1 where mid(a+0,6,3) in ( mid(20040106123400,6,3) ); +a +2004-01-06 12:34:00 +select a from t1 where mid(a+0,6,3) = ( mid(20040106123400,6,3) ); +a +2004-01-06 12:34:00 +drop table t1; diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index 6cd975b0911..5f89fe7b727 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -1,6 +1,6 @@ select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; 1+1 1-1 1+1*2 8/5 8%5 mod(8,5) mod(8,5)|0 -(1+1)*-2 -2 0 3 1.60 3 3 3 4 +2 0 3 1.60000 3 3 3 4 explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; 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 diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 1f78e5098f8..71a1a7539b0 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -328,6 +328,19 @@ trim(trailing 'foo' from 'foo') select trim(leading 'foo' from 'foo'); trim(leading 'foo' from 'foo') +select quote(ltrim(concat(' ', 'a'))); +quote(ltrim(concat(' ', 'a'))) +'a' +select quote(trim(concat(' ', 'a'))); +quote(trim(concat(' ', 'a'))) +'a' +CREATE TABLE t1 SELECT 1 UNION SELECT 2 UNION SELECT 3; +SELECT QUOTE('A') FROM t1; +QUOTE('A') +'A' +'A' +'A' +DROP TABLE t1; select 1=_latin1'1'; 1=_latin1'1' 1 @@ -694,12 +707,6 @@ select count(*) as total, left(c,10) as reg from t1 group by reg order by reg de total reg 10 2004-12-10 drop table t1; -select quote(ltrim(concat(' ', 'a'))); -quote(ltrim(concat(' ', 'a'))) -'a' -select quote(trim(concat(' ', 'a'))); -quote(trim(concat(' ', 'a'))) -'a' select trim(null from 'kate') as "must_be_null"; must_be_null NULL @@ -712,3 +719,26 @@ NULL select trim(trailing NULL from 'xyz') as "must_be_null"; must_be_null NULL +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +a bigint(20) unsigned default NULL, +PRIMARY KEY (id) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES +('0','16307858876001849059'); +SELECT CONV('e251273eb74a8ee3', 16, 10); +CONV('e251273eb74a8ee3', 16, 10) +16307858876001849059 +EXPLAIN +SELECT id +FROM t1 +WHERE a = 16307858876001849059; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +EXPLAIN +SELECT id +FROM t1 +WHERE a = CONV('e251273eb74a8ee3', 16, 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +DROP TABLE t1; diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index 2815500b33e..32883921e70 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -183,3 +183,13 @@ select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3; select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3; 5 mod 3 5 mod -3 -5 mod 3 -5 mod -3 2 2 -2 -2 +create table t1 (a int, b int); +insert into t1 values (1,2), (2,3), (3,4), (4,5); +select * from t1 where a not between 1 and 2; +a b +3 4 +4 5 +select * from t1 where a not between 1 and 2 and b not between 3 and 4; +a b +4 5 +drop table t1; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 18e4cb7a434..24740442821 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -440,12 +440,12 @@ create table t2 (user_id integer not null, date date); insert into t2 values (1, '2002-06-09'),(2, '2002-06-09'),(1, '2002-06-09'),(3, '2002-06-09'),(4, '2002-06-09'),(4, '2002-06-09'); select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender; gender dist_count percentage -F 3 60.00 -M 1 20.00 +F 3 60.00000 +M 1 20.00000 select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender order by percentage; gender dist_count percentage -M 1 20.00 -F 3 60.00 +M 1 20.00000 +F 3 60.00000 drop table t1,t2; CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID )); @@ -629,15 +629,6 @@ explain SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort DROP TABLE t1; -create table t1 ( col1 int, col2 int ); -insert into t1 values (1,1),(1,2),(1,3),(2,1),(2,2); -select group_concat( distinct col1 ) as alias from t1 -group by col2 having alias like '%'; -alias -1,2 -1,2 -1 -drop table t1; create table t1 (a int); insert into t1 values(null); select min(a) is null from t1; @@ -650,3 +641,39 @@ select 1 and min(a) is null from t1; 1 and min(a) is null 1 drop table t1; +create table t1 ( col1 int, col2 int ); +insert into t1 values (1,1),(1,2),(1,3),(2,1),(2,2); +select group_concat( distinct col1 ) as alias from t1 +group by col2 having alias like '%'; +alias +1,2 +1,2 +1 +drop table t1; +create table t1 (a integer, b integer, c integer); +insert into t1 (a,b) values (1,2),(1,3),(2,5); +select a, 0.1*0+1 r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2=1; +a r2 r1 +1 1.0 2 +select a, rand()*0+1 r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2=1; +a r2 r1 +1 1 2 +select a,sum(b) from t1 where a=1 group by c; +a sum(b) +1 5 +select a*sum(b) from t1 where a=1 group by c; +a*sum(b) +5 +select sum(a)*sum(b) from t1 where a=1 group by c; +sum(a)*sum(b) +10 +select a,sum(b) from t1 where a=1 group by c having a=1; +a sum(b) +1 5 +select a as d,sum(b) from t1 where a=1 group by c having d=1; +d sum(b) +1 5 +select sum(a)*sum(b) as d from t1 where a=1 group by c having d > 0; +d +10 +drop table t1; diff --git a/mysql-test/r/have_cp932.require b/mysql-test/r/have_cp932.require new file mode 100644 index 00000000000..988d720ed2c --- /dev/null +++ b/mysql-test/r/have_cp932.require @@ -0,0 +1,2 @@ +Collation Charset Id Default Compiled Sortlen +cp932_japanese_ci cp932 95 Yes Yes 1 diff --git a/mysql-test/r/have_eucjpms.require b/mysql-test/r/have_eucjpms.require new file mode 100644 index 00000000000..f35621b2c1a --- /dev/null +++ b/mysql-test/r/have_eucjpms.require @@ -0,0 +1,2 @@ +Collation Charset Id Default Compiled Sortlen +eucjpms_japanese_ci eucjpms 97 Yes Yes 1 diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result index 0f217b7b8ab..693cc63ba9e 100644 --- a/mysql-test/r/index_merge.result +++ b/mysql-test/r/index_merge.result @@ -371,11 +371,11 @@ alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(20 update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B -where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) -and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); +where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7or16 = 1 or A.key8=1) +and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7or16 = 1 or B.key8=1); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where -1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where +1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL 7or16 Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where +1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL 7or16 Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 4c6be698749..52e2a4046cf 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -69,9 +69,11 @@ id select_type table type possible_keys key key_len ref rows Extra select pk from t1 where key2 = 1 and key1 = 1; pk 26 +27 select pk from t1 ignore index(key1,key2) where key2 = 1 and key1 = 1; pk 26 +27 drop table t1; create table t1 ( pk int primary key auto_increment, diff --git a/mysql-test/r/index_merge_ror_cpk.result b/mysql-test/r/index_merge_ror_cpk.result index c344cef5db9..6cfeb20b2de 100644 --- a/mysql-test/r/index_merge_ror_cpk.result +++ b/mysql-test/r/index_merge_ror_cpk.result @@ -56,7 +56,7 @@ pk1 pk2 95 59 explain select * from t1 where badkey=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1 key1 4 const 101 Using where +1 SIMPLE t1 ref key1 key1 4 const 100 Using where explain select * from t1 where pk1 < 7500 and key1 = 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge PRIMARY,key1 key1,PRIMARY 4,4 NULL 38 Using intersect(key1,PRIMARY); Using where @@ -74,13 +74,13 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge PRIMARY,key1,pktail2ok pktail2ok,key1 8,4 NULL 199 Using sort_union(pktail2ok,key1); Using where explain select * from t1 where pktail3bad=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1,pktail3bad pktail3bad 4 const ROWS Using where +1 SIMPLE t1 ref key1,pktail3bad key1 4 const 100 Using where explain select * from t1 where pktail4bad=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1,pktail4bad pktail4bad 4 const 99 Using where +1 SIMPLE t1 ref key1,pktail4bad key1 4 const 100 Using where explain select * from t1 where pktail5bad=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1,pktail5bad pktail5bad 4 const 99 Using where +1 SIMPLE t1 ref key1,pktail5bad key1 4 const 100 Using where explain select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge key1,key2 key1,key2 4,4 NULL 1 Using intersect(key1,key2); Using where; Using index diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index eed3132c195..9bf21e9f061 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1,6 +1,6 @@ -show variables variable_name where variable_name like "skip_show_database"; -variable_name -skip_show_database +show variables where variable_name like "skip_show_database"; +Variable_name Value +skip_show_database OFF grant all privileges on test.* to mysqltest_1@localhost; select * from information_schema.SCHEMATA where schema_name > 'm'; CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH @@ -11,11 +11,6 @@ schema_name information_schema mysql test -show databases *; -CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH -NULL information_schema utf8 NULL -NULL mysql latin1 NULL -NULL test latin1 NULL show databases like 't%'; Database (t%) test @@ -24,11 +19,8 @@ Database information_schema mysql test -show databases * where schema_name like 't%'; -CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH -NULL test latin1 NULL -show databases * where schema_name = 't%'; -CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH +show databases where `database` = 't%'; +Database create database testtets; create table testtets.t1(a int, b VARCHAR(30), KEY string_data (b)); create table test.t2(a int); @@ -116,20 +108,13 @@ t4 select * from information_schema.STATISTICS where TABLE_SCHEMA = "testtets"; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT NULL testtets t1 1 testtets string_data 1 b A NULL NULL NULL YES BTREE -show keys * from t3 where TABLE_SCHEMA Like "test%"; -TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT -NULL test t3 1 test a_data 1 a A NULL NULL NULL YES BTREE -show keys from t3 where INDEX_NAME = "a_data"; +show keys from t3 where Key_name = "a_data"; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t3 1 a_data 1 a A NULL NULL NULL YES BTREE show tables like 't%'; Tables_in_test (t%) t2 t3 -show tables * from test where table_name like 't%'; -TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE -NULL test t2 -NULL test t3 show table status; 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 t2 MyISAM 9 Fixed 0 0 0 21474836479 1024 0 NULL # # NULL latin1_swedish_ci NULL @@ -148,10 +133,9 @@ select * from information_schema.COLUMNS where table_name="t1" and column_name= "a"; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT NULL testtets t1 a 1 NULL YES int 11 11 11 0 NULL NULL int(11) select,insert,update,references -show columns * from testtets.t1 where table_name = "t1"; -TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT -NULL testtets t1 a 1 NULL YES int 11 11 11 0 NULL NULL int(11) select,insert,update,references -NULL testtets t1 b 2 NULL YES varchar 30 30 NULL NULL latin1 latin1_swedish_ci varchar(30) MUL select,insert,update,references +show columns from testtets.t1 where field like "%a%"; +Field Type Null Key Default Extra +a int(11) YES NULL drop view v1; drop tables testtets.t4, testtets.t1, t2, t3; drop database testtets; @@ -162,18 +146,9 @@ latin1 latin1_swedish_ci ISO 8859-1 West European 1 SHOW CHARACTER SET LIKE 'latin1%'; Charset Description Default collation Maxlen latin1 ISO 8859-1 West European latin1_swedish_ci 1 -SHOW CHARACTER SET * LIKE 'latin1%'; -CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN -latin1 latin1_swedish_ci ISO 8859-1 West European 1 -SHOW CHARACTER SET WHERE CHARACTER_SET_NAME like 'latin1%'; +SHOW CHARACTER SET WHERE charset like 'latin1%'; Charset Description Default collation Maxlen latin1 ISO 8859-1 West European latin1_swedish_ci 1 -SHOW CHARACTER SET CHARACTER_SET_NAME WHERE CHARACTER_SET_NAME like 'latin1%'; -CHARACTER_SET_NAME -latin1 -SHOW CHARACTER SET * WHERE CHARACTER_SET_NAME like 'latin1%'; -CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN -latin1 latin1_swedish_ci ISO 8859-1 West European 1 select * from information_schema.COLLATIONS where COLLATION_NAME like 'latin1%'; COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN @@ -195,17 +170,7 @@ latin1_bin latin1 47 Yes 1 latin1_general_ci latin1 48 0 latin1_general_cs latin1 49 0 latin1_spanish_ci latin1 94 0 -SHOW COLLATION * LIKE 'latin1%'; -COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN -latin1_german1_ci latin1 5 0 -latin1_swedish_ci latin1 8 Yes Yes 1 -latin1_danish_ci latin1 15 0 -latin1_german2_ci latin1 31 Yes 2 -latin1_bin latin1 47 Yes 1 -latin1_general_ci latin1 48 0 -latin1_general_cs latin1 49 0 -latin1_spanish_ci latin1 94 0 -SHOW COLLATION WHERE COLLATION_NAME like 'latin1%'; +SHOW COLLATION WHERE collation like 'latin1%'; Collation Charset Id Default Compiled Sortlen latin1_german1_ci latin1 5 0 latin1_swedish_ci latin1 8 Yes Yes 1 @@ -215,26 +180,6 @@ latin1_bin latin1 47 Yes 1 latin1_general_ci latin1 48 0 latin1_general_cs latin1 49 0 latin1_spanish_ci latin1 94 0 -SHOW COLLATION COLLATION_NAME WHERE COLLATION_NAME like 'latin1%'; -COLLATION_NAME -latin1_german1_ci -latin1_swedish_ci -latin1_danish_ci -latin1_german2_ci -latin1_bin -latin1_general_ci -latin1_general_cs -latin1_spanish_ci -SHOW COLLATION * WHERE COLLATION_NAME like 'latin1%'; -COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN -latin1_german1_ci latin1 5 0 -latin1_swedish_ci latin1 8 Yes Yes 1 -latin1_danish_ci latin1 15 0 -latin1_german2_ci latin1 31 Yes 2 -latin1_bin latin1 47 Yes 1 -latin1_general_ci latin1 48 0 -latin1_general_cs latin1 49 0 -latin1_spanish_ci latin1 94 0 select * from information_schema.COLLATION_CHARACTER_SET_APPLICABILITY where COLLATION_NAME like 'latin1%'; COLLATION_NAME CHARACTER_SET_NAME @@ -435,26 +380,6 @@ delete from mysql.db where user='joe'; delete from mysql.tables_priv where user='joe'; delete from mysql.columns_priv where user='joe'; flush privileges; -create procedure px5 () -begin -declare v int; -declare c cursor for select version from -information_schema.tables where table_schema <> 'information_schema'; -open c; -fetch c into v; -select v; -close c; -end;// -call px5()// -v -9 -call px5()// -v -9 -select sql_mode from information_schema.ROUTINES; -sql_mode - -drop procedure px5; create table t1 (a int not null auto_increment,b int, primary key (a)); insert into t1 values (1,1),(NULL,3),(NULL,4); select AUTO_INCREMENT from information_schema.tables where table_name = 't1'; @@ -671,14 +596,11 @@ BASE TABLE show open tables where `table` like "user"; Database Table In_use Name_locked mysql user 0 0 -show status variable_name where variable_name like "%database%"; -variable_name -Com_show_databases -show variables variable_name where variable_name like "%database%"; -variable_name -character_set_database -collation_database -skip_show_database +show status where variable_name like "%database%"; +Variable_name Value +Com_show_databases 0 +show variables where variable_name like "skip_show_databas"; +Variable_name Value show global status like "Threads_running"; Variable_name Value Threads_running 1 diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 8d1c4e3fc90..5928688ca81 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -249,6 +249,30 @@ n 4 5 6 +set autocommit=0; +begin; +savepoint `my_savepoint`; +insert into t1 values (7); +savepoint `savept2`; +insert into t1 values (3); +select n from t1; +n +3 +4 +5 +6 +7 +rollback to savepoint `savept2`; +release savepoint `my_savepoint`; +select n from t1; +n +4 +5 +6 +7 +rollback to savepoint `my_savepoint`; +ERROR HY000: Got error 153 during ROLLBACK +set autocommit=1; rollback; drop table t1; create table t1 (n int not null primary key) engine=innodb; @@ -1609,14 +1633,14 @@ t2 CREATE TABLE `t2` ( drop table t2, t1; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 24 +Binlog_cache_use 25 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 0 create table t1 (a int) engine=innodb; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 25 +Binlog_cache_use 26 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 1 @@ -1625,7 +1649,7 @@ delete from t1; commit; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 26 +Binlog_cache_use 27 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 1 @@ -1693,10 +1717,10 @@ Variable_name Value Innodb_rows_deleted 2070 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 31706 +Innodb_rows_inserted 31708 show status like "Innodb_rows_read"; Variable_name Value -Innodb_rows_read 80153 +Innodb_rows_read 80162 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 29530 diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 8882b95f2d8..611c6f2712e 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -75,7 +75,7 @@ ERROR 23000: Duplicate entry '2' for key 1 show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 183 use `test`; insert into t1 select * from t2 +master-bin.000001 95 Query 1 190 use `test`; insert into t1 select * from t2 select * from t1; a 1 diff --git a/mysql-test/r/insert_select.result.es b/mysql-test/r/insert_select.result.es index 9e11402733d..9cac6d31b8f 100644 --- a/mysql-test/r/insert_select.result.es +++ b/mysql-test/r/insert_select.result.es @@ -633,3 +633,15 @@ No Field Count 0 1 100 0 2 100 drop table t1, t2; +CREATE TABLE t1 ( +ID int(11) NOT NULL auto_increment, +NO int(11) NOT NULL default '0', +SEQ int(11) NOT NULL default '0', +PRIMARY KEY (ID), +KEY t1$NO (SEQ,NO) +) ENGINE=MyISAM; +INSERT INTO t1 (SEQ, NO) SELECT "1" AS SEQ, IF(MAX(NO) IS NULL, 0, MAX(NO)) + 1 AS NO FROM t1 WHERE (SEQ = 1); +select SQL_BUFFER_RESULT * from t1 WHERE (SEQ = 1); +ID NO SEQ +1 1 1 +drop table t1; diff --git a/mysql-test/r/limit.result b/mysql-test/r/limit.result index c82105e6a49..6a3d2bffab0 100644 --- a/mysql-test/r/limit.result +++ b/mysql-test/r/limit.result @@ -67,3 +67,12 @@ SELECT * FROM t1; id id2 3 0 DROP TABLE t1; +create table t1 (a integer); +insert into t1 values (1); +select 1 as a from t1 union all select 1 from dual limit 1; +a +1 +(select 1 as a from t1) union all (select 1 from dual) limit 1; +a +1 +drop table t1; diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result index 429bc5ed352..db2842061b4 100644 --- a/mysql-test/r/lock.result +++ b/mysql-test/r/lock.result @@ -41,8 +41,8 @@ lock tables t1 write; check table t2; Table Op Msg_type Msg_text test.t2 check error Table 't2' was not locked with LOCK TABLES -insert into t1 select nr from t1; -ERROR HY000: Table 't1' was not locked with LOCK TABLES +insert into t1 select index1,nr from t1; +ERROR 42000: INSERT command denied to user 'root'@'localhost' for column 'index1' in table 't1' unlock tables; lock tables t1 write, t1 as t1_alias read; insert into t1 select index1,nr from t1 as t1_alias; diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 48c09f369b3..6a2cf466cfa 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 Name Type Length Max length Is_null Flags Decimals Charsetnr def 1 8 1 1 N 32897 0 63 -def 1.0 5 3 3 N 32897 1 63 +def 1.0 246 4 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 @@ -18,7 +18,7 @@ def test t1 t1 d d 3 11 0 Y 32768 0 63 def test t1 t1 e e 8 20 0 Y 32768 0 63 def test t1 t1 f f 4 3 0 Y 32768 2 63 def test t1 t1 g g 5 4 0 Y 32768 3 63 -def test t1 t1 h h 0 7 0 Y 32768 4 63 +def test t1 t1 h h 246 5 0 Y 0 4 63 def test t1 t1 i i 13 4 0 Y 32864 0 63 def test t1 t1 j j 10 10 0 Y 128 0 63 def test t1 t1 k k 7 19 0 N 1249 0 63 diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index abcb451df65..96a2ac551a9 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -9,9 +9,9 @@ commit; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(1) -master-bin.000001 238 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 326 Query 1 # use `test`; COMMIT +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(1) +master-bin.000001 252 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 347 Query 1 # use `test`; COMMIT delete from t1; delete from t2; reset master; @@ -24,9 +24,9 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(2) -master-bin.000001 238 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 326 Query 1 # use `test`; ROLLBACK +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(2) +master-bin.000001 252 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 347 Query 1 # use `test`; ROLLBACK delete from t1; delete from t2; reset master; @@ -42,12 +42,12 @@ commit; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(3) -master-bin.000001 238 Query 1 # use `test`; savepoint my_savepoint -master-bin.000001 317 Query 1 # use `test`; insert into t1 values(4) -master-bin.000001 398 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 486 Query 1 # use `test`; rollback to savepoint my_savepoint -master-bin.000001 577 Query 1 # use `test`; COMMIT +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(3) +master-bin.000001 252 Query 1 # use `test`; savepoint my_savepoint +master-bin.000001 338 Query 1 # use `test`; insert into t1 values(4) +master-bin.000001 426 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 521 Query 1 # use `test`; rollback to savepoint my_savepoint +master-bin.000001 619 Query 1 # use `test`; COMMIT delete from t1; delete from t2; reset master; @@ -68,13 +68,13 @@ a show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(5) -master-bin.000001 238 Query 1 # use `test`; savepoint my_savepoint -master-bin.000001 317 Query 1 # use `test`; insert into t1 values(6) -master-bin.000001 398 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 486 Query 1 # use `test`; rollback to savepoint my_savepoint -master-bin.000001 577 Query 1 # use `test`; insert into t1 values(7) -master-bin.000001 658 Query 1 # use `test`; COMMIT +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(5) +master-bin.000001 252 Query 1 # use `test`; savepoint my_savepoint +master-bin.000001 338 Query 1 # use `test`; insert into t1 values(6) +master-bin.000001 426 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 521 Query 1 # use `test`; rollback to savepoint my_savepoint +master-bin.000001 619 Query 1 # use `test`; insert into t1 values(7) +master-bin.000001 707 Query 1 # use `test`; COMMIT delete from t1; delete from t2; reset master; @@ -90,9 +90,9 @@ get_lock("a",10) show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(8) -master-bin.000001 238 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 326 Query 1 # use `test`; ROLLBACK +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(8) +master-bin.000001 252 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 347 Query 1 # use `test`; ROLLBACK delete from t1; delete from t2; reset master; @@ -101,7 +101,7 @@ insert into t2 select * from t1; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; insert into t1 values(9) -master-bin.000001 176 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 183 Query 1 # use `test`; insert into t2 select * from t1 delete from t1; delete from t2; reset master; @@ -111,16 +111,16 @@ insert into t2 select * from t1; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; insert into t1 values(10) -master-bin.000001 177 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 184 Query 1 # use `test`; insert into t2 select * from t1 insert into t1 values(11); commit; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; insert into t1 values(10) -master-bin.000001 177 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 265 Query 1 # use `test`; BEGIN -master-bin.000001 327 Query 1 # use `test`; insert into t1 values(11) -master-bin.000001 409 Query 1 # use `test`; COMMIT +master-bin.000001 184 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 279 Query 1 # use `test`; BEGIN +master-bin.000001 348 Query 1 # use `test`; insert into t1 values(11) +master-bin.000001 437 Query 1 # use `test`; COMMIT alter table t2 engine=INNODB; delete from t1; delete from t2; @@ -132,9 +132,9 @@ commit; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(12) -master-bin.000001 239 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 327 Query 1 # use `test`; COMMIT +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(12) +master-bin.000001 253 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 348 Query 1 # use `test`; COMMIT delete from t1; delete from t2; reset master; @@ -157,8 +157,8 @@ commit; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(14) -master-bin.000001 239 Query 1 # use `test`; COMMIT +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(14) +master-bin.000001 253 Query 1 # use `test`; COMMIT delete from t1; delete from t2; reset master; @@ -177,9 +177,9 @@ a show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 Query 1 # use `test`; BEGIN -master-bin.000001 157 Query 1 # use `test`; insert into t1 values(16) -master-bin.000001 239 Query 1 # use `test`; insert into t1 values(18) -master-bin.000001 321 Query 1 # use `test`; COMMIT +master-bin.000001 164 Query 1 # use `test`; insert into t1 values(16) +master-bin.000001 253 Query 1 # use `test`; insert into t1 values(18) +master-bin.000001 342 Query 1 # use `test`; COMMIT delete from t1; delete from t2; alter table t2 type=MyISAM; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index c18588d90a7..33fddabf232 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -19,6 +19,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; drop table if exists t1,t2; SET TIMESTAMP=1000000000; create table t1 (word varchar(20)); @@ -41,6 +42,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); --- --database -- @@ -53,6 +55,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); --- Remote -- @@ -61,6 +64,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; drop table if exists t1,t2; SET TIMESTAMP=1000000000; create table t1 (word varchar(20)); @@ -83,6 +87,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); --- --database -- @@ -95,5 +100,6 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); drop table t1, t2; diff --git a/mysql-test/r/mysqlbinlog2.result b/mysql-test/r/mysqlbinlog2.result index 9fe4edf7b82..805c25be086 100644 --- a/mysql-test/r/mysqlbinlog2.result +++ b/mysql-test/r/mysqlbinlog2.result @@ -20,6 +20,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -44,6 +45,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; @@ -60,10 +62,12 @@ insert into t1 values(null, "e"); --- start-position -- /*!40019 SET @@session.max_insert_delayed_threads=0*/; +SET INSERT_ID=4; use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; @@ -75,6 +79,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -85,7 +90,6 @@ insert into t1 values(null, "b"); SET INSERT_ID=3; SET TIMESTAMP=1579609944; insert into t1 values(null, "c"); -SET INSERT_ID=4; --- start-datetime -- /*!40019 SET @@session.max_insert_delayed_threads=0*/; @@ -94,6 +98,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; SET TIMESTAMP=1579609946; @@ -108,6 +113,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -122,6 +128,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -143,6 +150,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- offset -- @@ -152,6 +160,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; @@ -170,14 +179,17 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- start-position -- /*!40019 SET @@session.max_insert_delayed_threads=0*/; +SET INSERT_ID=4; use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; @@ -187,6 +199,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- stop-position -- @@ -195,6 +208,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -220,6 +234,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; SET TIMESTAMP=1579609946; @@ -232,6 +247,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- stop-datetime -- @@ -240,6 +256,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -254,6 +271,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -278,6 +296,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; @@ -294,10 +313,12 @@ insert into t1 values(null, "e"); --- start-position -- /*!40019 SET @@session.max_insert_delayed_threads=0*/; +SET INSERT_ID=4; use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; @@ -309,6 +330,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -319,7 +341,6 @@ insert into t1 values(null, "b"); SET INSERT_ID=3; SET TIMESTAMP=1579609944; insert into t1 values(null, "c"); -SET INSERT_ID=4; --- start-datetime -- /*!40019 SET @@session.max_insert_delayed_threads=0*/; @@ -328,6 +349,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; SET TIMESTAMP=1579609946; @@ -342,6 +364,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -356,6 +379,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -377,6 +401,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- offset -- @@ -386,6 +411,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; SET TIMESTAMP=1579609942; @@ -404,14 +430,17 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- start-position -- /*!40019 SET @@session.max_insert_delayed_threads=0*/; +SET INSERT_ID=4; use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; SET TIMESTAMP=1579609946; @@ -421,6 +450,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- stop-position -- @@ -429,6 +459,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -454,6 +485,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; SET TIMESTAMP=1579609946; @@ -466,6 +498,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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"); --- stop-datetime -- @@ -474,6 +507,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; @@ -488,6 +522,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; SET TIMESTAMP=1579609942; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index cea0733766e..9f08fae4964 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -19,13 +19,13 @@ INSERT INTO t1 VALUES (1), (2); DROP TABLE t1; -CREATE TABLE t1 (a decimal(240, 20)); +CREATE TABLE t1 (a decimal(64, 20)); INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); CREATE TABLE `t1` ( - `a` decimal(240,20) default NULL + `a` decimal(64,20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('0987654321098765432109876543210987654321.00000000000000000000'); +INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('987654321098765432109876543210987654321.00000000000000000000'); DROP TABLE t1; CREATE TABLE t1 (a double); INSERT INTO t1 VALUES ('-9e999999'); @@ -63,7 +63,7 @@ INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456) /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, @@ -86,7 +86,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, `b` float default NULL @@ -152,7 +152,7 @@ INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'), (NULL); /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` varchar(255) default NULL @@ -178,7 +178,7 @@ CREATE TABLE t1 (a int) ENGINE=MYISAM; INSERT INTO t1 VALUES (1), (2); /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL40' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -197,7 +197,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -228,7 +228,7 @@ create table t1(a int); /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -249,7 +249,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; DROP TABLE IF EXISTS "t1"; CREATE TABLE "t1" ( "a" int(11) default NULL @@ -273,7 +273,7 @@ set global sql_mode='ANSI_QUOTES'; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -294,7 +294,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; DROP TABLE IF EXISTS "t1"; CREATE TABLE "t1" ( "a" int(11) default NULL @@ -319,7 +319,7 @@ 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 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -344,7 +344,7 @@ create view v1 as select * from t1; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` int(11) default NULL @@ -375,7 +375,7 @@ drop table t1; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; @@ -396,7 +396,7 @@ create database mysqldump_test_db character set latin2 collate latin2_bin; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CHARACTER SET latin2 COLLATE latin2_bin */; @@ -419,7 +419,7 @@ INSERT INTO t1 VALUES (_latin1 ' /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -441,7 +441,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -460,7 +460,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -479,7 +479,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -498,7 +498,7 @@ UNLOCK TABLES; /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `a` char(10) default NULL @@ -527,7 +527,7 @@ INSERT INTO t2 VALUES (4),(5),(6); /*!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" */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; DROP TABLE IF EXISTS `t2`; CREATE TABLE `t2` ( `a` int(11) default NULL diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result index 6ec5338acbe..e1aa045d16e 100644 --- a/mysql-test/r/ndb_basic.result +++ b/mysql-test/r/ndb_basic.result @@ -573,3 +573,37 @@ select * from t1 where a12345678901234567890123456789a1234567890=2; a1234567890123456789012345678901234567890 a12345678901234567890123456789a1234567890 5 2 drop table t1; +create table t1 +(a bigint, b bigint, c bigint, d bigint, +primary key (a,b,c,d)) +engine=ndb +max_rows=800000000; +Warnings: +Warning 1105 Ndb might have problems storing the max amount of rows specified +insert into t1 values +(1,2,3,4),(2,3,4,5),(3,4,5,6), +(3,2,3,4),(1,3,4,5),(2,4,5,6), +(1,2,3,5),(2,3,4,8),(3,4,5,9), +(3,2,3,5),(1,3,4,8),(2,4,5,9), +(1,2,3,6),(2,3,4,6),(3,4,5,7), +(3,2,3,6),(1,3,4,6),(2,4,5,7), +(1,2,3,7),(2,3,4,7),(3,4,5,8), +(3,2,3,7),(1,3,4,7),(2,4,5,8), +(1,3,3,4),(2,4,4,5),(3,5,5,6), +(3,3,3,4),(1,4,4,5),(2,5,5,6), +(1,3,3,5),(2,4,4,8),(3,5,5,9), +(3,3,3,5),(1,4,4,8),(2,5,5,9), +(1,3,3,6),(2,4,4,6),(3,5,5,7), +(3,3,3,6),(1,4,4,6),(2,5,5,7), +(1,3,3,7),(2,4,4,7),(3,5,5,8), +(3,3,3,7),(1,4,4,7),(2,5,5,8); +select count(*) from t1; +count(*) +48 +drop table t1; +create table t1 +(a bigint, b bigint, c bigint, d bigint, +primary key (a)) +engine=ndb +max_rows=1; +drop table t1; diff --git a/mysql-test/r/ndb_cache.result b/mysql-test/r/ndb_cache.result index 714e1831267..478663b1aa1 100644 --- a/mysql-test/r/ndb_cache.result +++ b/mysql-test/r/ndb_cache.result @@ -1,43 +1,191 @@ +drop table if exists t1; +set GLOBAL query_cache_type=on; set GLOBAL query_cache_size=1355776; reset query cache; flush status; -drop table if exists t1,t2; -CREATE TABLE t1 (a int) ENGINE=ndbcluster; -CREATE TABLE t2 (a int); +CREATE TABLE t1 ( pk int not null primary key, +a int, b int not null, c varchar(20)) ENGINE=ndbcluster; +insert into t1 value (1, 2, 3, 'First row'); select * from t1; -a +pk a b c +1 2 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from t1; +pk a b c +1 2 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +update t1 set a=3 where pk=1; +select * from t1; +pk a b c +1 3 3 First row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +insert into t1 value (2, 7, 8, 'Second row'); +insert into t1 value (4, 5, 6, 'Fourth row'); +select * from t1 order by pk; +pk a b c +1 3 3 First row +2 7 8 Second row +4 5 6 Fourth row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +select * from t1 order by pk; +pk a b c +1 3 3 First row +2 7 8 Second row +4 5 6 Fourth row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +delete from t1 where c='Fourth row'; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +use test; +select * from t1 order by pk; +pk a b c +1 3 3 First row +2 7 8 Second row +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +update t1 set a=4 where b=3; +use test; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 7 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 5 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 7 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +begin; +update t1 set a=5 where pk=1; show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 0 +Qcache_inserts 7 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 0 -select * from t2; -a +Qcache_hits 7 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 1 +Qcache_inserts 8 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 0 -select * from t1; -a -select * from t2; -a +Qcache_hits 7 +commit; show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 1 +Qcache_inserts 8 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 1 -drop table t1, t2; +Qcache_hits 7 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 5 3 First row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 9 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 5 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 9 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +drop table t1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 SET GLOBAL query_cache_size=0; diff --git a/mysql-test/r/ndb_cache2.result b/mysql-test/r/ndb_cache2.result new file mode 100644 index 00000000000..de4b3e31874 --- /dev/null +++ b/mysql-test/r/ndb_cache2.result @@ -0,0 +1,193 @@ +drop table if exists t1; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +set GLOBAL ndb_cache_check_time=5; +reset query cache; +flush status; +CREATE TABLE t1 ( pk int not null primary key, +a int, b int not null, c varchar(20)) ENGINE=ndbcluster; +insert into t1 value (1, 2, 3, 'First row'); +select * from t1; +pk a b c +1 2 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from t1; +pk a b c +1 2 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +update t1 set a=3 where pk=1; +select * from t1; +pk a b c +1 3 3 First row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +insert into t1 value (2, 7, 8, 'Second row'); +insert into t1 value (4, 5, 6, 'Fourth row'); +select * from t1 order by pk desc; +pk a b c +4 5 6 Fourth row +2 7 8 Second row +1 3 3 First row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +select * from t1 order by pk desc; +pk a b c +4 5 6 Fourth row +2 7 8 Second row +1 3 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +delete from t1 where c='Fourth row'; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +use test; +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 3 3 First row +select * from t1 where b=3; +pk a b c +1 3 3 First row +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +update t1 set a=4 where b=3; +use test; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 7 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 5 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 7 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +begin; +update t1 set a=5 where pk=1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 7 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 4 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 8 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +commit; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 8 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 5 3 First row +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 9 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +select * from t1 order by pk desc; +pk a b c +2 7 8 Second row +1 5 3 First row +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 9 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +drop table t1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +SET GLOBAL query_cache_size=0; +SET GLOBAL ndb_cache_check_time=0; diff --git a/mysql-test/r/ndb_cache_multi.result b/mysql-test/r/ndb_cache_multi.result new file mode 100644 index 00000000000..c7135ed9e8a --- /dev/null +++ b/mysql-test/r/ndb_cache_multi.result @@ -0,0 +1,72 @@ +drop table if exists t1, t2; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +reset query cache; +flush status; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +reset query cache; +flush status; +create table t1 (a int) engine=ndbcluster; +create table t2 (a int) engine=ndbcluster; +insert into t1 value (2); +insert into t2 value (3); +select * from t1; +a +2 +select * from t2; +a +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from t1; +a +2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +update t1 set a=3 where a=2; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from t1; +a +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +drop table t1, t2; diff --git a/mysql-test/r/ndb_cache_multi2.result b/mysql-test/r/ndb_cache_multi2.result new file mode 100644 index 00000000000..6e435c071b5 --- /dev/null +++ b/mysql-test/r/ndb_cache_multi2.result @@ -0,0 +1,74 @@ +drop table if exists t1, t2; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +set GLOBAL ndb_cache_check_time=1; +reset query cache; +flush status; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +set GLOBAL ndb_cache_check_time=1; +reset query cache; +flush status; +create table t1 (a int) engine=ndbcluster; +create table t2 (a int) engine=ndbcluster; +insert into t1 value (2); +insert into t2 value (3); +select * from t1; +a +2 +select * from t2; +a +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from t1; +a +2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +update t1 set a=3 where a=2; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from t1; +a +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +drop table t1, t2; diff --git a/mysql-test/r/ndb_index_unique.result b/mysql-test/r/ndb_index_unique.result index 598b9dcccf7..517d09ddf29 100644 --- a/mysql-test/r/ndb_index_unique.result +++ b/mysql-test/r/ndb_index_unique.result @@ -1,4 +1,4 @@ -drop table if exists t1, t2, t3, t4, t5, t6, t7; +drop table if exists t1, t2, t3, t4, t5, t6, t7, t8; CREATE TABLE t1 ( a int unsigned NOT NULL PRIMARY KEY, b int unsigned not null, diff --git a/mysql-test/r/ndb_multi.result b/mysql-test/r/ndb_multi.result new file mode 100644 index 00000000000..4a2389cd1ff --- /dev/null +++ b/mysql-test/r/ndb_multi.result @@ -0,0 +1,49 @@ +drop table if exists t1, t2, t3, t4; +flush status; +create table t1 (a int) engine=ndbcluster; +create table t2 (a int) engine=ndbcluster; +insert into t1 value (2); +insert into t2 value (3); +select * from t1; +a +2 +select * from t2; +a +3 +show status like 'handler_discover%'; +Variable_name Value +Handler_discover 0 +flush status; +select * from t1; +a +2 +update t1 set a=3 where a=2; +show status like 'handler_discover%'; +Variable_name Value +Handler_discover 1 +create table t3 (a int not null primary key, b varchar(22), +c int, last_col text) engine=ndb; +insert into t3 values(1, 'Hi!', 89, 'Longtext column'); +create table t4 (pk int primary key, b int) engine=ndb; +select * from t1; +a +3 +select * from t3; +a b c last_col +1 Hi! 89 Longtext column +show status like 'handler_discover%'; +Variable_name Value +Handler_discover 1 +show tables like 't4'; +Tables_in_test (t4) +t4 +show status like 'handler_discover%'; +Variable_name Value +Handler_discover 2 +show tables; +Tables_in_test +t1 +t2 +t3 +t4 +drop table t1, t2, t3, t4; diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index f398c69a424..a04fa75082f 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -164,48 +164,48 @@ product country_id year sum(profit) NULL NULL NULL 7785 select concat(product,':',country_id) as 'prod', concat(":",year,":") as 'year',1+1, sum(profit)/count(*) from t1 group by 1,2 with rollup; prod year 1+1 sum(profit)/count(*) -Calculator:1 :1999: 2 50.00 -Calculator:1 :2000: 2 75.00 -Calculator:1 NULL 2 62.50 -Calculator:2 :2000: 2 75.00 -Calculator:2 NULL 2 75.00 -Computer:1 :1999: 2 1350.00 -Computer:1 :2000: 2 1500.00 -Computer:1 NULL 2 1400.00 -Computer:2 :2000: 2 1350.00 -Computer:2 NULL 2 1350.00 -Phone:3 :2003: 2 10.00 -Phone:3 NULL 2 10.00 -TV:1 :1999: 2 125.00 -TV:1 :2000: 2 150.00 -TV:1 NULL 2 133.33 -TV:2 :2000: 2 100.00 -TV:2 NULL 2 100.00 -NULL NULL 2 519.00 +Calculator:1 :1999: 2 50.00000 +Calculator:1 :2000: 2 75.00000 +Calculator:1 NULL 2 62.50000 +Calculator:2 :2000: 2 75.00000 +Calculator:2 NULL 2 75.00000 +Computer:1 :1999: 2 1350.00000 +Computer:1 :2000: 2 1500.00000 +Computer:1 NULL 2 1400.00000 +Computer:2 :2000: 2 1350.00000 +Computer:2 NULL 2 1350.00000 +Phone:3 :2003: 2 10.00000 +Phone:3 NULL 2 10.00000 +TV:1 :1999: 2 125.00000 +TV:1 :2000: 2 150.00000 +TV:1 NULL 2 133.33333 +TV:2 :2000: 2 100.00000 +TV:2 NULL 2 100.00000 +NULL NULL 2 519.00000 select product, sum(profit)/count(*) from t1 group by product with rollup; product sum(profit)/count(*) -Calculator 68.75 -Computer 1380.00 -Phone 10.00 -TV 120.00 -NULL 519.00 +Calculator 68.75000 +Computer 1380.00000 +Phone 10.00000 +TV 120.00000 +NULL 519.00000 select left(product,4) as prod, sum(profit)/count(*) from t1 group by prod with rollup; prod sum(profit)/count(*) -Calc 68.75 -Comp 1380.00 -Phon 10.00 -TV 120.00 -NULL 519.00 +Calc 68.75000 +Comp 1380.00000 +Phon 10.00000 +TV 120.00000 +NULL 519.00000 select concat(product,':',country_id), 1+1, sum(profit)/count(*) from t1 group by concat(product,':',country_id) with rollup; concat(product,':',country_id) 1+1 sum(profit)/count(*) -Calculator:1 2 62.50 -Calculator:2 2 75.00 -Computer:1 2 1400.00 -Computer:2 2 1350.00 -Phone:3 2 10.00 -TV:1 2 133.33 -TV:2 2 100.00 -NULL 2 519.00 +Calculator:1 2 62.50000 +Calculator:2 2 75.00000 +Computer:1 2 1400.00000 +Computer:2 2 1350.00000 +Phone:3 2 10.00000 +TV:1 2 133.33333 +TV:2 2 100.00000 +NULL 2 519.00000 select product, country , year, sum(profit) from t1,t2 where t1.country_id=t2.country_id group by product, country, year with rollup; product country year sum(profit) Calculator India 2000 150 diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index c65d11330ea..153121f0662 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -264,6 +264,18 @@ prepare stmt4 from ' show tables from test like ''t2%'' '; execute stmt4; Tables_in_test (t2%) t2 +prepare stmt4 from ' show columns from t2 where field in (select ?) '; +SET @arg00="a"; +execute stmt4 using @arg00; +Field Type Null Key Default Extra +a int(11) NO PRI +SET @arg00="b"; +execute stmt4 using @arg00; +Field Type Null Key Default Extra +b char(10) YES NULL +SET @arg00=1; +execute stmt4 using @arg00; +Field Type Null Key Default Extra prepare stmt4 from ' show columns from t2 from test like ''a%'' '; execute stmt4; Field Type Null Key Default Extra @@ -281,7 +293,7 @@ t2 MyISAM 9 Fixed 0 0 0 64424509439 1024 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show table status from test like ''t9%'' '; execute stmt4; 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 -t9 MyISAM 10 Dynamic 2 220 440 4294967295 2048 0 NULL # # # latin1_swedish_ci NULL +t9 MyISAM 10 Dynamic 2 216 432 4294967295 2048 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show status like ''Threads_running'' '; execute stmt4; Variable_name Value diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 50a74dfad63..78436b69ec7 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1772,8 +1772,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1794,7 +1794,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1802,9 +1802,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name 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 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1824,13 +1824,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1922,8 +1922,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1945,7 +1945,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1969,8 +1969,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2019,8 +2019,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2042,7 +2042,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2059,8 +2059,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2107,8 +2107,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2130,7 +2130,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2151,8 +2151,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2197,8 +2197,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2220,7 +2220,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2235,8 +2235,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2584,7 +2584,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2607,7 +2607,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2666,6 +2666,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2678,7 +2679,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2703,7 +2704,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2716,6 +2717,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2813,10 +2815,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 209a22e4a9e..e5db53e1c18 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1755,8 +1755,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1777,7 +1777,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1785,9 +1785,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name 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 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1807,13 +1807,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1905,8 +1905,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1928,7 +1928,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1952,8 +1952,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2002,8 +2002,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2025,7 +2025,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2042,8 +2042,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2090,8 +2090,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2113,7 +2113,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2134,8 +2134,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2180,8 +2180,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2203,7 +2203,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2218,8 +2218,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2567,7 +2567,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2590,7 +2590,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2649,6 +2649,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2661,7 +2662,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2686,7 +2687,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2699,6 +2700,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2796,10 +2798,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index f0be4d119bc..ad02de1110c 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -60,8 +60,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1756,8 +1756,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1778,7 +1778,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1786,9 +1786,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name 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 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1808,13 +1808,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1906,8 +1906,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1929,7 +1929,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1953,8 +1953,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2003,8 +2003,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2026,7 +2026,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2043,8 +2043,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2091,8 +2091,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2114,7 +2114,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2135,8 +2135,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2181,8 +2181,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2204,7 +2204,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2219,8 +2219,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2568,7 +2568,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2591,7 +2591,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2650,6 +2650,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2662,7 +2663,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2687,7 +2688,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2700,6 +2701,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2797,10 +2799,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50 50 50 50 50 50 50 50 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52 52 52 52 52 52 52 52 -53 5 53 53 53 53 53 53 53 53 53 53 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54 54 54 54 54 54 54 54 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56 56 56 56 56 56 56 56 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index a62d00c71c0..374f6142c44 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -102,8 +102,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1692,8 +1692,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1714,7 +1714,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1722,9 +1722,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name 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 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1744,13 +1744,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1842,8 +1842,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1865,7 +1865,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1889,8 +1889,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1939,8 +1939,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1962,7 +1962,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -1979,8 +1979,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2027,8 +2027,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2050,7 +2050,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2071,8 +2071,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2117,8 +2117,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2140,7 +2140,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2155,8 +2155,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2504,7 +2504,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2527,7 +2527,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2586,6 +2586,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2598,7 +2599,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2623,7 +2624,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2636,6 +2637,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2733,10 +2735,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 @@ -3111,8 +3113,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -4701,8 +4703,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -4723,7 +4725,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -4731,9 +4733,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name 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 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -4753,13 +4755,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -4851,8 +4853,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -4874,7 +4876,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -4898,8 +4900,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -4948,8 +4950,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -4971,7 +4973,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -4988,8 +4990,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5036,8 +5038,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5059,7 +5061,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -5080,8 +5082,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5126,8 +5128,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5149,7 +5151,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -5164,8 +5166,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5513,7 +5515,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5536,7 +5538,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5595,6 +5597,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -5607,7 +5610,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5632,7 +5635,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5645,6 +5648,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -5742,10 +5746,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index 9a922d75cdc..bf7ef64d052 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1755,8 +1755,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1777,7 +1777,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1785,9 +1785,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name 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 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1807,13 +1807,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1905,8 +1905,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1928,7 +1928,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1952,8 +1952,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2002,8 +2002,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2025,7 +2025,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2042,8 +2042,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2090,8 +2090,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2113,7 +2113,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2134,8 +2134,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2180,8 +2180,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2203,7 +2203,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2218,8 +2218,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2567,7 +2567,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2590,7 +2590,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2661,7 +2661,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2674,6 +2674,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 1 @@ -2686,7 +2687,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2724,6 +2725,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -1 @@ -2796,10 +2798,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 5047160bf75..4f6a62004d2 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -2674,6 +2674,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 1 @@ -2724,6 +2725,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -1 diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index 76d6fa13766..40a31563604 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -14,6 +14,8 @@ row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')); row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')) 1 +Warnings: +Error 1366 Incorrect decimal value: '' for column '' at row -1 select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)); row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)) 1 diff --git a/mysql-test/r/rpl_change_master.result b/mysql-test/r/rpl_change_master.result index 40bcc4100a8..5fbf4cc3318 100644 --- a/mysql-test/r/rpl_change_master.result +++ b/mysql-test/r/rpl_change_master.result @@ -16,11 +16,11 @@ n 1 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_MYPORT 1 master-bin.000001 355 # # master-bin.000001 No No 0 0 274 # None 0 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 376 # # master-bin.000001 No No 0 0 288 # None 0 No # change master to master_user='root'; 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_MYPORT 1 master-bin.000001 274 # # master-bin.000001 No No 0 0 274 # None 0 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 288 # # master-bin.000001 No No 0 0 288 # None 0 No # select release_lock("a"); release_lock("a") 1 diff --git a/mysql-test/r/rpl_charset.result b/mysql-test/r/rpl_charset.result index 0224bd6dba2..6b8a2ac70de 100644 --- a/mysql-test/r/rpl_charset.result +++ b/mysql-test/r/rpl_charset.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +set timestamp=1000000000; drop database if exists mysqltest2; drop database if exists mysqltest3; create database mysqltest2 character set latin2; @@ -87,7 +88,6 @@ a b 2 Muffler 3 latin1_german2_ci 4 Müller -load data infile '../../std_data/words.dat' into table t1 (b); set @a= _cp850 'Müller' collate cp850_general_ci; truncate table t1; insert into t1 (b) values(collation(@a)); @@ -108,63 +108,39 @@ Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # drop database if exists mysqltest2 master-bin.000001 # Query 1 # drop database if exists mysqltest3 master-bin.000001 # Query 1 # create database mysqltest2 character set latin2 -master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=30 master-bin.000001 # Query 1 # create database mysqltest3 -master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=64 master-bin.000001 # Query 1 # drop database mysqltest3 -master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=64 master-bin.000001 # Query 1 # create database mysqltest3 -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Query 1 # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100)) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=1 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@character_set_server) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=2 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_server) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=3 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@character_set_client) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=4 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@character_set_connection) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=5 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_connection) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Query 1 # use `mysqltest2`; truncate table t1 -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=1 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_connection) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=2 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler")) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=3 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_connection) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=4 master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler")) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 -master-bin.000001 # Intvar 1 # INSERT_ID=74 -master-bin.000001 # Create_file 1 # db=mysqltest2;table=t1;file_id=1;block_len=581 -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 -master-bin.000001 # Intvar 1 # INSERT_ID=5 -master-bin.000001 # Exec_load 1 # ;file_id=1 -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Query 1 # use `mysqltest2`; truncate table t1 -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Intvar 1 # INSERT_ID=1 master-bin.000001 # User var 1 # @`a`=_cp850 0x4DFC6C6C6572 COLLATE cp850_general_ci master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(collation(@a)) -master-bin.000001 # Query 1 # use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Query 1 # drop database mysqltest2 -master-bin.000001 # Query 1 # SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 # Query 1 # drop database mysqltest3 set global character_set_server=latin2; -ERROR HY000: Binary logging and replication forbid changing the global server character set, collation +set global character_set_server=latin1; set global character_set_server=latin2; -ERROR HY000: Binary logging and replication forbid changing the global server character set, collation +set global character_set_server=latin1; set one_shot @@character_set_server=latin5; set @@max_join_size=1000; select @@character_set_server; @@ -198,12 +174,74 @@ CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -stop slave; -delete from t1; -change master to master_log_pos=6809; -start slave until master_log_file='master-bin.000001', master_log_pos=6967; -start slave; -select hex(c1), hex(c2) from t1; -hex(c1) hex(c2) -CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 +/*!40019 SET @@session.max_insert_delayed_threads=0*/; +SET TIMESTAMP=1000000000; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; +SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; +drop database if exists mysqltest2; +SET TIMESTAMP=1000000000; +drop database if exists mysqltest3; +SET TIMESTAMP=1000000000; +create database mysqltest2 character set latin2; +SET TIMESTAMP=1000000000; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30; +create database mysqltest3; +SET TIMESTAMP=1000000000; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=64; +drop database mysqltest3; +SET TIMESTAMP=1000000000; +create database mysqltest3; +use mysqltest2; +SET TIMESTAMP=1000000000; +create table t1 (a int auto_increment primary key, b varchar(100)); +SET INSERT_ID=1; +SET TIMESTAMP=1000000000; +SET @@session.character_set_client=4,@@session.collation_connection=27,@@session.collation_server=64; +insert into t1 (b) values(@@character_set_server); +SET INSERT_ID=2; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(@@collation_server); +SET INSERT_ID=3; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(@@character_set_client); +SET INSERT_ID=4; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(@@character_set_connection); +SET INSERT_ID=5; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(@@collation_connection); +SET TIMESTAMP=1000000000; +SET @@session.character_set_client=8,@@session.collation_connection=5,@@session.collation_server=64; +truncate table t1; +SET INSERT_ID=1; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(@@collation_connection); +SET INSERT_ID=2; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(LEAST("Müller","Muffler")); +SET INSERT_ID=3; +SET TIMESTAMP=1000000000; +SET @@session.character_set_client=8,@@session.collation_connection=31,@@session.collation_server=64; +insert into t1 (b) values(@@collation_connection); +SET INSERT_ID=4; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(LEAST("Müller","Muffler")); +SET TIMESTAMP=1000000000; +truncate table t1; +SET INSERT_ID=1; +SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`; +SET TIMESTAMP=1000000000; +insert into t1 (b) values(collation(@a)); +SET TIMESTAMP=1000000000; +drop database mysqltest2; +SET TIMESTAMP=1000000000; +drop database mysqltest3; +use test; +SET TIMESTAMP=1000000000; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30; +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 ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); drop table t1; diff --git a/mysql-test/r/rpl_error_ignored_table.result b/mysql-test/r/rpl_error_ignored_table.result index 19c8ee2e8c7..917fe103b43 100644 --- a/mysql-test/r/rpl_error_ignored_table.result +++ b/mysql-test/r/rpl_error_ignored_table.result @@ -9,7 +9,7 @@ insert into t1 values (1),(1); ERROR 23000: Duplicate entry '1' for key 1 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 273 # # master-bin.000001 Yes Yes test.t3,test.t1,test.t2 0 0 273 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 287 # # master-bin.000001 Yes Yes test.t3,test.t1,test.t2 0 0 287 # None 0 No # show tables like 't1'; Tables_in_test (t1) drop table t1; @@ -28,12 +28,12 @@ kill @id; drop table t2,t3; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 95 Query 1 187 use `test`; create table t1 (a int primary key) -master-bin.000001 187 Query 1 273 use `test`; insert into t1 values (1),(1) -master-bin.000001 273 Query 1 343 use `test`; drop table t1 -master-bin.000001 343 Query 1 435 use `test`; create table t2 (a int primary key) -master-bin.000001 435 Query 1 516 use `test`; insert into t2 values(1) -master-bin.000001 516 Query 1 597 use `test`; create table t3 (id int) -master-bin.000001 597 Query 1 692 use `test`; insert into t3 values(connection_id()) -master-bin.000001 692 Query 1 805 use `test`; update t2 set a = a + 1 + get_lock('crash_lock%20C', 10) -master-bin.000001 805 Query 1 878 use `test`; drop table t2,t3 +master-bin.000001 95 Query 1 194 use `test`; create table t1 (a int primary key) +master-bin.000001 194 Query 1 287 use `test`; insert into t1 values (1),(1) +master-bin.000001 287 Query 1 364 use `test`; drop table t1 +master-bin.000001 364 Query 1 463 use `test`; create table t2 (a int primary key) +master-bin.000001 463 Query 1 551 use `test`; insert into t2 values(1) +master-bin.000001 551 Query 1 639 use `test`; create table t3 (id int) +master-bin.000001 639 Query 1 741 use `test`; insert into t3 values(connection_id()) +master-bin.000001 741 Query 1 861 use `test`; update t2 set a = a + 1 + get_lock('crash_lock%20C', 10) +master-bin.000001 861 Query 1 941 use `test`; drop table t2,t3 diff --git a/mysql-test/r/rpl_flush_log_loop.result b/mysql-test/r/rpl_flush_log_loop.result index 4b73458386d..c57f6877516 100644 --- a/mysql-test/r/rpl_flush_log_loop.result +++ b/mysql-test/r/rpl_flush_log_loop.result @@ -14,4 +14,4 @@ start slave; flush logs; show slave status; 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 SLAVE_PORT 60 slave-bin.000001 199 # # slave-bin.000001 Yes Yes 0 0 199 # None 0 No # +# 127.0.0.1 root SLAVE_PORT 60 slave-bin.000001 206 # # slave-bin.000001 Yes Yes 0 0 206 # None 0 No # diff --git a/mysql-test/r/rpl_flush_tables.result b/mysql-test/r/rpl_flush_tables.result index ef785bc9850..241aada0e40 100644 --- a/mysql-test/r/rpl_flush_tables.result +++ b/mysql-test/r/rpl_flush_tables.result @@ -15,26 +15,26 @@ flush no_write_to_binlog tables; show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: SERVER_VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 175 use `test`; create table t1 (a int) -master-bin.000001 175 Query 1 258 use `test`; insert into t1 values (10) -master-bin.000001 258 Query 1 338 use `test`; create table t2 (a int) -master-bin.000001 338 Query 1 441 use `test`; create table t3 (a int) engine=merge union(t1) -master-bin.000001 441 Query 1 521 use `test`; create table t4 (a int) -master-bin.000001 521 Query 1 609 use `test`; insert into t4 select * from t3 -master-bin.000001 609 Query 1 697 use `test`; rename table t1 to t5, t2 to t1 +master-bin.000001 95 Query 1 182 use `test`; create table t1 (a int) +master-bin.000001 182 Query 1 272 use `test`; insert into t1 values (10) +master-bin.000001 272 Query 1 359 use `test`; create table t2 (a int) +master-bin.000001 359 Query 1 469 use `test`; create table t3 (a int) engine=merge union(t1) +master-bin.000001 469 Query 1 556 use `test`; create table t4 (a int) +master-bin.000001 556 Query 1 651 use `test`; insert into t4 select * from t3 +master-bin.000001 651 Query 1 746 use `test`; rename table t1 to t5, t2 to t1 select * from t3; a flush tables; show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: SERVER_VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 175 use `test`; create table t1 (a int) -master-bin.000001 175 Query 1 258 use `test`; insert into t1 values (10) -master-bin.000001 258 Query 1 338 use `test`; create table t2 (a int) -master-bin.000001 338 Query 1 441 use `test`; create table t3 (a int) engine=merge union(t1) -master-bin.000001 441 Query 1 521 use `test`; create table t4 (a int) -master-bin.000001 521 Query 1 609 use `test`; insert into t4 select * from t3 -master-bin.000001 609 Query 1 697 use `test`; rename table t1 to t5, t2 to t1 -master-bin.000001 697 Query 1 766 use `test`; flush tables +master-bin.000001 95 Query 1 182 use `test`; create table t1 (a int) +master-bin.000001 182 Query 1 272 use `test`; insert into t1 values (10) +master-bin.000001 272 Query 1 359 use `test`; create table t2 (a int) +master-bin.000001 359 Query 1 469 use `test`; create table t3 (a int) engine=merge union(t1) +master-bin.000001 469 Query 1 556 use `test`; create table t4 (a int) +master-bin.000001 556 Query 1 651 use `test`; insert into t4 select * from t3 +master-bin.000001 651 Query 1 746 use `test`; rename table t1 to t5, t2 to t1 +master-bin.000001 746 Query 1 822 use `test`; flush tables select * from t3; a diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index 72f7fb8bdbe..ccf77083362 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -22,7 +22,7 @@ day id category name 2003-03-22 2416 a bbbbb show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -slave-bin.000001 1068 +slave-bin.000001 1096 drop table t1; drop table t2; drop table t3; @@ -33,7 +33,7 @@ set global sql_slave_skip_counter=1; start slave; 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 1503 # # master-bin.000001 Yes Yes 0 0 1503 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1559 # # master-bin.000001 Yes Yes 0 0 1559 # None 0 No # set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -43,7 +43,7 @@ change master to master_user='test'; change master to master_user='root'; 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 1611 # # master-bin.000001 No No 0 0 1611 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1667 # # master-bin.000001 No No 0 0 1667 # None 0 No # set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; @@ -64,5 +64,5 @@ terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by ERROR 23000: Duplicate entry '2003-03-22' for key 1 show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 529 +master-bin.000001 536 drop table t2; diff --git a/mysql-test/r/rpl_loaddata_rule_m.result b/mysql-test/r/rpl_loaddata_rule_m.result index b241fc9ce0b..973f7eb6abc 100644 --- a/mysql-test/r/rpl_loaddata_rule_m.result +++ b/mysql-test/r/rpl_loaddata_rule_m.result @@ -12,6 +12,6 @@ use mysqltest; load data infile '../../std_data/rpl_loaddata.dat' into table test.t1; show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 95 Query 1 190 drop database if exists mysqltest -master-bin.000001 190 Query 1 277 create database mysqltest +master-bin.000001 95 Query 1 197 drop database if exists mysqltest +master-bin.000001 197 Query 1 291 create database mysqltest drop database mysqltest; diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 784742fdacb..f3827ad5c32 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -20,24 +20,24 @@ drop table t1; show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 210 use `test`; create table t1(n int not null auto_increment primary key) -master-bin.000001 210 Intvar 1 238 INSERT_ID=1 -master-bin.000001 238 Query 1 323 use `test`; insert into t1 values (NULL) -master-bin.000001 323 Query 1 393 use `test`; drop table t1 -master-bin.000001 393 Query 1 490 use `test`; create table t1 (word char(20) not null) -master-bin.000001 490 Create_file 1 1160 db=test;table=t1;file_id=1;block_len=581 -master-bin.000001 1160 Exec_load 1 1183 ;file_id=1 -master-bin.000001 1183 Query 1 1253 use `test`; drop table t1 +master-bin.000001 95 Query 1 217 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 217 Intvar 1 245 INSERT_ID=1 +master-bin.000001 245 Query 1 337 use `test`; insert into t1 values (NULL) +master-bin.000001 337 Query 1 414 use `test`; drop table t1 +master-bin.000001 414 Query 1 518 use `test`; create table t1 (word char(20) not null) +master-bin.000001 518 Create_file 1 1188 db=test;table=t1;file_id=1;block_len=581 +master-bin.000001 1188 Exec_load 1 1211 ;file_id=1 +master-bin.000001 1211 Query 1 1288 use `test`; drop table t1 show binlog events from 95 limit 1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 95 Query 1 210 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 95 Query 1 217 use `test`; create table t1(n int not null auto_increment primary key) show binlog events from 95 limit 2; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 95 Query 1 210 use `test`; create table t1(n int not null auto_increment primary key) -master-bin.000001 210 Intvar 1 238 INSERT_ID=1 +master-bin.000001 95 Query 1 217 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 217 Intvar 1 245 INSERT_ID=1 show binlog events from 95 limit 2,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 238 Query 1 323 use `test`; insert into t1 values (NULL) +master-bin.000001 245 Query 1 337 use `test`; insert into t1 values (NULL) flush logs; create table t5 (a int); drop table t5; @@ -50,23 +50,23 @@ drop table t1; show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 210 use `test`; create table t1(n int not null auto_increment primary key) -master-bin.000001 210 Intvar 1 238 INSERT_ID=1 -master-bin.000001 238 Query 1 323 use `test`; insert into t1 values (NULL) -master-bin.000001 323 Query 1 393 use `test`; drop table t1 -master-bin.000001 393 Query 1 490 use `test`; create table t1 (word char(20) not null) -master-bin.000001 490 Create_file 1 1160 db=test;table=t1;file_id=1;block_len=581 -master-bin.000001 1160 Exec_load 1 1183 ;file_id=1 -master-bin.000001 1183 Query 1 1253 use `test`; drop table t1 -master-bin.000001 1253 Rotate 1 1297 master-bin.000002;pos=4 +master-bin.000001 95 Query 1 217 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 217 Intvar 1 245 INSERT_ID=1 +master-bin.000001 245 Query 1 337 use `test`; insert into t1 values (NULL) +master-bin.000001 337 Query 1 414 use `test`; drop table t1 +master-bin.000001 414 Query 1 518 use `test`; create table t1 (word char(20) not null) +master-bin.000001 518 Create_file 1 1188 db=test;table=t1;file_id=1;block_len=581 +master-bin.000001 1188 Exec_load 1 1211 ;file_id=1 +master-bin.000001 1211 Query 1 1288 use `test`; drop table t1 +master-bin.000001 1288 Rotate 1 1332 master-bin.000002;pos=4 show binlog events in 'master-bin.000002'; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000002 95 Query 1 175 use `test`; create table t5 (a int) -master-bin.000002 175 Query 1 245 use `test`; drop table t5 -master-bin.000002 245 Query 1 325 use `test`; create table t1 (n int) -master-bin.000002 325 Query 1 407 use `test`; insert into t1 values (1) -master-bin.000002 407 Query 1 477 use `test`; drop table t1 +master-bin.000002 95 Query 1 182 use `test`; create table t5 (a int) +master-bin.000002 182 Query 1 259 use `test`; drop table t5 +master-bin.000002 259 Query 1 346 use `test`; create table t1 (n int) +master-bin.000002 346 Query 1 435 use `test`; insert into t1 values (1) +master-bin.000002 435 Query 1 512 use `test`; drop table t1 show binary logs; Log_name master-bin.000001 @@ -79,25 +79,25 @@ slave-bin.000002 show binlog events in 'slave-bin.000001' from 4; Log_name Pos Event_type Server_id End_log_pos Info slave-bin.000001 4 Format_desc 2 95 Server ver: VERSION, Binlog ver: 4 -slave-bin.000001 95 Query 1 210 use `test`; create table t1(n int not null auto_increment primary key) -slave-bin.000001 210 Intvar 1 238 INSERT_ID=1 -slave-bin.000001 238 Query 1 323 use `test`; insert into t1 values (NULL) -slave-bin.000001 323 Query 1 393 use `test`; drop table t1 -slave-bin.000001 393 Query 1 490 use `test`; create table t1 (word char(20) not null) -slave-bin.000001 490 Create_file 1 1169 db=test;table=t1;file_id=1;block_len=581 -slave-bin.000001 1169 Exec_load 1 1192 ;file_id=1 -slave-bin.000001 1192 Query 1 1262 use `test`; drop table t1 -slave-bin.000001 1262 Query 1 1342 use `test`; create table t5 (a int) -slave-bin.000001 1342 Query 1 1412 use `test`; drop table t5 -slave-bin.000001 1412 Rotate 2 1455 slave-bin.000002;pos=4 +slave-bin.000001 95 Query 1 217 use `test`; create table t1(n int not null auto_increment primary key) +slave-bin.000001 217 Intvar 1 245 INSERT_ID=1 +slave-bin.000001 245 Query 1 337 use `test`; insert into t1 values (NULL) +slave-bin.000001 337 Query 1 414 use `test`; drop table t1 +slave-bin.000001 414 Query 1 518 use `test`; create table t1 (word char(20) not null) +slave-bin.000001 518 Create_file 1 1197 db=test;table=t1;file_id=1;block_len=581 +slave-bin.000001 1197 Exec_load 1 1220 ;file_id=1 +slave-bin.000001 1220 Query 1 1297 use `test`; drop table t1 +slave-bin.000001 1297 Query 1 1384 use `test`; create table t5 (a int) +slave-bin.000001 1384 Query 1 1461 use `test`; drop table t5 +slave-bin.000001 1461 Rotate 2 1504 slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from 4; Log_name Pos Event_type Server_id End_log_pos Info slave-bin.000002 4 Format_desc 2 95 Server ver: VERSION, Binlog ver: 4 -slave-bin.000002 95 Query 1 175 use `test`; create table t1 (n int) -slave-bin.000002 175 Query 1 257 use `test`; insert into t1 values (1) -slave-bin.000002 257 Query 1 327 use `test`; drop table t1 +slave-bin.000002 95 Query 1 182 use `test`; create table t1 (n int) +slave-bin.000002 182 Query 1 271 use `test`; insert into t1 values (1) +slave-bin.000002 271 Query 1 348 use `test`; drop table t1 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.000002 477 # # master-bin.000002 Yes Yes 0 0 477 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 512 # # master-bin.000002 Yes Yes 0 0 512 # None 0 No # show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log diff --git a/mysql-test/r/rpl_max_relay_size.result b/mysql-test/r/rpl_max_relay_size.result index c1589687eee..c1f8b0ad889 100644 --- a/mysql-test/r/rpl_max_relay_size.result +++ b/mysql-test/r/rpl_max_relay_size.result @@ -16,7 +16,7 @@ select @@global.max_relay_log_size; start slave; 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 68137 # # master-bin.000001 Yes Yes 0 0 68137 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73751 # # master-bin.000001 Yes Yes 0 0 73751 # None 0 No # stop slave; reset slave; set global max_relay_log_size=(5*4096); @@ -26,7 +26,7 @@ select @@global.max_relay_log_size; start slave; 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 68137 # # master-bin.000001 Yes Yes 0 0 68137 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73751 # # master-bin.000001 Yes Yes 0 0 73751 # None 0 No # stop slave; reset slave; set global max_relay_log_size=0; @@ -36,7 +36,7 @@ select @@global.max_relay_log_size; start slave; 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 68137 # # master-bin.000001 Yes Yes 0 0 68137 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73751 # # master-bin.000001 Yes Yes 0 0 73751 # None 0 No # stop slave; reset slave; flush logs; @@ -49,12 +49,12 @@ flush logs; create table t1 (a int); 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 68217 # # master-bin.000001 Yes Yes 0 0 68217 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73838 # # master-bin.000001 Yes Yes 0 0 73838 # None 0 No # flush logs; drop table t1; 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 68287 # # master-bin.000001 Yes Yes 0 0 68287 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73915 # # master-bin.000001 Yes Yes 0 0 73915 # None 0 No # flush logs; show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/r/rpl_multi_update2.result b/mysql-test/r/rpl_multi_update2.result new file mode 100644 index 00000000000..99356ebf970 --- /dev/null +++ b/mysql-test/r/rpl_multi_update2.result @@ -0,0 +1,42 @@ +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; +CREATE TABLE t1 ( +a int unsigned not null auto_increment primary key, +b int unsigned +) ENGINE=MyISAM; +CREATE TABLE t2 ( +a int unsigned not null auto_increment primary key, +b int unsigned +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 SELECT NULL, 0 FROM t1; +INSERT INTO t2 VALUES (NULL, 0), (NULL,1); +SELECT * FROM t1 ORDER BY a; +a b +1 0 +2 0 +SELECT * FROM t2 ORDER BY a; +a b +1 0 +2 1 +UPDATE t1, t2 SET t1.b = (t2.b+4) WHERE t1.a = t2.a; +SELECT * FROM t1 ORDER BY a; +a b +1 4 +2 5 +SELECT * FROM t2 ORDER BY a; +a b +1 0 +2 1 +SELECT * FROM t1 ORDER BY a; +a b +1 4 +2 5 +SELECT * FROM t2 ORDER BY a; +a b +1 0 +2 1 diff --git a/mysql-test/r/rpl_relayrotate.result b/mysql-test/r/rpl_relayrotate.result index bd6e10409b9..38a5a634dd6 100644 --- a/mysql-test/r/rpl_relayrotate.result +++ b/mysql-test/r/rpl_relayrotate.result @@ -18,5 +18,5 @@ max(a) 8000 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_MYPORT 1 master-bin.000001 687207 # # master-bin.000001 Yes Yes 0 0 687207 # None 0 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 743228 # # master-bin.000001 Yes Yes 0 0 743228 # None 0 No # drop table t1; diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result index 5cdcb6f30fb..df75433e84e 100644 --- a/mysql-test/r/rpl_replicate_do.result +++ b/mysql-test/r/rpl_replicate_do.result @@ -28,4 +28,4 @@ ERROR 42S02: Table 'test.t11' doesn't exist 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 1554 # # master-bin.000001 Yes Yes test.t1 0 0 1554 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1617 # # master-bin.000001 Yes Yes test.t1 0 0 1617 # None 0 No # diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index b1847636790..e675f8177ab 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -16,7 +16,7 @@ create table t1 (s text); insert into t1 values('Could not break slave'),('Tried hard'); 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 60 master-bin.000001 521 # # master-bin.000001 Yes Yes 0 0 521 # None 0 No # +# 127.0.0.1 root MASTER_PORT 60 master-bin.000001 549 # # master-bin.000001 Yes Yes 0 0 549 # None 0 No # select * from t1; s Could not break slave @@ -57,7 +57,7 @@ master-bin.000003 insert into t2 values (65); 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 60 master-bin.000003 469 # # master-bin.000003 Yes Yes 0 0 469 # None 0 No # +# 127.0.0.1 root MASTER_PORT 60 master-bin.000003 497 # # master-bin.000003 Yes Yes 0 0 497 # None 0 No # select * from t2; m 34 @@ -79,13 +79,13 @@ master-bin.000004 master-bin.000005 show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000005 1387 +master-bin.000005 2050 select * from t4; a testing temporary tables part 2 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 60 master-bin.000005 1387 # # master-bin.000005 Yes Yes 0 0 1387 # None 0 No # +# 127.0.0.1 root MASTER_PORT 60 master-bin.000005 2050 # # master-bin.000005 Yes Yes 0 0 2050 # None 0 No # lock tables t3 read; select count(*) from t3 where n >= 4; count(*) diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index 3e8c11883be..7d3ebd4ad32 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -39,18 +39,18 @@ f show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 178 use `test`; drop table if exists t1,t2 -master-bin.000001 178 Query 1 257 use `test`; create table t1(f int) -master-bin.000001 257 Query 1 336 use `test`; create table t2(f int) -master-bin.000001 336 Query 1 455 use `test`; insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10) -master-bin.000001 455 Query 1 544 use `test`; create temporary table t3(f int) -master-bin.000001 544 Query 1 642 use `test`; insert into t3 select * from t1 where f<6 -master-bin.000001 642 Query 1 731 use `test`; create temporary table t3(f int) -master-bin.000001 731 Query 1 826 use `test`; insert into t2 select count(*) from t3 -master-bin.000001 826 Query 1 925 use `test`; insert into t3 select * from t1 where f>=4 -master-bin.000001 925 Query 1 1005 use `test`; drop temporary table t3 -master-bin.000001 1005 Query 1 1100 use `test`; insert into t2 select count(*) from t3 -master-bin.000001 1100 Query 1 1180 use `test`; drop temporary table t3 +master-bin.000001 95 Query 1 185 use `test`; drop table if exists t1,t2 +master-bin.000001 185 Query 1 271 use `test`; create table t1(f int) +master-bin.000001 271 Query 1 357 use `test`; create table t2(f int) +master-bin.000001 357 Query 1 483 use `test`; insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10) +master-bin.000001 483 Query 1 579 use `test`; create temporary table t3(f int) +master-bin.000001 579 Query 1 684 use `test`; insert into t3 select * from t1 where f<6 +master-bin.000001 684 Query 1 780 use `test`; create temporary table t3(f int) +master-bin.000001 780 Query 1 882 use `test`; insert into t2 select count(*) from t3 +master-bin.000001 882 Query 1 988 use `test`; insert into t3 select * from t1 where f>=4 +master-bin.000001 988 Query 1 1075 use `test`; drop temporary table t3 +master-bin.000001 1075 Query 1 1177 use `test`; insert into t2 select count(*) from t3 +master-bin.000001 1177 Query 1 1264 use `test`; drop temporary table t3 drop table t1, t2; use test; SET TIMESTAMP=1040323920; diff --git a/mysql-test/r/rpl_timezone.result b/mysql-test/r/rpl_timezone.result index 495fccd35a3..ac219fe9d1c 100644 --- a/mysql-test/r/rpl_timezone.result +++ b/mysql-test/r/rpl_timezone.result @@ -33,12 +33,12 @@ t show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 181 use `test`; create table t1 (t timestamp) -master-bin.000001 181 Query 1 266 use `test`; create table t2 (t char(32)) -master-bin.000001 266 Query 1 351 use `test`; SET ONE_SHOT TIME_ZONE='UTC' -master-bin.000001 351 Query 1 468 use `test`; insert into t1 values ('20040101000000'), ('20040611093902') -master-bin.000001 468 Query 1 539 use `test`; delete from t1 -master-bin.000001 539 Query 1 656 use `test`; insert into t1 values ('20040101000000'), ('20040611093902') +master-bin.000001 95 Query 1 188 use `test`; create table t1 (t timestamp) +master-bin.000001 188 Query 1 280 use `test`; create table t2 (t char(32)) +master-bin.000001 280 Query 1 372 use `test`; SET ONE_SHOT TIME_ZONE='UTC' +master-bin.000001 372 Query 1 496 use `test`; insert into t1 values ('20040101000000'), ('20040611093902') +master-bin.000001 496 Query 1 574 use `test`; delete from t1 +master-bin.000001 574 Query 1 698 use `test`; insert into t1 values ('20040101000000'), ('20040611093902') set time_zone='MET'; insert into t2 (select t from t1); select * from t1; diff --git a/mysql-test/r/rpl_until.result b/mysql-test/r/rpl_until.result index ba8c0c1f131..90ea94b89e6 100644 --- a/mysql-test/r/rpl_until.result +++ b/mysql-test/r/rpl_until.result @@ -15,13 +15,13 @@ drop table t2; show binlog events; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 95 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 95 Query 1 210 use `test`; create table t1(n int not null auto_increment primary key) -master-bin.000001 210 Query 1 304 use `test`; insert into t1 values (1),(2),(3),(4) -master-bin.000001 304 Query 1 374 use `test`; drop table t1 -master-bin.000001 374 Query 1 489 use `test`; create table t2(n int not null auto_increment primary key) -master-bin.000001 489 Query 1 575 use `test`; insert into t2 values (1),(2) -master-bin.000001 575 Query 1 661 use `test`; insert into t2 values (3),(4) -master-bin.000001 661 Query 1 731 use `test`; drop table t2 +master-bin.000001 95 Query 1 217 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 217 Query 1 318 use `test`; insert into t1 values (1),(2),(3),(4) +master-bin.000001 318 Query 1 395 use `test`; drop table t1 +master-bin.000001 395 Query 1 517 use `test`; create table t2(n int not null auto_increment primary key) +master-bin.000001 517 Query 1 610 use `test`; insert into t2 values (1),(2) +master-bin.000001 610 Query 1 703 use `test`; insert into t2 values (3),(4) +master-bin.000001 703 Query 1 780 use `test`; drop table t2 start slave until master_log_file='master-bin.000001', master_log_pos=304; select * from t1; n @@ -31,7 +31,7 @@ n 4 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_MYPORT 1 master-bin.000001 731 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 304 # Master master-bin.000001 304 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 318 # Master master-bin.000001 304 No # start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; select * from t1; n @@ -41,7 +41,7 @@ n 4 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_MYPORT 1 master-bin.000001 731 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 304 # Master master-no-such-bin.000001 291 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 318 # Master master-no-such-bin.000001 291 No # start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=710; select * from t2; n @@ -49,13 +49,13 @@ n 2 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_MYPORT 1 master-bin.000001 731 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 575 # Relay slave-relay-bin.000004 710 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 610 # Relay slave-relay-bin.000004 710 No # start slave; stop slave; start slave until master_log_file='master-bin.000001', master_log_pos=710; 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_MYPORT 1 master-bin.000001 731 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 731 # Master master-bin.000001 710 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 780 # Master master-bin.000001 710 No # start slave until master_log_file='master-bin', master_log_pos=561; ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL start slave until master_log_file='master-bin.000001', master_log_pos=561, relay_log_pos=12; diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result index dd9a11e370f..2e39f1f6422 100644 --- a/mysql-test/r/rpl_user_variables.result +++ b/mysql-test/r/rpl_user_variables.result @@ -76,34 +76,35 @@ abcn1n2 NULL NULL NULL -show binlog events from 179; +show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info -slave-bin.000001 179 User var 2 222 @`i1`=12345678901234 -slave-bin.000001 222 User var 2 265 @`i2`=-12345678901234 -slave-bin.000001 265 User var 2 308 @`i3`=0 -slave-bin.000001 308 User var 2 351 @`i4`=-1 -slave-bin.000001 351 Query 1 456 use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4) -slave-bin.000001 456 User var 2 499 @`r1`=12.5 -slave-bin.000001 499 User var 2 542 @`r2`=-12.5 -slave-bin.000001 542 Query 1 633 use `test`; insert into t1 values (@r1), (@r2) -slave-bin.000001 633 User var 2 682 @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci -slave-bin.000001 682 User var 2 717 @`s2`=_latin1 "" COLLATE latin1_swedish_ci -slave-bin.000001 717 User var 2 759 @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci -slave-bin.000001 759 User var 2 801 @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci -slave-bin.000001 801 User var 2 843 @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci -slave-bin.000001 843 Query 1 955 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5) -slave-bin.000001 955 User var 2 981 @`n1`=NULL -slave-bin.000001 981 Query 1 1065 use `test`; insert into t1 values (@n1) -slave-bin.000001 1065 User var 2 1091 @`n2`=NULL -slave-bin.000001 1091 Query 1 1175 use `test`; insert into t1 values (@n2) -slave-bin.000001 1175 Query 1 1285 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1) -slave-bin.000001 1285 User var 2 1327 @`a`=2 -slave-bin.000001 1327 Query 1 1421 use `test`; insert into t1 values (@a+(@b:=@a+1)) -slave-bin.000001 1421 User var 2 1458 @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci -slave-bin.000001 1458 Query 1 1584 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')) -slave-bin.000001 1584 User var 2 1626 @`a`=5 -slave-bin.000001 1626 Query 1 1714 use `test`; insert into t1 values (@a),(@a) -slave-bin.000001 1714 User var 2 1739 @`a`=NULL -slave-bin.000001 1739 Query 1 1834 use `test`; insert into t1 values (@a),(@a),(@a*5) +slave-bin.000001 95 Query 1 186 use `test`; create table t1(n char(30)) +slave-bin.000001 186 User var 2 229 @`i1`=12345678901234 +slave-bin.000001 229 User var 2 272 @`i2`=-12345678901234 +slave-bin.000001 272 User var 2 315 @`i3`=0 +slave-bin.000001 315 User var 2 358 @`i4`=-1 +slave-bin.000001 358 Query 1 470 use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4) +slave-bin.000001 470 User var 2 509 @`r1`=12.5 +slave-bin.000001 509 User var 2 548 @`r2`=-12.5 +slave-bin.000001 548 Query 1 646 use `test`; insert into t1 values (@r1), (@r2) +slave-bin.000001 646 User var 2 695 @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci +slave-bin.000001 695 User var 2 730 @`s2`=_latin1 "" COLLATE latin1_swedish_ci +slave-bin.000001 730 User var 2 772 @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 772 User var 2 814 @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci +slave-bin.000001 814 User var 2 856 @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 856 Query 1 975 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5) +slave-bin.000001 975 User var 2 1001 @`n1`=NULL +slave-bin.000001 1001 Query 1 1092 use `test`; insert into t1 values (@n1) +slave-bin.000001 1092 User var 2 1118 @`n2`=NULL +slave-bin.000001 1118 Query 1 1209 use `test`; insert into t1 values (@n2) +slave-bin.000001 1209 Query 1 1326 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1) +slave-bin.000001 1326 User var 2 1368 @`a`=2 +slave-bin.000001 1368 Query 1 1469 use `test`; insert into t1 values (@a+(@b:=@a+1)) +slave-bin.000001 1469 User var 2 1506 @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci +slave-bin.000001 1506 Query 1 1639 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')) +slave-bin.000001 1639 User var 2 1681 @`a`=5 +slave-bin.000001 1681 Query 1 1776 use `test`; insert into t1 values (@a),(@a) +slave-bin.000001 1776 User var 2 1801 @`a`=NULL +slave-bin.000001 1801 Query 1 1903 use `test`; insert into t1 values (@a),(@a),(@a*5) drop table t1; stop slave; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 7d5b2ed18cb..b72754d3374 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1672,7 +1672,7 @@ fld1 count(*) 158402 4181 select sum(Period)/count(*) from t1; sum(Period)/count(*) -9410.00 +9410.00000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func 37 12543 309394878010 0.0000 464091 @@ -2109,7 +2109,7 @@ select @b; aaaa select @c; @c -6.26 +6.260 create table t1 (a int not null auto_increment primary key); insert into t1 values (); insert into t1 values (); diff --git a/mysql-test/r/server_id.require b/mysql-test/r/server_id.require new file mode 100644 index 00000000000..adffcc483b1 --- /dev/null +++ b/mysql-test/r/server_id.require @@ -0,0 +1,2 @@ +Variable_name Value +server_id 1 diff --git a/mysql-test/r/server_id1.require b/mysql-test/r/server_id1.require new file mode 100644 index 00000000000..666c94ef633 --- /dev/null +++ b/mysql-test/r/server_id1.require @@ -0,0 +1,2 @@ +Variable_name Value +server_id 102 diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 57126162e3f..1c2f4662ef1 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -120,15 +120,8 @@ ERROR 42000: End-label bar without match create procedure foo() return 42| ERROR 42000: RETURN is only allowed in a FUNCTION -create function foo() returns int -begin -declare x int; -select max(c) into x from test.t; -return x; -end| -ERROR 0A000: Statements like SELECT, INSERT, UPDATE (and others) are not allowed in a FUNCTION create procedure p(x int) -insert into test.t1 values (x)| +set @x = x| create function f(x int) returns int return x+42| call p()| @@ -336,10 +329,6 @@ ERROR 42S22: Unknown column 'valname' in 'order clause' drop procedure bug1965| select 1 into a| ERROR 42000: Undeclared variable: a -create function bug1654() -returns int -return (select sum(t.data) from test.t2 t)| -ERROR 0A000: Statements like SELECT, INSERT, UPDATE (and others) are not allowed in a FUNCTION drop table if exists t3| create table t3 (column_1_0 int)| create procedure bug1653() @@ -354,7 +343,7 @@ drop table t3| create procedure bug2259() begin declare v1 int; -declare c1 cursor for select s1 from t10; +declare c1 cursor for select s1 from t1; fetch c1 into v1; end| call bug2259()| @@ -458,7 +447,9 @@ create procedure bug3294() begin declare continue handler for sqlexception drop table t5; drop table t5; +drop table t5; end| +create table t5 (x int)| call bug3294()| ERROR 42S02: Unknown table 't5' drop procedure bug3294| diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1fd519bc729..0af6b821ce0 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -693,7 +693,7 @@ drop procedure if exists create_select| create procedure create_select(x char(16), y int) begin insert into test.t1 values (x, y); -create table test.t3 select * from test.t1; +create temporary table test.t3 select * from test.t1; insert into test.t3 values (concat(x, "2"), y+2); end| drop table if exists t3| @@ -775,11 +775,11 @@ drop procedure if exists hndlr1| create procedure hndlr1(val int) begin declare x int default 0; -declare foo condition for 1146; +declare foo condition for 1136; declare bar condition for sqlstate '42S98'; # Just for testing syntax declare zip condition for sqlstate value '42S99'; # Just for testing syntax declare continue handler for foo set x = 1; -insert into test.t666 values ("hndlr1", val); # Non-existing table +insert into test.t1 values ("hndlr1", val, 2); # Too many values if (x) then insert into test.t1 values ("hndlr1", val); # This instead then end if; @@ -795,8 +795,8 @@ create procedure hndlr2(val int) begin declare x int default 0; begin -declare exit handler for sqlstate '42S02' set x = 1; -insert into test.t666 values ("hndlr2", val); # Non-existing table +declare exit handler for sqlstate '21S01' set x = 1; +insert into test.t1 values ("hndlr2", val, 2); # Too many values end; insert into test.t1 values ("hndlr2", x); end| @@ -820,7 +820,7 @@ if val < 10 then begin declare y int; set y = val + 10; -insert into test.t666 values ("hndlr3", y); # Non-existing table +insert into test.t1 values ("hndlr3", y, 2); # Too many values if x then insert into test.t1 values ("hndlr3", y); end if; @@ -1239,18 +1239,6 @@ call bug2227(9)| 1.3 x y 42 z 1.3 9 2.6 42 zzz drop procedure bug2227| -drop procedure if exists bug2614| -create procedure bug2614() -begin -drop table if exists t3; -create table t3 (id int default '0' not null); -insert into t3 select 12; -insert into t3 select * from t3; -end| -call bug2614()| -call bug2614()| -drop table t3| -drop procedure bug2614| drop function if exists bug2674| create function bug2674() returns int return @@sort_buffer_size| @@ -1551,7 +1539,7 @@ drop procedure if exists bug2460_2| create procedure bug2460_2() begin drop table if exists t3; -create table t3 (s1 int); +create temporary table t3 (s1 int); insert into t3 select 1 union select 1; end| call bug2460_2()| @@ -1681,22 +1669,6 @@ call bug4726()| call bug4726()| drop procedure bug4726| drop table t3| -drop table if exists t3| -create table t3 (s1 int)| -insert into t3 values (3), (4)| -drop procedure if exists bug4318| -create procedure bug4318() -handler t3 read next| -handler t3 open| -call bug4318()| -s1 -3 -call bug4318()| -s1 -4 -handler t3 close| -drop procedure bug4318| -drop table t3| drop procedure if exists bug4902| create procedure bug4902() begin @@ -2302,22 +2274,110 @@ show procedure status like 'bar'| Db Name Type Definer Modified Created Security_type Comment test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333 drop procedure bar| -drop table t1; -drop table t2; -drop procedure if exists p1; -create procedure p1 () select (select s1 from t1) from t1; -create table t1 (s1 int); -call p1(); -(select s1 from t1) -insert into t1 values (1); -call p1(); -(select s1 from t1) +drop procedure if exists p1| +create procedure p1 () +select (select s1 from t3) from t3| +create table t3 (s1 int)| +call p1()| +(select s1 from t3) +insert into t3 values (1)| +call p1()| +(select s1 from t3) 1 -drop procedure p1; -drop table t1; -drop function if exists foo; -create function `foo` () returns int return 5; -select `foo` (); +drop procedure p1| +drop table t3| +drop function if exists foo| +create function `foo` () returns int +return 5| +select `foo` ()| `foo` () 5 -drop function `foo`; +drop function `foo`| +drop function if exists t1max| +Warnings: +Note 1305 FUNCTION t1max does not exist +create function t1max() returns int +begin +declare x int; +select max(data) into x from t1; +return x; +end| +insert into t1 values ("foo", 3), ("bar", 2), ("zip", 5), ("zap", 1)| +select t1max()| +t1max() +5 +drop function t1max| +drop table if exists t3| +create table t3 ( +v char(16) not null primary key, +c int unsigned not null +)| +create function getcount(s char(16)) returns int +begin +declare x int; +select count(*) into x from t3 where v = s; +if x = 0 then +insert into t3 values (s, 1); +else +update t3 set c = c+1 where v = s; +end if; +return x; +end| +select * from t1 where data = getcount("bar")| +id data +zap 1 +select * from t3| +v c +bar 4 +select getcount("zip")| +getcount("zip") +0 +select getcount("zip")| +getcount("zip") +1 +select * from t3| +v c +bar 4 +zip 2 +select getcount(id) from t1 where data = 3| +getcount(id) +0 +select getcount(id) from t1 where data = 5| +getcount(id) +1 +select * from t3| +v c +bar 4 +zip 3 +foo 1 +drop table t3| +drop function getcount| +drop function if exists bug5240| +create function bug5240 () returns int +begin +declare x int; +declare c cursor for select data from t1 limit 1; +open c; +fetch c into x; +close c; +return x; +end| +delete from t1| +insert into t1 values ("answer", 42)| +select id, bug5240() from t1| +id bug5240() +42 42 +drop function bug5240| +drop function if exists bug5278| +create function bug5278 () returns char +begin +SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass'); +return 'okay'; +end| +select bug5278()| +ERROR 42000: Can't find any matching row in the user table +select bug5278()| +ERROR 42000: Can't find any matching row in the user table +drop function bug5278| +drop table t1; +drop table t2; diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index 5492a7a65fc..09adc48259c 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -386,4 +386,18 @@ p mask example 20 \\\\% \\\\% 20 \\\\% \\\\_ DROP TABLE t1; +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +a\\b a\\\"b a'\\b a'\\\"b +a\\b a\\\"b a'\\b a'\\\"b +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; +a\\b a\\\'b a"\\b a"\\\'b +a\\b a\\\'b a"\\b a"\\\'b +SET @@SQL_MODE=''; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +a\b a\"b a'\b a'\"b +a\b a\"b a'\b a'\"b +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; +a\b a\'b a"\b a"\'b +a\b a\'b a"\b a"\'b SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 72a763db1b1..2e48ddf6d53 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -531,7 +531,6 @@ 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 -Warning 1264 Out of range value adjusted for column 'col2' at row 2 UPDATE IGNORE t1 SET col2=1/NULL where col1=0; SELECT * FROM t1; col1 col2 @@ -556,6 +555,7 @@ 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); 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); INSERT INTO t1 (col2) VALUES(-1); INSERT INTO t1 (col2) VALUES(18446744073709551616); @@ -595,6 +595,7 @@ Error 1365 Division by 0 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 2 INSERT IGNORE INTO t1 VALUES('-9223372036854775809','-1'),('9223372036854775808','18446744073709551616'); Warnings: @@ -616,9 +617,8 @@ col1 col2 9223372036854775807 18446744073709551615 -9223372036854775808 0 9223372036854775807 18446744073709551615 --9223372036854773760 0 -9223372036854775807 1844674407370953984 --9223372036854775808 NULL +-9223372036854774000 0 +9223372036854775700 1844674407370954000 -9223372036854775808 NULL NULL 18446744073709551615 2 NULL @@ -632,12 +632,17 @@ NULL NULL DROP TABLE t1; CREATE TABLE t1 (col1 NUMERIC(4,2)); INSERT INTO t1 VALUES (10.55),(10.5555),(0),(-10.55),(-10.5555),(11),(1e+01); +Warnings: +Note 1265 Data truncated for column 'col1' at row 2 +Note 1265 Data truncated for column 'col1' at row 5 INSERT INTO t1 VALUES ('10.55'),('10.5555'),('-10.55'),('-10.5555'),('11'),('1e+01'); Warnings: Note 1265 Data truncated for column 'col1' at row 2 Note 1265 Data truncated for column 'col1' at row 4 INSERT INTO t1 VALUES (101.55); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (101); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (-101.55); ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (1010.55); @@ -645,7 +650,9 @@ ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (1010); ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('101.55'); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('101'); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('-101.55'); ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('-1010.55'); @@ -661,14 +668,15 @@ ERROR 22012: Division by 0 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0; ERROR 22012: Division by 0 INSERT INTO t1 (col1) VALUES (''); -ERROR 01000: Data truncated for column 'col1' at row 1 +ERROR HY000: Incorrect decimal value: '' for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES ('a59b'); -ERROR 01000: Data truncated for column 'col1' at row 1 +ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES ('1a'); -ERROR 01000: Data truncated for column 'col1' at row 1 +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 (col1) VALUES ('2a'); Warnings: -Warning 1265 Data truncated for column 'col1' at row 1 +Note 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0); Warnings: Error 1365 Division by 0 @@ -695,22 +703,19 @@ NULL 11.00 10.00 10.55 -10.55 --10.55 +10.56 -10.55 +-10.56 11.00 10.00 -101.55 -101.00 -101.55 -101.00 +1.00 2.00 NULL -999.99 +99.99 -99.99 -999.99 +99.99 -99.99 -999.99 +99.99 -99.99 DROP TABLE t1; CREATE TABLE t1 (col1 FLOAT, col2 FLOAT UNSIGNED); diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 5fd2053a3ec..2e9f199e8bb 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -890,7 +890,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index 2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a`,(((`test`.`t1`.`a`) in t2 on a chicking NULL))) AS `t1.a in (select t2.a from t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a`,(((`test`.`t1`.`a`) in t2 on a checking NULL))) AS `t1.a in (select t2.a from t2)` from `test`.`t1` CREATE TABLE t3 (a int(11) default '0'); INSERT INTO t3 VALUES (1),(2),(3); SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; @@ -1462,25 +1462,25 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,not((`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 chicking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,not((`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 checking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,(`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 chicking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,(`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 checking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,not((`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 chicking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,not((`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 checking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 1 Using index; Using where Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,not((`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 chicking NULL where (`test`.`t2`.`s1` < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,not((`test`.`t1`.`s1`,(((`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1` drop table t1,t2; create table t2 (a int, b int); create table t3 (a int); @@ -2168,3 +2168,39 @@ ERROR 42S22: Unknown column 'a2' in 'scalar IN/ALL/ANY subquery' select * from t1 where a1 > any(select b1 from t2); a1 drop table t1,t2; +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +(select * from t1) = (select 1,2) +NULL +select (select 1,2) = (select * from t1); +(select 1,2) = (select * from t1) +NULL +select row(1,2) = ANY (select * from t1); +row(1,2) = ANY (select * from t1) +0 +select row(1,2) != ALL (select * from t1); +row(1,2) != ALL (select * from t1) +1 +drop table t1; +create table t1 (a integer, b integer); +select row(1,(2,2)) in (select * from t1 ); +ERROR 21000: Operand should contain 2 column(s) +select row(1,(2,2)) = (select * from t1 ); +ERROR 21000: Operand should contain 2 column(s) +select (select * from t1) = row(1,(2,2)); +ERROR 21000: Operand should contain 1 column(s) +drop table t1; +create table t1 (a integer); +insert into t1 values (1); +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +xx 1 = ALL ( select 1 from t1 where 1 = xx ) +1 1 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +drop table t1; diff --git a/mysql-test/r/subselect_innodb.result b/mysql-test/r/subselect_innodb.result index 0b813a07a1d..0666fd76661 100644 --- a/mysql-test/r/subselect_innodb.result +++ b/mysql-test/r/subselect_innodb.result @@ -140,3 +140,15 @@ id date1 coworkerid description sum_used sum_remaining comments 6 2004-01-01 1 test 22 33 comment 7 2004-01-01 1 test 22 33 comment drop table t1; +CREATE TABLE `t1` ( `a` char(3) NOT NULL default '', `b` char(3) NOT NULL default '', `c` char(3) NOT NULL default '', PRIMARY KEY (`a`,`b`,`c`)) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (1,1,1); +INSERT INTO t2 VALUES (1,1,1); +PREPARE my_stmt FROM "SELECT t1.b, count(*) FROM t1 group by t1.b having +count(*) > ALL (SELECT COUNT(*) FROM t2 WHERE t2.a=1 GROUP By t2.b)"; +EXECUTE my_stmt; +b count(*) +EXECUTE my_stmt; +b count(*) +deallocate prepare my_stmt; +drop table t1,t2; diff --git a/mysql-test/r/sum_distinct.result b/mysql-test/r/sum_distinct.result index c7f1a660267..34242817a54 100644 --- a/mysql-test/r/sum_distinct.result +++ b/mysql-test/r/sum_distinct.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1 ( id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, gender CHAR(1), diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index 71d1b9ad381..e88eebffb55 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -96,3 +96,11 @@ f2 19781126 19781126 DROP TABLE t1, t2, t3; +CREATE TABLE t1 (y YEAR); +INSERT INTO t1 VALUES ('abc'); +Warnings: +Warning 1264 Out of range value adjusted for column 'y' at row 1 +SELECT * FROM t1; +y +0000 +DROP TABLE t1; diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index c9a272df1ba..2045b7e65dd 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -156,6 +156,9 @@ insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); insert into t1 values ("-.1"),("+.1"),(".1"); insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 @@ -164,7 +167,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 -Warning 1265 Data truncated for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: @@ -172,24 +175,24 @@ Note 1265 Data truncated for column 'a' at row 3 select * from t1; a 0.00 --0.00 -+0.00 -01.00 -+01.00 --01.00 +0.00 +0.00 +1.00 +1.00 +-1.00 -0.10 -+0.10 0.10 -000000001.00 -+00000001.00 --00000001.00 -111111111.11 -111111111.11 +0.10 +1.00 +1.00 +-1.00 +99999999.99 +99999999.99 -11111111.11 -99999999.99 -999999999.99 -999999999.99 -999999999.99 +99999999.99 +99999999.99 +99999999.99 0.00 -99999999.99 123.40 @@ -222,7 +225,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 -Warning 1265 Data truncated for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: @@ -231,15 +234,15 @@ select * from t1; a 0.00 0.00 -+0.00 -01.00 -+01.00 +0.00 +1.00 +1.00 0.00 0.00 -+0.10 0.10 -00000001.00 -+0000001.00 +0.10 +1.00 +1.00 0.00 99999999.99 99999999.99 @@ -280,7 +283,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 -Warning 1265 Data truncated for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: @@ -319,6 +322,9 @@ insert into t1 values (0.0),("-0.0"),(+0.0),(01.0),(+01.0),(-01.0); insert into t1 values (-.1),(+.1),(.1); insert into t1 values (00000000000001),(+0000000000001),(-0000000000001); insert into t1 values (+111111111.11),(111111111.11),(-11111111.11); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 @@ -327,12 +333,15 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values (1e+100),(1e-100),(-1e+100); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); +Warnings: +Note 1265 Data truncated for column 'a' at row 3 select * from t1; a 0.00 --0.00 +0.00 0.00 1.00 1.00 @@ -343,13 +352,13 @@ a 1.00 1.00 -1.00 -111111111.11 -111111111.11 +99999999.99 +99999999.99 -11111111.11 -99999999.99 -999999999.99 -999999999.99 -999999999.99 +99999999.99 +99999999.99 +99999999.99 0.00 -99999999.99 123.40 @@ -362,16 +371,17 @@ create table t1 (a decimal); insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 6 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -9999999999 -1 -+1 -01 -+0000000001 -12345678901 -99999999999 +1 +1 +1 +9999999999 +9999999999 drop table t1; create table t1 (a decimal unsigned); insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); @@ -381,11 +391,11 @@ Warning 1264 Out of range value adjusted for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -0 -0 -+1 -01 -+000000001 +9999999999 +9999999999 +1 +1 +1 1234567890 9999999999 drop table t1; @@ -397,8 +407,8 @@ Warning 1264 Out of range value adjusted for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -0000000000 -0000000000 +9999999999 +9999999999 0000000001 0000000001 0000000001 @@ -413,8 +423,8 @@ Warning 1264 Out of range value adjusted for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -0000000000 -0000000000 +9999999999 +9999999999 0000000001 0000000001 0000000001 @@ -424,19 +434,17 @@ drop table t1; create table t1(a decimal(10,0)); insert into t1 values ("1e4294967295"); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 Warning 1264 Out of range value adjusted for column 'a' at row 1 select * from t1; a -99999999999 +9999999999 delete from t1; insert into t1 values("1e4294967297"); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 Warning 1264 Out of range value adjusted for column 'a' at row 1 select * from t1; a -99999999999 +9999999999 drop table t1; CREATE TABLE t1 (a_dec DECIMAL(-1,0)); 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,0))' at line 1 @@ -448,7 +456,7 @@ CREATE TABLE t1 (a_dec DECIMAL(0,11)); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a_dec` decimal(12,11) default NULL + `a_dec` decimal(11,11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; create table t1(a decimal(7,3)); @@ -456,64 +464,64 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000 select * from t1; a 1.000 -+1.000 +1.000 +-1.000 +1.000 +1.000 -1.000 -00001.000 -+0001.000 --0001.000 10.000 -+10.000 +10.000 +-10.000 +10.000 +10.000 -10.000 -00010.000 -+0010.000 --0010.000 100.000 -+100.000 +100.000 +-100.000 +100.000 +100.000 -100.000 -00100.000 -+0100.000 --0100.000 1000.000 -+1000.000 +1000.000 -1000.000 -01000.000 -+1000.000 +1000.000 +1000.000 -1000.000 -10000.000 -10000.000 +9999.999 +9999.999 -9999.999 -10000.000 -10000.000 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 drop table t1; create table t1(a decimal(7,3) unsigned); @@ -521,22 +529,22 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000 select * from t1; a 1.000 -+1.000 +1.000 0.000 -0001.000 -+001.000 +1.000 +1.000 0.000 10.000 -+10.000 +10.000 0.000 -0010.000 -+010.000 +10.000 +10.000 0.000 100.000 -+100.000 +100.000 0.000 -0100.000 -+100.000 +100.000 +100.000 0.000 1000.000 1000.000 diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index c77b3ad7578..8140167870e 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -66,7 +66,7 @@ select a from t1 order by a; a -0.010 -0.002 --0.000 +0.000 0.000 1.000 select min(a) from t1; @@ -119,7 +119,7 @@ select a from t1 order by a; a -0.010 -0.002 --0.000 +0.000 0.000 1.000 select min(a) from t1; @@ -142,6 +142,9 @@ create table t1 (c20 char); insert into t1 values (5000.0); Warnings: Warning 1265 Data truncated for column 'c20' at row 1 +insert into t1 values (0.5e4); +Warnings: +Warning 1265 Data truncated for column 'c20' at row 1 drop table t1; create table t1 (f float(54)); ERROR 42000: Incorrect column specifier for column 'f' diff --git a/mysql-test/r/type_float.result.es b/mysql-test/r/type_float.result.es index 2751e6cb33b..f2639ef545a 100644 --- a/mysql-test/r/type_float.result.es +++ b/mysql-test/r/type_float.result.es @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1,t2; SELECT 10,10.0,10.,.1e+2,100.0e-1; 10 10.0 10. .1e+2 100.0e-1 10 10.0 10 10 10 @@ -8,6 +8,9 @@ SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000; SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1; 1e1 1.e1 1.0e1 1e+1 1.e+1 1.0e+1 1e-1 1.e-1 1.0e-1 10 10 10 10 10 10 0.1 0.1 0.1 +SELECT 0.001e+1,0.001e-1, -0.001e+01,-0.001e-01; +0.001e+1 0.001e-1 -0.001e+01 -0.001e-01 +0.01 0.0001 -0.01 -0.0001 create table t1 (f1 float(24),f2 float(52)); show full columns from t1; Field Type Collation Null Key Default Extra Privileges Comment @@ -143,6 +146,15 @@ drop table t1; create table t1 (f float(54)); ERROR 42000: Incorrect column specifier for column 'f' drop table if exists t1; +create table t1 (d1 double, d2 double unsigned); +insert into t1 set d1 = -1.0; +update t1 set d2 = d1; +Warnings: +Warning 1264 Out of range value adjusted for column 'd2' at row 1 +select * from t1; +d1 d2 +-1 0 +drop table t1; create table t1 (f float(4,3)); insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); Warnings: diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result new file mode 100644 index 00000000000..cf23d4162ae --- /dev/null +++ b/mysql-test/r/type_newdecimal.result @@ -0,0 +1,843 @@ +drop table if exists t1; +select 1.1 IN (1.0, 1.2); +1.1 IN (1.0, 1.2) +0 +select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5); +1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5) +1 +select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5); +1.1 IN (1.0, 1.2, NULL, 1.4, 0.5) +NULL +select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5); +0.5 IN (1.0, 1.2, NULL, 1.4, 0.5) +1 +select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5); +1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5) +1 +select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5); +1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5) +NULL +select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END +b +select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END +a +select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 1 when 0.1 then "a" when 1.0 then "b" else "c" END +b +select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END; +case 1.0 when 0.1 then "a" when 1 then "b" else "c" END +b +select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END; +case 1.001 when 0.1 then "a" when 1 then "b" else "c" END +c +create table t1 (a decimal(6,3)); +insert into t1 values (1.0), (NULL), (0.1); +select * from t1; +a +1.000 +NULL +0.100 +select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1; +0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) +0 +NULL +1 +drop table t1; +create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2); +select * from t1; +if(1, 1.1, 1.2) if(0, 1.1, 1.2) if(0.1, 1.1, 1.2) if(0, 1, 1.1) if(0, NULL, 1.2) if(1, 0.22e1, 1.1) if(1E0, 1.1, 1.2) +1.1 1.2 1.1 1.1 1.2 2.2 1.1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `if(1, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0', + `if(0, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0', + `if(0.1, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0', + `if(0, 1, 1.1)` decimal(5,1) NOT NULL default '0.0', + `if(0, NULL, 1.2)` decimal(5,1) default NULL, + `if(1, 0.22e1, 1.1)` double NOT NULL default '0', + `if(1E0, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1); +select * from t1; +nullif(1.1, 1.1) nullif(1.1, 1.2) nullif(1.1, 0.11e1) nullif(1.0, 1) nullif(1, 1.0) nullif(1, 1.1) +NULL 1.1 NULL NULL NULL 1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `nullif(1.1, 1.1)` decimal(5,1) default NULL, + `nullif(1.1, 1.2)` decimal(5,1) default NULL, + `nullif(1.1, 0.11e1)` double(4,1) default NULL, + `nullif(1.0, 1)` decimal(5,1) default NULL, + `nullif(1, 1.0)` decimal(1,0) default NULL, + `nullif(1, 1.1)` decimal(1,0) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a decimal(4,2)); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +select a from t1; +a +99.99 +99.99 +99.99 +99.99 +-99.99 +-99.99 +-99.99 +-99.99 +drop table t1; +create table t1 (a decimal(4,2) unsigned); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +select a from t1; +a +99.99 +99.99 +99.99 +99.99 +99.99 +0.00 +0.00 +0.00 +drop table t1; +create table t1 (a bigint); +insert into t1 values (18446744073709551615.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (9223372036854775808.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (-18446744073709551615.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +select * from t1; +a +9223372036854775807 +9223372036854775807 +-9223372036854775808 +drop table t1; +create table t1 (a bigint unsigned); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (9999999999999999999999999.000); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (-1.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +select * from t1; +a +18446744073709551615 +9223372036854775808 +18446744073709551615 +0 +drop table t1; +create table t1 (a tinyint); +insert into t1 values (18446744073709551615.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (9223372036854775808.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 1 +select * from t1; +a +127 +127 +drop table t1; +create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `round(15.4,-1)` decimal(5,0) NOT NULL default '0', + `truncate(-5678.123451,-3)` decimal(13,0) NOT NULL default '0', + `abs(-1.1)` decimal(6,1) NOT NULL default '0.0', + `-(-1.1)` decimal(7,1) NOT NULL default '0.0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); +INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0); +update t1 set b=a; +SELECT * FROM t1; +a b +1.1 1.100 +2.1 2.100 +DROP TABLE t1; +set session sql_mode='traditional'; +select 1e10/0e0; +1e10/0e0 +NULL +Warnings: +Error 1365 Division by 0 +create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10)); +insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890); +select * from wl1612; +col1 col2 col3 +1 12345678901234567890.1234567890 12345678901234567890.1234567890 +insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789); +select * from wl1612 where col1=2; +col1 col2 col3 +2 1234567890123456789.0123456789 1234567890123456789.0123456789 +insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789); +select * from wl1612 where col1=3; +col1 col2 col3 +3 1234567890123456789012345678.0123456789 1234567890123456789012345678.0123456789 +select col1/0 from wl1612; +col1/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +select col2/0 from wl1612; +col2/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +select col3/0 from wl1612; +col3/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +insert into wl1612 values(5,5000.0005,5000.0005); +insert into wl1612 values(6,5000.0005,5000.0005); +select sum(col2),sum(col3) from wl1612; +sum(col2) sum(col3) +1234567903703703580370380357.1491481468 1234567903703703580370380357.1491481468 +insert into wl1612 values(7,500000.000005,500000.000005); +insert into wl1612 values(8,500000.000005,500000.000005); +select sum(col2),sum(col3) from wl1612 where col1>4; +sum(col2) sum(col3) +1010000.0010100000 1010000.0010100000 +insert into wl1612 (col1, col2) values(9,1.01234567891); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(10,1.01234567894); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(11,1.01234567895); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(12,1.01234567896); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +select col1,col2 from wl1612 where col1>8; +col1 col2 +9 1.0123456789 +10 1.0123456789 +11 1.0123456790 +12 1.0123456790 +insert into wl1612 (col1, col3) values(13,1.01234567891); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(14,1.01234567894); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(15,1.01234567895); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(16,1.01234567896); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +select col1,col3 from wl1612 where col1>12; +col1 col3 +13 1.0123456789 +14 1.0123456789 +15 1.0123456790 +16 1.0123456790 +select col1 from wl1612 where col1>4 and col2=1.01234567891; +col1 +select col1 from wl1612 where col1>4 and col2=1.0123456789; +col1 +9 +10 +select col1 from wl1612 where col1>4 and col2<>1.0123456789; +col1 +5 +6 +7 +8 +11 +12 +select col1 from wl1612 where col1>4 and col2<1.0123456789; +col1 +select col1 from wl1612 where col1>4 and col2<=1.0123456789; +col1 +9 +10 +select col1 from wl1612 where col1>4 and col2>1.0123456789; +col1 +5 +6 +7 +8 +11 +12 +select col1 from wl1612 where col1>4 and col2>=1.0123456789; +col1 +5 +6 +7 +8 +9 +10 +11 +12 +select col1 from wl1612 where col1>4 and col2=1.012345679; +col1 +11 +12 +select col1 from wl1612 where col1>4 and col2<>1.012345679; +col1 +5 +6 +7 +8 +9 +10 +select col1 from wl1612 where col1>4 and col3=1.01234567891; +col1 +select col1 from wl1612 where col1>4 and col3=1.0123456789; +col1 +13 +14 +select col1 from wl1612 where col1>4 and col3<>1.0123456789; +col1 +5 +6 +7 +8 +15 +16 +select col1 from wl1612 where col1>4 and col3<1.0123456789; +col1 +select col1 from wl1612 where col1>4 and col3<=1.0123456789; +col1 +13 +14 +select col1 from wl1612 where col1>4 and col3>1.0123456789; +col1 +5 +6 +7 +8 +15 +16 +select col1 from wl1612 where col1>4 and col3>=1.0123456789; +col1 +5 +6 +7 +8 +13 +14 +15 +16 +select col1 from wl1612 where col1>4 and col3=1.012345679; +col1 +15 +16 +select col1 from wl1612 where col1>4 and col3<>1.012345679; +col1 +5 +6 +7 +8 +13 +14 +drop table wl1612; +select 1/3; +1/3 +0.33333 +select 0.8=0.7+0.1; +0.8=0.7+0.1 +1 +select 0.7+0.1; +0.7+0.1 +0.8 +create table wl1612_1 (col1 int); +insert into wl1612_1 values(10); +select * from wl1612_1 where 0.8=0.7+0.1; +col1 +10 +select 0.07+0.07 from wl1612_1; +0.07+0.07 +0.14 +select 0.07-0.07 from wl1612_1; +0.07-0.07 +0.00 +select 0.07*0.07 from wl1612_1; +0.07*0.07 +0.0049 +select 0.07/0.07 from wl1612_1; +0.07/0.07 +1.000000000 +drop table wl1612_1; +create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_2 values(1,1); +insert into wl1612_2 values(+1,+1); +insert into wl1612_2 values(+01,+01); +insert into wl1612_2 values(+001,+001); +select col1,count(*) from wl1612_2 group by col1; +col1 count(*) +1.00 4 +select col2,count(*) from wl1612_2 group by col2; +col2 count(*) +1.00 4 +drop table wl1612_2; +create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_3 values('1','1'); +insert into wl1612_3 values('+1','+1'); +insert into wl1612_3 values('+01','+01'); +insert into wl1612_3 values('+001','+001'); +select col1,count(*) from wl1612_3 group by col1; +col1 count(*) +1.00 4 +select col2,count(*) from wl1612_3 group by col2; +col2 count(*) +1.00 4 +drop table wl1612_3; +select mod(234,10) ; +mod(234,10) +4 +select mod(234.567,10.555); +mod(234.567,10.555) +2.357 +select mod(-234.567,10.555); +mod(-234.567,10.555) +-2.357 +select mod(234.567,-10.555); +mod(234.567,-10.555) +2.357 +select round(15.1); +round(15.1) +15 +select round(15.4); +round(15.4) +15 +select round(15.5); +round(15.5) +16 +select round(15.6); +round(15.6) +16 +select round(15.9); +round(15.9) +16 +select round(-15.1); +round(-15.1) +-15 +select round(-15.4); +round(-15.4) +-15 +select round(-15.5); +round(-15.5) +-16 +select round(-15.6); +round(-15.6) +-16 +select round(-15.9); +round(-15.9) +-16 +select round(15.1,1); +round(15.1,1) +15.1 +select round(15.4,1); +round(15.4,1) +15.4 +select round(15.5,1); +round(15.5,1) +15.5 +select round(15.6,1); +round(15.6,1) +15.6 +select round(15.9,1); +round(15.9,1) +15.9 +select round(-15.1,1); +round(-15.1,1) +-15.1 +select round(-15.4,1); +round(-15.4,1) +-15.4 +select round(-15.5,1); +round(-15.5,1) +-15.5 +select round(-15.6,1); +round(-15.6,1) +-15.6 +select round(-15.9,1); +round(-15.9,1) +-15.9 +select round(15.1,0); +round(15.1,0) +15 +select round(15.4,0); +round(15.4,0) +15 +select round(15.5,0); +round(15.5,0) +16 +select round(15.6,0); +round(15.6,0) +16 +select round(15.9,0); +round(15.9,0) +16 +select round(-15.1,0); +round(-15.1,0) +-15 +select round(-15.4,0); +round(-15.4,0) +-15 +select round(-15.5,0); +round(-15.5,0) +-16 +select round(-15.6,0); +round(-15.6,0) +-16 +select round(-15.9,0); +round(-15.9,0) +-16 +select round(15.1,-1); +round(15.1,-1) +20 +select round(15.4,-1); +round(15.4,-1) +20 +select round(15.5,-1); +round(15.5,-1) +20 +select round(15.6,-1); +round(15.6,-1) +20 +select round(15.9,-1); +round(15.9,-1) +20 +select round(-15.1,-1); +round(-15.1,-1) +-20 +select round(-15.4,-1); +round(-15.4,-1) +-20 +select round(-15.5,-1); +round(-15.5,-1) +-20 +select round(-15.6,-1); +round(-15.6,-1) +-20 +select round(-15.91,-1); +round(-15.91,-1) +-20 +select truncate(5678.123451,0); +truncate(5678.123451,0) +5678 +select truncate(5678.123451,1); +truncate(5678.123451,1) +5678.1 +select truncate(5678.123451,2); +truncate(5678.123451,2) +5678.12 +select truncate(5678.123451,3); +truncate(5678.123451,3) +5678.123 +select truncate(5678.123451,4); +truncate(5678.123451,4) +5678.1234 +select truncate(5678.123451,5); +truncate(5678.123451,5) +5678.12345 +select truncate(5678.123451,6); +truncate(5678.123451,6) +5678.123451 +select truncate(5678.123451,-1); +truncate(5678.123451,-1) +5670 +select truncate(5678.123451,-2); +truncate(5678.123451,-2) +5600 +select truncate(5678.123451,-3); +truncate(5678.123451,-3) +5000 +select truncate(5678.123451,-4); +truncate(5678.123451,-4) +0 +select truncate(-5678.123451,0); +truncate(-5678.123451,0) +-5678 +select truncate(-5678.123451,1); +truncate(-5678.123451,1) +-5678.1 +select truncate(-5678.123451,2); +truncate(-5678.123451,2) +-5678.12 +select truncate(-5678.123451,3); +truncate(-5678.123451,3) +-5678.123 +select truncate(-5678.123451,4); +truncate(-5678.123451,4) +-5678.1234 +select truncate(-5678.123451,5); +truncate(-5678.123451,5) +-5678.12345 +select truncate(-5678.123451,6); +truncate(-5678.123451,6) +-5678.123451 +select truncate(-5678.123451,-1); +truncate(-5678.123451,-1) +-5670 +select truncate(-5678.123451,-2); +truncate(-5678.123451,-2) +-5600 +select truncate(-5678.123451,-3); +truncate(-5678.123451,-3) +-5000 +select truncate(-5678.123451,-4); +truncate(-5678.123451,-4) +0 +create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345); +select col2/9999999999 from wl1612_4 where col1=1; +col2/9999999999 +0.0000000000012345678902469135781481410000000000000000000 +select col3/9999999999 from wl1612_4 where col1=1; +col3/9999999999 +0.0000000000012345678902469135781481410000000000000000000 +select 9999999999/col2 from wl1612_4 where col1=1; +9999999999/col2 +810000007209.00007 +select 9999999999/col3 from wl1612_4 where col1=1; +9999999999/col3 +810000007209.00007 +select col2*9999999999 from wl1612_4 where col1=1; +col2*9999999999 +123456789.0000000000111104321087655 +select col3*9999999999 from wl1612_4 where col1=1; +col3*9999999999 +123456789.0000000000111104321087655 +insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345); +select col2/9999999999 from wl1612_4 where col1=2; +col2/9999999999 +0.0000055555012351234402469691331481460000000000000000000 +select col3/9999999999 from wl1612_4 where col1=2; +col3/9999999999 +0.0000055555012351234402469691331481460000000000000000000 +select 9999999999/col2 from wl1612_4 where col1=2; +9999999999/col2 +180001.76000 +select 9999999999/col3 from wl1612_4 where col1=2; +9999999999/col3 +180001.76000 +select col2*9999999999 from wl1612_4 where col1=2; +col2*9999999999 +555550123401234.0000000000111104321087655 +select col3*9999999999 from wl1612_4 where col1=2; +col3*9999999999 +555550123401234.0000000000111104321087655 +drop table wl1612_4; +set sql_mode=''; +select 23.4 + (-41.7), 23.4 - (41.7) = -18.3; +23.4 + (-41.7) 23.4 - (41.7) = -18.3 +-18.3 1 +select -18.3=-18.3; +-18.3=-18.3 +1 +select 18.3=18.3; +18.3=18.3 +1 +select -18.3=18.3; +-18.3=18.3 +0 +select 0.8 = 0.7 + 0.1; +0.8 = 0.7 + 0.1 +1 +create procedure p1 () begin +declare v1, v2, v3, v4 decimal(16,12); declare v5 int; +set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0; +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.000000100000000000 1.999999900000000000 +drop procedure p1; +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (col1 decimal(38)); +insert into t1 values (12345678901234567890123456789012345678); +select * from t1; +col1 +12345678901234567890123456789012345678 +drop table t1; +create table t1 (col1 decimal(31,30)); +insert into t1 values (0.00000000001); +select * from t1; +col1 +0.000000000010000000000000000000 +drop table t1; +select 7777777777777777777777777777777777777 * 10; +7777777777777777777777777777777777777 * 10 +77777777777777777777777777777777777770 +select .7777777777777777777777777777777777777 * +1000000000000000000; +.7777777777777777777777777777777777777 * +1000000000000000000 +777777777777777777.7777777777777777777000000000000000000 +select .7777777777777777777777777777777777777 - 0.1; +.7777777777777777777777777777777777777 - 0.1 +0.6777777777777777777777777777777777777 +select .343434343434343434 + .343434343434343434; +.343434343434343434 + .343434343434343434 +0.686868686868686868 +select abs(9999999999999999999999); +abs(9999999999999999999999) +9999999999999999999999 +select abs(-9999999999999999999999); +abs(-9999999999999999999999) +9999999999999999999999 +select ceiling(99999999999999999999); +ceiling(99999999999999999999) +99999999999999999999 +select ceiling(9.9999999999999999999); +ceiling(9.9999999999999999999) +10 +select ceiling(-9.9999999999999999999); +ceiling(-9.9999999999999999999) +-10 +select floor(9999999999999999999999); +floor(9999999999999999999999) +9999999999999999999999 +select floor(9.999999999999999999999); +floor(9.999999999999999999999) +10 +select floor(-9.999999999999999999999); +floor(-9.999999999999999999999) +-10 +select floor(-999999999999999999999.999); +floor(-999999999999999999999.999) +-1000000000000000000000 +select ceiling(999999999999999999999.999); +ceiling(999999999999999999999.999) +1000000000000000000000 +select 99999999999999999999999999999999999999 mod 3; +99999999999999999999999999999999999999 mod 3 +0 +select round(99999999999999999.999); +round(99999999999999999.999) +100000000000000000 +select round(-99999999999999999.999); +round(-99999999999999999.999) +-100000000000000000 +select round(99999999999999999.999,3); +round(99999999999999999.999,3) +99999999999999999.999 +select round(-99999999999999999.999,3); +round(-99999999999999999.999,3) +-99999999999999999.999 +select truncate(99999999999999999999999999999999999999,31); +truncate(99999999999999999999999999999999999999,31) +99999999999999999999999999999999999999.000000000000000000000000000 +select truncate(99.999999999999999999999999999999999999,31); +truncate(99.999999999999999999999999999999999999,31) +99.9999999999999999999999999999999 +select truncate(99999999999999999999999999999999999999,-31); +truncate(99999999999999999999999999999999999999,-31) +99999990000000000000000000000000000000 +create table t1 as select 0.5; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `0.5` decimal(3,1) NOT NULL default '0.0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +select round(1.5),round(2.5); +round(1.5) round(2.5) +2 3 +select 0.07 * 0.07; +0.07 * 0.07 +0.0049 +set sql_mode='traditional'; +select 1E-500 = 0; +1E-500 = 0 +1 +select 1 / 1E-500; +1 / 1E-500 +NULL +Warnings: +Error 1365 Division by 0 +select 1 / 0; +1 / 0 +NULL +Warnings: +Error 1365 Division by 0 +set sql_mode='ansi,traditional'; +CREATE TABLE Sow6_2f (col1 NUMERIC(4,2)); +INSERT INTO Sow6_2f VALUES (10.55); +INSERT INTO Sow6_2f VALUES (10.5555); +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 +INSERT INTO Sow6_2f VALUES (-10.55); +INSERT INTO Sow6_2f VALUES (-10.5555); +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 +INSERT INTO Sow6_2f VALUES (11); +INSERT INTO Sow6_2f VALUES (101.55); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 +UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11; +ERROR 22003: Out of range value adjusted for column 'col1' at row 5 +UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0; +ERROR 22012: Division by 0 +SELECT MOD(col1,0) FROM Sow6_2f; +MOD(col1,0) +NULL +NULL +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +INSERT INTO Sow6_2f VALUES ('a59b'); +ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1 +drop table Sow6_2f; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index 1a66f0d91d2..e553d9d86f2 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -87,6 +87,8 @@ DROP INDEX test ON t1; insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); +Warnings: +Warning 1265 Data truncated for column 'string' at row 1 insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); Warnings: Warning 1264 Out of range value adjusted for column 'utiny' at row 1 @@ -122,7 +124,7 @@ select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,ut auto string tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000) date_field time_field date_time blob_col tinyblob_col mediumblob_col longblob_col 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.33 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 +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 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 @@ -174,7 +176,7 @@ Warning 1265 Data truncated for column 'new_field' at row 7 select * from t2; auto string mediumblob_col new_field 1 2 2 ne -2 0.33 ne +2 0.33333333 ne 3 -1 -1 ne 4 -429496729 -4294967295 ne 5 4294967295 4294967295 ne @@ -268,7 +270,7 @@ drop table t2; create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment -auto bigint(17) unsigned NULL NO PRI 0 select,insert,update,references +auto int(6) unsigned NULL NO PRI 0 select,insert,update,references t1 bigint(1) NULL NO 0 select,insert,update,references t2 varchar(1) latin1_swedish_ci NO select,insert,update,references t3 varchar(256) latin1_swedish_ci NO select,insert,update,references diff --git a/mysql-test/r/type_ranges.result.es b/mysql-test/r/type_ranges.result.es index c1f6d2453e9..5e2ea2aebbc 100644 --- a/mysql-test/r/type_ranges.result.es +++ b/mysql-test/r/type_ranges.result.es @@ -40,30 +40,30 @@ KEY (options,flags) ); show full fields from t1; Field Type Collation Null Key Default Extra Privileges Comment -auto int(5) unsigned NULL PRI NULL auto_increment -string varchar(10) latin1_swedish_ci YES hello -tiny tinyint(4) NULL MUL 0 -short smallint(6) NULL MUL 1 -medium mediumint(8) NULL MUL 0 -long_int int(11) NULL 0 -longlong bigint(13) NULL MUL 0 -real_float float(13,1) NULL MUL 0.0 +auto int(5) unsigned NULL NO PRI NULL auto_increment +string char(10) latin1_swedish_ci YES hello +tiny tinyint(4) NULL NO MUL 0 +short smallint(6) NULL NO MUL 1 +medium mediumint(8) NULL NO MUL 0 +long_int int(11) NULL NO 0 +longlong bigint(13) NULL NO MUL 0 +real_float float(13,1) NULL NO MUL 0.0 real_double double(16,4) NULL YES NULL -utiny tinyint(3) unsigned NULL MUL 0 -ushort smallint(5) unsigned zerofill NULL MUL 00000 -umedium mediumint(8) unsigned NULL MUL 0 -ulong int(11) unsigned NULL MUL 0 -ulonglong bigint(13) unsigned NULL MUL 0 +utiny tinyint(3) unsigned NULL NO MUL 0 +ushort smallint(5) unsigned zerofill NULL NO MUL 00000 +umedium mediumint(8) unsigned NULL NO MUL 0 +ulong int(11) unsigned NULL NO MUL 0 +ulonglong bigint(13) unsigned NULL NO MUL 0 time_stamp timestamp NULL YES CURRENT_TIMESTAMP date_field date NULL YES NULL time_field time NULL YES NULL date_time datetime NULL YES NULL blob_col blob NULL YES NULL tinyblob_col tinyblob NULL YES NULL -mediumblob_col mediumblob NULL -longblob_col longblob NULL -options enum('one','two','tree') latin1_swedish_ci MUL one -flags set('one','two','tree') latin1_swedish_ci +mediumblob_col mediumblob NULL NO +longblob_col longblob NULL NO +options enum('one','two','tree') latin1_swedish_ci NO MUL one +flags set('one','two','tree') latin1_swedish_ci NO show keys from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 0 PRIMARY 1 auto A 0 NULL NULL BTREE @@ -89,33 +89,33 @@ insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,N insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); Warnings: -Warning 1264 Data truncated; out of range for column 'utiny' at row 1 -Warning 1264 Data truncated; out of range for column 'ushort' at row 1 -Warning 1264 Data truncated; out of range for column 'umedium' at row 1 -Warning 1264 Data truncated; out of range for column 'ulong' at row 1 +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 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"); Warnings: Warning 1265 Data truncated for column 'string' at row 1 -Warning 1264 Data truncated; out of range for column 'tiny' at row 1 -Warning 1264 Data truncated; out of range for column 'short' at row 1 -Warning 1264 Data truncated; out of range for column 'medium' at row 1 -Warning 1264 Data truncated; out of range for column 'long_int' at row 1 -Warning 1264 Data truncated; out of range for column 'utiny' at row 1 -Warning 1264 Data truncated; out of range for column 'ushort' at row 1 -Warning 1264 Data truncated; out of range for column 'umedium' at row 1 -Warning 1264 Data truncated; out of range for column 'ulong' at row 1 +Warning 1264 Out of range value adjusted for column 'tiny' at row 1 +Warning 1264 Out of range value adjusted for column 'short' at row 1 +Warning 1264 Out of range value adjusted for column 'medium' at row 1 +Warning 1264 Out of range value adjusted for column 'long_int' at row 1 +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 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: -Warning 1264 Data truncated; out of range for column 'tiny' at row 1 -Warning 1264 Data truncated; out of range for column 'short' at row 1 -Warning 1264 Data truncated; out of range for column 'medium' at row 1 -Warning 1264 Data truncated; out of range for column 'long_int' at row 1 -Warning 1264 Data truncated; out of range for column 'utiny' at row 1 -Warning 1264 Data truncated; out of range for column 'ushort' at row 1 -Warning 1264 Data truncated; out of range for column 'umedium' at row 1 +Warning 1264 Out of range value adjusted for column 'tiny' at row 1 +Warning 1264 Out of range value adjusted for column 'short' at row 1 +Warning 1264 Out of range value adjusted for column 'medium' at row 1 +Warning 1264 Out of range value adjusted for column 'long_int' at row 1 +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 1265 Data truncated for column 'options' at row 1 insert into t1 (tiny) values (1); select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,utiny,ushort,umedium,ulong,ulonglong,mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000),date_field,time_field,date_time,blob_col,tinyblob_col,mediumblob_col,longblob_col from t1; @@ -208,56 +208,56 @@ Warning 1265 Data truncated for column 'options' at row 6 update t2 set string="changed" where auto=16; show full columns from t1; Field Type Collation Null Key Default Extra Privileges Comment -auto int(5) unsigned NULL MUL NULL auto_increment -string varchar(10) latin1_swedish_ci YES new defaul -tiny tinyint(4) NULL MUL 0 -short smallint(6) NULL MUL 0 -medium mediumint(8) NULL MUL 0 -long_int int(11) NULL 0 -longlong bigint(13) NULL MUL 0 -real_float float(13,1) NULL MUL 0.0 +auto int(5) unsigned NULL NO MUL NULL auto_increment +string char(10) latin1_swedish_ci YES new defaul +tiny tinyint(4) NULL NO MUL 0 +short smallint(6) NULL NO MUL 0 +medium mediumint(8) NULL NO MUL 0 +long_int int(11) NULL NO 0 +longlong bigint(13) NULL NO MUL 0 +real_float float(13,1) NULL NO MUL 0.0 real_double double(16,4) NULL YES NULL -utiny tinyint(3) unsigned NULL 0 -ushort smallint(5) unsigned zerofill NULL 00000 -umedium mediumint(8) unsigned NULL MUL 0 -ulong int(11) unsigned NULL MUL 0 -ulonglong bigint(13) unsigned NULL MUL 0 +utiny tinyint(3) unsigned NULL NO 0 +ushort smallint(5) unsigned zerofill NULL NO 00000 +umedium mediumint(8) unsigned NULL NO MUL 0 +ulong int(11) unsigned NULL NO MUL 0 +ulonglong bigint(13) unsigned NULL NO MUL 0 time_stamp timestamp NULL YES CURRENT_TIMESTAMP date_field char(10) latin1_swedish_ci YES NULL time_field time NULL YES NULL date_time datetime NULL YES NULL new_blob_col varchar(20) latin1_swedish_ci YES NULL tinyblob_col tinyblob NULL YES NULL -mediumblob_col mediumblob NULL -options enum('one','two','tree') latin1_swedish_ci MUL one -flags set('one','two','tree') latin1_swedish_ci -new_field char(10) latin1_swedish_ci new +mediumblob_col mediumblob NULL NO +options enum('one','two','tree') latin1_swedish_ci NO MUL one +flags set('one','two','tree') latin1_swedish_ci NO +new_field char(10) latin1_swedish_ci NO new show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment -auto int(5) unsigned NULL 0 -string varchar(10) latin1_swedish_ci YES new defaul -tiny tinyint(4) NULL 0 -short smallint(6) NULL 0 -medium mediumint(8) NULL 0 -long_int int(11) NULL 0 -longlong bigint(13) NULL 0 -real_float float(13,1) NULL 0.0 +auto int(5) unsigned NULL NO 0 +string char(10) latin1_swedish_ci YES new defaul +tiny tinyint(4) NULL NO 0 +short smallint(6) NULL NO 0 +medium mediumint(8) NULL NO 0 +long_int int(11) NULL NO 0 +longlong bigint(13) NULL NO 0 +real_float float(13,1) NULL NO 0.0 real_double double(16,4) NULL YES NULL -utiny tinyint(3) unsigned NULL 0 -ushort smallint(5) unsigned zerofill NULL 00000 -umedium mediumint(8) unsigned NULL 0 -ulong int(11) unsigned NULL 0 -ulonglong bigint(13) unsigned NULL 0 +utiny tinyint(3) unsigned NULL NO 0 +ushort smallint(5) unsigned zerofill NULL NO 00000 +umedium mediumint(8) unsigned NULL NO 0 +ulong int(11) unsigned NULL NO 0 +ulonglong bigint(13) unsigned NULL NO 0 time_stamp timestamp NULL YES 0000-00-00 00:00:00 date_field char(10) latin1_swedish_ci YES NULL time_field time NULL YES NULL date_time datetime NULL YES NULL new_blob_col varchar(20) latin1_swedish_ci YES NULL tinyblob_col tinyblob NULL YES NULL -mediumblob_col mediumblob NULL -options enum('one','two','tree') latin1_swedish_ci one -flags set('one','two','tree') latin1_swedish_ci -new_field char(10) latin1_swedish_ci new +mediumblob_col mediumblob NULL NO +options enum('one','two','tree') latin1_swedish_ci NO one +flags set('one','two','tree') latin1_swedish_ci NO +new_field char(10) latin1_swedish_ci NO new select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and ((t1.string<>t2.string and (t1.string is not null or t2.string is not null)) or (t1.tiny<>t2.tiny and (t1.tiny is not null or t2.tiny is not null)) or (t1.short<>t2.short and (t1.short is not null or t2.short is not null)) or (t1.medium<>t2.medium and (t1.medium is not null or t2.medium is not null)) or (t1.long_int<>t2.long_int and (t1.long_int is not null or t2.long_int is not null)) or (t1.longlong<>t2.longlong and (t1.longlong is not null or t2.longlong is not null)) or (t1.real_float<>t2.real_float and (t1.real_float is not null or t2.real_float is not null)) or (t1.real_double<>t2.real_double and (t1.real_double is not null or t2.real_double is not null)) or (t1.utiny<>t2.utiny and (t1.utiny is not null or t2.utiny is not null)) or (t1.ushort<>t2.ushort and (t1.ushort is not null or t2.ushort is not null)) or (t1.umedium<>t2.umedium and (t1.umedium is not null or t2.umedium is not null)) or (t1.ulong<>t2.ulong and (t1.ulong is not null or t2.ulong is not null)) or (t1.ulonglong<>t2.ulonglong and (t1.ulonglong is not null or t2.ulonglong is not null)) or (t1.time_stamp<>t2.time_stamp and (t1.time_stamp is not null or t2.time_stamp is not null)) or (t1.date_field<>t2.date_field and (t1.date_field is not null or t2.date_field is not null)) or (t1.time_field<>t2.time_field and (t1.time_field is not null or t2.time_field is not null)) or (t1.date_time<>t2.date_time and (t1.date_time is not null or t2.date_time is not null)) or (t1.new_blob_col<>t2.new_blob_col and (t1.new_blob_col is not null or t2.new_blob_col is not null)) or (t1.tinyblob_col<>t2.tinyblob_col and (t1.tinyblob_col is not null or t2.tinyblob_col is not null)) or (t1.mediumblob_col<>t2.mediumblob_col and (t1.mediumblob_col is not null or t2.mediumblob_col is not null)) or (t1.options<>t2.options and (t1.options is not null or t2.options is not null)) or (t1.flags<>t2.flags and (t1.flags is not null or t2.flags is not null)) or (t1.new_field<>t2.new_field and (t1.new_field is not null or t2.new_field is not null))); auto auto 16 16 @@ -265,23 +265,27 @@ select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and not (t1.string<=>t2. auto auto 16 16 drop table t2; -create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, "a" as t2, repeat("a",256) as t3, binary repeat("b",256) as t4 from t1; +create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment -auto bigint(17) unsigned NULL PRI 0 -t1 bigint(1) NULL 0 -t2 char(1) latin1_swedish_ci -t3 longtext latin1_swedish_ci -t4 longblob NULL -select * from t2; -auto t1 t2 t3 t4 -11 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -12 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -13 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -14 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -15 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -16 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -17 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +auto bigint(17) unsigned NULL NO PRI 0 +t1 bigint(1) NULL NO 0 +t2 varchar(1) latin1_swedish_ci NO +t3 varchar(256) latin1_swedish_ci NO +t4 varbinary(256) NULL NO +t5 longtext latin1_swedish_ci NO +t6 longblob NULL NO +t7 char(0) latin1_swedish_ci NO +t8 binary(0) NULL NO +select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2; +t1 t2 length(t3) length(t4) length(t5) length(t6) t7 t8 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 drop table t1,t2; create table t1 (c int); insert into t1 values(1),(2); @@ -293,7 +297,7 @@ show full columns from t3; Field Type Collation Null Key Default Extra Privileges Comment c1 int(11) NULL YES NULL c2 int(11) NULL YES NULL -const bigint(1) NULL 0 +const bigint(1) NULL NO 0 drop table t1,t2,t3; create table t1 ( myfield INT NOT NULL, UNIQUE INDEX (myfield), unique (myfield), index(myfield)); drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index a63358ff2bc..5a60ef8abfb 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -565,7 +565,7 @@ a show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` double(53,1) NOT NULL default '0.0' + `a` decimal(20,1) NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob, tx text); @@ -788,11 +788,11 @@ create table t3 select * from t2 union select * from t1; select * from t3; d 1.234567800 -100000000.0 +100000000.000000000 show create table t3; Table Create Table t3 CREATE TABLE `t3` ( - `d` decimal(10,9) default NULL + `d` decimal(19,9) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1,t2,t3; create table t1 select 1 union select -1; @@ -1137,3 +1137,39 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; drop table t2; +create table t1(a1 int, f1 char(10)); +create table t2 +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +union +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +order by f2, a1; +show columns from t2; +Field Type Null Key Default Extra +f2 date YES NULL +a1 int(11) YES NULL +drop table t1, t2; +create table t1 (f1 int); +create table t2 (f1 int, f2 int ,f3 date); +create table t3 (f1 int, f2 char(10)); +create table t4 +( +select t2.f3 as sdate +from t1 +left outer join t2 on (t1.f1 = t2.f1) +inner join t3 on (t2.f2 = t3.f1) +order by t1.f1, t3.f1, t2.f3 +) +union +( +select cast('2004-12-31' as date) as sdate +from t1 +left outer join t2 on (t1.f1 = t2.f1) +inner join t3 on (t2.f2 = t3.f1) +group by t1.f1 +order by t1.f1, t3.f1, t2.f3 +) +order by sdate; +show columns from t4; +Field Type Null Key Default Extra +sdate date YES NULL +drop table t1, t2, t3, t4; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index beab6105f79..ac370db9ecc 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -212,3 +212,10 @@ insert into t1 values (1, "t1c2-1", 10), (2, "t1c2-2", 20); update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1"; update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1" where t1.c3 = 10; drop table t1, t2; +create table t1 (id int not null auto_increment primary key, id_str varchar(32)); +insert into t1 (id_str) values ("test"); +update t1 set id_str = concat(id_str, id) where id = last_insert_id(); +select * from t1; +id id_str +1 test1 +drop table t1; diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 69fcc5c45fe..ba5cb264013 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -113,8 +113,8 @@ select @a:=0; select @a, @a:=@a+count(*), count(*), @a from t1 group by i; @a @a:=@a+count(*) count(*) @a 0 1 1 0 -0 2 2 0 -0 3 3 0 +0 3 2 0 +0 6 3 0 select @a:=0; @a:=0 0 @@ -177,16 +177,17 @@ insert into t1 values (@var1),(@var2); show binlog events from 95; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 95 User var 1 136 @`a b`=_latin1 0x68656C6C6F COLLATE latin1_swedish_ci -master-bin.000001 136 Query 1 222 use `test`; INSERT INTO t1 VALUES(@`a b`) -master-bin.000001 222 User var 1 264 @`var1`=_latin1 0x273B616161 COLLATE latin1_swedish_ci -master-bin.000001 264 User var 1 302 @`var2`=_latin1 0x61 COLLATE latin1_swedish_ci -master-bin.000001 302 Query 1 396 use `test`; insert into t1 values (@var1),(@var2) +master-bin.000001 136 Query 1 229 use `test`; INSERT INTO t1 VALUES(@`a b`) +master-bin.000001 229 User var 1 271 @`var1`=_latin1 0x273B616161 COLLATE latin1_swedish_ci +master-bin.000001 271 User var 1 309 @`var2`=_latin1 0x61 COLLATE latin1_swedish_ci +master-bin.000001 309 Query 1 410 use `test`; insert into t1 values (@var1),(@var2) /*!40019 SET @@session.max_insert_delayed_threads=0*/; SET @`a b`:=_latin1 0x68656C6C6F COLLATE `latin1_swedish_ci`; use test; SET TIMESTAMP=10000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; 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`; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 1659a9dddb5..57b73a0515e 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -500,14 +500,15 @@ t1 CREATE TABLE `t1` ( `c5` bigint(20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; -set @arg00= 8, @arg01= 8.8, @arg02= 'a string'; -create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3; +set @arg00= 8, @arg01= 8.8, @arg02= 'a string', @arg03= 0.2e0; +create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3, @arg03 as c4; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` bigint(20) default NULL, - `c2` double default NULL, - `c3` longtext + `c2` decimal(64,30) default NULL, + `c3` longtext, + `c4` double default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index aa010da7e8f..5f466b7c84e 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -448,7 +448,7 @@ create view v1 as select a+1 from t1; create table t2 select * from v1; show columns from t2; Field Type Null Key Default Extra -a+1 bigint(17) YES NULL +a+1 bigint(12) YES NULL select * from t2; a+1 2 @@ -889,10 +889,6 @@ ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function drop view v1; create view v1 (a,a) as select 'a','a'; ERROR 42S21: Duplicate column name 'a' -create procedure p1 () begin declare v int; create view v1 as select v; end;// -call p1(); -ERROR HY000: View's SELECT contains a variable or parameter -drop procedure p1; create table t1 (col1 int,col2 char(22)); insert into t1 values(5,'Hello, world of views'); create view v1 as select * from t1; diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 87e456baba7..fed3ff07a13 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -58,7 +58,10 @@ CREATE TABLE t1 SELECT CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6, CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7, CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8, - CASE WHEN 1 THEN 1.0 END AS c9 + CASE WHEN 1 THEN 1.0 END AS c9, + CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10, + CASE WHEN 1 THEN 0.1e1 else 1 END AS c11, + CASE WHEN 1 THEN 0.1e1 else '1' END AS c12 ; SHOW CREATE TABLE t1; DROP TABLE t1; diff --git a/mysql-test/t/client_xml.test b/mysql-test/t/client_xml.test new file mode 100644 index 00000000000..dd7a812b54f --- /dev/null +++ b/mysql-test/t/client_xml.test @@ -0,0 +1,18 @@ +# Test of the xml output of the 'mysql' and 'mysqldump' clients -- makes +# sure that basic encoding issues are handled properly +create table t1 ( + `a&b` int, + `ab` text +); +insert into t1 values (1, 2, 'a&b ab'); +--exec $MYSQL --xml test -e 'select * from t1' +--exec $MYSQL_DUMP --xml --skip-create test + +--exec $MYSQL --xml test -e 'select count(*) from t1' +--exec $MYSQL --xml test -e 'select 1 < 2 from dual' +--exec $MYSQL --xml test -e 'select 1 > 2 from dual' +--exec $MYSQL --xml test -e 'select 1 & 3 from dual' +--exec $MYSQL --xml test -e 'select null from dual' + +drop table t1; diff --git a/mysql-test/t/compare.test b/mysql-test/t/compare.test index b0cef48dd3f..bc20786227b 100644 --- a/mysql-test/t/compare.test +++ b/mysql-test/t/compare.test @@ -30,3 +30,8 @@ CREATE TABLE t1 (a char(10) not null); INSERT INTO t1 VALUES ('a'),('a\0'),('a\t'),('a '); SELECT hex(a),STRCMP(a,'a'), STRCMP(a,'a ') FROM t1; DROP TABLE t1; + +# Bug #8134: Comparison against CHAR(31) at end of string +SELECT CHAR(31) = '', '' = CHAR(31); +# Extra test +SELECT CHAR(30) = '', '' = CHAR(30); diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test index 24da8a76dcd..fed87af3adc 100644 --- a/mysql-test/t/ctype_cp932.test +++ b/mysql-test/t/ctype_cp932.test @@ -1,3 +1,5 @@ +-- source include/have_cp932.inc + --character_set cp932 --disable_warnings drop table if exists t1; diff --git a/mysql-test/t/ctype_eucjpms.test b/mysql-test/t/ctype_eucjpms.test index 578d116fcb9..cec1e2a9861 100644 --- a/mysql-test/t/ctype_eucjpms.test +++ b/mysql-test/t/ctype_eucjpms.test @@ -1,3 +1,6 @@ +-- source include/have_eucjpms.inc + + --disable_warnings drop table if exists t1; drop table if exists t2; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 928d79ab15b..df860d92b38 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -214,6 +214,16 @@ insert into t1 values (128, 'rozn', 2, now(), 10),(128, 'rozn', 1, now(), 10); SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MAX(concat(date_,";",price)), 12) price FROM t1 WHERE itemid=128 AND grpid='rozn' GROUP BY itemid, grpid, vendor) lastprices; DROP TABLE t1; +# +# DISTINCT over grouped select on subquery in the FROM clause +# +create table t1 (a integer, b integer); +insert into t1 values (1,4), (2,2),(2,2), (4,1),(4,1),(4,1),(4,1); +select distinct sum(b) from t1 group by a; +select distinct sum(b) from (select a,b from t1) y group by a; +drop table t1; + + # # Test for bug #7413 "Subquery with non-scalar results participating in # select list of derived table crashes server" aka "VIEW with sub query can diff --git a/mysql-test/t/drop_temp_table.test b/mysql-test/t/drop_temp_table.test index 1a7d8796bb3..dcd95721179 100644 --- a/mysql-test/t/drop_temp_table.test +++ b/mysql-test/t/drop_temp_table.test @@ -4,7 +4,9 @@ connection con1; reset master; create database `drop-temp+table-test`; use `drop-temp+table-test`; +create temporary table shortn1 (a int); create temporary table `table:name` (a int); +create temporary table shortn2 (a int); select get_lock("a",10); disconnect con1; @@ -15,5 +17,6 @@ connection con2; select get_lock("a",10); let $VERSION=`select version()`; --replace_result $VERSION VERSION +--replace_column 2 # 5 # show binlog events; drop database `drop-temp+table-test`; diff --git a/mysql-test/t/func_equal.test b/mysql-test/t/func_equal.test index cbf589ffcc2..f446e277c92 100644 --- a/mysql-test/t/func_equal.test +++ b/mysql-test/t/func_equal.test @@ -11,10 +11,12 @@ drop table if exists t1,t2; # First some simple tests # -select 0<=>0,0.0<=>0.0,"A"<=>"A",NULL<=>NULL; +select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL; select 1<=>0,0<=>NULL,NULL<=>0; select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0; select "A"<=>"B","A"<=>NULL,NULL<=>"A"; +select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1; +select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0; # # Test with tables diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 65ef9f2535c..a47218e5c01 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -473,3 +473,17 @@ INSERT INTO t1 VALUES select val, count(*) from t1 group by val; drop table t1; + + +# +# Bug 7833: Wrong datatype of aggregate column is returned +# + +create table t1(f1 datetime); +insert into t1 values (now()); +create table t2 select f2 from (select max(now()) f2 from t1) a; +show columns from t2; +drop table t2; +create table t2 select f2 from (select now() f2 from t1) a; +show columns from t2; +drop table t2, t1; diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index e73f2a1b26c..89aba7ee583 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -23,3 +23,18 @@ select length(format('nan', 2)) > 0; # Test for bug #628 # select concat("$",format(2500,2)); + +# Test for BUG#7716 +create table t1 ( a timestamp ); +insert into t1 values ( '2004-01-06 12:34' ); +select a from t1 where left(a+0,6) in ( left(20040106,6) ); +select a from t1 where left(a+0,6) = ( left(20040106,6) ); + +select a from t1 where right(a+0,6) in ( right(20040106123400,6) ); +select a from t1 where right(a+0,6) = ( right(20040106123400,6) ); + +select a from t1 where mid(a+0,6,3) in ( mid(20040106123400,6,3) ); +select a from t1 where mid(a+0,6,3) = ( mid(20040106123400,6,3) ); + +drop table t1; + diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 4a1b8470ada..ffbcc1d774b 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -196,6 +196,18 @@ select trim(trailing 'foo' from 'foo'); select trim(leading 'foo' from 'foo'); # +# crashing bug with QUOTE() and LTRIM() or TRIM() fixed +# Bug #7495 +# + +select quote(ltrim(concat(' ', 'a'))); +select quote(trim(concat(' ', 'a'))); + +# Bad results from QUOTE(). Bug #8248 +CREATE TABLE t1 SELECT 1 UNION SELECT 2 UNION SELECT 3; +SELECT QUOTE('A') FROM t1; +DROP TABLE t1; + # Test collation and coercibility # @@ -430,12 +442,6 @@ create table t1 (a int not null primary key, b varchar(40), c datetime); insert into t1 (a,b,c) values (1,'Tom','2004-12-10 12:13:14'),(2,'ball games','2004-12-10 12:13:14'), (3,'Basil','2004-12-10 12:13:14'), (4,'Dean','2004-12-10 12:13:14'),(5,'Ellis','2004-12-10 12:13:14'), (6,'Serg','2004-12-10 12:13:14'), (7,'Sergei','2004-12-10 12:13:14'),(8,'Georg','2004-12-10 12:13:14'),(9,'Salle','2004-12-10 12:13:14'),(10,'Sinisa','2004-12-10 12:13:14'); select count(*) as total, left(c,10) as reg from t1 group by reg order by reg desc limit 0,12; drop table t1; -# crashing bug with QUOTE() and LTRIM() or TRIM() fixed -# Bug #7495 -# - -select quote(ltrim(concat(' ', 'a'))); -select quote(trim(concat(' ', 'a'))); # # Bug#7455 unexpected result: TRIM( FROM ) gives NOT NULL @@ -446,3 +452,30 @@ select trim(null from 'kate') as "must_be_null"; select trim('xyz' from null) as "must_be_null"; select trim(leading NULL from 'kate') as "must_be_null"; select trim(trailing NULL from 'xyz') as "must_be_null"; + +# +# Bug #7751 - conversion for a bigint unsigned constant +# + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + a bigint(20) unsigned default NULL, + PRIMARY KEY (id) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES +('0','16307858876001849059'); + +SELECT CONV('e251273eb74a8ee3', 16, 10); + +EXPLAIN +SELECT id + FROM t1 + WHERE a = 16307858876001849059; + +EXPLAIN + SELECT id + FROM t1 + WHERE a = CONV('e251273eb74a8ee3', 16, 10); + +DROP TABLE t1; diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index eb506a58870..732cdc12cae 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -107,3 +107,12 @@ select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3; # select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3; + +# +# Bug#6726: NOT BETWEEN parse failure +# +create table t1 (a int, b int); +insert into t1 values (1,2), (2,3), (3,4), (4,5); +select * from t1 where a not between 1 and 2; +select * from t1 where a not between 1 and 2 and b not between 3 and 4; +drop table t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index c0447b06303..379f668df1a 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -457,15 +457,6 @@ SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; explain SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; DROP TABLE t1; -# Test for BUG#5400: GROUP_CONCAT returns everything twice. -create table t1 ( col1 int, col2 int ); -insert into t1 values (1,1),(1,2),(1,3),(2,1),(2,2); -select group_concat( distinct col1 ) as alias from t1 - group by col2 having alias like '%'; - -drop table t1; - - #Test for BUG#6976: Aggregate functions have incorrect NULL-ness create table t1 (a int); insert into t1 values(null); @@ -474,3 +465,26 @@ select min(a) is null or null from t1; select 1 and min(a) is null from t1; drop table t1; +# Test for BUG#5400: GROUP_CONCAT returns everything twice. +create table t1 ( col1 int, col2 int ); +insert into t1 values (1,1),(1,2),(1,3),(2,1),(2,2); +select group_concat( distinct col1 ) as alias from t1 + group by col2 having alias like '%'; + +drop table t1; + +# +# Test BUG#8216 when referring in HAVING to n alias which is rand() function +# + +create table t1 (a integer, b integer, c integer); +insert into t1 (a,b) values (1,2),(1,3),(2,5); +select a, 0.1*0+1 r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2=1; +select a, rand()*0+1 r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2=1; +select a,sum(b) from t1 where a=1 group by c; +select a*sum(b) from t1 where a=1 group by c; +select sum(a)*sum(b) from t1 where a=1 group by c; +select a,sum(b) from t1 where a=1 group by c having a=1; +select a as d,sum(b) from t1 where a=1 group by c having d=1; +select sum(a)*sum(b) as d from t1 where a=1 group by c having d > 0; +drop table t1; diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test index f2f71cbe208..5acbcd8eaeb 100644 --- a/mysql-test/t/index_merge.test +++ b/mysql-test/t/index_merge.test @@ -306,6 +306,11 @@ select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200); update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; + +# The next query will not use index i7 in intersection if the OS doesn't +# support file sizes > 2GB. (ha_myisam::ref_length depends on this and index +# scan cost estimates depend on ha_myisam::ref_length) +--replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?" 7 7or16 16 7or16 explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 177867f5205..c34dfc94576 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -2,16 +2,14 @@ # Test for information_schema.schemata & # show databases -show variables variable_name where variable_name like "skip_show_database"; +show variables where variable_name like "skip_show_database"; grant all privileges on test.* to mysqltest_1@localhost; select * from information_schema.SCHEMATA where schema_name > 'm'; select schema_name from information_schema.schemata; -show databases *; show databases like 't%'; show databases; -show databases * where schema_name like 't%'; -show databases * where schema_name = 't%'; +show databases where `database` = 't%'; # Test for information_schema.tables & # show tables @@ -35,12 +33,9 @@ select table_name from information_schema.TABLES where table_schema = "testtets" and table_name like "t%"; select * from information_schema.STATISTICS where TABLE_SCHEMA = "testtets"; -show keys * from t3 where TABLE_SCHEMA Like "test%"; -show keys from t3 where INDEX_NAME = "a_data"; +show keys from t3 where Key_name = "a_data"; show tables like 't%'; ---replace_column 15 # 16 # -show tables * from test where table_name like 't%'; --replace_column 12 # 13 # --replace_result "2147483647 " "21474836479 " show table status; @@ -49,7 +44,7 @@ show full columns from mysql.db like "Insert%"; show full columns from v1; select * from information_schema.COLUMNS where table_name="t1" and column_name= "a"; -show columns * from testtets.t1 where table_name = "t1"; +show columns from testtets.t1 where field like "%a%"; drop view v1; drop tables testtets.t4, testtets.t1, t2, t3; @@ -61,10 +56,7 @@ drop database testtets; select * from information_schema.CHARACTER_SETS where CHARACTER_SET_NAME like 'latin1%'; SHOW CHARACTER SET LIKE 'latin1%'; -SHOW CHARACTER SET * LIKE 'latin1%'; -SHOW CHARACTER SET WHERE CHARACTER_SET_NAME like 'latin1%'; -SHOW CHARACTER SET CHARACTER_SET_NAME WHERE CHARACTER_SET_NAME like 'latin1%'; -SHOW CHARACTER SET * WHERE CHARACTER_SET_NAME like 'latin1%'; +SHOW CHARACTER SET WHERE charset like 'latin1%'; # Test for information_schema.COLLATIONS & # SHOW COLLATION @@ -72,10 +64,7 @@ SHOW CHARACTER SET * WHERE CHARACTER_SET_NAME like 'latin1%'; select * from information_schema.COLLATIONS where COLLATION_NAME like 'latin1%'; SHOW COLLATION LIKE 'latin1%'; -SHOW COLLATION * LIKE 'latin1%'; -SHOW COLLATION WHERE COLLATION_NAME like 'latin1%'; -SHOW COLLATION COLLATION_NAME WHERE COLLATION_NAME like 'latin1%'; -SHOW COLLATION * WHERE COLLATION_NAME like 'latin1%'; +SHOW COLLATION WHERE collation like 'latin1%'; select * from information_schema.COLLATION_CHARACTER_SET_APPLICABILITY where COLLATION_NAME like 'latin1%'; @@ -200,23 +189,27 @@ delete from mysql.tables_priv where user='joe'; delete from mysql.columns_priv where user='joe'; flush privileges; -delimiter //; -create procedure px5 () -begin -declare v int; -declare c cursor for select version from -information_schema.tables where table_schema <> 'information_schema'; -open c; -fetch c into v; -select v; -close c; -end;// - -call px5()// -call px5()// -delimiter ;// -select sql_mode from information_schema.ROUTINES; -drop procedure px5; +# QQ This results in NULLs instead of the version numbers when +# QQ a LOCK TABLES is in effect when selecting from +# QQ information_schema.tables. Until this bug has been fixed, +# QQ this test is disabled /pem +#delimiter //; +#create procedure px5 () +#begin +#declare v int; +#declare c cursor for select version from +#information_schema.tables where table_schema <> 'information_schema'; +#open c; +#fetch c into v; +#select v; +#close c; +#end;// +# +#call px5()// +#call px5()// +#delimiter ;// +#select sql_mode from information_schema.ROUTINES; +#drop procedure px5; create table t1 (a int not null auto_increment,b int, primary key (a)); insert into t1 values (1,1),(NULL,3),(NULL,4); @@ -351,9 +344,9 @@ where table_schema="mysql" and table_name="user"; # test for 'show open tables ... where' show open tables where `table` like "user"; # test for 'show status ... where' -show status variable_name where variable_name like "%database%"; +show status where variable_name like "%database%"; # test for 'show variables ... where' -show variables variable_name where variable_name like "%database%"; +show variables where variable_name like "skip_show_databas"; # # Bug #7981:SHOW GLOBAL STATUS crashes server diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 4fff24a61d5..da27fcfc734 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -129,6 +129,19 @@ insert into t1 values (6); -- error 1062 insert into t1 values (4); select n from t1; +set autocommit=0; +begin; +savepoint `my_savepoint`; +insert into t1 values (7); +savepoint `savept2`; +insert into t1 values (3); +select n from t1; +rollback to savepoint `savept2`; +release savepoint `my_savepoint`; +select n from t1; +-- error 1181 +rollback to savepoint `my_savepoint`; +set autocommit=1; # nop rollback; drop table t1; diff --git a/mysql-test/t/limit.test b/mysql-test/t/limit.test index 61c57c9b468..28b287a5d4a 100644 --- a/mysql-test/t/limit.test +++ b/mysql-test/t/limit.test @@ -49,3 +49,13 @@ SELECT * FROM t1; DELETE FROM t1 WHERE id2 = 0 ORDER BY id desc LIMIT 1; SELECT * FROM t1; DROP TABLE t1; + +# +# Bug#8023 - limit on UNION with from DUAL, causes syntax error +# +create table t1 (a integer); +insert into t1 values (1); +# both queries must return one row +select 1 as a from t1 union all select 1 from dual limit 1; +(select 1 as a from t1) union all (select 1 from dual) limit 1; +drop table t1; diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test index 26fc4e32bda..80da2cad192 100644 --- a/mysql-test/t/lock.test +++ b/mysql-test/t/lock.test @@ -53,8 +53,8 @@ check table t1; # Check error message lock tables t1 write; check table t2; ---error 1100 -insert into t1 select nr from t1; +--error 1143 +insert into t1 select index1,nr from t1; unlock tables; lock tables t1 write, t1 as t1_alias read; insert into t1 select index1,nr from t1 as t1_alias; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4b74dcbe1fb..3f19c7f0c52 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -14,7 +14,7 @@ DROP TABLE t1; # Bug #2005 # -CREATE TABLE t1 (a decimal(240, 20)); +CREATE TABLE t1 (a decimal(64, 20)); INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); --exec $MYSQL_DUMP --compact test t1 diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test index 713aa326e4d..d305c1a9dd7 100644 --- a/mysql-test/t/ndb_autodiscover.test +++ b/mysql-test/t/ndb_autodiscover.test @@ -199,7 +199,7 @@ insert into t4 values (1, "Automatic"); select * from t4; # Remove the table from NDB -system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t4 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t4 >> $NDB_TOOLS_OUTPUT ; # # Test that correct error is returned @@ -230,7 +230,7 @@ select * from t4; flush tables; # Remove the table from NDB -system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t4 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t4 >> $NDB_TOOLS_OUTPUT ; SHOW TABLES; @@ -264,8 +264,8 @@ insert into t8 values (8, "myisam table 8"); insert into t9 values (9); # Remove t3, t5 from NDB -system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t3 > /dev/null ; -system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t5 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t3 >> $NDB_TOOLS_OUTPUT ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t5 >> $NDB_TOOLS_OUTPUT ; # Remove t6, t7 from disk system rm var/master-data/test/t6.frm > /dev/null ; system rm var/master-data/test/t7.frm > /dev/null ; @@ -498,4 +498,4 @@ create table t10 ( insert into t10 values (1, 'kalle'); ---exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test `$NDB_TOOLS_DIR/ndb_show_tables --no-defaults | grep BLOB` > /dev/null 2>&1 || true +--exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test `$NDB_TOOLS_DIR/ndb_show_tables --no-defaults | grep BLOB` >> $NDB_TOOLS_OUTPUT 2>&1 || true diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test index 2671223ada8..a6064f30556 100644 --- a/mysql-test/t/ndb_basic.test +++ b/mysql-test/t/ndb_basic.test @@ -539,3 +539,41 @@ insert into t1 values (1,1),(2,1),(3,1),(4,1),(5,2),(6,1),(7,1); explain select * from t1 where a12345678901234567890123456789a1234567890=2; select * from t1 where a12345678901234567890123456789a1234567890=2; drop table t1; + +# +# test fragment creation +# +# first a table with _many_ fragments per node group +# then a table with just one fragment per node group +# +create table t1 + (a bigint, b bigint, c bigint, d bigint, + primary key (a,b,c,d)) + engine=ndb + max_rows=800000000; +insert into t1 values + (1,2,3,4),(2,3,4,5),(3,4,5,6), + (3,2,3,4),(1,3,4,5),(2,4,5,6), + (1,2,3,5),(2,3,4,8),(3,4,5,9), + (3,2,3,5),(1,3,4,8),(2,4,5,9), + (1,2,3,6),(2,3,4,6),(3,4,5,7), + (3,2,3,6),(1,3,4,6),(2,4,5,7), + (1,2,3,7),(2,3,4,7),(3,4,5,8), + (3,2,3,7),(1,3,4,7),(2,4,5,8), + (1,3,3,4),(2,4,4,5),(3,5,5,6), + (3,3,3,4),(1,4,4,5),(2,5,5,6), + (1,3,3,5),(2,4,4,8),(3,5,5,9), + (3,3,3,5),(1,4,4,8),(2,5,5,9), + (1,3,3,6),(2,4,4,6),(3,5,5,7), + (3,3,3,6),(1,4,4,6),(2,5,5,7), + (1,3,3,7),(2,4,4,7),(3,5,5,8), + (3,3,3,7),(1,4,4,7),(2,5,5,8); +select count(*) from t1; +drop table t1; + +create table t1 + (a bigint, b bigint, c bigint, d bigint, + primary key (a)) + engine=ndb + max_rows=1; +drop table t1; diff --git a/mysql-test/t/ndb_cache.test b/mysql-test/t/ndb_cache.test index abd09424f64..e899e94e4ac 100644 --- a/mysql-test/t/ndb_cache.test +++ b/mysql-test/t/ndb_cache.test @@ -1,31 +1,121 @@ -- source include/have_query_cache.inc -- source include/have_ndb.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + +# Turn on and reset query cache +set GLOBAL query_cache_type=on; set GLOBAL query_cache_size=1355776; reset query cache; flush status; ---disable_warnings -drop table if exists t1,t2; ---enable_warnings - -CREATE TABLE t1 (a int) ENGINE=ndbcluster; -CREATE TABLE t2 (a int); +# Create test table in NDB +CREATE TABLE t1 ( pk int not null primary key, + a int, b int not null, c varchar(20)) ENGINE=ndbcluster; +insert into t1 value (1, 2, 3, 'First row'); +# Perform one query which should be inerted in query cache select * from t1; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; show status like "Qcache_hits"; -select * from t2; -show status like "Qcache_queries_in_cache"; + +# Perform the same query and make sure the query cache is hit +select * from t1; +show status like "Qcache_hits"; + +# Update the table and make sure the correct data is returned +update t1 set a=3 where pk=1; +select * from t1; show status like "Qcache_inserts"; show status like "Qcache_hits"; -select * from t1; -select * from t2; + +# Insert a new record and make sure the correct data is returned +insert into t1 value (2, 7, 8, 'Second row'); +insert into t1 value (4, 5, 6, 'Fourth row'); +select * from t1 order by pk; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1 order by pk; +show status like "Qcache_hits"; + +# Perform a "new" query and make sure the query cache is not hit +select * from t1 where b=3; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +# Same query again... +select * from t1 where b=3; +show status like "Qcache_hits"; + +# Delete from the table +delete from t1 where c='Fourth row'; +show status like "Qcache_queries_in_cache"; +select * from t1 where b=3; +show status like "Qcache_hits"; + +# Start another connection and check that the query cache is hit +connect (con1,localhost,root,,); +connection con1; +use test; +select * from t1 order by pk; +select * from t1 where b=3; +show status like "Qcache_hits"; + +# Update the table and switch to other connection +update t1 set a=4 where b=3; +connect (con2,localhost,root,,); +connection con2; +use test; +show status like "Qcache_queries_in_cache"; +select * from t1 order by pk desc; +select * from t1 order by pk desc; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con1; +select * from t1 order by pk desc; +select * from t1 order by pk desc; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; show status like "Qcache_hits"; -drop table t1, t2; +# Use transactions and make sure the query cache is not updated until +# transaction is commited +begin; +update t1 set a=5 where pk=1; +# Note!! the below test shows that table is invalidated +# before transaction is committed +# TODO Fix so that cache is not invalidated HERE! +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con2; +select * from t1 order by pk desc; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con1; +commit; +# TODO Here query is invalidated once again, commit count in NDB has changed +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con2; +select * from t1 order by pk desc; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con1; +select * from t1 order by pk desc; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +drop table t1; + +show status like "Qcache_queries_in_cache"; SET GLOBAL query_cache_size=0; + + diff --git a/mysql-test/t/ndb_cache2.test b/mysql-test/t/ndb_cache2.test new file mode 100644 index 00000000000..c46935e8601 --- /dev/null +++ b/mysql-test/t/ndb_cache2.test @@ -0,0 +1,126 @@ +-- source include/have_query_cache.inc +-- source include/have_ndb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + + +# Turn on and reset query cache +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +# Turn on thread that will fetch commit count for open tables +set GLOBAL ndb_cache_check_time=5; +reset query cache; +flush status; + +# Wait for thread to wake up and start "working" +sleep 20; + +# Create test table in NDB +CREATE TABLE t1 ( pk int not null primary key, + a int, b int not null, c varchar(20)) ENGINE=ndbcluster; +insert into t1 value (1, 2, 3, 'First row'); + +# Perform one query which should be inerted in query cache +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +# Perform the same query and make sure the query cache is hit +select * from t1; +show status like "Qcache_hits"; + +# Update the table and make sure the correct data is returned +update t1 set a=3 where pk=1; +select * from t1; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +# Insert a new record and make sure the correct data is returned +insert into t1 value (2, 7, 8, 'Second row'); +insert into t1 value (4, 5, 6, 'Fourth row'); +select * from t1 order by pk desc; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1 order by pk desc; +show status like "Qcache_hits"; + +# Perform a "new" query and make sure the query cache is not hit +select * from t1 where b=3; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +# Same query again... +select * from t1 where b=3; +show status like "Qcache_hits"; + +# Delete from the table +delete from t1 where c='Fourth row'; +show status like "Qcache_queries_in_cache"; +select * from t1 where b=3; +show status like "Qcache_hits"; + +# Start another connection and check that the query cache is hit +connect (con1,localhost,root,,); +connection con1; +use test; +select * from t1 order by pk desc; +select * from t1 where b=3; +show status like "Qcache_hits"; + +# Update the table and switch to other connection +update t1 set a=4 where b=3; +connect (con2,localhost,root,,); +connection con2; +use test; +show status like "Qcache_queries_in_cache"; +select * from t1 order by pk desc; +select * from t1 order by pk desc; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con1; +select * from t1 order by pk desc; +select * from t1 order by pk desc; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +# Use transactions and make sure the query cache is not updated until +# transaction is commited +begin; +update t1 set a=5 where pk=1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con2; +select * from t1 order by pk desc; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con1; +commit; +# Sleep to let the query cache thread update commit count +sleep 10; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con2; +select * from t1 order by pk desc; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +connection con1; +select * from t1 order by pk desc; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +drop table t1; + +show status like "Qcache_queries_in_cache"; + +SET GLOBAL query_cache_size=0; +SET GLOBAL ndb_cache_check_time=0; + + diff --git a/mysql-test/t/ndb_cache_multi.test b/mysql-test/t/ndb_cache_multi.test new file mode 100644 index 00000000000..7202b5f8558 --- /dev/null +++ b/mysql-test/t/ndb_cache_multi.test @@ -0,0 +1,64 @@ +-- source include/have_query_cache.inc +-- source include/have_ndb.inc +-- source include/have_multi_ndb.inc + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + + +# Turn on and reset query cache on server1 +connection server1; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +reset query cache; +flush status; + +# Turn on and reset query cache on server2 +connection server2; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +reset query cache; +flush status; + + + +# Create test tables in NDB and load them into cache +# on server1 +connection server1; +create table t1 (a int) engine=ndbcluster; +create table t2 (a int) engine=ndbcluster; +insert into t1 value (2); +insert into t2 value (3); +select * from t1; +select * from t2; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + + +# Connect server2, load table in to cache, then update the table +connection server2; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +update t1 set a=3 where a=2; + +# Connect to server1 and check that cache is invalidated +# and correct data is returned +connection server1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +drop table t1, t2; + + diff --git a/mysql-test/t/ndb_cache_multi2.test b/mysql-test/t/ndb_cache_multi2.test new file mode 100644 index 00000000000..a9d008dba7c --- /dev/null +++ b/mysql-test/t/ndb_cache_multi2.test @@ -0,0 +1,71 @@ +-- source include/have_query_cache.inc +-- source include/have_ndb.inc +-- source include/have_multi_ndb.inc + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + + +# Turn on and reset query cache on server1 +connection server1; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +set GLOBAL ndb_cache_check_time=1; +reset query cache; +flush status; + +# Turn on and reset query cache on server2 +connection server2; +set GLOBAL query_cache_type=on; +set GLOBAL query_cache_size=1355776; +set GLOBAL ndb_cache_check_time=1; +reset query cache; +flush status; + +# Sleep so that the query cache check thread has time to start +sleep 15; + + +# Create test tables in NDB and load them into cache +# on server1 +connection server1; +create table t1 (a int) engine=ndbcluster; +create table t2 (a int) engine=ndbcluster; +insert into t1 value (2); +insert into t2 value (3); +select * from t1; +select * from t2; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + + +# Connect server2, load table in to cache, then update the table +connection server2; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +update t1 set a=3 where a=2; + +# Sleep so that the query cache check thread has time to run +sleep 5; + +# Connect to server1 and check that cache is invalidated +# and correct data is returned +connection server1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +drop table t1, t2; + + diff --git a/mysql-test/t/ndb_index_unique.test b/mysql-test/t/ndb_index_unique.test index 9bbea75028b..2fc7c496fea 100644 --- a/mysql-test/t/ndb_index_unique.test +++ b/mysql-test/t/ndb_index_unique.test @@ -1,7 +1,7 @@ -- source include/have_ndb.inc --disable_warnings -drop table if exists t1, t2, t3, t4, t5, t6, t7; +drop table if exists t1, t2, t3, t4, t5, t6, t7, t8; --enable_warnings # diff --git a/mysql-test/t/ndb_multi.test b/mysql-test/t/ndb_multi.test new file mode 100644 index 00000000000..9286721b677 --- /dev/null +++ b/mysql-test/t/ndb_multi.test @@ -0,0 +1,44 @@ +-- source include/have_ndb.inc +-- source include/have_multi_ndb.inc + + +--disable_warnings +drop table if exists t1, t2, t3, t4; +--enable_warnings + +flush status; + +# Create test tables on server1 +create table t1 (a int) engine=ndbcluster; +create table t2 (a int) engine=ndbcluster; +insert into t1 value (2); +insert into t2 value (3); +select * from t1; +select * from t2; +show status like 'handler_discover%'; + +# Connect to server2 and use the tables from there +connection server2; +flush status; +select * from t1; +update t1 set a=3 where a=2; +show status like 'handler_discover%'; + +# Create a new table on server2 +create table t3 (a int not null primary key, b varchar(22), +c int, last_col text) engine=ndb; +insert into t3 values(1, 'Hi!', 89, 'Longtext column'); +create table t4 (pk int primary key, b int) engine=ndb; + +# Check that the tables are accessible from server1 +connection server1; +select * from t1; +select * from t3; +show status like 'handler_discover%'; +show tables like 't4'; +show status like 'handler_discover%'; +show tables; + +drop table t1, t2, t3, t4; + + diff --git a/mysql-test/t/ndb_restore.test b/mysql-test/t/ndb_restore.test index 3a77289a8fb..d084461f9be 100644 --- a/mysql-test/t/ndb_restore.test +++ b/mysql-test/t/ndb_restore.test @@ -142,10 +142,10 @@ create table t8_c engine=ndbcluster as select * from t8; create table t9_c engine=ndbcluster as select * from t9; ---exec $NDB_MGM --no-defaults -e "start backup" > /dev/null +--exec $NDB_MGM --no-defaults -e "start backup" >> $NDB_TOOLS_OUTPUT drop table t1_c,t2_c,t3_c,t4_c,t5_c,t6_c,t7_c,t8_c,t9_c; ---exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 1 -m -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-1 > /tmp/ndb_restore.out ---exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 2 -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-1 > /tmp/ndb_restore.out +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 1 -m -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-1 >> $NDB_TOOLS_OUTPUT +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 2 -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-1 >> $NDB_TOOLS_OUTPUT show tables; diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index 4b55593fde5..aaff899bf82 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -290,6 +290,14 @@ prepare stmt4 from ' show databases '; execute stmt4; prepare stmt4 from ' show tables from test like ''t2%'' '; execute stmt4; +prepare stmt4 from ' show columns from t2 where field in (select ?) '; +SET @arg00="a"; +execute stmt4 using @arg00; +SET @arg00="b"; +execute stmt4 using @arg00; +SET @arg00=1; +execute stmt4 using @arg00; + prepare stmt4 from ' show columns from t2 from test like ''a%'' '; execute stmt4; create index t2_idx on t2(b); @@ -321,7 +329,7 @@ prepare stmt4 from ' show engine bdb logs '; execute stmt4; --enable_result_log prepare stmt4 from ' show full processlist '; ---replace_column 1 number 6 time +--replace_column 1 number 6 time 3 localhost execute stmt4; prepare stmt4 from ' show grants for user '; --error 1295 diff --git a/mysql-test/t/rpl_charset.test b/mysql-test/t/rpl_charset.test index 52ace9a6aa5..e8a12ff8317 100644 --- a/mysql-test/t/rpl_charset.test +++ b/mysql-test/t/rpl_charset.test @@ -1,11 +1,9 @@ # Replication of character sets. # This test will fail if the server/client does not support enough charsets. -# Remember that there currently exists -# Bug #2326: Charset of table is determined by charset of db only if "USE db;" - source include/master-slave.inc; --disable_warnings +set timestamp=1000000000; drop database if exists mysqltest2; drop database if exists mysqltest3; --enable_warnings @@ -46,7 +44,7 @@ set character_set_client=cp850, collation_connection=latin2_croatian_ci; insert into t1 (b) values(@@character_set_server); insert into t1 (b) values(@@collation_server); # character_set_database and collation_database are not tested as they -# are not replicated (Bar said that this variable may be removed shortly). +# needn't be replicated (Bar said in Jan 2005). insert into t1 (b) values(@@character_set_client); # collation_client does not exist insert into t1 (b) values(@@character_set_connection); @@ -79,9 +77,10 @@ select "--- --slave--" as ""; --enable_query_log select * from mysqltest2.t1 order by a; -# See if SET ONE_SHOT gets into binlog when LOAD DATA -connection master; -load data infile '../../std_data/words.dat' into table t1 (b); +# Presently charset info is not logged with LOAD DATA but it will +# change in Jan 2005 when Dmitri pushes his new LOAD DATA, +# before 5.0.3 goes out. When done, LOAD DATA INFILE should be tested +# here. # See if user var is prefixed with collation in binlog and replicated well. # Note: replication of user variables is broken as far as derivation is @@ -90,6 +89,7 @@ load data infile '../../std_data/words.dat' into table t1 (b); # know if the collation was explicit or not, so we use DERIVATION_NONE, # which provokes error messages (like 'Illegal mix of collation') when # we replay the master's INSERT/etc statements. +connection master; set @a= _cp850 'Müller' collate cp850_general_ci; truncate table t1; insert into t1 (b) values(collation(@a)); @@ -110,13 +110,13 @@ drop database mysqltest3; show binlog events from 95; sync_slave_with_master; -# Check that we can't change global.collation_server +# Check that we can change global.collation_server (since 5.0.3) -error 1387; set global character_set_server=latin2; +set global character_set_server=latin1; # back connection master; -error 1387; set global character_set_server=latin2; +set global character_set_server=latin1; # back # Check that SET ONE_SHOT is really one shot @@ -150,35 +150,9 @@ select hex(c1), hex(c2) from t1; sync_slave_with_master; select hex(c1), hex(c2) from t1; -# Now test for BUG##5705: SET CHARACTER_SET_SERVER etc will be lost if -# STOP SLAVE before following query - -stop slave; -delete from t1; -# Slave is now supposed to have stopped _after_ the INSERT - -# Note that the following positions may change between MySQL versions! - -# This position should be position for the SET ONE SHOT CHARACTER_SET_CLIENT -# command just before the INSERT. -# You can find it by doing: -# ../client/mysqlbinlog var/log/master-bin.000001 | grep -3 CHARACTER_SET | tail -7 -change master to master_log_pos=6809; - -# This position should be position of the INSERT command. -# You can find it by doing: -# -# ../client/mysqlbinlog var/log/master-bin.000001 | grep -3 INSERT | tail -4 - -start slave until master_log_file='master-bin.000001', master_log_pos=6967; - -# Slave is supposed to stop _after_ the INSERT, even though 'master_log_pos' is -# the position of the beginning of the INSERT; after SET slave is not -# supposed to increment position. -wait_for_slave_to_stop; -start slave; -sync_with_master; -select hex(c1), hex(c2) from t1; connection master; +# Let's have a look at generated SETs. +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 drop table t1; sync_slave_with_master; diff --git a/mysql-test/t/rpl_multi_update2-slave.opt b/mysql-test/t/rpl_multi_update2-slave.opt new file mode 100644 index 00000000000..17d4171af0e --- /dev/null +++ b/mysql-test/t/rpl_multi_update2-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=nothing.sensible diff --git a/mysql-test/t/rpl_multi_update2.test b/mysql-test/t/rpl_multi_update2.test new file mode 100644 index 00000000000..bba7700a88e --- /dev/null +++ b/mysql-test/t/rpl_multi_update2.test @@ -0,0 +1,33 @@ +# Let's verify that multi-update is not always skipped by slave if +# some replicate-* rules exist. +# (BUG#7011) + +source include/master-slave.inc; + +CREATE TABLE t1 ( + a int unsigned not null auto_increment primary key, + b int unsigned +) ENGINE=MyISAM; + +CREATE TABLE t2 ( + a int unsigned not null auto_increment primary key, + b int unsigned +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 SELECT NULL, 0 FROM t1; + +INSERT INTO t2 VALUES (NULL, 0), (NULL,1); + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +UPDATE t1, t2 SET t1.b = (t2.b+4) WHERE t1.a = t2.a; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +save_master_pos; +connection slave; +sync_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test index 01d4b0e033c..c0327a7ddb3 100644 --- a/mysql-test/t/rpl_user_variables.test +++ b/mysql-test/t/rpl_user_variables.test @@ -46,7 +46,7 @@ save_master_pos; connection slave; sync_with_master; select * from t1; -show binlog events from 179; +show binlog events from 95; connection master; drop table t1; save_master_pos; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index b0d7ca60f27..594daf66fcb 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -163,18 +163,9 @@ end loop bar| create procedure foo() return 42| -# Doesn't allow queries in FUNCTIONs (for now :-( ) ---error 1314 -create function foo() returns int -begin - declare x int; - select max(c) into x from test.t; - return x; -end| - # Wrong number of arguments create procedure p(x int) - insert into test.t1 values (x)| + set @x = x| create function f(x int) returns int return x+42| @@ -439,14 +430,6 @@ drop procedure bug1965| --error 1327 select 1 into a| -# -# BUG#1654 -# ---error 1314 -create function bug1654() - returns int -return (select sum(t.data) from test.t2 t)| - # # BUG#1653 # @@ -475,7 +458,7 @@ drop table t3| create procedure bug2259() begin declare v1 int; - declare c1 cursor for select s1 from t10; + declare c1 cursor for select s1 from t1; fetch c1 into v1; end| @@ -628,8 +611,10 @@ create procedure bug3294() begin declare continue handler for sqlexception drop table t5; drop table t5; + drop table t5; end| +create table t5 (x int)| --error 1051 call bug3294()| drop procedure bug3294| diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 4f556e34d51..d474fb1c84e 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -859,7 +859,7 @@ drop procedure if exists create_select| create procedure create_select(x char(16), y int) begin insert into test.t1 values (x, y); - create table test.t3 select * from test.t1; + create temporary table test.t3 select * from test.t1; insert into test.t3 values (concat(x, "2"), y+2); end| @@ -970,12 +970,12 @@ drop procedure if exists hndlr1| create procedure hndlr1(val int) begin declare x int default 0; - declare foo condition for 1146; + declare foo condition for 1136; declare bar condition for sqlstate '42S98'; # Just for testing syntax declare zip condition for sqlstate value '42S99'; # Just for testing syntax declare continue handler for foo set x = 1; - insert into test.t666 values ("hndlr1", val); # Non-existing table + insert into test.t1 values ("hndlr1", val, 2); # Too many values if (x) then insert into test.t1 values ("hndlr1", val); # This instead then end if; @@ -994,9 +994,9 @@ begin declare x int default 0; begin - declare exit handler for sqlstate '42S02' set x = 1; + declare exit handler for sqlstate '21S01' set x = 1; - insert into test.t666 values ("hndlr2", val); # Non-existing table + insert into test.t1 values ("hndlr2", val, 2); # Too many values end; insert into test.t1 values ("hndlr2", x); @@ -1027,7 +1027,7 @@ begin declare y int; set y = val + 10; - insert into test.t666 values ("hndlr3", y); # Non-existing table + insert into test.t1 values ("hndlr3", y, 2); # Too many values if x then insert into test.t1 values ("hndlr3", y); end if; @@ -1517,23 +1517,30 @@ drop procedure bug2227| # # BUG#2614 # ---disable_warnings -drop procedure if exists bug2614| ---enable_warnings -create procedure bug2614() -begin - drop table if exists t3; - create table t3 (id int default '0' not null); - insert into t3 select 12; - insert into t3 select * from t3; -end| - ---disable_warnings -call bug2614()| ---enable_warnings -call bug2614()| -drop table t3| -drop procedure bug2614| +# QQ The second insert doesn't work with temporary tables (it was an +# QQ ordinary table before we changed the locking scheme). It results +# QQ in an error: 1137: Can't reopen table: 't3' +# QQ which is a known limit with temporary tables. +# QQ For this reason we can't run this test any more (i.e., if we modify +# QQ it, it's no longer a test case for the bug), but we keep it here +# QQ anyway, for tracability. +#--disable_warnings +#drop procedure if exists bug2614| +#--enable_warnings +#create procedure bug2614() +#begin +# drop table if exists t3; +# create temporary table t3 (id int default '0' not null); +# insert into t3 select 12; +# insert into t3 select * from t3; +#end| +# +#--disable_warnings +#call bug2614()| +#--enable_warnings +#call bug2614()| +#drop table t3| +#drop procedure bug2614| # # BUG#2674 @@ -1912,7 +1919,7 @@ drop procedure if exists bug2460_2| create procedure bug2460_2() begin drop table if exists t3; - create table t3 (s1 int); + create temporary table t3 (s1 int); insert into t3 select 1 union select 1; end| @@ -2093,27 +2100,28 @@ drop table t3| # # BUG#4318 # ---disable_warnings -drop table if exists t3| ---enable_warnings - -create table t3 (s1 int)| -insert into t3 values (3), (4)| - ---disable_warnings -drop procedure if exists bug4318| ---enable_warnings -create procedure bug4318() - handler t3 read next| - -handler t3 open| -# Expect no results, as tables are closed, but there shouldn't be any errors -call bug4318()| -call bug4318()| -handler t3 close| - -drop procedure bug4318| -drop table t3| +#QQ Don't know if HANDLER commands can work with SPs, or at all... +#--disable_warnings +#drop table if exists t3| +#--enable_warnings +# +#create table t3 (s1 int)| +#insert into t3 values (3), (4)| +# +#--disable_warnings +#drop procedure if exists bug4318| +#--enable_warnings +#create procedure bug4318() +# handler t3 read next| +# +#handler t3 open| +## Expect no results, as tables are closed, but there shouldn't be any errors +#call bug4318()| +#call bug4318()| +#handler t3 close| +# +#drop procedure bug4318| +#drop table t3| # # BUG#4902: Stored procedure with SHOW WARNINGS leads to packet error @@ -2712,30 +2720,136 @@ show create procedure bar| --replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like 'bar'| drop procedure bar| -delimiter ;| -drop table t1; -drop table t2; # # rexecution # --disable_warnings -drop procedure if exists p1; +drop procedure if exists p1| --enable_warnings -create procedure p1 () select (select s1 from t1) from t1; -create table t1 (s1 int); -call p1(); -insert into t1 values (1); -call p1(); -drop procedure p1; -drop table t1; +create procedure p1 () + select (select s1 from t3) from t3| + +create table t3 (s1 int)| + +call p1()| +insert into t3 values (1)| +call p1()| +drop procedure p1| +drop table t3| # # backticks # --disable_warnings -drop function if exists foo; +drop function if exists foo| --enable_warnings -create function `foo` () returns int return 5; -select `foo` (); -drop function `foo`; +create function `foo` () returns int + return 5| +select `foo` ()| +drop function `foo`| + +# +# Implicit LOCK/UNLOCK TABLES for table access in functions +# + +--disable_warning +drop function if exists t1max| +--enable_warnings +create function t1max() returns int +begin + declare x int; + select max(data) into x from t1; + return x; +end| + +insert into t1 values ("foo", 3), ("bar", 2), ("zip", 5), ("zap", 1)| +select t1max()| +drop function t1max| + +--disable_warnings +drop table if exists t3| +--enable_warnings +create table t3 ( + v char(16) not null primary key, + c int unsigned not null +)| + +create function getcount(s char(16)) returns int +begin + declare x int; + + select count(*) into x from t3 where v = s; + if x = 0 then + insert into t3 values (s, 1); + else + update t3 set c = c+1 where v = s; + end if; + return x; +end| + +select * from t1 where data = getcount("bar")| +select * from t3| +select getcount("zip")| +select getcount("zip")| +select * from t3| +select getcount(id) from t1 where data = 3| +select getcount(id) from t1 where data = 5| +select * from t3| +drop table t3| +drop function getcount| + +# +# Former BUG#1654 +# QQ Currently crashes +# +#create function bug1654() returns int +# return (select sum(t1.data) from test.t1 t)| +# +#select bug1654()| + +# +# BUG#5240: Stored procedure crash if function has cursor declaration +# +--disable_warnings +drop function if exists bug5240| +--enable_warnings +create function bug5240 () returns int +begin + declare x int; + declare c cursor for select data from t1 limit 1; + + open c; + fetch c into x; + close c; + return x; +end| + +delete from t1| +insert into t1 values ("answer", 42)| +# QQ BUG: This returns the wrong result, id=42 instead of "answer". +select id, bug5240() from t1| +drop function bug5240| + +# +# BUG#5278: Stored procedure packets out of order if SET PASSWORD. +# +--disable_warnings +drop function if exists bug5278| +--enable_warnings +create function bug5278 () returns char +begin + SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass'); + return 'okay'; +end| + +--error 1133 +select bug5278()| +--error 1133 +select bug5278()| +drop function bug5278| + + +delimiter ;| +drop table t1; +drop table t2; diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index fa5c6cb8a5b..e80752eb71b 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -174,4 +174,14 @@ order by masks.p, example; DROP TABLE t1; +# Bug #6368: Make sure backslashes mixed with doubled quotes are handled +# correctly in NO_BACKSLASH_ESCAPES mode +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; + +SET @@SQL_MODE=''; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; + SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index df3f6b49f84..2c15edb5fc3 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -388,9 +388,7 @@ 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); -# The following should give an error, but doesn't until we fix the interface -# for Field_longlong::store() - +-- error 1264 INSERT INTO t1 (col1) VALUES(-9223372036854775809); INSERT INTO t1 (col1) VALUES(9223372036854775808); INSERT INTO t1 (col2) VALUES(-1); @@ -449,7 +447,9 @@ INSERT INTO t1 VALUES ('10.55'),('10.5555'),('-10.55'),('-10.5555'),('11'),('1e+ -- The 2 following inserts should generate a warning, but doesn't yet -- because NUMERIC works like DECIMAL +--error 1264 INSERT INTO t1 VALUES (101.55); +--error 1264 INSERT INTO t1 VALUES (101); --error 1264 INSERT INTO t1 VALUES (-101.55); @@ -459,7 +459,9 @@ INSERT INTO t1 VALUES (1010.55); INSERT INTO t1 VALUES (1010); -- The 2 following inserts should generate a warning, but doesn't yet -- because NUMERIC works like DECIMAL +--error 1264 INSERT INTO t1 VALUES ('101.55'); +--error 1264 INSERT INTO t1 VALUES ('101'); --error 1264 INSERT INTO t1 VALUES ('-101.55'); @@ -475,11 +477,13 @@ UPDATE t1 SET col1 =col1 * 50000 WHERE col1 =11; UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0; --error 1365 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0; ---error 1265 +#--error 1265 +--error 1366 INSERT INTO t1 (col1) VALUES (''); ---error 1265 +#--error 1265 +--error 1366 INSERT INTO t1 (col1) VALUES ('a59b'); ---error 1265 +#--error 1265 INSERT INTO t1 (col1) VALUES ('1a'); INSERT IGNORE INTO t1 (col1) VALUES ('2a'); INSERT IGNORE INTO t1 values (1/0); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 244802d4d6e..9baf082487f 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1419,8 +1419,11 @@ SELECT f1 FROM t1 WHERE f1 <> ALL ( SELECT SUM(f1) AS sf1 FROM t2 HAVING sf1 > 10000); drop table t1,t2; + +# # Test for BUG#7885: Server crash when 'any' subselect compared to # non-existant field. +# create table t1 (a1 int); create table t2 (b1 int); --error 1054 @@ -1428,3 +1431,42 @@ select * from t1 where a2 > any(select b1 from t2); select * from t1 where a1 > any(select b1 from t2); drop table t1,t2; + +# +# Comparison subquery with * and row +# +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +select (select 1,2) = (select * from t1); +# queries whih can be converted to IN +select row(1,2) = ANY (select * from t1); +select row(1,2) != ALL (select * from t1); +drop table t1; + +# +# Comparison subquery and row with nested rows +# +create table t1 (a integer, b integer); +-- error 1241 +select row(1,(2,2)) in (select * from t1 ); +-- error 1241 +select row(1,(2,2)) = (select * from t1 ); +-- error 1241 +select (select * from t1) = row(1,(2,2)); +drop table t1; + +# +# Forward reference detection +# +create table t1 (a integer); +insert into t1 values (1); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +drop table t1; diff --git a/mysql-test/t/subselect_innodb.test b/mysql-test/t/subselect_innodb.test index aa7fe138876..5d796988178 100644 --- a/mysql-test/t/subselect_innodb.test +++ b/mysql-test/t/subselect_innodb.test @@ -145,3 +145,17 @@ SELECT DISTINCT FROM t1; select * from t1; drop table t1; + +# +# cleaning up of results of subselects (BUG#8125) +# +CREATE TABLE `t1` ( `a` char(3) NOT NULL default '', `b` char(3) NOT NULL default '', `c` char(3) NOT NULL default '', PRIMARY KEY (`a`,`b`,`c`)) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (1,1,1); +INSERT INTO t2 VALUES (1,1,1); +PREPARE my_stmt FROM "SELECT t1.b, count(*) FROM t1 group by t1.b having +count(*) > ALL (SELECT COUNT(*) FROM t2 WHERE t2.a=1 GROUP By t2.b)"; +EXECUTE my_stmt; +EXECUTE my_stmt; +deallocate prepare my_stmt; +drop table t1,t2; diff --git a/mysql-test/t/sum_distinct.test b/mysql-test/t/sum_distinct.test index efbb21a7b85..964da9defa6 100644 --- a/mysql-test/t/sum_distinct.test +++ b/mysql-test/t/sum_distinct.test @@ -2,7 +2,7 @@ # Various tests for SUM(DISTINCT ...) # --disable_warnings -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; --enable_warnings CREATE TABLE t1 ( diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index 64420a85189..304ed19b971 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -107,3 +107,10 @@ SELECT * FROM t2; SELECT * FROM t3; DROP TABLE t1, t2, t3; + +# Test that setting YEAR to invalid string results in default value, not +# 2000. (Bug #6067) +CREATE TABLE t1 (y YEAR); +INSERT INTO t1 VALUES ('abc'); +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 80eff1f2859..4f40d97743a 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -84,6 +84,7 @@ drop table t1; # create table t1 (c20 char); insert into t1 values (5000.0); +insert into t1 values (0.5e4); drop table t1; # Errors diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test new file mode 100644 index 00000000000..3922a0448e9 --- /dev/null +++ b/mysql-test/t/type_newdecimal.test @@ -0,0 +1,873 @@ +--disable_warnings +drop table if exists t1; +--enable_warnings +# +# constant IN function test +# +select 1.1 IN (1.0, 1.2); +select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5); +select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5); +select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5); +select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5); +select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5); + +# +# case function test +# +select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END; +select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END; + +# +# non constant IN test +# +create table t1 (a decimal(6,3)); +insert into t1 values (1.0), (NULL), (0.1); +select * from t1; +select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1; +drop table t1; + +# +# if function test +# +create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2); +select * from t1; +show create table t1; +drop table t1; + +# +# NULLIF +# +create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1); +select * from t1; +show create table t1; +drop table t1; + +# +# saving in decimal field with overflow +# + +create table t1 (a decimal(4,2)); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +select a from t1; +drop table t1; +create table t1 (a decimal(4,2) unsigned); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +select a from t1; +drop table t1; + + +# +# saving in field with overflow from decimal +# +create table t1 (a bigint); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (-18446744073709551615.0); +select * from t1; +drop table t1; +create table t1 (a bigint unsigned); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (9999999999999999999999999.000); +insert into t1 values (-1.0); +select * from t1; +drop table t1; +create table t1 (a tinyint); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +select * from t1; +drop table t1; + +# +# test that functions create decimal fields +# +create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1); +show create table t1; +drop table t1; + +# +# conversion from ucs2 +# +CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); +INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0); +update t1 set b=a; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Trydy's tests +# +set session sql_mode='traditional'; +select 1e10/0e0; +create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10)); +insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890); +select * from wl1612; +insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789); +select * from wl1612 where col1=2; +insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789); +select * from wl1612 where col1=3; + +select col1/0 from wl1612; +select col2/0 from wl1612; +select col3/0 from wl1612; + +insert into wl1612 values(5,5000.0005,5000.0005); +insert into wl1612 values(6,5000.0005,5000.0005); +select sum(col2),sum(col3) from wl1612; +#select avg(col2),avg(col3) from wl1612; + +insert into wl1612 values(7,500000.000005,500000.000005); +insert into wl1612 values(8,500000.000005,500000.000005); +select sum(col2),sum(col3) from wl1612 where col1>4; +#select avg(col2),avg(col3) from wl1612 where col1>4; + +#insert into wl1612 (col1,col2) values(9,123456789012345678901234567890); +#insert into wl1612 (col1,col3) values(9,123456789012345678901234567890); + +insert into wl1612 (col1, col2) values(9,1.01234567891); +insert into wl1612 (col1, col2) values(10,1.01234567894); +insert into wl1612 (col1, col2) values(11,1.01234567895); +insert into wl1612 (col1, col2) values(12,1.01234567896); +select col1,col2 from wl1612 where col1>8; + +insert into wl1612 (col1, col3) values(13,1.01234567891); +insert into wl1612 (col1, col3) values(14,1.01234567894); +insert into wl1612 (col1, col3) values(15,1.01234567895); +insert into wl1612 (col1, col3) values(16,1.01234567896); +select col1,col3 from wl1612 where col1>12; + +select col1 from wl1612 where col1>4 and col2=1.01234567891; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col2=1.0123456789; +#-- should return col1 values 9 & 10 +# +select col1 from wl1612 where col1>4 and col2<>1.0123456789; +#-- should return col1 values 5,6,7,8,11,12 +# +select col1 from wl1612 where col1>4 and col2<1.0123456789; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col2<=1.0123456789; +#-- should return col1 values 9 & 10 +# +select col1 from wl1612 where col1>4 and col2>1.0123456789; +#-- should return col1 values 5,6,7,8,11,12 +# +select col1 from wl1612 where col1>4 and col2>=1.0123456789; +#-- should return col1 values 5,6,7,8,910,11,12 +# +#select col1, col2 from wl1612 where col1=11 or col1=12; +select col1 from wl1612 where col1>4 and col2=1.012345679; +#-- should return col1 values 11,12 +# +select col1 from wl1612 where col1>4 and col2<>1.012345679; +#-- should return col1 values 5,6,7,8,9,10 +# +select col1 from wl1612 where col1>4 and col3=1.01234567891; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col3=1.0123456789; +#-- should return col1 values 13,14 +# +select col1 from wl1612 where col1>4 and col3<>1.0123456789; +#-- should return col1 values 5,6,7,8,15,16 +# +select col1 from wl1612 where col1>4 and col3<1.0123456789; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col3<=1.0123456789; +#-- should return col1 values 13,14 +# +select col1 from wl1612 where col1>4 and col3>1.0123456789; +#-- should return col1 values 5,6,7,8,15,16 +# +select col1 from wl1612 where col1>4 and col3>=1.0123456789; +#-- should return col1 values 5,6,7,8,13,14,15,16 +# +select col1 from wl1612 where col1>4 and col3=1.012345679; +#-- should return col1 values 15,16 +# +select col1 from wl1612 where col1>4 and col3<>1.012345679; +#-- should return col1 values 5,6,7,8,13,14 +# +drop table wl1612; +# +select 1/3; +# +select 0.8=0.7+0.1; +#-- should return 1 (true) +# +select 0.7+0.1; +# +create table wl1612_1 (col1 int); +insert into wl1612_1 values(10); +# +select * from wl1612_1 where 0.8=0.7+0.1; +#--should return 1 row (col1=10) +# +select 0.07+0.07 from wl1612_1; +# +select 0.07-0.07 from wl1612_1; +# +select 0.07*0.07 from wl1612_1; +# +select 0.07/0.07 from wl1612_1; +# +drop table wl1612_1; +# +create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_2 values(1,1); +insert into wl1612_2 values(+1,+1); +insert into wl1612_2 values(+01,+01); +insert into wl1612_2 values(+001,+001); +# +select col1,count(*) from wl1612_2 group by col1; +# +select col2,count(*) from wl1612_2 group by col2; +# +drop table wl1612_2; +# +create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_3 values('1','1'); +insert into wl1612_3 values('+1','+1'); +# +insert into wl1612_3 values('+01','+01'); +insert into wl1612_3 values('+001','+001'); +# +select col1,count(*) from wl1612_3 group by col1; +# +select col2,count(*) from wl1612_3 group by col2; +# +drop table wl1612_3; +# +select mod(234,10) ; +#-- should return 4 +# +select mod(234.567,10.555); +#-- should return 2.357 +# +select mod(-234.567,10.555); +#-- should return -2.357 +# +select mod(234.567,-10.555); +#-- should return 2.357 +# +select round(15.1); +#-- should return 15 +# +select round(15.4); +#-- should return 15 +# +select round(15.5); +#-- should return 16 +# +select round(15.6); +#-- should return 16 +# +select round(15.9); +#-- should return 16 +# +select round(-15.1); +#-- should return -15 +# +select round(-15.4); +#-- should return -15 +# +select round(-15.5); +#-- should return -16 +# +select round(-15.6); +#-- should return -16 +# +select round(-15.9); +#-- should return -16 +# +select round(15.1,1); +#-- should return 15.1 +# +select round(15.4,1); +#-- should return 15.4 +# +select round(15.5,1); +#-- should return 15.5 +# +select round(15.6,1); +#-- should return 15.6 +# +select round(15.9,1); +#-- should return 15.9 +# +select round(-15.1,1); +#-- should return -15.1 +# +select round(-15.4,1); +#-- should return -15.4 +# +select round(-15.5,1); +#-- should return -15.5 +# +select round(-15.6,1); +#-- should return -15.6 +# +select round(-15.9,1); +#-- should return -15.9 +# +select round(15.1,0); +#-- should return 15 +# +select round(15.4,0); +#-- should return 15 +# +select round(15.5,0); +#-- should return 16 +# +select round(15.6,0); +#-- should return 16 +# +select round(15.9,0); +#-- should return 16 +# +select round(-15.1,0); +#-- should return -15 +# +select round(-15.4,0); +#-- should return -15 +# +select round(-15.5,0); +#-- should return -16 +# +select round(-15.6,0); +#-- should return -16 +# +select round(-15.9,0); +#-- should return -16 +# +select round(15.1,-1); +#-- should return 20 +# +select round(15.4,-1); +#-- should return 20 +# +select round(15.5,-1); +#-- should return 20 +# +select round(15.6,-1); +#-- should return 20 +# +select round(15.9,-1); +#-- should return 20 +# +select round(-15.1,-1); +#-- should return -20 +# +select round(-15.4,-1); +#-- should return -20 +# +select round(-15.5,-1); +#-- should return -20 +# +select round(-15.6,-1); +#-- should return -20 +# +select round(-15.91,-1); +#-- should return -20 +# +select truncate(5678.123451,0); +#-- should return 5678 +# +select truncate(5678.123451,1); +#-- should return 5678.1 +# +select truncate(5678.123451,2); +#-- should return 5678.12 +# +select truncate(5678.123451,3); +#-- should return 5678.123 +# +select truncate(5678.123451,4); +#-- should return 5678.1234 +# +select truncate(5678.123451,5); +#-- should return 5678.12345 +# +select truncate(5678.123451,6); +#-- should return 5678.123451 +# +select truncate(5678.123451,-1); +#-- should return 5670 +# +select truncate(5678.123451,-2); +#-- should return 5600 +# +select truncate(5678.123451,-3); +#-- should return 5000 +# +select truncate(5678.123451,-4); +#-- should return 0 +# +select truncate(-5678.123451,0); +#-- should return -5678 +# +select truncate(-5678.123451,1); +#-- should return -5678.1 +# +select truncate(-5678.123451,2); +#-- should return -5678.12 +# +select truncate(-5678.123451,3); +#-- should return -5678.123 +# +select truncate(-5678.123451,4); +#-- should return -5678.1234 +# +select truncate(-5678.123451,5); +#-- should return -5678.12345 +# +select truncate(-5678.123451,6); +#-- should return -5678.123451 +# +select truncate(-5678.123451,-1); +#-- should return -5670 +# +select truncate(-5678.123451,-2); +#-- should return -5600 +# +select truncate(-5678.123451,-3); +#-- should return -5000 +# +select truncate(-5678.123451,-4); +#-- should return 0 +# +#drop table if exists wl1612_4; +create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +# +insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345); +# +select col2/9999999999 from wl1612_4 where col1=1; +# +select col3/9999999999 from wl1612_4 where col1=1; +# +select 9999999999/col2 from wl1612_4 where col1=1; +# +select 9999999999/col3 from wl1612_4 where col1=1; +# +select col2*9999999999 from wl1612_4 where col1=1; +# +select col3*9999999999 from wl1612_4 where col1=1; +# +insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345); +# +select col2/9999999999 from wl1612_4 where col1=2; +# +select col3/9999999999 from wl1612_4 where col1=2; +# +select 9999999999/col2 from wl1612_4 where col1=2; +# +select 9999999999/col3 from wl1612_4 where col1=2; +# +select col2*9999999999 from wl1612_4 where col1=2; +# +select col3*9999999999 from wl1612_4 where col1=2; +# +drop table wl1612_4; +# +# +# +# +#-- Additional tests for WL#1612 Precision math +# +#-- 1. Comparisons should show that a number is +#-- exactly equal to its value as displayed. +# +set sql_mode=''; +# +select 23.4 + (-41.7), 23.4 - (41.7) = -18.3; +# +select -18.3=-18.3; +# +select 18.3=18.3; +# +select -18.3=18.3; +# +select 0.8 = 0.7 + 0.1; +# +#-- 2. Adding (one millionth) one million times should be the same as +#-- adding 1. So a stored procedure with many iterations will show if +#-- small errors accumulate. +# +#drop procedure p1; +# +delimiter // +# +create procedure p1 () begin + declare v1, v2, v3, v4 decimal(16,12); declare v5 int; + set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0; + 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()// +#-- should return +# -- v1=1.0000001 +# -- v2=1.999999900000 +# -- v3=1.0000001 +# -- v4=1.999999900000 +# +delimiter ;// +# +drop procedure p1; +# +#-- 3. It should be possible to define a column +#-- with up to 38 digits precision either before +#-- or after the decimal point. Any number which +#-- is inserted, if it's within the range, should +#-- be exactly the same as the number that gets +#-- selected. +# +drop table if exists t1; +# +create table t1 (col1 decimal(38)); +# +insert into t1 values (12345678901234567890123456789012345678); +# +select * from t1; +#-- should return: +#+----------------------------------------+ +#| col1 | +#+----------------------------------------+ +#| 12345678901234567890123456789012345678 | +#+----------------------------------------+ +# +#drop table t1; +# +#create table t1 (col1 decimal(38,38)); +# +#insert into t1 values (.12345678901234567890123456789012345678); +# +#select * from t1; +#-- should return: +#+------------------------------------------+ +#| col1 | +#+------------------------------------------+ +#| 0.12345678901234567890123456789012345678 | +#+------------------------------------------+ +# +drop table t1; +# +create table t1 (col1 decimal(31,30)); +# +insert into t1 values (0.00000000001); +# +select * from t1; +#-- should return: +#+---------------+ +#|col1 | +#+---------------+ +#| 0.00000000001 | +#+---------------+ +# +drop table t1; +# +#-- 4. The usual arithmetic operators / * + - should work. +# +#select 77777777777777777777777777777777777777 / 7777777777777777777777777777777777777 = 10; +#-- should return 0 (false). +# +select 7777777777777777777777777777777777777 * 10; +#-- should return 77777777777777777777777777777777777770 +# +select .7777777777777777777777777777777777777 * + 1000000000000000000; +#-- should return 777777777777777777.7777777777777777777 +# +select .7777777777777777777777777777777777777 - 0.1; +#-- should return .6777777777777777777777777777777777777 +# +select .343434343434343434 + .343434343434343434; +#-- should return .686868686868686868 +# +#-- 5. All arithmetic functions mentioned in the +#MySQL Reference Manual should work. +# +select abs(9999999999999999999999); +#-- should return 9999999999999999999999 +# +select abs(-9999999999999999999999); +#-- should return 9999999999999999999999 +# +select ceiling(99999999999999999999); +#-- should return 99999999999999999999 +# +select ceiling(9.9999999999999999999); +#-- should return 10 +# +select ceiling(-9.9999999999999999999); +#-- should return 9 +# +select floor(9999999999999999999999); +#-- should return 9999999999999999999999 +# +select floor(9.999999999999999999999); +#-- should return 9 +# +select floor(-9.999999999999999999999); +#-- should return -10 +# +select floor(-999999999999999999999.999); +select ceiling(999999999999999999999.999); +# +# +select 99999999999999999999999999999999999999 mod 3; +#-- should return 0 +# +select round(99999999999999999.999); +#-- should return 100000000000000000 +# +select round(-99999999999999999.999); +#-- should return -100000000000000000 +# +select round(99999999999999999.999,3); +#-- should return 100000000000000000.000 +# +select round(-99999999999999999.999,3); +#-- should return -100000000000000000.000 +# +select truncate(99999999999999999999999999999999999999,31); +#-- should return 99999999999999999999999999999999999999.000 +# +select truncate(99.999999999999999999999999999999999999,31); +#-- should return 99.9999999999999999999999999999999 +# +select truncate(99999999999999999999999999999999999999,-31); +-- should return 90000000000000000000000000000000 +# +#-- 6. Set functions (AVG, SUM, COUNT) should work. +# +#drop table if exists t1; +# +#delimiter // +# +#create procedure p1 () begin +# declare v1 int default 1; declare v2 decimal(0,38) default 0; +# create table t1 (col1 decimal(0,38)); +# while v1 <= 10000 do +# insert into t1 values (-v2); +# set v2 = v2 + 0.00000000000000000000000000000000000001; +# set v1 = v1 + 1; +# end while; +# select avg(col1),sum(col1),count(col1) from t1; end;// +# +#call p1()// +#-- should return +# -- avg(col1)=0.00000000000000000000000000000000000001 added 10,000 times, then divided by 10,000 +# -- sum(col1)=0.00000000000000000000000000000000000001 added 10,000 times +# +# -- count(col1)=10000 +# +#delimiter ;// +# +#drop procedure p1; +#drop table t1; +# +#-- 7. When I say DECIMAL(x) I should be able to store x digits. +#-- If I can't, there should be an error at CREATE time. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(254)); +#-- should return SQLSTATE 22003 numeric value out of range +# +#-- 8. When I say DECIMAL(x,y) there should be no silent change of precision or scale. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(0,38)); +# +#show create table t1; +#-- should return: +#+-------+--------------------------------+ +#| Table | Create Table | +#+-------+--------------------------------+ +#| t9 | CREATE TABLE `t1` ( | +#|`s1` decimal(0,38) default NULL | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+--------------------------------+ +# +#drop table t1; +# +#-- 9. From WL#1612 "The future" point 2.: +#-- The standard requires that we treat numbers like "0.5" as +#-- DECIMAL or NUMERIC, not as floating-point. +# +#drop table if exists t1; +# +# +create table t1 as select 0.5; +# +show create table t1; +#-- should return: +#+-------+-----------------------------------+ +#| Table | Create Table | +#+-------+-----------------------------------+ +#| t7 | CREATE TABLE `t1` ( | +#| `0.5` decimal(3,1) NOT NULL default '0.0' | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+-----------------------------------+ +# +drop table t1; +# +#-- 10. From WL#1612, "The future", point 3.: We have to start rounding correctly. +# +select round(1.5),round(2.5); +#-- should return: +#+------------+------------+ +#| round(1.5) | round(2.5) | +#+------------+------------+ +#| 2 | 3 | +#+------------+------------+ +# +#-- 11. From WL#1612, "The future", point 4.: "select 0.07 * 0.07;" should return 0.0049, not 0.00. +#-- If operand#1 has scale X and operand#2 has scale Y, then result should have scale (X+Y). +# +select 0.07 * 0.07; +#-- should return 0.0049 +# +#-- 12. From WL#1612, "The future", point 5.: Division by zero is an error. +# +set sql_mode='traditional'; +# +select 1E-500 = 0; +#-- should return 1 (true). +# +select 1 / 1E-500; +# +#-- should return SQLSTATE 22012 division by zero. +# +select 1 / 0; +#-- should return SQLSTATE 22012 division by zero. +# +#+-------+ +#| 1 / 0 | +#+-------+ +#| NULL | +#+-------+ +#1 row in set, 1 warning (0.00 sec) +# +#-- 13. From WL#1612 "The future" point 6.: Overflow is an error. +# +#set sql_mode=''; +# +#select 1E300 * 1E300; +#-- should return SQLSTATE 22003 numeric value out of range +# +#select 18446744073709551615 + 1; +#-- should return SQLSTATE 22003 numeric value out of range +# +#-- 14. From WL#1612 "The future" point 7.: +#-- If s1 is INTEGER and s2 is DECIMAL, then +#-- "create table tk7 as select avg(s1),avg(s2) from tk;" +#-- should not create a table with "double(17,4)" data types. +#-- The result of AVG must still be exact numeric, with a +#-- scale the same or greater than the operand's scale. +#-- The result of SUM must still be exact numeric, with +#-- a scale the same as the operand's scale. +# +#drop table if exists t1; +#drop table if exists t2; +# +#create table t1 (col1 int, col2 decimal(5)); +# +#create table t2 as select avg(col1),avg(col2) from t1; +# +# +#show create table t2; +#-- should return: +#+-------+---------------------------------+ +#| Table | Create Table | +#+-------+---------------------------------+ +#| t2 | CREATE TABLE `t2` ( | +#| `avg(col1)` decimal(17,4) default NULL, | +#| `avg(col2)` decimal(17,5) default NULL | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+---------------------------------+ +# +#drop table t2; +#drop table t1; +# +#-- 15. From WL#1612 "The future" point 8.: Stop storing leading "+" signs and leading "0"s. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(5,2),col2 decimal(5) zerofill, col3 decimal(3,1)); +# +#insert into t1 values (1,1,1); +# +#select col1 from t1 union select col2 from t1 union select col3 from t1; +# +#drop table t1; +# +#-- 16. From WL#1612, The future" point 9.: +#-- Accept the data type and precision and scale as the user +#-- asks, or return an error, but don't change to something else. +# +#drop table if exists t1; +# +#create table t1 (col1 numeric(4,2)); +# +#show create table t1; +# +#drop table t1; +# +#-- 17. The scripts in the following bugs should work: +# + +#BUG#559 Maximum precision for DECIMAL column ... +#BUG#1499 INSERT/UPDATE into decimal field rounding problem +#BUG#1845 Not correctly recognising value for decimal field +#BUG#2493 Round function doesn't work correctly +#BUG#2649 round(0.5) gives 0 (should be 1) +#BUG#3612 impicite rounding of VARCHARS during aritchmetic operations... +#BUG#3722 SELECT fails for certain values in Double(255,10) column. +#BUG#4485 Floating point conversions are inconsistent +#BUG#4891 MATH +#BUG#5931 Out-of-range values are accepted +#BUG#6048 Stored procedure causes operating system reboot +#BUG#6053 DOUBLE PRECISION literal + +-- 18. Tests from 'traditional' mode tests +# +set sql_mode='ansi,traditional'; +# +CREATE TABLE Sow6_2f (col1 NUMERIC(4,2)); +#-- should return OK +INSERT INTO Sow6_2f VALUES (10.55); +#-- should return OK +INSERT INTO Sow6_2f VALUES (10.5555); +#-- should return OK +INSERT INTO Sow6_2f VALUES (-10.55); +#-- should return OK +INSERT INTO Sow6_2f VALUES (-10.5555); +#-- should return OK +INSERT INTO Sow6_2f VALUES (11); +#-- should return OK +-- error 1264 +INSERT INTO Sow6_2f VALUES (101.55); +#-- should return SQLSTATE 22003 numeric value out of range +-- error 1264 +UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11; +#-- should return SQLSTATE 22003 numeric value out of range +-- error 1365 +UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0; +#-- should return SQLSTATE 22012 division by zero +SELECT MOD(col1,0) FROM Sow6_2f; +#-- should return SQLSTATE 22012 division by zero +-- error 1366 +INSERT INTO Sow6_2f VALUES ('a59b'); +#-- should return SQLSTATE 22018 invalid character value for cast +drop table Sow6_2f; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 6045d8e3c30..be6bc7a48d8 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -682,3 +682,38 @@ show create table t1; drop table t1; drop table t2; +# +# Bug 6931: Date Type column problem when using UNION-Table. +# +create table t1(a1 int, f1 char(10)); +create table t2 +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +union +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +order by f2, a1; +show columns from t2; +drop table t1, t2; + +create table t1 (f1 int); +create table t2 (f1 int, f2 int ,f3 date); +create table t3 (f1 int, f2 char(10)); +create table t4 +( + select t2.f3 as sdate + from t1 + left outer join t2 on (t1.f1 = t2.f1) + inner join t3 on (t2.f2 = t3.f1) + order by t1.f1, t3.f1, t2.f3 +) +union +( + select cast('2004-12-31' as date) as sdate + from t1 + left outer join t2 on (t1.f1 = t2.f1) + inner join t3 on (t2.f2 = t3.f1) + group by t1.f1 + order by t1.f1, t3.f1, t2.f3 +) +order by sdate; +show columns from t4; +drop table t1, t2, t3, t4; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 704263b1216..04192f25ac8 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -170,3 +170,12 @@ insert into t1 values (1, "t1c2-1", 10), (2, "t1c2-2", 20); update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1"; update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1" where t1.c3 = 10; drop table t1, t2; + +# +# Bug #8057 +# +create table t1 (id int not null auto_increment primary key, id_str varchar(32)); +insert into t1 (id_str) values ("test"); +update t1 set id_str = concat(id_str, id) where id = last_insert_id(); +select * from t1; +drop table t1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 6c1ae733647..44a324de867 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -368,8 +368,8 @@ show create table t1; drop table t1; # # What types and widths have variables? -set @arg00= 8, @arg01= 8.8, @arg02= 'a string'; -create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3; +set @arg00= 8, @arg01= 8.8, @arg02= 'a string', @arg03= 0.2e0; +create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3, @arg03 as c4; show create table t1; drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 3a60f538a31..46ba0953008 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -863,12 +863,15 @@ create view v1 (a,a) as select 'a','a'; # # SP variables inside view test # -delimiter //; -create procedure p1 () begin declare v int; create view v1 as select v; end;// -delimiter ;// --- error 1351 -call p1(); -drop procedure p1; +# QQ This can't be tested with the new table locking for functions, +# QQ since views created in an SP can't be used within the same SP +# QQ (just as for tables). Instead it fails with error 1146. +#delimiter //; +#create procedure p1 () begin declare v int; create view v1 as select v; end;// +#delimiter ;// +#-- error 1351 +#call p1(); +#drop procedure p1; # # updatablity should be transitive diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index c14b2899b4b..e0d6288f76b 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -166,7 +166,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) gptr point; reg1 USED_MEM *next= 0; reg2 USED_MEM **prev; - + DBUG_ENTER("alloc_root"); + DBUG_PRINT("enter",("root: 0x%lx", mem_root)); DBUG_ASSERT(alloc_root_inited(mem_root)); Size= ALIGN_SIZE(Size); @@ -213,7 +214,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) mem_root->used= next; mem_root->first_block_usage= 0; } - return(point); + DBUG_PRINT("exit",("ptr: 0x%lx", (ulong) point)); + DBUG_RETURN(point); #endif } diff --git a/mysys/my_handler.c b/mysys/my_handler.c index 6e634dc447c..87e526d0ea3 100644 --- a/mysys/my_handler.c +++ b/mysys/my_handler.c @@ -43,7 +43,7 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, return 0; if (skip_end_space && a_length != b_length) { - int swap= 0; + int swap= 1; /* We are using space compression. We have to check if longer key has next character < ' ', in which case it's less than the shorter @@ -57,12 +57,12 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, /* put shorter key in a */ a_length= b_length; a= b; - swap= -1 ^ 1; /* swap sign of result */ + swap= -1; /* swap sign of result */ } for (end= a + a_length-length; a < end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } return 0; } diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp index 91cfc0cb22a..6b9085fbdca 100644 --- a/ndb/include/ndbapi/NdbDictionary.hpp +++ b/ndb/include/ndbapi/NdbDictionary.hpp @@ -140,9 +140,9 @@ public: enum FragmentType { FragUndefined = 0, ///< Fragmentation type undefined or default FragSingle = 1, ///< Only one fragment - FragAllSmall = 2, ///< One fragment per node group - FragAllMedium = 3, ///< Default value. Two fragments per node group. - FragAllLarge = 4 ///< Eight fragments per node group. + FragAllSmall = 2, ///< One fragment per node, default + FragAllMedium = 3, ///< two fragments per node + FragAllLarge = 4 ///< Four fragments per node. }; }; diff --git a/ndb/include/ndbapi/NdbTransaction.hpp b/ndb/include/ndbapi/NdbTransaction.hpp index e0b78511ca3..50e4e766803 100644 --- a/ndb/include/ndbapi/NdbTransaction.hpp +++ b/ndb/include/ndbapi/NdbTransaction.hpp @@ -804,6 +804,8 @@ private: void remove_list(NdbOperation*& head, NdbOperation*); void define_scan_op(NdbIndexScanOperation*); + + friend class HugoOperations; }; #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL diff --git a/ndb/include/portlib/NdbThread.h b/ndb/include/portlib/NdbThread.h index 212f7de9384..e86deee4354 100644 --- a/ndb/include/portlib/NdbThread.h +++ b/ndb/include/portlib/NdbThread.h @@ -76,7 +76,7 @@ int NdbThread_WaitFor(struct NdbThread* p_wait_thread, void** status); * * * status: exit code */ -void NdbThread_Exit(int status); +void NdbThread_Exit(void *status); /** * Set thread concurrency level diff --git a/ndb/src/common/portlib/NdbPortLibTest.cpp b/ndb/src/common/portlib/NdbPortLibTest.cpp index 55b9ccec5f2..d7892411851 100644 --- a/ndb/src/common/portlib/NdbPortLibTest.cpp +++ b/ndb/src/common/portlib/NdbPortLibTest.cpp @@ -54,10 +54,7 @@ extern "C" void* thread1func(void* arg) if (arg1 != 7) fail("TEST1", "Wrong arg"); - NdbThread_Exit(returnvalue); - - return NULL; - + return returnvalue; } // test 2 variables and funcs @@ -80,10 +77,7 @@ extern "C" void* test2func(void* arg) fail("TEST2", "Failed to unlock mutex"); int returnvalue = arg1; - NdbThread_Exit(returnvalue); - - return NULL; - + return returnvalue; } @@ -129,8 +123,7 @@ extern "C" void* testfunc(void* arg) } while(tmpVar<100); - NdbThread_Exit(0); - return NULL; + return 0; } extern "C" void* testTryLockfunc(void* arg) @@ -169,8 +162,7 @@ extern "C" void* testTryLockfunc(void* arg) } while(tmpVar<100); - NdbThread_Exit(0); - return NULL; + return 0; } diff --git a/ndb/src/common/portlib/NdbThread.c b/ndb/src/common/portlib/NdbThread.c index 5f2e6021c43..aaee9b45069 100644 --- a/ndb/src/common/portlib/NdbThread.c +++ b/ndb/src/common/portlib/NdbThread.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #define MAX_THREAD_NAME 16 @@ -39,21 +39,28 @@ struct NdbThread static void* ndb_thread_wrapper(void* _ss){ - void * ret; - struct NdbThread * ss = (struct NdbThread *)_ss; - DBUG_ENTER("ndb_thread_wrapper"); -#ifdef NDB_SHM_TRANSPORTER - if (g_ndb_shm_signum) + my_thread_init(); { - sigset_t mask; - DBUG_PRINT("info",("Block signum %d",g_ndb_shm_signum)); - sigemptyset(&mask); - sigaddset(&mask, g_ndb_shm_signum); - pthread_sigmask(SIG_BLOCK, &mask, 0); - } + DBUG_ENTER("ndb_thread_wrapper"); +#ifdef NDB_SHM_TRANSPORTER + if (g_ndb_shm_signum) + { + sigset_t mask; + DBUG_PRINT("info",("Block signum %d",g_ndb_shm_signum)); + sigemptyset(&mask); + sigaddset(&mask, g_ndb_shm_signum); + pthread_sigmask(SIG_BLOCK, &mask, 0); + } #endif - ret= (* ss->func)(ss->object); - DBUG_RETURN(ret); + { + void *ret; + struct NdbThread * ss = (struct NdbThread *)_ss; + ret= (* ss->func)(ss->object); + NdbThread_Exit(ret); + } + /* will never be reached */ + DBUG_RETURN(0); + } } @@ -130,9 +137,10 @@ int NdbThread_WaitFor(struct NdbThread* p_wait_thread, void** status) } -void NdbThread_Exit(int status) +void NdbThread_Exit(void *status) { - pthread_exit(&status); + my_thread_end(); + pthread_exit(status); } diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp index 7b0f2d7247b..e22b0c30c1e 100644 --- a/ndb/src/common/transporter/TransporterRegistry.cpp +++ b/ndb/src/common/transporter/TransporterRegistry.cpp @@ -1108,11 +1108,8 @@ TransporterRegistry::setIOState(NodeId nodeId, IOState state) { static void * run_start_clients_C(void * me) { - my_thread_init(); ((TransporterRegistry*) me)->start_clients_thread(); - my_thread_end(); - NdbThread_Exit(0); - return me; + return 0; } // Run by kernel thread diff --git a/ndb/src/common/util/NdbSqlUtil.cpp b/ndb/src/common/util/NdbSqlUtil.cpp index d5f06f119ee..bff829cbaf8 100644 --- a/ndb/src/common/util/NdbSqlUtil.cpp +++ b/ndb/src/common/util/NdbSqlUtil.cpp @@ -15,6 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include int NdbSqlUtil::char_compare(const char* s1, unsigned n1, @@ -550,8 +551,6 @@ NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p return +1; return 0; } - assert(! full); - return CmpUnknown; #else char t1[4], t2[4]; if (n1 == 3 && n2 == 3) @@ -562,6 +561,7 @@ NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p p2 = t2; n1 = n2 = 4; } +#ifdef ndb_date_sol9x86_cc_xO3_madness if (n2 >= 4) { // may access 4-th byte const uchar* v1 = (const uchar*)p1; const uchar* v2 = (const uchar*)p2; @@ -576,9 +576,40 @@ NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p return +1; return 0; } +#else + if (n2 >= 4) { + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + uint j1 = uint3korr(v1); + uint j2 = uint3korr(v2); + uint d1 = (j1 & 31); + uint d2 = (j2 & 31); + j1 = (j1 >> 5); + j2 = (j2 >> 5); + uint m1 = (j1 & 15); + uint m2 = (j2 & 15); + j1 = (j1 >> 4); + j2 = (j2 >> 4); + uint y1 = j1; + uint y2 = j2; + if (y1 < y2) + return -1; + if (y1 > y2) + return +1; + if (m1 < m2) + return -1; + if (m1 > m2) + return +1; + if (d1 < d2) + return -1; + if (d1 > d2) + return +1; + return 0; + } +#endif +#endif assert(! full); return CmpUnknown; -#endif } // not supported @@ -828,6 +859,8 @@ NdbSqlUtil::strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstL int n2 = (*cs->coll->strnxfrm)(cs, xsp, sizeof(xsp), nsp, n1); if (n2 <= 0) return -1; + // XXX bug workaround - strnxfrm may not write full string + memset(dst, 0x0, dstLen); // strxfrm argument string - returns no error indication int n3 = (*cs->coll->strnxfrm)(cs, dst, dstLen, src, srcLen); // pad with strxfrm-ed space chars diff --git a/ndb/src/common/util/SocketServer.cpp b/ndb/src/common/util/SocketServer.cpp index 8bee256684d..da06389b5df 100644 --- a/ndb/src/common/util/SocketServer.cpp +++ b/ndb/src/common/util/SocketServer.cpp @@ -186,11 +186,7 @@ extern "C" void* socketServerThread_C(void* _ss){ SocketServer * ss = (SocketServer *)_ss; - - my_thread_init(); ss->doRun(); - my_thread_end(); - NdbThread_Exit(0); return 0; } @@ -309,11 +305,8 @@ void* sessionThread_C(void* _sc){ SocketServer::Session * si = (SocketServer::Session *)_sc; - my_thread_init(); if(!transfer(si->m_socket)){ si->m_stopped = true; - my_thread_end(); - NdbThread_Exit(0); return 0; } @@ -325,8 +318,6 @@ sessionThread_C(void* _sc){ } si->m_stopped = true; - my_thread_end(); - NdbThread_Exit(0); return 0; } diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 86bbf27f40e..840466460cb 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -3201,7 +3201,7 @@ Backup::execSTART_BACKUP_REQ(Signal* signal) return; }//if - tabPtr.p->triggerAllocated[i] = true; + tabPtr.p->triggerAllocated[j] = true; trigPtr.p->backupPtr = ptr.i; trigPtr.p->tableId = tabPtr.p->tableId; trigPtr.p->tab_ptr_i = tabPtr.i; diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index 0b87a2f9691..dd68599f4f6 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -4385,7 +4385,8 @@ void Dbacc::commitOperation(Signal* signal) Uint32 tmp2Olq; if ((operationRecPtr.p->commitDeleteCheckFlag == ZFALSE) && - (operationRecPtr.p->operation != ZSCAN_OP)) { + (operationRecPtr.p->operation != ZSCAN_OP) && + (operationRecPtr.p->operation != ZREAD)) { jam(); /* This method is used to check whether the end result of the transaction will be to delete the tuple. In this case all operation will be marked diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index cf0b1419697..af75707560a 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -6178,7 +6178,7 @@ void Dbdih::execCREATE_FRAGMENTATION_REQ(Signal * signal){ break; case DictTabInfo::AllNodesMediumTable: jam(); - noOfFragments = csystemnodes; + noOfFragments = 2 * csystemnodes; break; case DictTabInfo::AllNodesLargeTable: jam(); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index d9fe17af40a..c34d4ddb566 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -8817,13 +8817,14 @@ void Dblqh::finishScanrec(Signal* signal) return; } + ndbrequire(restart.p->scanState == ScanRecord::IN_QUEUE); + ScanRecordPtr tmpScan = scanptr; TcConnectionrecPtr tmpTc = tcConnectptr; tcConnectptr.i = restart.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); restart.p->scanNumber = scanNumber; - restart.p->scanState = ScanRecord::WAIT_ACC_SCAN; queue.remove(restart); scans.add(restart); @@ -8838,10 +8839,18 @@ void Dblqh::finishScanrec(Signal* signal) ndbout_c("adding-r (%d %d)", restart.p->scanNumber, restart.p->fragPtrI); #endif } - - scanptr = restart; - continueAfterReceivingAllAiLab(signal); - + + restart.p->scanState = ScanRecord::SCAN_FREE; // set in initScanRec + if(tcConnectptr.p->transactionState == TcConnectionrec::SCAN_STATE_USED) + { + jam(); + scanptr = restart; + continueAfterReceivingAllAiLab(signal); + } + else + { + ndbrequire(tcConnectptr.p->transactionState == TcConnectionrec::WAIT_SCAN_AI); + } scanptr = tmpScan; tcConnectptr = tmpTc; }//Dblqh::finishScanrec() diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 51fd50c8c46..6325f659e39 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -9220,6 +9220,8 @@ void Dbtc::execDIGETPRIMCONF(Signal* signal) scanFragptr.p->lqhBlockref = ref; scanFragptr.p->m_connectCount = getNodeInfo(tnodeid).m_connectCount; sendScanFragReq(signal, scanptr.p, scanFragptr.p); + if(ERROR_INSERTED(8035)) + globalTransporterRegistry.performSend(); attrbufptr.i = cachePtr.p->firstAttrbuf; while (attrbufptr.i != RNIL) { jam(); @@ -9229,6 +9231,8 @@ void Dbtc::execDIGETPRIMCONF(Signal* signal) attrbufptr.p, ref); attrbufptr.i = attrbufptr.p->attrbuf[ZINBUF_NEXT]; + if(ERROR_INSERTED(8035)) + globalTransporterRegistry.performSend(); }//while scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE; scanFragptr.p->startFragTimer(ctcTimer); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 9778c938e0f..bc1700c12ad 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1865,6 +1865,11 @@ int Dbtup::interpreterNextLab(Signal* signal, } else { + /* --------------------------------------------------------- */ + // If length of argument rounded to nearest word is + // the same as attribute size, use that as argument size + /* --------------------------------------------------------- */ + if ((((argLen + 3) >> 2) << 2) == attrLen) argLen= attrLen; res = (*sqlType.m_cmp)(cs, s1, attrLen, s2, argLen, true); } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp index f50d3a49df6..5640fdf2899 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp @@ -250,7 +250,7 @@ Dbtux::readKeyAttrs(const Frag& frag, TreeEnt ent, unsigned start, Data keyData) debugOut << "readKeyAttrs:" << endl; ConstData data = keyData; Uint32 totalSize = 0; - for (Uint32 i = start; i < numAttrs; i++) { + for (Uint32 i = start; i < frag.m_numAttrs; i++) { Uint32 attrId = data.ah().getAttributeId(); Uint32 dataSize = data.ah().getDataSize(); debugOut << i << " attrId=" << attrId << " size=" << dataSize; diff --git a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp index ddf1681479c..f76440a462a 100644 --- a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp +++ b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp @@ -82,7 +82,6 @@ static int numAsyncFiles = 0; extern "C" void * runAsyncFile(void* arg) { - my_thread_init(); ((AsyncFile*)arg)->run(); return (NULL); } @@ -219,7 +218,8 @@ AsyncFile::run() rmrfReq(request, (char*)theFileName.c_str(), request->par.rmrf.own_directory); break; case Request:: end: - closeReq(request); + if (theFd > 0) + closeReq(request); endReq(); return; default: @@ -239,6 +239,7 @@ void AsyncFile::openReq(Request* request) { m_openedWithSync = false; m_syncFrequency = 0; + m_syncCount= 0; // for open.flags, see signal FSOPENREQ #ifdef NDB_WIN32 @@ -329,7 +330,6 @@ void AsyncFile::openReq(Request* request) } else { #endif m_openedWithSync = false; - m_syncCount = 0; m_syncFrequency = Global_syncFreq; #if 0 } @@ -656,6 +656,7 @@ AsyncFile::writeBuffer(const char * buf, size_t size, off_t offset, } #endif + m_syncCount+= bytes_written; buf += bytes_written; size -= bytes_written; offset += bytes_written; @@ -682,6 +683,10 @@ AsyncFile::closeReq(Request * request) hFile = INVALID_HANDLE_VALUE; #else if (-1 == ::close(theFd)) { +#ifndef DBUG_OFF + if (theFd == -1) + abort(); +#endif request->error = errno; } theFd = -1; @@ -700,7 +705,8 @@ bool AsyncFile::isOpen(){ void AsyncFile::syncReq(Request * request) { - if(m_openedWithSync){ + if(m_openedWithSync || + m_syncCount == 0){ return; } #ifdef NDB_WIN32 @@ -756,7 +762,6 @@ AsyncFile::appendReq(Request * request){ if(m_syncFrequency != 0 && m_syncCount > m_syncFrequency){ syncReq(request); - request->error = 0; } } @@ -870,8 +875,6 @@ void AsyncFile::endReq() { // Thread is ended with return if (theWriteBuffer) NdbMem_Free(theWriteBuffer); - my_thread_end(); - NdbThread_Exit(0); } diff --git a/ndb/src/kernel/blocks/ndbfs/MemoryChannelTest/MemoryChannelTest.cpp b/ndb/src/kernel/blocks/ndbfs/MemoryChannelTest/MemoryChannelTest.cpp index aeab9f7828d..b98c60693f4 100644 --- a/ndb/src/kernel/blocks/ndbfs/MemoryChannelTest/MemoryChannelTest.cpp +++ b/ndb/src/kernel/blocks/ndbfs/MemoryChannelTest/MemoryChannelTest.cpp @@ -40,7 +40,6 @@ extern "C" void* runProducer(void*arg) NdbSleep_MilliSleep(i); i++; } - NdbThread_Exit(0); return NULL; } @@ -58,7 +57,6 @@ extern "C" void* runConsumer(void* arg) delete p; } - NdbThread_Exit(0); return NULL; } @@ -92,7 +90,6 @@ extern "C" void* runProducer2(void*arg) NdbSleep_MilliSleep(i); i++; } - NdbThread_Exit(0); return NULL; } @@ -111,7 +108,6 @@ extern "C" void* runConsumer2(void* arg) delete p; } ndbout << "Consumer2: " << count << " received" << endl; - NdbThread_Exit(0); return NULL; } diff --git a/ndb/src/kernel/vm/FastScheduler.cpp b/ndb/src/kernel/vm/FastScheduler.cpp index bd7dd2d1942..a883882e452 100644 --- a/ndb/src/kernel/vm/FastScheduler.cpp +++ b/ndb/src/kernel/vm/FastScheduler.cpp @@ -76,19 +76,26 @@ FastScheduler::activateSendPacked() globalData.loopMax = 2048; }//FastScheduler::activateSendPacked() +//------------------------------------------------------------------------ +// sendPacked is executed at the end of the loop. +// To ensure that we don't send any messages before executing all local +// packed signals we do another turn in the loop (unless we have already +// executed too many signals in the loop). +//------------------------------------------------------------------------ void FastScheduler::doJob() { + Uint32 init_loopCount = 0; + Uint32 TminLoops = getBOccupancy() + EXTRA_SIGNALS_PER_DO_JOB; + Uint32 TloopMax = (Uint32)globalData.loopMax; + if (TminLoops < TloopMax) { + TloopMax = TminLoops; + }//if + if (TloopMax < MIN_NUMBER_OF_SIG_PER_DO_JOB) { + TloopMax = MIN_NUMBER_OF_SIG_PER_DO_JOB; + }//if do{ - Uint32 loopCount = 0; - Uint32 TminLoops = getBOccupancy() + EXTRA_SIGNALS_PER_DO_JOB; - Uint32 TloopMax = (Uint32)globalData.loopMax; - if (TminLoops < TloopMax) { - TloopMax = TminLoops; - }//if - if (TloopMax < MIN_NUMBER_OF_SIG_PER_DO_JOB) { - TloopMax = MIN_NUMBER_OF_SIG_PER_DO_JOB; - }//if + Uint32 loopCount = init_loopCount; register Uint32 tHighPrio = globalData.highestAvailablePrio; register Signal* signal = getVMSignals(); while ((tHighPrio < LEVEL_IDLE) && (loopCount < TloopMax)) { @@ -151,7 +158,7 @@ FastScheduler::doJob() if (globalData.sendPackedActivated == 1) { Uint32 t1 = theDoJobTotalCounter; Uint32 t2 = theDoJobCallCounter; - t1 += loopCount; + t1 += (loopCount - init_loopCount); t2++; theDoJobTotalCounter = t1; theDoJobCallCounter = t2; @@ -161,7 +168,11 @@ FastScheduler::doJob() theDoJobTotalCounter = 0; }//if }//if - } while (getBOccupancy() > MAX_OCCUPANCY); + init_loopCount = loopCount; + sendPacked(); + } while ((getBOccupancy() > MAX_OCCUPANCY) || + ((init_loopCount < TloopMax) && + (globalData.highestAvailablePrio < LEVEL_IDLE))); }//FastScheduler::doJob() void FastScheduler::sendPacked() diff --git a/ndb/src/kernel/vm/ThreadConfig.cpp b/ndb/src/kernel/vm/ThreadConfig.cpp index 4844bb9a477..76fcc4ba84f 100644 --- a/ndb/src/kernel/vm/ThreadConfig.cpp +++ b/ndb/src/kernel/vm/ThreadConfig.cpp @@ -173,9 +173,6 @@ void ThreadConfig::ipControlLoop() // until all buffers are empty or until we have executed 2048 signals. //-------------------------------------------------------------------- globalScheduler.doJob(); - - globalScheduler.sendPacked(); - }//while globalData.incrementWatchDogCounter(6); diff --git a/ndb/src/kernel/vm/WatchDog.cpp b/ndb/src/kernel/vm/WatchDog.cpp index 4e07dc1df90..23475a478d3 100644 --- a/ndb/src/kernel/vm/WatchDog.cpp +++ b/ndb/src/kernel/vm/WatchDog.cpp @@ -27,10 +27,7 @@ extern "C" void* runWatchDog(void* w){ - my_thread_init(); ((WatchDog*)w)->run(); - my_thread_end(); - NdbThread_Exit(0); return NULL; } diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index bb48f08dda0..c0fceac66e0 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -457,8 +457,6 @@ event_thread_run(void* m) { NdbMgmHandle handle= *(NdbMgmHandle*)m; - my_thread_init(); - int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 }; int fd = ndb_mgm_listen_event(handle, filter); if (fd > 0) @@ -478,9 +476,7 @@ event_thread_run(void* m) do_event_thread= -1; } - my_thread_end(); - NdbThread_Exit(0); - return 0; + return NULL; } bool diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index a9c53f606e2..d2682d7dd58 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -3204,13 +3204,27 @@ fixShmKey(InitConfigFileParser::Context & ctx, const char *) { DBUG_ENTER("fixShmKey"); { + static int last_signum= -1; Uint32 signum; if(!ctx.m_currentSection->get("Signum", &signum)) { signum= OPT_NDB_SHM_SIGNUM_DEFAULT; + if (signum <= 0) + { + ctx.reportError("Unable to set default parameter for [SHM]Signum" + " please specify [SHM DEFAULT]Signum"); + return false; + } ctx.m_currentSection->put("Signum", signum); DBUG_PRINT("info",("Added Signum=%u", signum)); } + if ( last_signum != (int)signum && last_signum >= 0 ) + { + ctx.reportError("All shared memory transporters must have same [SHM]Signum defined." + " Use [SHM DEFAULT]Signum"); + return false; + } + last_signum= (int)signum; } { Uint32 id1= 0, id2= 0, key= 0; diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 6c52747e222..fc880079b40 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -70,12 +70,7 @@ void * MgmtSrvr::logLevelThread_C(void* m) { MgmtSrvr *mgm = (MgmtSrvr*)m; - my_thread_init(); mgm->logLevelThreadRun(); - - my_thread_end(); - NdbThread_Exit(0); - /* NOTREACHED */ return 0; } @@ -83,12 +78,7 @@ void * MgmtSrvr::signalRecvThread_C(void *m) { MgmtSrvr *mgm = (MgmtSrvr*)m; - my_thread_init(); mgm->signalRecvThreadRun(); - - my_thread_end(); - NdbThread_Exit(0); - /* NOTREACHED */ return 0; } diff --git a/ndb/src/ndbapi/ClusterMgr.cpp b/ndb/src/ndbapi/ClusterMgr.cpp index ef6e35e0702..41ae532164b 100644 --- a/ndb/src/ndbapi/ClusterMgr.cpp +++ b/ndb/src/ndbapi/ClusterMgr.cpp @@ -54,7 +54,6 @@ runClusterMgr_C(void * me) #ifdef NDB_OSE NdbSleep_MilliSleep(50); #endif - NdbThread_Exit(0); return NULL; } @@ -563,10 +562,7 @@ extern "C" void* runArbitMgr_C(void* me) { - my_thread_init(); ((ArbitMgr*) me)->threadMain(); - my_thread_end(); - NdbThread_Exit(0); return NULL; } diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index ca118cd0994..f917fcce18b 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -295,7 +295,7 @@ void NdbTableImpl::init(){ clearNewProperties(); m_frm.clear(); - m_fragmentType = NdbDictionary::Object::FragAllMedium; + m_fragmentType = NdbDictionary::Object::FragAllSmall; m_logging = true; m_kvalue = 6; m_minLoadFactor = 78; diff --git a/ndb/src/ndbapi/TransporterFacade.cpp b/ndb/src/ndbapi/TransporterFacade.cpp index 20d98c63a67..5b5394f0965 100644 --- a/ndb/src/ndbapi/TransporterFacade.cpp +++ b/ndb/src/ndbapi/TransporterFacade.cpp @@ -405,11 +405,8 @@ extern "C" void* runSendRequest_C(void * me) { - my_thread_init(); ((TransporterFacade*) me)->threadMainSend(); - my_thread_end(); - NdbThread_Exit(0); - return me; + return 0; } void TransporterFacade::threadMainSend(void) @@ -443,11 +440,8 @@ extern "C" void* runReceiveResponse_C(void * me) { - my_thread_init(); ((TransporterFacade*) me)->threadMainReceive(); - my_thread_end(); - NdbThread_Exit(0); - return me; + return 0; } void TransporterFacade::threadMainReceive(void) diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index 56c007350e6..157eff16f26 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -87,11 +87,8 @@ const char *Ndb_cluster_connection::get_connectstring(char *buf, extern "C" pthread_handler_decl(run_ndb_cluster_connection_connect_thread, me) { - my_thread_init(); g_run_connect_thread= 1; ((Ndb_cluster_connection_impl*) me)->connect_thread(); - my_thread_end(); - NdbThread_Exit(0); return me; } diff --git a/ndb/test/include/HugoOperations.hpp b/ndb/test/include/HugoOperations.hpp index 38e53d765ec..e421d9b5b6d 100644 --- a/ndb/test/include/HugoOperations.hpp +++ b/ndb/test/include/HugoOperations.hpp @@ -33,6 +33,8 @@ public: int closeTransaction(Ndb*); NdbTransaction* getTransaction(); void refresh(); + + void setTransactionId(Uint64); int pkInsertRecord(Ndb*, int recordNo, diff --git a/ndb/test/include/NDBT_Test.hpp b/ndb/test/include/NDBT_Test.hpp index f9fbb6b186d..1b9c2751f64 100644 --- a/ndb/test/include/NDBT_Test.hpp +++ b/ndb/test/include/NDBT_Test.hpp @@ -191,7 +191,7 @@ public: NDBT_TestCase(NDBT_TestSuite* psuite, const char* name, const char* comment); - virtual ~NDBT_TestCase(){} + virtual ~NDBT_TestCase() {} // This is the default executor of a test case // When a test case is executed it will need to be suplied with a number of @@ -228,6 +228,8 @@ protected: void stopTimer(NDBT_Context*); void printTimer(NDBT_Context*); + BaseString _name; + BaseString _comment; const char* name; const char* comment; NDBT_TestSuite* suite; diff --git a/ndb/test/ndbapi/benchronja.cpp b/ndb/test/ndbapi/benchronja.cpp index 91b2a041186..a7523e8e416 100644 --- a/ndb/test/ndbapi/benchronja.cpp +++ b/ndb/test/ndbapi/benchronja.cpp @@ -984,7 +984,6 @@ void* ThreadExec(void* ThreadData){ delete pMyNdb; pMyNdb = NULL ; ThreadReady[thread_no] = 1; - NdbThread_Exit(0) ; return 0 ; }//if @@ -1197,7 +1196,6 @@ void* ThreadExec(void* ThreadData){ } // for(;;) delete pMyNdb ; - NdbThread_Exit(0) ; - return 0 ; // Compiler is happy now + return 0 ; } diff --git a/ndb/test/ndbapi/flexAsynch.cpp b/ndb/test/ndbapi/flexAsynch.cpp index d840993470c..8a7dbec1561 100644 --- a/ndb/test/ndbapi/flexAsynch.cpp +++ b/ndb/test/ndbapi/flexAsynch.cpp @@ -504,8 +504,7 @@ threadLoop(void* ThreadData) delete localNdb; ThreadReady[threadNo] = 1; - NdbThread_Exit(0); - return NULL; // Just to keep compiler happy + return NULL; }//threadLoop() static diff --git a/ndb/test/ndbapi/flexBench.cpp b/ndb/test/ndbapi/flexBench.cpp index 728188ab28d..abddecfdc40 100644 --- a/ndb/test/ndbapi/flexBench.cpp +++ b/ndb/test/ndbapi/flexBench.cpp @@ -628,7 +628,7 @@ static void* flexBenchThread(void* pArg) free(attrRefValue) ; free(pOps) ; delete pNdb ; - NdbThread_Exit(0) ; + return 0; // thread exits } pNdb->init(); @@ -945,8 +945,7 @@ static void* flexBenchThread(void* pArg) free(longKeyAttrValue); } // if - NdbThread_Exit(0); - return NULL; // Just to keep compiler happy + return NULL; // Thread exits } diff --git a/ndb/test/ndbapi/flexHammer.cpp b/ndb/test/ndbapi/flexHammer.cpp index 49629dac875..f254b1e5ccf 100644 --- a/ndb/test/ndbapi/flexHammer.cpp +++ b/ndb/test/ndbapi/flexHammer.cpp @@ -621,10 +621,7 @@ flexHammerThread(void* pArg) flexHammerErrorData->resetErrorCounters(); - // And exit using NDBT - NdbThread_Exit(0); - - return NULL; + return NULL; // thread exits } // flexHammerThread diff --git a/ndb/test/ndbapi/flexScan.cpp b/ndb/test/ndbapi/flexScan.cpp index c7f4041a525..4d2c85d6955 100644 --- a/ndb/test/ndbapi/flexScan.cpp +++ b/ndb/test/ndbapi/flexScan.cpp @@ -701,8 +701,7 @@ flexScanThread(void* ThreadData) free(pkValue); } // if - NdbThread_Exit(0); - return NULL; + return NULL; // thread exits } // flexScanThread diff --git a/ndb/test/ndbapi/flexTT.cpp b/ndb/test/ndbapi/flexTT.cpp index 2ad9ef19ddf..7cd5ac8e3b4 100644 --- a/ndb/test/ndbapi/flexTT.cpp +++ b/ndb/test/ndbapi/flexTT.cpp @@ -398,8 +398,7 @@ threadLoop(void* ThreadData) delete localNdb; ThreadReady[loc_threadNo] = 1; - NdbThread_Exit(0); - return NULL; // Just to keep compiler happy + return NULL; // Thread exits }//threadLoop() static diff --git a/ndb/test/ndbapi/flexTimedAsynch.cpp b/ndb/test/ndbapi/flexTimedAsynch.cpp index 27380cc79fd..2b8c0bdd5f8 100644 --- a/ndb/test/ndbapi/flexTimedAsynch.cpp +++ b/ndb/test/ndbapi/flexTimedAsynch.cpp @@ -406,9 +406,8 @@ threadLoop(void* ThreadData) delete localNdb; ThreadReady[threadNo] = 1; - NdbThread_Exit(0); - return NULL; + return NULL; // thread exits } void executeThread(StartType aType, Ndb* aNdbObject, ThreadNdb* threadInfo) diff --git a/ndb/test/ndbapi/flex_bench_mysql.cpp b/ndb/test/ndbapi/flex_bench_mysql.cpp index ad84390a9e5..3efb7ee2094 100644 --- a/ndb/test/ndbapi/flex_bench_mysql.cpp +++ b/ndb/test/ndbapi/flex_bench_mysql.cpp @@ -711,7 +711,7 @@ static void* flexBenchThread(void* pArg) the_socket_name, 0) == NULL ) { ndbout << "failed" << endl; - NdbThread_Exit(0) ; + return 0; } mysql.reconnect= 1; ndbout << "ok" << endl; @@ -724,7 +724,7 @@ static void* flexBenchThread(void* pArg) if (r) { ndbout << "autocommit on/off failed" << endl; - NdbThread_Exit(0) ; + return 0; } } #endif @@ -743,7 +743,7 @@ static void* flexBenchThread(void* pArg) ndbout << threadNo << endl ; ndbout << "Thread #" << threadNo << " will now exit" << endl ; tResult = 13 ; - NdbThread_Exit(0) ; + return 0; } if (use_ndb) { @@ -752,7 +752,7 @@ static void* flexBenchThread(void* pArg) ndbout << "Failed to get an NDB object" << endl; ndbout << "Thread #" << threadNo << " will now exit" << endl ; tResult = 13; - NdbThread_Exit(0) ; + return 0; } pNdb->waitUntilReady(); return_ndb_object(pNdb, ndb_id); @@ -902,11 +902,11 @@ static void* flexBenchThread(void* pArg) prep_insert[i] = mysql_prepare(&mysql, buf, pos); if (prep_insert[i] == 0) { ndbout << "mysql_prepare: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } if (mysql_bind_param(prep_insert[i], bind_insert)) { ndbout << "mysql_bind_param: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } } @@ -928,11 +928,11 @@ static void* flexBenchThread(void* pArg) prep_update[i] = mysql_prepare(&mysql, buf, pos); if (prep_update[i] == 0) { ndbout << "mysql_prepare: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } if (mysql_bind_param(prep_update[i], bind_update)) { ndbout << "mysql_bind_param: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } } @@ -955,15 +955,15 @@ static void* flexBenchThread(void* pArg) prep_read[i] = mysql_prepare(&mysql, buf, pos); if (prep_read[i] == 0) { ndbout << "mysql_prepare: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } if (mysql_bind_param(prep_read[i], bind_read)) { ndbout << "mysql_bind_param: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } if (mysql_bind_result(prep_read[i], &bind_read[1])) { ndbout << "mysql_bind_result: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } } @@ -980,11 +980,11 @@ static void* flexBenchThread(void* pArg) prep_delete[i] = mysql_prepare(&mysql, buf, pos); if (prep_delete[i] == 0) { ndbout << "mysql_prepare: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } if (mysql_bind_param(prep_delete[i], bind_delete)) { ndbout << "mysql_bind_param: " << mysql_error(&mysql) << endl; - NdbThread_Exit(0) ; + return 0; } } } @@ -1433,8 +1433,7 @@ static void* flexBenchThread(void* pArg) ndbout << "I got here " << endl; return_ndb_object(pNdb, ndb_id); } - NdbThread_Exit(0); - return NULL; // Just to keep compiler happy + return NULL; } diff --git a/ndb/test/ndbapi/mainAsyncGenerator.cpp b/ndb/test/ndbapi/mainAsyncGenerator.cpp index 16cb50e160f..73a8b98ab57 100644 --- a/ndb/test/ndbapi/mainAsyncGenerator.cpp +++ b/ndb/test/ndbapi/mainAsyncGenerator.cpp @@ -274,8 +274,6 @@ threadRoutine(void *arg) asyncDbDisconnect(pNDB); - NdbThread_Exit(0); - return NULL; } diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp index 33482bd9b11..ce1851083b1 100644 --- a/ndb/test/ndbapi/testOIBasic.cpp +++ b/ndb/test/ndbapi/testOIBasic.cpp @@ -1812,14 +1812,16 @@ Val::calckeychars(Par par, unsigned i, unsigned& n, unsigned char* buf) const Chs* chs = col.m_chs; CHARSET_INFO* cs = chs->m_cs; n = 0; - // our random chars may not fill value exactly - while (n + cs->mbmaxlen <= col.m_bytelength) { + unsigned len = 0; + while (len < col.m_length) { if (i % (1 + n) == 0) { break; } const Chr& chr = chs->m_chr[i % maxcharcount]; + assert(n + chr.m_size <= col.m_bytelength); memcpy(buf + n, chr.m_bytes, chr.m_size); n += chr.m_size; + len++; } } @@ -1884,8 +1886,8 @@ Val::calcnokeychars(Par par, unsigned& n, unsigned char* buf) const Chs* chs = col.m_chs; CHARSET_INFO* cs = chs->m_cs; n = 0; - // our random chars may not fill value exactly - while (n + cs->mbmaxlen <= col.m_bytelength) { + unsigned len = 0; + while (len < col.m_length) { if (urandom(1 + col.m_bytelength) == 0) { break; } @@ -1898,8 +1900,10 @@ Val::calcnokeychars(Par par, unsigned& n, unsigned char* buf) unsigned i = half + r; assert(i < maxcharcount); const Chr& chr = chs->m_chr[i]; + assert(n + chr.m_size <= col.m_bytelength); memcpy(buf + n, chr.m_bytes, chr.m_size); n += chr.m_size; + len++; } } diff --git a/ndb/test/ndbapi/testOperations.cpp b/ndb/test/ndbapi/testOperations.cpp index 949f08281a5..e254aff58dc 100644 --- a/ndb/test/ndbapi/testOperations.cpp +++ b/ndb/test/ndbapi/testOperations.cpp @@ -98,6 +98,15 @@ OperationTestCase matrix[] = { result = NDBT_FAILED; \ break; } +#define C3(b) if (!(b)) { \ + g_err << "ERR: "<< step->getName() \ + << " failed on line " << __LINE__ << endl; \ + abort(); return NDBT_FAILED; } + +#define C3(b) if (!(b)) { \ + g_err << "ERR: failed on line " << __LINE__ << endl; \ + return NDBT_FAILED; } + int runOp(HugoOperations & hugoOps, Ndb * pNdb, @@ -228,11 +237,369 @@ runClearTable(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_OK; } +enum OPS { o_DONE= 0, o_INS= 1, o_UPD= 2, o_DEL= 3 }; +typedef Vector Sequence; + +static +bool +valid(const Sequence& s) +{ + if(s.size() == 0) + return false; + + for(size_t i = 1; i>= 2; + } +} + +static +void +generate(Vector& out, size_t len) +{ + int max= 1; + while(len) + { + max <<= 2; + len--; + } + + len= 1; + for(int i = 0; i= len && valid(tmp)) + { + out.push_back(i); + len= tmp.size(); + } + else + { + //ndbout << "DISCARD: " << tmp << endl; + } + } +} + +static const Uint32 DUMMY = 0; +static const Uint32 ROW = 1; + +int +verify_other(NDBT_Context* ctx, + Ndb* pNdb, int seq, OPS latest, bool initial_row, bool commit) +{ + Uint32 no_wait = NdbOperation::LM_CommittedRead* + ctx->getProperty("NoWait", (Uint32)1); + + for(size_t j = no_wait; j<3; j++) + { + HugoOperations other(*ctx->getTab()); + C3(other.startTransaction(pNdb) == 0); + C3(other.pkReadRecord(pNdb, ROW, 1, (NdbOperation::LockMode)j) == 0); + int tmp= other.execute_Commit(pNdb); + if(seq == 0){ + if(j == NdbOperation::LM_CommittedRead) + { + C3(initial_row? tmp==0 && other.verifyUpdatesValue(0) == 0 : tmp==626); + } + else + { + C3(tmp == 266); + } + } + else if(commit) + { + switch(latest){ + case o_INS: + case o_UPD: + C3(tmp == 0 && other.verifyUpdatesValue(seq) == 0); + break; + case o_DEL: + C3(tmp == 626); + break; + case o_DONE: + abort(); + } + } + else + { + // rollback + C3(initial_row? tmp==0 && other.verifyUpdatesValue(0) == 0 : tmp==626); + } + } + + return NDBT_OK; +} + +int +verify_savepoint(NDBT_Context* ctx, + Ndb* pNdb, int seq, OPS latest, + Uint64 transactionId) +{ + bool initial_row= (seq == 0) && latest == o_INS; + + for(size_t j = 0; j<3; j++) + { + const NdbOperation::LockMode lm= (NdbOperation::LockMode)j; + + HugoOperations same(*ctx->getTab()); + C3(same.startTransaction(pNdb) == 0); + same.setTransactionId(transactionId); // Cheat + + /** + * Increase savepoint to k + */ + for(size_t l = 1; l<=seq; l++) + { + C3(same.pkReadRecord(pNdb, DUMMY, 1, lm) == 0); // Read dummy row + C3(same.execute_NoCommit(pNdb) == 0); + g_info << "savepoint: " << l << endl; + } + + g_info << "op(" << seq << "): " + << " lock mode " << lm << endl; + + C3(same.pkReadRecord(pNdb, ROW, 1, lm) == 0); // Read real row + int tmp= same.execute_Commit(pNdb); + if(seq == 0) + { + if(initial_row) + { + C3(tmp == 0 && same.verifyUpdatesValue(0) == 0); + } else + { + C3(tmp == 626); + } + } + else + { + switch(latest){ + case o_INS: + case o_UPD: + C3(tmp == 0 && same.verifyUpdatesValue(seq) == 0); + break; + case o_DEL: + C3(tmp == 626); + break; + case o_DONE: + abort(); + } + } + } + return NDBT_OK; +} + +int +runOperations(NDBT_Context* ctx, NDBT_Step* step) +{ + int tmp; + Ndb* pNdb = GETNDB(step); + + Uint32 seqNo = ctx->getProperty("Sequence", (Uint32)0); + Uint32 commit= ctx->getProperty("Commit", (Uint32)1); + + if(seqNo == 0) + { + return NDBT_FAILED; + } + + Sequence seq; + generate(seq, seqNo); + + { + // Dummy row + HugoOperations hugoOps(*ctx->getTab()); + C3(hugoOps.startTransaction(pNdb) == 0); + C3(hugoOps.pkInsertRecord(pNdb, DUMMY, 1, 0) == 0); + C3(hugoOps.execute_Commit(pNdb) == 0); + } + + const bool initial_row= (seq[0] != o_INS); + if(initial_row) + { + HugoOperations hugoOps(*ctx->getTab()); + C3(hugoOps.startTransaction(pNdb) == 0); + C3(hugoOps.pkInsertRecord(pNdb, ROW, 1, 0) == 0); + C3(hugoOps.execute_Commit(pNdb) == 0); + } + + HugoOperations trans1(*ctx->getTab()); + C3(trans1.startTransaction(pNdb) == 0); + for(size_t i = 0; igetTransactionId(); + + for(size_t k=0; k<=i+1; k++) + { + if(verify_savepoint(ctx, pNdb, k, + k>0 ? seq[k-1] : initial_row ? o_INS : o_DONE, + transactionId) != NDBT_OK) + return NDBT_FAILED; + } + } + + if(commit) + { + C3(trans1.execute_Commit(pNdb) == 0); + } + else + { + C3(trans1.execute_Rollback(pNdb) == 0); + } + + if(verify_other(ctx, pNdb, seq.size(), seq.back(), + initial_row, commit) != NDBT_OK) + return NDBT_FAILED; + + return NDBT_OK; +} + int main(int argc, const char** argv){ ndb_init(); + Vector tmp; + generate(tmp, 5); + NDBT_TestSuite ts("testOperations"); + for(size_t i = 0; isetProperty("Sequence", tmp[i]); + pt->addInitializer(new NDBT_Initializer(pt, + "runClearTable", + runClearTable)); + + pt->addStep(new NDBT_ParallelStep(pt, + "run", + runOperations)); + + pt->addFinalizer(new NDBT_Finalizer(pt, + "runClearTable", + runClearTable)); + + ts.addTest(pt); + + name.append("_ABORT"); + pt = new NDBT_TestCaseImpl1(&ts, name.c_str()+1, ""); + pt->setProperty("Sequence", tmp[i]); + pt->setProperty("Commit", (Uint32)0); + pt->addInitializer(new NDBT_Initializer(pt, + "runClearTable", + runClearTable)); + + pt->addStep(new NDBT_ParallelStep(pt, + "run", + runOperations)); + + pt->addFinalizer(new NDBT_Finalizer(pt, + "runClearTable", + runClearTable)); + + ts.addTest(pt); + } + for(Uint32 i = 0; i; +template class Vector; diff --git a/ndb/test/ndbapi/testScan.cpp b/ndb/test/ndbapi/testScan.cpp index 1f40a52b334..3b52778a013 100644 --- a/ndb/test/ndbapi/testScan.cpp +++ b/ndb/test/ndbapi/testScan.cpp @@ -35,7 +35,8 @@ getTable(Ndb* pNdb, int i){ int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){ - int records = ctx->getNumRecords(); + int records = ctx->getProperty("Rows", ctx->getNumRecords()); + HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), records) != 0){ return NDBT_FAILED; @@ -264,7 +265,7 @@ int runVerifyTable(NDBT_Context* ctx, NDBT_Step* step){ int runScanRead(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); - int records = ctx->getNumRecords(); + int records = ctx->getProperty("Rows", ctx->getNumRecords()); int parallelism = ctx->getProperty("Parallelism", 240); int abort = ctx->getProperty("AbortProb", 5); @@ -375,7 +376,20 @@ int runScanReadError(NDBT_Context* ctx, NDBT_Step* step){ restarter.insertErrorInAllNodes(0); return result; } - + +int +runInsertError(NDBT_Context* ctx, NDBT_Step* step){ + int error = ctx->getProperty("ErrorCode"); + NdbRestarter restarter; + + ctx->setProperty("ErrorCode", (Uint32)0); + if (restarter.insertErrorInAllNodes(error) != 0){ + ndbout << "Could not insert error in all nodes "<getNumLoops(); @@ -1258,6 +1272,16 @@ TESTCASE("ScanRead100", STEPS(runScanRead, 100); FINALIZER(runClearTable); } +TESTCASE("Scan-bug8262", + ""){ + TC_PROPERTY("Rows", 1); + TC_PROPERTY("ErrorCode", 8035); + INITIALIZER(runLoadTable); + INITIALIZER(runInsertError); // Will reset error code + STEPS(runScanRead, 25); + FINALIZER(runInsertError); + FINALIZER(runClearTable); +} TESTCASE("ScanRead40RandomTable", "Verify scan requirement: Scan with 40 simultaneous threads. "\ "Use random table for the scan"){ diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt index 89675acb59f..b666f27d05f 100644 --- a/ndb/test/run-test/daily-basic-tests.txt +++ b/ndb/test/run-test/daily-basic-tests.txt @@ -353,6 +353,10 @@ max-time: 500 cmd: testScan args: -n ScanRestart T1 +max-time: 500 +cmd: testScan +args: -l 100 -n Scan-bug8262 T7 + max-time: 500 cmd: testScan args: -n ScanParallelism diff --git a/ndb/test/src/HugoOperations.cpp b/ndb/test/src/HugoOperations.cpp index bdb4013600a..3dcbe3d5ffd 100644 --- a/ndb/test/src/HugoOperations.cpp +++ b/ndb/test/src/HugoOperations.cpp @@ -45,6 +45,13 @@ int HugoOperations::setTransaction(NdbTransaction* new_trans){ return NDBT_OK; } +void +HugoOperations::setTransactionId(Uint64 id){ + if (pTrans != NULL){ + pTrans->setTransactionId(id); + } +} + int HugoOperations::closeTransaction(Ndb* pNdb){ if (pTrans != NULL){ @@ -369,6 +376,10 @@ HugoOperations::HugoOperations(const NdbDictionary::Table& _tab, HugoOperations::~HugoOperations(){ deallocRows(); + if (pTrans != NULL){ + pTrans->close(); + pTrans = NULL; + } } diff --git a/ndb/test/src/HugoTransactions.cpp b/ndb/test/src/HugoTransactions.cpp index 0515c0a99f8..bfe7ea72394 100644 --- a/ndb/test/src/HugoTransactions.cpp +++ b/ndb/test/src/HugoTransactions.cpp @@ -68,20 +68,20 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, pOp = getScanOperation(pTrans); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if( pOp ->readTuples(lm, 0, parallelism) ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->interpret_exit_ok(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -89,7 +89,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, if((row.attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -99,13 +99,13 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -124,7 +124,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, while((eof = pOp->nextResult(true)) == 0){ rows++; if (calc.verifyRowValues(&row) != 0){ - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -134,11 +134,11 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, pOp->close(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_OK; } } @@ -147,7 +147,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR_INFO(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); switch (err.code){ case 488: @@ -161,17 +161,17 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); g_info << rows << " rows have been read" << endl; if (records != 0 && rows != records){ g_err << "Check expected number of records failed" << endl - << " expected=" << records <<", " << endl - << " read=" << rows << endl; + << " expected=" << records <<", " << endl + << " read=" << rows << endl; return NDBT_FAILED; } @@ -220,20 +220,20 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, pOp = pTrans->getNdbIndexScanOperation(pIdx->getName(), tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if( pOp ->readTuples(lm, 0, parallelism, sorted) ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->interpret_exit_ok(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -241,7 +241,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, if((row.attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -251,13 +251,13 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -276,7 +276,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, while((eof = pOp->nextResult(true)) == 0){ rows++; if (calc.verifyRowValues(&row) != 0){ - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -286,11 +286,11 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, pOp->close(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_OK; } } @@ -299,7 +299,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR_INFO(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); switch (err.code){ case 488: @@ -313,17 +313,17 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); g_info << rows << " rows have been read" << endl; if (records != 0 && rows != records){ g_err << "Check expected number of records failed" << endl - << " expected=" << records <<", " << endl - << " read=" << rows << endl; + << " expected=" << records <<", " << endl + << " read=" << rows << endl; return NDBT_FAILED; } @@ -337,9 +337,9 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, int HugoTransactions::scanUpdateRecords(Ndb* pNdb, - int records, - int abortPercent, - int parallelism){ + int records, + int abortPercent, + int parallelism){ if(m_defaultScanUpdateMethod == 1){ return scanUpdateRecords1(pNdb, records, abortPercent, parallelism); } else if(m_defaultScanUpdateMethod == 2){ @@ -383,7 +383,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, while (true){ - restart: +restart: if (retryAttempt++ >= retryMax){ g_info << "ERROR: has retried this operation " << retryAttempt << " times, failing!" << endl; @@ -404,13 +404,13 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, pOp = getScanOperation(pTrans); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if( pOp->readTuplesExclusive(parallelism) ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -418,7 +418,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, for(a=0; agetValue(tab.getColumn(a)->getName())) == NULL){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -427,7 +427,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, if( check == -1 ) { const NdbError err = pTrans->getNdbError(); ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); if (err.status == NdbError::TemporaryError){ NdbSleep_MilliSleep(50); continue; @@ -452,7 +452,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, NdbOperation* pUp = pOp->updateCurrentTuple(); if(pUp == 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } const int updates = calc.getUpdatesValue(&row) + 1; @@ -461,7 +461,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, if (tab.getColumn(a)->getPrimaryKey() == false){ if(setValueForAttr(pUp, a, r, updates ) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -470,7 +470,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, if (rows == abortCount && abortTrans == true){ g_info << "Scan is aborted" << endl; // This scan should be aborted - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_OK; } } while((check = pOp->nextResult(false)) == 0); @@ -482,7 +482,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, const NdbError err = pTrans->getNdbError(); if( check == -1 ) { - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); ERR(err); if (err.status == NdbError::TemporaryError){ NdbSleep_MilliSleep(50); @@ -494,7 +494,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, const NdbError err = pTrans->getNdbError(); if( check == -1 ) { - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); ERR(err); if (err.status == NdbError::TemporaryError){ NdbSleep_MilliSleep(50); @@ -503,7 +503,7 @@ HugoTransactions::scanUpdateRecords3(Ndb* pNdb, return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); g_info << rows << " rows have been updated" << endl; return NDBT_OK; @@ -575,7 +575,7 @@ HugoTransactions::loadTable(Ndb* pNdb, if(pkInsertRecord(pNdb, c, batch) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -591,7 +591,7 @@ HugoTransactions::loadTable(Ndb* pNdb, } if(check == -1 ) { const NdbError err = pTrans->getNdbError(); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); pTrans= 0; switch(err.status){ case NdbError::Success: @@ -633,7 +633,7 @@ HugoTransactions::loadTable(Ndb* pNdb, } else{ if (closeTrans) { - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); pTrans= 0; } } @@ -644,7 +644,7 @@ HugoTransactions::loadTable(Ndb* pNdb, } if(pTrans) - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_OK; } @@ -696,7 +696,7 @@ HugoTransactions::fillTable(Ndb* pNdb, if(pkInsertRecord(pNdb, c, batch) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -704,7 +704,7 @@ HugoTransactions::fillTable(Ndb* pNdb, check = pTrans->execute( Commit, CommitAsMuchAsPossible ); if(check == -1 ) { const NdbError err = pTrans->getNdbError(); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); switch(err.status){ case NdbError::Success: @@ -756,7 +756,7 @@ HugoTransactions::fillTable(Ndb* pNdb, } } else{ - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); } // Step to next record @@ -1088,7 +1088,7 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, if(pkReadRecord(pNdb, r, batch, lm) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1098,7 +1098,7 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; @@ -1111,7 +1111,7 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, default: ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } else { @@ -1122,13 +1122,13 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, { rows_found++; if (calc.verifyRowValues(rows[0]) != 0){ - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } if(check != 1 || rows_found > batch) { - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } else if(rows_found < batch) @@ -1146,7 +1146,7 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, { for (int b=0; (bcloseTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } reads++; @@ -1155,7 +1155,7 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, } } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); } deallocRows(); g_info << reads << " records read" << endl; @@ -1209,7 +1209,7 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, if(pkReadRecord(pNdb, r, batch, NdbOperation::LM_Exclusive) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1219,13 +1219,13 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1237,7 +1237,7 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, do { if (calc.verifyRowValues(rows[0]) != 0){ - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1246,7 +1246,7 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, if(pkUpdateRecord(pNdb, r+rows_found, 1, updates) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } rows_found++; @@ -1259,7 +1259,7 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, } if(check != 1 || rows_found != batch) { - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1269,7 +1269,7 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, { if (calc.verifyRowValues(rows[b]) != 0) { - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1278,7 +1278,7 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, if(pkUpdateRecord(pNdb, r+b, 1, updates) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1289,21 +1289,21 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); ndbout << "r = " << r << endl; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } else{ updated += batch; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); r += batch; // Read next record } @@ -1348,15 +1348,15 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, NdbOperation* pOp = pTrans->getNdbOperation(tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->readTupleExclusive(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); - return NDBT_FAILED; + closeTransaction(pNdb); + return NDBT_FAILED; } // Define primary keys @@ -1364,7 +1364,7 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, if (tab.getColumn(a)->getPrimaryKey() == true){ if(equalForAttr(pOp, a, r) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1376,7 +1376,7 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, if((row.attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1388,13 +1388,13 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1404,14 +1404,14 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, pUpdOp = pTrans->getNdbOperation(tab.getName()); if (pUpdOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pUpdOp->interpretedUpdateTuple(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1420,7 +1420,7 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, if (tab.getColumn(a)->getPrimaryKey() == true){ if(equalForAttr(pUpdOp, a, r) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1437,7 +1437,7 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, check = pUpdOp->incValue(attr->getName(), valToIncWith); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1449,7 +1449,7 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, (calc.isUpdateCol(a) == false)){ if(setValueForAttr(pUpdOp, a, r, updates ) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1463,14 +1463,14 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); ndbout << "r = " << r << endl; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } else{ @@ -1478,7 +1478,7 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb, } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); r++; // Read next record @@ -1533,7 +1533,7 @@ HugoTransactions::pkDelRecords(Ndb* pNdb, if(pkDeleteRecord(pNdb, r, batch) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1544,7 +1544,7 @@ HugoTransactions::pkDelRecords(Ndb* pNdb, switch(err.status){ case NdbError::TemporaryError: ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; @@ -1563,20 +1563,20 @@ HugoTransactions::pkDelRecords(Ndb* pNdb, } } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; break; default: ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } else { deleted += batch; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); r += batch; // Read next record @@ -1641,7 +1641,7 @@ HugoTransactions::lockRecords(Ndb* pNdb, if(pkReadRecord(pNdb, r, lockBatch, lm) != NDBT_OK) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1656,18 +1656,18 @@ HugoTransactions::lockRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } for (int b=0; (bcloseTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1682,26 +1682,26 @@ HugoTransactions::lockRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } else{ for (int b=0; (bcloseTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } r++; // Read next record } } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); } deallocRows(); @@ -1765,7 +1765,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, pOp = pTrans->getNdbIndexOperation(idxName, tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->readTuple(); @@ -1773,7 +1773,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, pOp = sOp = pTrans->getNdbIndexScanOperation(idxName, tab.getName()); if (sOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = sOp->readTuples(); @@ -1781,7 +1781,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1790,7 +1790,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, if (tab.getColumn(a)->getPrimaryKey() == true){ if(equalForAttr(pOp, a, r+b) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1801,7 +1801,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, if((rows[b]->attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1814,7 +1814,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; @@ -1827,13 +1827,13 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, default: ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } else{ for (int b=0; (bcloseTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } reads++; @@ -1842,11 +1842,11 @@ HugoTransactions::indexReadRecords(Ndb* pNdb, if(ordered && sOp->nextResult(true) == 0){ ndbout << "Error when comparing records " << " - index op next_result to many" << endl; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); } deallocRows(); g_info << reads << " records read" << endl; @@ -1905,21 +1905,21 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, pOp = pTrans->getNdbIndexOperation(idxName, tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->readTupleExclusive(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } else { pOp = sOp = pTrans->getNdbIndexScanOperation(idxName, tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1932,7 +1932,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if (tab.getColumn(a)->getPrimaryKey() == true){ if(equalForAttr(pOp, a, r+b) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1943,7 +1943,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if((rows[b]->attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1954,7 +1954,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if( check == -1 ) { const NdbError err = pTrans->getNdbError(); ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); if (err.status == NdbError::TemporaryError){ NdbSleep_MilliSleep(50); @@ -1966,13 +1966,13 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if(ordered && check != 0){ g_err << check << " - Row: " << r << " not found!!" << endl; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } for(b = 0; bcloseTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1988,13 +1988,13 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if (pUpdOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -2003,7 +2003,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if (tab.getColumn(a)->getPrimaryKey() == true){ if(equalForAttr(pUpdOp, a, r+b) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -2014,7 +2014,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if (tab.getColumn(a)->getPrimaryKey() == false){ if(setValueForAttr(pUpdOp, a, r+b, updates ) != 0){ ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -2025,7 +2025,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, if( check == -1 ) { const NdbError err = pTrans->getNdbError(); ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); if (err.status == NdbError::TemporaryError){ NdbSleep_MilliSleep(50); @@ -2038,7 +2038,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb, updated += batch; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); r+= batch; // Read next record } diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 0e45572ca3b..7fd92db533e 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -330,13 +330,17 @@ NDBT_Finalizer::NDBT_Finalizer(NDBT_TestCase* ptest, NDBT_TestCase::NDBT_TestCase(NDBT_TestSuite* psuite, const char* pname, const char* pcomment) : - name(pname) , - comment(pcomment), - suite(psuite){ + name(strdup(pname)) , + comment(strdup(pcomment)), + suite(psuite) +{ + _name.assign(pname); + _comment.assign(pcomment); + name= _name.c_str(); + comment= _comment.c_str(); assert(suite != NULL); } - NDBT_TestCaseImpl1::NDBT_TestCaseImpl1(NDBT_TestSuite* psuite, const char* pname, const char* pcomment) : @@ -477,10 +481,7 @@ extern "C" void * runStep_C(void * s) { - my_thread_init(); runStep(s); - my_thread_end(); - NdbThread_Exit(0); return NULL; } diff --git a/ndb/test/tools/transproxy.cpp b/ndb/test/tools/transproxy.cpp index 88267801172..28a621fa584 100644 --- a/ndb/test/tools/transproxy.cpp +++ b/ndb/test/tools/transproxy.cpp @@ -291,7 +291,6 @@ extern "C" void* copyrun_C(void* copy) { ((Copy*) copy)->run(); - NdbThread_Exit(0); return 0; } @@ -322,7 +321,6 @@ extern "C" void* connrun_C(void* conn) { ((Conn*) conn)->run(); - NdbThread_Exit(0); return 0; } diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 221fab13635..c26cc8afedb 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -140,6 +140,9 @@ SUFFIXES = .sh -e 's!@''IS_LINUX''@!@IS_LINUX@!' \ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \ + -e 's!@''STATIC_NSS_FLAGS''@!@STATIC_NSS_FLAGS@!' \ + -e 's!@''NON_THREADED_LIBS''@!@NON_THREADED_LIBS@!' \ + -e 's!@''ZLIB_DEPS''@!@ZLIB_DEPS@!' \ -e "s!@MAKE@!$(MAKE)!" \ $< > $@-t @CHMOD@ +x $@-t diff --git a/scripts/fill_help_tables.sh b/scripts/fill_help_tables.sh index fbe7c597b34..fc0c684c2dc 100644 --- a/scripts/fill_help_tables.sh +++ b/scripts/fill_help_tables.sh @@ -493,6 +493,24 @@ sub print_insert_header } } +print <crashed= TRUE; else (void)write_meta_file(share->meta_file, share->rows_recorded, TRUE); + /* It is expensive to open and close the data files and since you can't have a gzip file that can be both read and written we keep a writer open @@ -393,7 +395,8 @@ int ha_archive::free_share(ARCHIVE_SHARE *share) (void)write_meta_file(share->meta_file, share->rows_recorded, FALSE); if (gzclose(share->archive_write) == Z_ERRNO) rc= 1; - my_close(share->meta_file,MYF(0)); + if (my_close(share->meta_file, MYF(0))) + rc= 1; my_free((gptr) share, MYF(0)); } pthread_mutex_unlock(&archive_mutex); diff --git a/sql/field.cc b/sql/field.cc index aa2c5805bfe..ad66fec2fc2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -52,6 +52,25 @@ const char field_separator=','; Static help functions *****************************************************************************/ +/* + Numeric fields base class constructor +*/ +Field_num::Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg) + :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg), + dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg) +{ + if (zerofill) + flags|=ZEROFILL_FLAG; + if (unsigned_flag) + flags|=UNSIGNED_FLAG; +} + + void Field_num::prepend_zeros(String *value) { int diff; @@ -82,7 +101,7 @@ void Field_num::prepend_zeros(String *value) Make this multi-byte-character safe RETURN - 0 ok + 0 OK 1 error. A warning is pushed if field_name != 0 */ @@ -104,7 +123,7 @@ bool Field::check_int(const char *str, int length, const char *int_end, } end= str+length; if ((str= int_end) == end) - return 0; // ok; All digits was used + return 0; // OK; All digits was used /* Allow end .0000 */ if (*str == '.') @@ -125,6 +144,32 @@ bool Field::check_int(const char *str, int length, const char *int_end, } +/* + Process decimal library return codes and issue warnings for overflow and + truncation. + + SYNOPSIS + Field::check_overflow() + op_result decimal library return code (E_DEC_* see include/decimal.h) + + RETURN + 1 there was overflow + 0 no error or some other errors except overflow +*/ + +int Field::check_overflow(int op_result) +{ + if (op_result == E_DEC_OVERFLOW) + { + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + return 1; + } + else if (op_result == E_DEC_TRUNCATED) + set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + /* we return 1 only in case of EFL */ + return 0; +} + #ifdef NOT_USED static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) { @@ -191,6 +236,10 @@ static Field::field_cast_enum field_cast_decimal[]= {Field::FIELD_CAST_DECIMAL, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +static Field::field_cast_enum field_cast_new_decimal[]= +{Field::FIELD_CAST_NEWDECIMAL, + Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, + Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_tiny[]= {Field::FIELD_CAST_TINY, Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, @@ -261,6 +310,7 @@ static Field::field_cast_enum field_cast_date[]= Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_newdate[]= {Field::FIELD_CAST_NEWDATE, + Field::FIELD_CAST_DATE, Field::FIELD_CAST_DATETIME, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; @@ -282,6 +332,9 @@ static Field::field_cast_enum field_cast_varstring[]= static Field::field_cast_enum field_cast_blob[]= {Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +static Field::field_cast_enum field_cast_bit[]= +{Field::FIELD_CAST_BIT, + Field::FIELD_CAST_STOP}; /* Geometrical, enum and set fields can be casted only to expressions */ @@ -301,7 +354,8 @@ static Field::field_cast_enum *field_cast_array[]= field_cast_timestamp, field_cast_year, field_cast_date, field_cast_newdate, field_cast_time, field_cast_datetime, field_cast_string, field_cast_varstring, field_cast_blob, - field_cast_geom, field_cast_enum, field_cast_set + field_cast_geom, field_cast_enum, field_cast_set, field_cast_bit, + field_cast_new_decimal }; @@ -397,6 +451,14 @@ bool Field::send_binary(Protocol *protocol) } +my_decimal *Field::val_decimal(my_decimal *decimal) +{ + /* This never have to be called */ + DBUG_ASSERT(0); + return 0; +} + + void Field_num::add_zerofill_and_unsigned(String &res) const { if (unsigned_flag) @@ -405,6 +467,7 @@ void Field_num::add_zerofill_and_unsigned(String &res) const res.append(" zerofill"); } + void Field::make_field(Send_field *field) { field->db_name= orig_table->s->table_cache_key; @@ -419,12 +482,155 @@ void Field::make_field(Send_field *field) } +/* + Conversion from decimal to longlong with checking overflow and + setting correct value (min/max) in case of overflow + + SYNOPSIS + Field::convert_decimal2longlong() + val value which have to be converted + unsigned_flag type of integer in which we convert val + err variable to pass error code + + RETURN + value converted from val +*/ +longlong Field::convert_decimal2longlong(const my_decimal *val, + bool unsigned_flag, int *err) +{ + longlong i; + if (unsigned_flag) + { + if (val->sign()) + { + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + i= 0; + *err= 1; + } + else if (check_overflow(my_decimal2int(E_DEC_ERROR & + ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED, + val, TRUE, &i))) + { + i= ~(longlong) 0; + *err= 1; + } + } + else if (check_overflow(my_decimal2int(E_DEC_ERROR & + ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED, + val, FALSE, &i))) + { + i= (val->sign() ? LONGLONG_MIN : LONGLONG_MAX); + *err= 1; + } + return i; +} + + +/* + Storing decimal in integer fields. + + SYNOPSIS + Field_num::store_decimal() + val value for storing + + NOTE + This method is used by all integer fields, real/decimal redefine it + + RETURN + 0 OK + != 0 error +*/ + +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 decimal value of integer field + + SYNOPSIS + Field_num::val_decimal() + decimal_value buffer for storing decimal value + + NOTE + This method is used by all integer fields, real/decimal redefine it + All longlong values fit in our decimal buffer which cal store 8*9=72 + digits of integer number + + RETURN + pointer to decimal buffer with value of field +*/ + +my_decimal* Field_num::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(result_type() == INT_RESULT); + longlong nr= val_int(); + if (!is_null()) + int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value); + return decimal_value; +} + + +Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg,CHARSET_INFO *charset) + :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg) +{ + field_charset=charset; + if (charset->state & MY_CS_BINSORT) + flags|=BINARY_FLAG; +} + + void Field_num::make_field(Send_field *field) { Field::make_field(field); field->decimals= dec; } +/* + Decimal representation of Field_str + + SYNOPSIS + Field_str::store_decimal() + d value for storing + + NOTE + Field_str is the base class for fields like Field_date, and some + similar. Some dates use fraction and also string value should be + converted to floating point value according our rules, so we use double + to store value of decimal in string + + RETURN + 0 OK + != 0 error +*/ + +int Field_str::store_decimal(const my_decimal *d) +{ + double val; + /* TODO: use decimal2string? */ + int err= check_overflow(my_decimal2double(E_DEC_FATAL_ERROR & + ~E_DEC_OVERFLOW, d, &val)); + return err | store(val); +} + + +my_decimal *Field_str::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(result_type() == INT_RESULT); + longlong nr= val_int(); + if (is_null()) + int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value); + return decimal_value; +} + uint Field::fill_cache_field(CACHE_FIELD *copy) { @@ -696,7 +902,7 @@ void Field_decimal::overflow(bool negative) int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff,sizeof(buff), &my_charset_bin); /* Convert character set if the old one is multi byte */ @@ -837,7 +1043,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) /* We only have to generate warnings if count_cuted_fields is set. This is to avoid extra checks of the number when they are not needed. - Even if this flag is not set, it's ok to increment warnings, if + Even if this flag is not set, it's OK to increment warnings, if it makes the code easer to read. */ @@ -1253,6 +1459,275 @@ void Field_decimal::sql_type(String &res) const } +/**************************************************************************** +** Field_new_decimal +****************************************************************************/ + +/* + Constructors of new decimal field. In case of using NOT_FIXED_DEC it try + to use maximally allowed length (DECIMAL_MAX_LENGTH) and number of digits + after decimal point maximally close to half of this range + (min(DECIMAL_MAX_LENGTH/2, NOT_FIXED_DEC-1)) +*/ +Field_new_decimal::Field_new_decimal(char *ptr_arg, + uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg,bool zero_arg, + bool unsigned_arg) + :Field_num(ptr_arg, + (dec_arg == NOT_FIXED_DEC || len_arg > DECIMAL_MAX_LENGTH ? + DECIMAL_MAX_LENGTH : len_arg), + null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + (dec_arg == NOT_FIXED_DEC ? + min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) : + dec_arg), + zero_arg, unsigned_arg) +{ + bin_size= my_decimal_get_binary_size(field_length, dec); +} + + +Field_new_decimal::Field_new_decimal(uint32 len_arg, + bool maybe_null, + const char *name, + struct st_table *t_arg, + uint8 dec_arg) + :Field_num((char*) 0, + (dec_arg == NOT_FIXED_DEC|| len_arg > DECIMAL_MAX_LENGTH ? + DECIMAL_MAX_LENGTH : len_arg), + maybe_null ? (uchar*) "": 0, 0, + NONE, name, t_arg, + (dec_arg == NOT_FIXED_DEC ? + min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) : + dec_arg), + 0, 0) +{ + bin_size= my_decimal_get_binary_size(field_length, dec); +} + + +void Field_new_decimal::reset(void) +{ + store_value(&decimal_zero); +} + + +/* + Generate max/min decimal value in case of overflow. + + SYNOPSIS + Field_new_decimal::set_value_on_overflow(); + decimal_value buffer for value + sign sign of value which caused overflow +*/ + +void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, + bool sign) +{ + DBUG_ENTER("Field_new_decimal::set_value_on_overflow"); + max_my_decimal(decimal_value, field_length, decimals()); + if (sign) + { + if (unsigned_flag) + my_decimal_set_zero(decimal_value); + else + decimal_value->sign(TRUE); + } + DBUG_VOID_RETURN; +} + + +/* + Store decimal value in the binary buffer + + SYNOPSIS + store_value(const my_decimal *decimal_value) + decimal_value my_decimal + + DESCRIPTION + checks if decimal_value fits into field size. + if it does, stores the decimal in the buffer using binary format. + Otherwise sets maximal number that can be stored in the field. +*/ + +bool Field_new_decimal::store_value(const my_decimal *decimal_value) +{ + DBUG_ENTER("Field_new_decimal::store_value"); + my_decimal *dec= (my_decimal*)decimal_value; + DBUG_EXECUTE("enter", print_decimal(dec);); + + /* check that we do not try to write negative value in unsigned field */ + if (unsigned_flag && decimal_value->sign()) + { + DBUG_PRINT("info", ("unsigned overflow")); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + dec= &decimal_zero; + } + DBUG_PRINT("info", ("saving with precision %d, scale: %d", + (int)field_length, (int)decimals())); + DBUG_EXECUTE("info", print_decimal(dec);); + + if (check_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, + dec, ptr, + field_length, + decimals()))) + { + my_decimal buff; + DBUG_PRINT("info", ("overflow")); + set_value_on_overflow(&buff, dec->sign()); + my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, field_length, decimals()); + DBUG_EXECUTE("info", print_decimal_buff(&buff, ptr, bin_size);); + DBUG_RETURN(1); + } + DBUG_EXECUTE("info", print_decimal_buff(dec, ptr, bin_size);); + DBUG_RETURN(0); +} + + +int Field_new_decimal::store(const char *from, uint length, + CHARSET_INFO *charset) +{ + DBUG_ENTER("Field_new_decimal::store(char*)"); + int err; + my_decimal decimal_value; + switch ((err= str2my_decimal(E_DEC_FATAL_ERROR & + ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM), + from, length, charset, &decimal_value))) + { + case E_DEC_TRUNCATED: + set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + break; + case E_DEC_OVERFLOW: + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_value_on_overflow(&decimal_value, decimal_value.sign()); + break; + case E_DEC_BAD_NUM: + push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + "decimal", from, field_name, + (ulong) table->in_use->row_count); + my_decimal_set_zero(&decimal_value); + break; + } + + DBUG_EXECUTE("info", print_decimal(&decimal_value);); + store_value(&decimal_value); + DBUG_RETURN(err); +} + + +int Field_new_decimal::store(double nr) +{ + my_decimal decimal_value; + int err= double2my_decimal(E_DEC_FATAL_ERROR & + ~E_DEC_OVERFLOW, nr, + &decimal_value); + /* + TODO: fix following when double2my_decimal when double2decimal + will return E_DEC_TRUNCATED always correctly + */ + if (!err) + { + double nr2; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &nr2); + if (nr2 != nr) + err= E_DEC_TRUNCATED; + } + if (check_overflow(err)) + set_value_on_overflow(&decimal_value, decimal_value.sign()); + store_value(&decimal_value); + return err; +} + + +int Field_new_decimal::store(longlong nr) +{ + my_decimal decimal_value; + int err; + if ((err= check_overflow(int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, + nr, unsigned_flag, &decimal_value)))) + set_value_on_overflow(&decimal_value, decimal_value.sign()); + store_value(&decimal_value); + return err; +} + + +int Field_new_decimal::store_decimal(const my_decimal *decimal_value) +{ + return store_value(decimal_value); +} + + +double Field_new_decimal::val_real(void) +{ + double dbl; + my_decimal decimal_value; + my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl); + return dbl; +} + + +longlong Field_new_decimal::val_int(void) +{ + longlong i; + my_decimal decimal_value; + my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), + unsigned_flag, &i); + return i; +} + + +my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value) +{ + DBUG_ENTER("Field_new_decimal::val_decimal"); + binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value, + field_length, + decimals()); + DBUG_EXECUTE("info", print_decimal_buff(decimal_value, ptr, bin_size);); + DBUG_RETURN(decimal_value); +} + + +String *Field_new_decimal::val_str(String *val_buffer, + String *val_ptr __attribute__((unused))) +{ + my_decimal decimal_value; + int fixed_precision= (zerofill ? + (field_length + (decimals() ? 1 : 0)) : + 0); + my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), + fixed_precision, decimals(), '0', + val_buffer); + return val_buffer; +} + + +int Field_new_decimal::cmp(const char *a,const char*b) +{ + return memcmp(a, b, bin_size); +} + + +void Field_new_decimal::sort_string(char *buff, + uint length __attribute__((unused))) +{ + memcpy(buff, ptr, bin_size); +} + + +void Field_new_decimal::sql_type(String &str) const +{ + CHARSET_INFO *cs= str.charset(); + str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(), + "decimal(%d,%d)", field_length, (int)dec)); + add_zerofill_and_unsigned(str); +} + /**************************************************************************** ** tiny int ****************************************************************************/ @@ -2553,7 +3028,6 @@ int Field_float::store(longlong nr) return store((double)nr); } - double Field_float::val_real(void) { float j; @@ -2834,6 +3308,12 @@ int Field_double::store(longlong nr) return store((double)nr); } +int Field_real::store_decimal(const my_decimal *dm) +{ + double dbl; + my_decimal2double(E_DEC_FATAL_ERROR, dm, &dbl); + return store(dbl); +} double Field_double::val_real(void) { @@ -2864,6 +3344,13 @@ longlong Field_double::val_int(void) } +my_decimal *Field_real::val_decimal(my_decimal *decimal_value) +{ + double2my_decimal(E_DEC_FATAL_ERROR, val_real(), decimal_value); + return decimal_value; +} + + String *Field_double::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -3031,7 +3518,7 @@ void Field_double::sql_type(String &res) const TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with auto-set-on-update (or now() as default) in this table before, then this field has NOW() as default and is updated when row changes, else it is - field which has 0 as default value and is not automaitcally updated. + field which has 0 as default value and is not automatically updated. TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update automatically (TIMESTAMP DEFAULT NOW()) TIMESTAMP_UN_FIELD - field which is set on update automatically but has not @@ -3093,7 +3580,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const return TIMESTAMP_AUTO_SET_ON_UPDATE; case TIMESTAMP_OLD_FIELD: /* - Altough we can have several such columns in legacy tables this + Although we can have several such columns in legacy tables this function should be called only for first of them (i.e. the one having auto-set property). */ @@ -3597,7 +4084,7 @@ String *Field_time::val_str(String *val_buffer, /* - Normally we would not consider 'time' as a vaild date, but we allow + Normally we would not consider 'time' as a valid date, but we allow get_date() here to be able to do things like DATE_FORMAT(time, "%l.%i %p") */ @@ -4318,7 +4805,7 @@ String *Field_datetime::val_str(String *val_buffer, longlongget(tmp,ptr); /* - Avoid problem with slow longlong aritmetic and sprintf + Avoid problem with slow longlong arithmetic and sprintf */ part1=(long) (tmp/LL(1000000)); @@ -4436,14 +4923,14 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { int error= 0; uint32 not_used; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); uint copy_length; /* See the comment for Field_long::store(long long) */ DBUG_ASSERT(table->in_use == current_thd); - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used)) { uint conv_errors; @@ -4541,6 +5028,16 @@ int Field_string::store(longlong nr) return Field_string::store(buff,(uint)l,cs); } +int Field_longstr::store_decimal(const my_decimal *d) +{ + uint buf_size= my_decimal_string_length(d); + char *buff= (char *)my_alloca(buf_size); + String str(buff, buf_size, &my_charset_bin); + my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); + int result= store(str.ptr(), str.length(), str.charset()); + my_afree(buff); + return result; +} double Field_string::val_real(void) { @@ -4560,6 +5057,14 @@ longlong Field_string::val_int(void) } +my_decimal *Field_longstr::val_decimal(my_decimal *decimal_value) +{ + str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(), + decimal_value); + return decimal_value; +} + + String *Field_string::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { @@ -4791,11 +5296,11 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) { int error= 0; uint32 not_used, copy_length; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN; - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used)) { uint conv_errors; @@ -4871,7 +5376,6 @@ longlong Field_varstring::val_int(void) &end_not_used, ¬_used); } - String *Field_varstring::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { @@ -5272,7 +5776,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg,uint blob_pack_length, CHARSET_INFO *cs) - :Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L, + :Field_longstr(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg, cs), packlength(blob_pack_length) @@ -5395,12 +5899,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) else { bool was_conversion; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); uint copy_length; uint32 not_used; - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if ((was_conversion= String::needs_conversion(length, cs, field_charset, ¬_used))) { @@ -5414,7 +5918,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) copy_length= max_data_length(); /* - copy_length is ok as last argument to well_formed_len as this is never + copy_length is OK as last argument to well_formed_len as this is never used to limit the length of the data. The cut of long data is done with the 'min()' call below. */ @@ -5456,7 +5960,6 @@ int Field_blob::store(longlong nr) return Field_blob::store(value.ptr(), (uint) value.length(), cs); } - double Field_blob::val_real(void) { int not_used; @@ -5484,7 +5987,6 @@ longlong Field_blob::val_int(void) return my_strntoll(charset(),blob,length,10,NULL,¬_used); } - String *Field_blob::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { @@ -5997,10 +6499,10 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) { int err= 0; uint32 not_used; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used)) { uint dummy_errors; @@ -6181,10 +6683,10 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) char *not_used; uint not_used2; uint32 not_used_offset; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used_offset)) { uint dummy_errors; @@ -6443,6 +6945,14 @@ int Field_bit::store(longlong nr) } +int Field_bit::store_decimal(const my_decimal *val) +{ + int err= 0; + longlong i= convert_decimal2longlong(val, 1, &err); + return test(err | store(i)); +} + + double Field_bit::val_real(void) { return (double) Field_bit::val_int(); @@ -6486,6 +6996,13 @@ String *Field_bit::val_str(String *val_buffer, } +my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value) +{ + int2my_decimal(E_DEC_FATAL_ERROR, val_int(), 1, deciaml_value); + return deciaml_value; +} + + int Field_bit::key_cmp(const byte *str, uint length) { if (bit_len) @@ -6592,6 +7109,9 @@ void create_field::create_length_to_internal_length(void) /* We need one extra byte to store the bits we save among the null bits */ key_length= pack_length+ test(length & 7); break; + case MYSQL_TYPE_NEWDECIMAL: + key_length= pack_length= my_decimal_get_binary_size(length, decimals); + break; default: key_length= pack_length= calc_pack_length(sql_type, length); break; @@ -6645,7 +7165,8 @@ uint32 calc_pack_length(enum_field_types type,uint32 length) case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr; case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr; case FIELD_TYPE_SET: - case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen + case FIELD_TYPE_ENUM: + case FIELD_TYPE_NEWDECIMAL: abort(); return 0; // This shouldn't happen case FIELD_TYPE_BIT: return length / 8; default: return 0; } @@ -6766,6 +7287,12 @@ Field *make_field(char *ptr, uint32 field_length, f_decimals(pack_flag), f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); + case FIELD_TYPE_NEWDECIMAL: + return new Field_new_decimal(ptr,field_length,null_pos,null_bit, + unireg_check, field_name, table, + f_decimals(pack_flag), + f_is_zerofill(pack_flag) != 0, + f_is_dec(pack_flag) == 0); case FIELD_TYPE_FLOAT: return new Field_float(ptr,field_length,null_pos,null_bit, unireg_check, field_name, table, @@ -6834,6 +7361,40 @@ Field *make_field(char *ptr, uint32 field_length, } +/* + Check if field_type is appropriate field type + to create field for tmp table using + item->tmp_table_field() method + + SYNOPSIS + field_types_to_be_kept() + field_type - field type + + NOTE + it is used in function get_holder_example_field() + from item.cc + + RETURN + 1 - can use item->tmp_table_field() method + 0 - can not use item->tmp_table_field() method + +*/ + +bool field_types_to_be_kept(enum_field_types field_type) +{ + switch (field_type) + { + case FIELD_TYPE_DATE: + case FIELD_TYPE_NEWDATE: + case FIELD_TYPE_TIME: + case FIELD_TYPE_DATETIME: + return 1; + default: + return 0; + } +} + + /* Create a field suitable for create of table */ create_field::create_field(Field *old_field,Field *orig_field) @@ -6924,7 +7485,7 @@ create_field::create_field(Field *old_field,Field *orig_field) /* Produce warning or note about data saved into field - SYNOPSYS + SYNOPSIS set_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced @@ -6956,7 +7517,7 @@ Field::set_warning(const uint level, const uint code, int cuted_increment) /* Produce warning or note about datetime string data saved into field - SYNOPSYS + SYNOPSIS set_datime_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced @@ -6985,7 +7546,7 @@ Field::set_datetime_warning(const uint level, const uint code, /* Produce warning or note about integer datetime value saved into field - SYNOPSYS + SYNOPSIS set_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced @@ -7017,7 +7578,7 @@ Field::set_datetime_warning(const uint level, const uint code, /* Produce warning or note about double datetime data saved into field - SYNOPSYS + SYNOPSIS set_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced diff --git a/sql/field.h b/sql/field.h index af300c8d471..d0b43e77e5a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -80,7 +80,8 @@ public: FIELD_CAST_TIMESTAMP, FIELD_CAST_YEAR, FIELD_CAST_DATE, FIELD_CAST_NEWDATE, FIELD_CAST_TIME, FIELD_CAST_DATETIME, FIELD_CAST_STRING, FIELD_CAST_VARSTRING, FIELD_CAST_BLOB, - FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT + FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT, + FIELD_CAST_NEWDECIMAL }; utype unireg_check; @@ -96,9 +97,11 @@ public: 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_decimal(const my_decimal *d)=0; virtual int store_time(TIME *ltime, timestamp_type t_type); virtual double val_real(void)=0; virtual longlong val_int(void)=0; + virtual my_decimal *val_decimal(my_decimal *); inline String *val_str(String *str) { return val_str(str, str); } /* val_str(buf1, buf2) gets two buffers and should use them as follows: @@ -287,10 +290,16 @@ public: int cuted_increment); void set_datetime_warning(const uint level, const uint code, double nr, timestamp_type ts_type); + int check_overflow(int op_result); virtual field_cast_enum field_cast_type()= 0; bool field_cast_compatible(field_cast_enum type); /* maximum possible display length */ virtual uint32 max_length()= 0; + /* length of field value symbolic representation (in bytes) */ + virtual uint32 representation_length() { return field_length; } + /* convert decimal to longlong with overflow check */ + longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, + int *err); friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -317,16 +326,7 @@ public: uchar null_bit_arg, utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg), - dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg) - { - if (zerofill) - flags|=ZEROFILL_FLAG; - if (unsigned_flag) - flags|=UNSIGNED_FLAG; - } + uint8 dec_arg, bool zero_arg, bool unsigned_arg); Item_result result_type () const { return REAL_RESULT; } void prepend_zeros(String *value); void add_zerofill_and_unsigned(String &res) const; @@ -335,6 +335,8 @@ public: uint decimals() const { return (uint) dec; } uint size_of() const { return sizeof(*this); } bool eq_def(Field *field); + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); }; @@ -345,18 +347,12 @@ public: Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg,CHARSET_INFO *charset) - :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg) - { - field_charset=charset; - if (charset->state & MY_CS_BINSORT) - flags|=BINARY_FLAG; - } + struct st_table *table_arg, CHARSET_INFO *charset); 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_decimal(const my_decimal *); int store(const char *to,uint length,CHARSET_INFO *cs)=0; uint size_of() const { return sizeof(*this); } CHARSET_INFO *charset(void) const { return field_charset; } @@ -364,19 +360,54 @@ public: bool binary() const { return field_charset == &my_charset_bin; } uint32 max_length() { return field_length; } friend class create_field; + my_decimal *val_decimal(my_decimal *); +}; + +/* base class for Item_string, Item_valstring, Item_blob */ +class Field_longstr :public Field_str +{ +public: + Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg,CHARSET_INFO *charset) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, table_arg, charset) + {} + + my_decimal *val_decimal(my_decimal *); + int store_decimal(const my_decimal *d); +}; + +/* base class for float and double and decimal (old one) */ +class Field_real :public Field_num { +public: + + Field_real(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, table_arg, dec_arg, zero_arg, unsigned_arg) + {} + + + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); }; -class Field_decimal :public Field_num { +class Field_decimal :public Field_real { public: Field_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, - dec_arg, zero_arg,unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + dec_arg, zero_arg, unsigned_arg) {} enum_field_types type() const { return FIELD_TYPE_DECIMAL;} enum ha_base_keytype key_type() const @@ -398,6 +429,46 @@ public: }; +/* New decimal/numeric field which use fixed point arithmetic */ +class Field_new_decimal :public Field_num { +public: + uint bin_size; + Field_new_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg); + Field_new_decimal(uint32 len_arg, bool maybe_null_arg, + const char *field_name_arg, + struct st_table *table_arg, uint8 dec_arg); + enum_field_types type() const { return FIELD_TYPE_NEWDECIMAL;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + Item_result result_type () const { return DECIMAL_RESULT; } + void reset(void); + bool store_value(const my_decimal *decimal_value); + 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_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*, String *); + int cmp(const char *, const char*); + void sort_string(char *buff, uint length); + bool zero_pack() const { return 0; } + void sql_type(String &str) const; + uint32 max_length() + { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); } + uint32 representation_length() + { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); }; + field_cast_enum field_cast_type() { return FIELD_CAST_NEWDECIMAL; } + uint size_of() const { return sizeof(*this); } + uint32 pack_length() const { return (uint32) bin_size; } +}; + + class Field_tiny :public Field_num { public: Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, @@ -576,21 +647,22 @@ public: }; #endif -class Field_float :public Field_num { + +class Field_float :public Field_real { public: Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, - dec_arg, zero_arg,unsigned_arg) + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + dec_arg, zero_arg, unsigned_arg) {} Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg) - :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, table_arg,dec_arg,0,0) + :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, table_arg, dec_arg, 0, 0) {} enum_field_types type() const { return FIELD_TYPE_FLOAT;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } @@ -611,21 +683,21 @@ public: }; -class Field_double :public Field_num { +class Field_double :public Field_real { public: Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, - dec_arg, zero_arg,unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + dec_arg, zero_arg, unsigned_arg) {} Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg) - :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, table_arg,dec_arg,0,0) + :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, table_arg, dec_arg, 0, 0) {} enum_field_types type() const { return FIELD_TYPE_DOUBLE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } @@ -646,7 +718,7 @@ public: }; -/* Everything saved in this will disapper. It will always return NULL */ +/* Everything saved in this will disappear. It will always return NULL */ class Field_null :public Field_str { static uchar null[1]; @@ -662,9 +734,11 @@ public: { 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_decimal(const my_decimal *d) { null[0]=1; return 0; } void reset(void) {} double val_real(void) { return 0.0;} longlong val_int(void) { return 0;} + my_decimal *val_decimal(my_decimal *) { return 0; } String *val_str(String *value,String *value2) { value2->length(0); return value2;} int cmp(const char *a, const char *b) { return 0;} @@ -892,18 +966,18 @@ public: }; -class Field_string :public Field_str { +class Field_string :public Field_longstr { public: Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg,cs) {}; + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, cs) {}; Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg, cs) {}; + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_longstr((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) {}; enum_field_types type() const { @@ -942,7 +1016,7 @@ public: }; -class Field_varstring :public Field_str { +class Field_varstring :public Field_longstr { public: /* Store number of bytes used to store length (1 or 2) */ uint32 length_bytes; @@ -952,19 +1026,19 @@ public: uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, cs), - length_bytes(length_bytes_arg) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, cs), + length_bytes(length_bytes_arg) { if (table) table->s->varchar_fields++; } Field_varstring(uint32 len_arg,bool maybe_null_arg, - const char *field_name_arg, - struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg, cs), - length_bytes(len_arg < 256 ? 1 :2) + const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs), + length_bytes(len_arg < 256 ? 1 :2) { if (table) table->s->varchar_fields++; @@ -1012,7 +1086,7 @@ public: }; -class Field_blob :public Field_str { +class Field_blob :public Field_longstr { protected: uint packlength; String value; // For temporaries @@ -1023,8 +1097,8 @@ public: CHARSET_INFO *cs); Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg, cs), + :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs), packlength(4) { flags|= BLOB_FLAG; @@ -1103,9 +1177,7 @@ public: bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } field_cast_enum field_cast_type() { return FIELD_CAST_BLOB; } - uint32 max_length(); -}; - + uint32 max_length();}; #ifdef HAVE_SPATIAL class Field_geom :public Field_blob { @@ -1130,7 +1202,7 @@ public: int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr) { return 1; } int store(longlong nr) { return 1; } - + int store_decimal(const my_decimal *) { return 1; } void get_key_image(char *buff,uint length,imagetype type); field_cast_enum field_cast_type() { return FIELD_CAST_GEOM; } }; @@ -1224,9 +1296,11 @@ public: int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); int store(longlong nr); + int store_decimal(const my_decimal *); double val_real(void); longlong val_int(void); String *val_str(String*, String *); + my_decimal *val_decimal(my_decimal *); int cmp(const char *a, const char *b) { return cmp_binary(a, b); } int key_cmp(const byte *a, const byte *b) @@ -1333,6 +1407,7 @@ enum_field_types get_blob_type_from_length(ulong length); uint32 calc_pack_length(enum_field_types type,uint32 length); int set_field_to_null(Field *field); int set_field_to_null_with_conversions(Field *field, bool no_conversions); +bool field_types_to_be_kept(enum_field_types field_type); /* The following are for the interface with the .frm file diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 002f059f70b..57161a7063e 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -586,6 +586,9 @@ void field_conv(Field *to,Field *from) !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && to->real_type() != FIELD_TYPE_ENUM && to->real_type() != FIELD_TYPE_SET && + (to->real_type() != FIELD_TYPE_NEWDECIMAL || + (to->field_length == from->field_length && + (((Field_num*)to)->dec == ((Field_num*)from)->dec))) && from->charset() == to->charset() && to->table->s->db_low_byte_first == from->table->s->db_low_byte_first) { // Identical fields @@ -623,6 +626,11 @@ void field_conv(Field *to,Field *from) } else if (from->result_type() == REAL_RESULT) to->store(from->val_real()); + else if (from->result_type() == DECIMAL_RESULT) + { + my_decimal buff; + to->store_decimal(from->val_decimal(&buff)); + } else to->store(from->val_int()); } diff --git a/sql/filesort.cc b/sql/filesort.cc index 1665358dbf0..956ac2ef61b 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -703,6 +703,22 @@ static void make_sortkey(register SORTPARAM *param, #endif break; } + case DECIMAL_RESULT: + { + my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf); + if ((maybe_null=item->null_value)) + { + bzero((char*)to, sort_field->length+1); + to++; + break; + } + if ((maybe_null=item->maybe_null)) + *to++=1; + my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, (byte*)to, + item->max_length - (item->decimals ? 1:0), + item->decimals); + break; + } case REAL_RESULT: { double value= item->val_real(); @@ -1212,6 +1228,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) sortorder->length=4; #endif break; + case DECIMAL_RESULT: + sortorder->length= + my_decimal_get_binary_size(sortorder->item->max_length - + (sortorder->item->decimals ? 1 : 0), + sortorder->item->decimals); + break; case REAL_RESULT: sortorder->length=sizeof(double); break; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 5185e0bbe9a..695c71677c0 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -586,16 +586,13 @@ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row) DBUG_RETURN(0); } -bool ha_federated::create_where_from_key( - String *to, - KEY *key_info, - const byte *key, - uint key_length - ) +bool ha_federated::create_where_from_key(String *to, KEY *key_info, + const byte *key, uint key_length) { uint second_loop= 0; KEY_PART_INFO *key_part; bool needs_quotes; + String tmp; DBUG_ENTER("ha_federated::create_where_from_key"); for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++) @@ -656,7 +653,9 @@ bool ha_federated::create_where_from_key( uint blob_length= uint2korr(key); key+= HA_KEY_BLOB_LENGTH; key_length-= HA_KEY_BLOB_LENGTH; - if (append_escaped(to, (char *)(key), blob_length)) + + tmp.set_quick((char*) key, blob_length, &my_charset_bin); + if (append_escaped(to, &tmp)) DBUG_RETURN(1); DBUG_PRINT("ha_federated::create_where_from_key", ("blob type %s", to->c_ptr_quick())); @@ -666,7 +665,8 @@ bool ha_federated::create_where_from_key( { length= uint2korr(key); key+= HA_KEY_BLOB_LENGTH; - if (append_escaped(to, (char *)(key), length)) + tmp.set_quick((char*) key, length, &my_charset_bin); + if (append_escaped(to, &tmp)) DBUG_RETURN(1); DBUG_PRINT("ha_federated::create_where_from_key", ("varchar type %s", to->c_ptr_quick())); @@ -680,7 +680,7 @@ bool ha_federated::create_where_from_key( res= field->val_str(&str, (char *)(key)); if (field->result_type() == STRING_RESULT) { - if (append_escaped(to, (char *) res->ptr(), res->length())) + if (append_escaped(to, res)) DBUG_RETURN(1); res= field->val_str(&str, (char *)(key)); @@ -1235,7 +1235,7 @@ int ha_federated::update_row( update_string.append(new_field_value); new_field_value.length(0); - if (x+1 < table->s->fields) + if ((uint) x+1 < table->s->fields) { update_string.append(", "); if (! has_a_primary_key) @@ -1311,7 +1311,7 @@ int ha_federated::delete_row(const byte * buf) delete_string.append(data_string); data_string.length(0); - if (x+1 < table->s->fields) + if ((uint) x+1 < table->s->fields) delete_string.append(" AND "); } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 01580586bf6..052ee0643ee 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -787,8 +787,9 @@ innobase_query_caching_of_table_permitted( char* full_name, /* in: concatenation of database name, the null character '\0', and the table name */ - uint full_name_len) /* in: length of the full name, i.e. + uint full_name_len, /* in: length of the full name, i.e. len(dbname) + len(tablename) + 1 */ + ulonglong *unused) /* unused for this engine */ { ibool is_autocommit; trx_t* trx; @@ -1612,6 +1613,31 @@ innobase_rollback_to_savepoint( DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); } +/********************************************************************* +Release transaction savepoint name. */ + +int +innobase_release_savepoint_name( +/*===========================*/ + /* out: 0 if success, HA_ERR_NO_SAVEPOINT if + no savepoint with the given name */ + THD* thd, /* in: handle to the MySQL thread of the user + whose transaction should be rolled back */ + char* savepoint_name) /* in: savepoint name */ +{ + ib_longlong mysql_binlog_cache_pos; + int error = 0; + trx_t* trx; + + DBUG_ENTER("innobase_release_savepoint_name"); + + trx = check_trx_exists(thd); + + error = trx_release_savepoint_for_mysql(trx, savepoint_name); + + DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); +} + /********************************************************************* Sets a transaction savepoint. */ @@ -2133,6 +2159,8 @@ get_innobase_type_from_mysql_type( } else { return(DATA_MYSQL); } + case FIELD_TYPE_NEWDECIMAL: + return(DATA_BINARY); case FIELD_TYPE_LONG: case FIELD_TYPE_LONGLONG: case FIELD_TYPE_TINY: @@ -4128,7 +4156,7 @@ ha_innobase::delete_all_rows(void) goto fallback; } - innobase_commit_low(trx); + innobase_commit(thd, trx); error = convert_error_code_to_mysql(error, NULL); @@ -4846,12 +4874,12 @@ ha_innobase::update_table_comment( dict_print_info_on_foreign_keys(FALSE, file, prebuilt->trx, prebuilt->table); flen = ftell(file); - if(length + flen + 3 > 64000) { + if (flen < 0) { + flen = 0; + } else if (length + flen + 3 > 64000) { flen = 64000 - 3 - length; } - ut_ad(flen > 0); - /* allocate buffer for the full string, and read the contents of the temporary file */ @@ -4915,12 +4943,12 @@ ha_innobase::get_foreign_key_create_info(void) prebuilt->trx->op_info = (char*)""; flen = ftell(file); - if(flen > 64000 - 1) { + if (flen < 0) { + flen = 0; + } else if(flen > 64000 - 1) { flen = 64000 - 1; } - ut_ad(flen >= 0); - /* allocate buffer for the string, and read the contents of the temporary file */ @@ -5521,12 +5549,12 @@ innodb_show_status( srv_printf_innodb_monitor(srv_monitor_file); flen = ftell(srv_monitor_file); os_file_set_eof(srv_monitor_file); - if(flen > 64000 - 1) { + if (flen < 0) { + flen = 0; + } else if (flen > 64000 - 1) { flen = 64000 - 1; } - ut_ad(flen > 0); - /* allocate buffer for the string, and read the contents of the temporary file */ @@ -5745,7 +5773,7 @@ ha_innobase::store_lock( { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - if ((lock_type == TL_READ && thd->in_lock_tables) || + if ((lock_type == TL_READ && thd->in_lock_tables) || (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) || lock_type == TL_READ_WITH_SHARED_LOCKS || lock_type == TL_READ_NO_INSERT || @@ -5768,8 +5796,27 @@ ha_innobase::store_lock( unexpected if an obsolete consistent read view would be used. */ - prebuilt->select_lock_type = LOCK_S; - prebuilt->stored_select_lock_type = LOCK_S; + if (srv_locks_unsafe_for_binlog && + prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE && + (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && + thd->lex->sql_command != SQLCOM_SELECT && + thd->lex->sql_command != SQLCOM_UPDATE_MULTI && + thd->lex->sql_command != SQLCOM_DELETE_MULTI ) { + + /* In case we have innobase_locks_unsafe_for_binlog + option set and isolation level of the transaction + is not set to serializable and MySQL is doing + INSERT INTO...SELECT without FOR UPDATE or IN + SHARE MODE we use consistent read for select. + Similarly, in case of DELETE...SELECT and + UPDATE...SELECT when these are not multi 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; + } } else if (lock_type != TL_IGNORE) { @@ -6117,13 +6164,19 @@ innobase_get_at_most_n_mbchars( extern "C" { /********************************************************************** -This function returns true if SQL-query in the current thread +This function returns true if + +1) SQL-query in the current thread is either REPLACE or LOAD DATA INFILE REPLACE. + +2) SQL-query in the current thread +is INSERT ON DUPLICATE KEY UPDATE. + NOTE that /mysql/innobase/row/row0ins.c must contain the prototype for this function ! */ ibool -innobase_query_is_replace(void) +innobase_query_is_update(void) /*===========================*/ { THD* thd; @@ -6135,17 +6188,23 @@ innobase_query_is_replace(void) ( thd->lex->sql_command == SQLCOM_LOAD && thd->lex->duplicates == DUP_REPLACE )) { return true; - } else { - return false; } + + if ( thd->lex->sql_command == SQLCOM_INSERT && + thd->lex->duplicates == DUP_UPDATE ) { + return true; + } + + return false; } } /*********************************************************************** This function is used to prepare X/Open XA distributed transaction */ -int innobase_xa_prepare( -/*====================*/ +int +innobase_xa_prepare( +/*================*/ /* out: 0 or error number */ THD* thd, /* in: handle to the MySQL thread of the user whose XA transaction should be prepared */ @@ -6208,12 +6267,13 @@ int innobase_xa_prepare( /*********************************************************************** This function is used to recover X/Open XA distributed transactions */ -int innobase_xa_recover( +int +innobase_xa_recover( +/*================*/ /* out: number of prepared transactions stored in xid_list */ XID* xid_list, /* in/out: prepared transactions */ uint len) /* in: number of slots in xid_list */ -/*====================*/ { if (len == 0 || xid_list == NULL) { return 0; @@ -6226,8 +6286,9 @@ int innobase_xa_recover( This function is used to commit one X/Open XA distributed transaction which is in the prepared state */ -int innobase_commit_by_xid( -/*=======================*/ +int +innobase_commit_by_xid( +/*===================*/ /* out: 0 or error number */ XID* xid) /* in: X/Open XA Transaction Identification */ { @@ -6248,7 +6309,9 @@ int innobase_commit_by_xid( This function is used to rollback one X/Open XA distributed transaction which is in the prepared state */ -int innobase_rollback_by_xid( +int +innobase_rollback_by_xid( +/*=====================*/ /* out: 0 or error number */ XID *xid) /* in : X/Open XA Transaction Idenfification */ { @@ -6263,36 +6326,4 @@ int innobase_rollback_by_xid( } } -/*********************************************************************** -This function is used to test commit/rollback of XA transactions */ - -int innobase_xa_end( -/*================*/ - THD* thd) /* in: MySQL thread handle of the user for whom - transactions should be recovered */ -{ - DBUG_ENTER("innobase_xa_end"); - - XID trx_list[100]; - int trx_num, trx_num_max = 100; - int i; - XID xid; - - while((trx_num = innobase_xa_recover(trx_list, trx_num_max))) { - - for(i=0;i < trx_num; i++) { - xid = trx_list[i]; - - if ( i % 2) { - innobase_commit_by_xid(&xid); - } else { - innobase_rollback_by_xid(&xid); - } - } - } - - free(trx_list); - - DBUG_RETURN(0); -} #endif /* HAVE_INNOBASE_DB */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 2154e238fd1..cca33cbbe1c 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -33,6 +33,10 @@ typedef struct st_innobase_share { } INNOBASE_SHARE; +my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name, + uint full_name_len, + ulonglong *unused); + /* The class defining a handle to an Innodb table */ class ha_innobase: public handler { @@ -173,6 +177,20 @@ class ha_innobase: public handler void init_table_handle_for_HANDLER(); ulonglong get_auto_increment(); uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; } + /* + ask handler about permission to cache table during query registration + */ + my_bool register_query_cache_table(THD *thd, char *table_key, + uint key_length, + qc_engine_callback *call_back, + ulonglong *engine_data) + { + *call_back= innobase_query_caching_of_table_permitted; + *engine_data= 0; + return innobase_query_caching_of_table_permitted(thd, table_key, + key_length, + engine_data); + } static char *get_mysql_bin_log_name(); static ulonglong get_mysql_bin_log_pos(); bool primary_key_is_clustered() { return true; } @@ -244,14 +262,15 @@ int innobase_savepoint( THD* thd, char* savepoint_name, my_off_t binlog_cache_pos); +int innobase_release_savepoint_name( + THD* thd, + char* savepoint_name); int innobase_close_connection(THD *thd); int innobase_drop_database(char *path); bool innodb_show_status(THD* thd); bool innodb_mutex_show_status(THD* thd); void innodb_export_status(void); -my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name, - uint full_name_len); void innobase_release_temporary_latches(void* innobase_tid); void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 9631b78bca3..ad7e775aacf 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -727,7 +727,7 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt) if ((error= mi_assign_to_key_cache(file, map, new_key_cache))) { - char buf[80]; + char buf[STRING_BUFFER_USUAL_SIZE]; my_snprintf(buf, sizeof(buf), "Failed to flush to index file (errno: %d)", error); errmsg= buf; diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index d2fe36c8357..7e14a3b7941 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -88,8 +88,12 @@ class ha_myisam: public handler ft_handler->please->reinit_search(ft_handler); return 0; } - FT_INFO *ft_init_ext(uint flags, uint inx,const byte *key, uint keylen) - { return ft_init_search(flags,file,inx,(byte*) key,keylen, table->record[0]); } + FT_INFO *ft_init_ext(uint flags, uint inx,String *key) + { + return ft_init_search(flags,file,inx, + (byte *)key->ptr(), key->length(), key->charset(), + table->record[0]); + } int ft_read(byte *buf); int rnd_init(bool scan); int rnd_next(byte *buf); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index f2b159353e3..58f744438fc 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -87,6 +87,12 @@ static int unpackfrm(const void **data, uint *len, static int ndb_get_table_statistics(Ndb*, const char *, struct Ndb_statistics *); +// Util thread variables +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); +ulong ndb_cache_check_time; /* Dummy buffer to read zero pack_length fields @@ -2351,22 +2357,21 @@ void ha_ndbcluster::print_results() if (!_db_on_) DBUG_VOID_RETURN; - + char buf_type[MAX_FIELD_WIDTH], buf_val[MAX_FIELD_WIDTH]; - String type(buf_type, sizeof(buf_type), &my_charset_bin); + String type(buf_type, sizeof(buf_type), &my_charset_bin); String val(buf_val, sizeof(buf_val), &my_charset_bin); for (uint f=0; fs->fields;f++) { - // Use DBUG_PRINT since DBUG_FILE cannot be filtered out + /* Use DBUG_PRINT since DBUG_FILE cannot be filtered out */ char buf[2000]; Field *field; void* ptr; - const NDBCOL *col= NULL; NdbValue value; NdbBlob *ndb_blob; buf[0]= 0; - field= table->field[f]; + field= table->field[f]; if (!(value= m_value[f]).ptr) { my_snprintf(buf, sizeof(buf), "not read"); @@ -2374,8 +2379,6 @@ void ha_ndbcluster::print_results() } ptr= field->ptr; - DBUG_DUMP("field->ptr", (char*)ptr, field->pack_length()); - col= tab->getColumn(f); if (! (field->flags & BLOB_FLAG)) { @@ -2401,9 +2404,9 @@ void ha_ndbcluster::print_results() goto print_value; } } - + print_value: - DBUG_PRINT("value", ("%u,%s: %s", f, col->getName(), buf)); + DBUG_PRINT("value", ("%u,%s: %s", f, field->field_name, buf)); } #endif DBUG_VOID_RETURN; @@ -3053,9 +3056,13 @@ int ha_ndbcluster::reset() DBUG_RETURN(1); } +static const char *ha_ndb_bas_ext[]= { ha_ndb_ext, NullS }; -const char **ha_ndbcluster::bas_ext() const -{ static const char *ext[]= { ha_ndb_ext, NullS }; return ext; } +const char** +ha_ndbcluster::bas_ext() const +{ + return ha_ndb_bas_ext; +} /* @@ -3223,7 +3230,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) m_transaction_on= FALSE; else m_transaction_on= thd->variables.ndb_use_transactions; - // m_use_local_query_cache= thd->variables.ndb_use_local_query_cache; m_active_trans= thd->transaction.all.ndb_tid ? (NdbTransaction*)thd->transaction.all.ndb_tid: @@ -3650,6 +3656,52 @@ static int create_ndb_column(NDBCOL &col, Create a table in NDB Cluster */ +static void ndb_set_fragmentation(NDBTAB &tab, TABLE *form, uint pk_length) +{ + if (form->s->max_rows == 0) /* default setting, don't set fragmentation */ + return; + /** + * get the number of fragments right + */ + uint no_fragments; + { +#if MYSQL_VERSION_ID >= 50000 + uint acc_row_size= 25 + /*safety margin*/ 2; +#else + uint acc_row_size= pk_length*4; + /* add acc overhead */ + if (pk_length <= 8) /* main page will set the limit */ + acc_row_size+= 25 + /*safety margin*/ 2; + else /* overflow page will set the limit */ + acc_row_size+= 4 + /*safety margin*/ 4; +#endif + ulonglong acc_fragment_size= 512*1024*1024; + ulonglong max_rows= form->s->max_rows; +#if MYSQL_VERSION_ID >= 50100 + no_fragments= (max_rows*acc_row_size)/acc_fragment_size+1; +#else + no_fragments= ((max_rows*acc_row_size)/acc_fragment_size+1 + +1/*correct rounding*/)/2; +#endif + } + { + uint no_nodes= g_ndb_cluster_connection->no_db_nodes(); + NDBTAB::FragmentType ftype; + if (no_fragments > 2*no_nodes) + { + ftype= NDBTAB::FragAllLarge; + if (no_fragments > 4*no_nodes) + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Ndb might have problems storing the max amount of rows specified"); + } + else if (no_fragments > no_nodes) + ftype= NDBTAB::FragAllMedium; + else + ftype= NDBTAB::FragAllSmall; + tab.setFragmentType(ftype); + } +} + int ha_ndbcluster::create(const char *name, TABLE *form, HA_CREATE_INFO *info) @@ -3751,7 +3803,9 @@ int ha_ndbcluster::create(const char *name, break; } } - + + ndb_set_fragmentation(tab, form, pk_length); + if ((my_errno= check_ndb_connection())) DBUG_RETURN(my_errno); @@ -4017,7 +4071,6 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_force_send(TRUE), m_autoincrement_prefetch(32), m_transaction_on(TRUE), - m_use_local_query_cache(FALSE), m_multi_cursor(NULL) { int i; @@ -4068,6 +4121,7 @@ ha_ndbcluster::~ha_ndbcluster() } + /* Open a table for further use - fetch metadata for this table from NDB @@ -4168,16 +4222,14 @@ void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb) Ndb* check_ndb_in_thd(THD* thd) { - DBUG_ENTER("check_ndb_in_thd"); - Thd_ndb *thd_ndb= (Thd_ndb*)thd->transaction.thd_ndb; - + Thd_ndb *thd_ndb= (Thd_ndb*)thd->transaction.thd_ndb; if (!thd_ndb) { if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb())) - DBUG_RETURN(NULL); + return NULL; thd->transaction.thd_ndb= thd_ndb; } - DBUG_RETURN(thd_ndb->ndb); + return thd_ndb->ndb; } @@ -4530,13 +4582,21 @@ bool ndbcluster_init() (void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0, (hash_get_key) ndbcluster_get_key,0,0); pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST); + pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_ndb_util_thread, NULL); + + // Create utility thread + pthread_t tmp; + if (pthread_create(&tmp, &connection_attrib, ndb_util_thread_func, 0)) + { + DBUG_PRINT("error", ("Could not create ndb utility thread")); + goto ndbcluster_init_error; + } + ndbcluster_inited= 1; -#ifdef USE_DISCOVER_ON_STARTUP - if (ndb_discover_tables() != 0) - goto ndbcluster_init_error; -#endif DBUG_RETURN(FALSE); + ndbcluster_init_error: ndbcluster_end(); DBUG_RETURN(TRUE); @@ -4546,12 +4606,19 @@ bool ndbcluster_init() /* End use of the NDB Cluster table handler - free all global variables allocated by - ndcluster_init() + ndbcluster_init() */ bool ndbcluster_end() { DBUG_ENTER("ndbcluster_end"); + + // Kill ndb utility thread + (void) pthread_mutex_lock(&LOCK_ndb_util_thread); + DBUG_PRINT("exit",("killing ndb util thread: %lx", ndb_util_thread)); + (void) pthread_cond_signal(&COND_ndb_util_thread); + (void) pthread_mutex_unlock(&LOCK_ndb_util_thread); + if(g_ndb) delete g_ndb; g_ndb= NULL; @@ -4562,6 +4629,8 @@ bool ndbcluster_end() DBUG_RETURN(0); hash_free(&ndbcluster_open_tables); pthread_mutex_destroy(&ndbcluster_mutex); + pthread_mutex_destroy(&LOCK_ndb_util_thread); + pthread_cond_destroy(&COND_ndb_util_thread); ndbcluster_inited= 0; DBUG_RETURN(0); } @@ -4754,16 +4823,174 @@ const char* ha_ndbcluster::index_type(uint key_number) return "HASH"; } } + uint8 ha_ndbcluster::table_cache_type() { - if (m_use_local_query_cache) - return HA_CACHE_TBL_TRANSACT; - else - return HA_CACHE_TBL_NOCACHE; + DBUG_ENTER("ha_ndbcluster::table_cache_type=HA_CACHE_TBL_ASKTRANSACT"); + DBUG_RETURN(HA_CACHE_TBL_ASKTRANSACT); } + +uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, + Uint64 *commit_count) +{ + DBUG_ENTER("ndb_get_commitcount"); + + if (ndb_cache_check_time > 0) + { + /* Use cached commit_count from share */ + char name[FN_REFLEN]; + NDB_SHARE *share; + (void)strxnmov(name, FN_REFLEN, + "./",dbname,"/",tabname,NullS); + DBUG_PRINT("info", ("name: %s", name)); + pthread_mutex_lock(&ndbcluster_mutex); + if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables, + (byte*) name, + strlen(name)))) + { + pthread_mutex_unlock(&ndbcluster_mutex); + DBUG_RETURN(1); + } + *commit_count= share->commit_count; + DBUG_PRINT("info", ("commit_count: %d", *commit_count)); + pthread_mutex_unlock(&ndbcluster_mutex); + DBUG_RETURN(0); + } + + /* Get commit_count from NDB */ + Ndb *ndb; + if (!(ndb= check_ndb_in_thd(thd))) + DBUG_RETURN(1); + ndb->setDatabaseName(dbname); + + struct Ndb_statistics stat; + if (ndb_get_table_statistics(ndb, tabname, &stat)) + DBUG_RETURN(1); + *commit_count= stat.commit_count; + DBUG_RETURN(0); +} + + /* - Handling the shared NDB_SHARE structure that is needed to + Check if a cached query can be used. + This is done by comparing the supplied engine_data to commit_count of + the table. + The commit_count is either retrieved from the share for the table, where + it has been cached by the util thread. If the util thread is not started, + NDB has to be contacetd to retrieve the commit_count, this will introduce + a small delay while waiting for NDB to answer. + + + SYNOPSIS + ndbcluster_cache_retrieval_allowed + thd thread handle + full_name concatenation of database name, + the null character '\0', and the table + name + full_name_len length of the full name, + i.e. len(dbname) + len(tablename) + 1 + + engine_data parameter retrieved when query was first inserted into + the cache. If the value of engine_data is changed, + all queries for this table should be invalidated. + + RETURN VALUE + TRUE Yes, use the query from cache + FALSE No, don't use the cached query, and if engine_data + has changed, all queries for this table should be invalidated + +*/ + +static my_bool +ndbcluster_cache_retrieval_allowed(THD *thd, + char *full_name, uint full_name_len, + ulonglong *engine_data) +{ + DBUG_ENTER("ndbcluster_cache_retrieval_allowed"); + + Uint64 commit_count; + bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)); + char *dbname= full_name; + char *tabname= dbname+strlen(dbname)+1; + + DBUG_PRINT("enter",("dbname=%s, tabname=%s, autocommit=%d", + dbname, tabname, is_autocommit)); + + if (!is_autocommit) + DBUG_RETURN(FALSE); + + if (ndb_get_commitcount(thd, dbname, tabname, &commit_count)) + { + *engine_data+= 1; /* invalidate */ + DBUG_RETURN(FALSE); + } + DBUG_PRINT("info", ("*engine_data=%llu, commit_count=%llu", + *engine_data, commit_count)); + if (*engine_data != commit_count) + { + *engine_data= commit_count; /* invalidate */ + DBUG_PRINT("exit",("Do not use cache, commit_count has changed")); + DBUG_RETURN(FALSE); + } + + DBUG_PRINT("exit",("OK to use cache, *engine_data=%llu",*engine_data)); + DBUG_RETURN(TRUE); +} + + +/** + Register a table for use in the query cache. Fetch the commit_count + for the table and return it in engine_data, this will later be used + to check if the table has changed, before the cached query is reused. + + SYNOPSIS + ha_ndbcluster::can_query_cache_table + thd thread handle + full_name concatenation of database name, + the null character '\0', and the table + name + full_name_len length of the full name, + i.e. len(dbname) + len(tablename) + 1 + qc_engine_callback function to be called before using cache on this table + engine_data out, commit_count for this table + + RETURN VALUE + TRUE Yes, it's ok to cahce this query + FALSE No, don't cach the query + +*/ + +my_bool +ha_ndbcluster::register_query_cache_table(THD *thd, + char *full_name, uint full_name_len, + qc_engine_callback *engine_callback, + ulonglong *engine_data) +{ + DBUG_ENTER("ha_ndbcluster::register_query_cache_table"); + + bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)); + DBUG_PRINT("enter",("dbname=%s, tabname=%s, is_autocommit=%d", + m_dbname,m_tabname,is_autocommit)); + if (!is_autocommit) + DBUG_RETURN(FALSE); + + Uint64 commit_count; + if (ndb_get_commitcount(thd, m_dbname, m_tabname, &commit_count)) + { + *engine_data= 0; + DBUG_PRINT("error", ("Could not get commitcount")) + DBUG_RETURN(FALSE); + } + *engine_data= commit_count; + *engine_callback= ndbcluster_cache_retrieval_allowed; + DBUG_PRINT("exit",("*engine_data=%llu", *engine_data)); + DBUG_RETURN(TRUE); +} + + +/* + Handling the shared NDB_SHARE structure that is needed to provide table locking. It's also used for sharing data with other NDB handlers in the same MySQL Server. There is currently not much @@ -4800,8 +5027,14 @@ static NDB_SHARE* get_share(const char *table_name) } thr_lock_init(&share->lock); pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST); + share->commit_count= 0; } } + DBUG_PRINT("share", + ("table_name: %s, length: %d, use_count: %d, commit_count: %d", + share->table_name, share->table_name_length, share->use_count, + share->commit_count)); + share->use_count++; pthread_mutex_unlock(&ndbcluster_mutex); return share; @@ -5374,7 +5607,7 @@ ha_ndbcluster::update_table_comment( const char* comment)/* in: table comment defined by user */ { uint length= strlen(comment); - if(length > 64000 - 3) + if(length > 64000 - 3) { return((char*)comment); /* string too long */ } @@ -5407,4 +5640,125 @@ ha_ndbcluster::update_table_comment( return str; } + +// Utility thread main loop +extern "C" pthread_handler_decl(ndb_util_thread_func, + arg __attribute__((unused))) +{ + THD *thd; /* needs to be first for thread_stack */ + int error= 0; + struct timespec abstime; + + my_thread_init(); + DBUG_ENTER("ndb_util_thread"); + DBUG_PRINT("enter", ("ndb_cache_check_time: %d", ndb_cache_check_time)); + + thd= new THD; /* note that contructor of THD uses DBUG_ */ + THD_CHECK_SENTRY(thd); + + pthread_detach_this_thread(); + ndb_util_thread= pthread_self(); + + thd->thread_stack= (char*)&thd; /* remember where our stack is */ + if (thd->store_globals()) + { + thd->cleanup(); + delete thd; + DBUG_RETURN(NULL); + } + + List util_open_tables; + set_timespec(abstime, ndb_cache_check_time); + for (;;) + { + + pthread_mutex_lock(&LOCK_ndb_util_thread); + error= 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", + ndb_cache_check_time)); + + if (abort_loop) + break; /* Shutting down server */ + + if (ndb_cache_check_time == 0) + { + set_timespec(abstime, 10); + continue; + } + + /* Set new time to wake up */ + set_timespec(abstime, ndb_cache_check_time); + + /* Lock mutex and fill list with pointers to all open tables */ + NDB_SHARE *share; + pthread_mutex_lock(&ndbcluster_mutex); + for (uint i= 0; i < ndbcluster_open_tables.records; i++) + { + share= (NDB_SHARE *)hash_element(&ndbcluster_open_tables, i); + share->use_count++; /* Make sure the table can't be closed */ + + DBUG_PRINT("ndb_util_thread", + ("Found open table[%d]: %s, use_count: %d", + i, share->table_name, share->use_count)); + + /* Store pointer to table */ + util_open_tables.push_back(share); + } + pthread_mutex_unlock(&ndbcluster_mutex); + + /* Iterate through the open files list */ + List_iterator_fast it(util_open_tables); + while (share= it++) + { + /* Split tab- and dbname */ + char buf[FN_REFLEN]; + char *tabname, *db; + uint length= dirname_length(share->table_name); + tabname= share->table_name+length; + memcpy(buf, share->table_name, length-1); + buf[length-1]= 0; + db= buf+dirname_length(buf); + DBUG_PRINT("ndb_util_thread", + ("Fetching commit count for: %s, db: %s, tab: %s", + share->table_name, db, tabname)); + + /* Contact NDB to get commit count for table */ + g_ndb->setDatabaseName(db); + struct Ndb_statistics stat;; + if(ndb_get_table_statistics(g_ndb, tabname, &stat) == 0) + { + DBUG_PRINT("ndb_util_thread", + ("Table: %s, rows: %llu, commit_count: %llu", + share->table_name, stat.row_count, stat.commit_count)); + share->commit_count= stat.commit_count; + } + else + { + DBUG_PRINT("ndb_util_thread", + ("Error: Could not get commit count for table %s", + share->table_name)); + share->commit_count++; /* Invalidate */ + } + /* Decrease the use count and possibly free share */ + free_share(share); + } + + /* Clear the list of open tables */ + util_open_tables.empty(); + + } + + thd->cleanup(); + delete thd; + DBUG_PRINT("exit", ("ndb_util_thread")); + my_thread_end(); + pthread_exit(0); + DBUG_RETURN(NULL); +} + + #endif /* HAVE_NDBCLUSTER_DB */ diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 942a4988252..b27908c20ea 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -37,6 +37,7 @@ class NdbBlob; // connectstring to cluster if given by mysqld extern const char *ndbcluster_connectstring; +extern ulong ndb_cache_check_time; typedef enum ndb_index_type { UNDEFINED_INDEX = 0, @@ -59,6 +60,7 @@ typedef struct st_ndbcluster_share { pthread_mutex_t mutex; char *table_name; uint table_name_length,use_count; + ulonglong commit_count; } NDB_SHARE; /* @@ -155,8 +157,11 @@ class ha_ndbcluster: public handler static Thd_ndb* seize_thd_ndb(); static void release_thd_ndb(Thd_ndb* thd_ndb); uint8 table_cache_type(); - - private: + my_bool register_query_cache_table(THD *thd, char *table_key, + uint key_length, + qc_engine_callback *engine_callback, + ulonglong *engine_data); +private: int alter_table_name(const char *to); int drop_table(); int create_index(const char *name, KEY *key_info, bool unique); @@ -256,7 +261,6 @@ class ha_ndbcluster: public handler bool m_force_send; ha_rows m_autoincrement_prefetch; bool m_transaction_on; - bool m_use_local_query_cache; bool m_disable_multi_read; byte *m_multi_range_result_ptr; diff --git a/sql/handler.cc b/sql/handler.cc index 059d1feaed1..b4fed363e87 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -234,15 +234,6 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) } } -bool ha_caching_allowed(THD* thd, char* table_key, - uint key_length, uint8 cache_type) -{ -#ifdef HAVE_INNOBASE_DB - if (cache_type == HA_CACHE_TBL_ASKTRANSACT) - return innobase_query_caching_of_table_permitted(thd, table_key, key_length); -#endif - return 1; -} /* @@ -869,6 +860,35 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name) DBUG_RETURN(error); } +int ha_release_savepoint_name(THD *thd, char *savepoint_name) +{ + my_off_t binlog_cache_pos=0; + bool operation_done=0; + int error=0; + DBUG_ENTER("ha_release_savepoint_name"); +#ifdef USING_TRANSACTIONS + if (opt_using_transactions) + { +#ifdef HAVE_INNOBASE_DB + if ((error=innobase_release_savepoint_name(thd, savepoint_name))) + { + my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error); + error=1; + } + else if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE); + if (mysql_bin_log.write(&qinfo)) + error= 1; + } + operation_done=1; +#endif + } +#endif /* USING_TRANSACTIONS */ + + DBUG_RETURN(error); +} + /* Sets a transaction savepoint. diff --git a/sql/handler.h b/sql/handler.h index e5a794ca1b2..8ad49456bf6 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -455,8 +455,7 @@ public: int compare_key(key_range *range); virtual int ft_init() { return HA_ERR_WRONG_COMMAND; } void ft_end() { ft_handler=NULL; } - virtual FT_INFO *ft_init_ext(uint flags,uint inx,const byte *key, - uint keylen) + virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key) { return NULL; } virtual int ft_read(byte *buf) { return HA_ERR_WRONG_COMMAND; } virtual int rnd_next(byte *buf)=0; @@ -592,6 +591,16 @@ public: /* Type of table for caching query */ virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; } + /* ask handler about permission to cache table when query is to be cached */ + virtual my_bool register_query_cache_table(THD *thd, char *table_key, + uint key_length, + qc_engine_callback + *engine_callback, + ulonglong *engine_data) + { + *engine_callback= 0; + return 1; + } /* RETURN @@ -622,8 +631,6 @@ extern TYPELIB tx_isolation_typelib; T != DB_TYPE_BERKELEY_DB && \ T != DB_TYPE_NDBCLUSTER) -bool ha_caching_allowed(THD* thd, char* table_key, - uint key_length, uint8 cache_type); 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); @@ -653,6 +660,7 @@ int ha_commit_trans(THD *thd, THD_TRANS *trans); int ha_rollback_trans(THD *thd, THD_TRANS *trans); int ha_rollback_to_savepoint(THD *thd, char *savepoint_name); int ha_savepoint(THD *thd, char *savepoint_name); +int ha_release_savepoint_name(THD *thd, char *savepoint_name); int ha_autocommit_or_rollback(THD *thd, int error); void ha_set_spin_retries(uint retries); bool ha_flush_logs(void); diff --git a/sql/item.cc b/sql/item.cc index 93c51a49a81..a93511db026 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -44,6 +44,34 @@ void item_init(void) item_user_lock_init(); } + +/* +TODO: make this functions class dependent +*/ +bool Item::val_bool() +{ + switch(result_type()) + { + case INT_RESULT: + return val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *val= val_decimal(&decimal_value); + if (val) + return !my_decimal_is_zero(val); + return 0; + } + case REAL_RESULT: + case STRING_RESULT: + return val_real() != 0.0; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } +} + + Item::Item(): name(0), orig_name(0), name_length(0), fixed(0), collation(&my_charset_bin, DERIVATION_COERCIBLE) @@ -72,7 +100,7 @@ Item::Item(): } /* - Constructor used by Item_field, Item_*_ref & agregate (sum) functions. + Constructor used by Item_field, Item_*_ref & aggregate (sum) functions. Used for duplicating lists in processing queries with temporary tables */ @@ -148,7 +176,7 @@ bool Item::cleanup_processor(byte *arg) void Item::rename(char *new_name) { /* - we can compare pointers to names here, bacause if name was not changed, + we can compare pointers to names here, because if name was not changed, pointer will be same */ if (!orig_name && new_name != name) @@ -411,6 +439,55 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions) } +double Item_splocal::val_real() +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + double ret= it->val_real(); + Item::null_value= it->null_value; + return ret; +} + + +longlong Item_splocal::val_int() +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + longlong ret= it->val_int(); + Item::null_value= it->null_value; + return ret; +} + + +String *Item_splocal::val_str(String *sp) +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + String *ret= it->val_str(sp); + Item::null_value= it->null_value; + return ret; +} + + +my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + my_decimal value, *val= it->val_decimal(&value); + Item::null_value= it->null_value; + return val; +} + + +bool Item_splocal::is_null() +{ + Item *it= this_item(); + bool ret= it->is_null(); + Item::null_value= it->null_value; + return ret; +} + + Item * Item_splocal::this_item() { @@ -438,12 +515,38 @@ Item_splocal::type() const } +bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **) +{ + Item *it= this_item(); + DBUG_ASSERT(it->fixed); + max_length= it->max_length; + decimals= it->decimals; + fixed= 1; + return FALSE; +} + + +void Item_splocal::cleanup() +{ + fixed= 0; +} + + +void Item_splocal::print(String *str) +{ + str->reserve(m_name.length+8); + str->append(m_name.str, m_name.length); + str->append('@'); + str->qs_append(m_offset); +} + + /* Aggregate two collations together taking into account their coercibility (aka derivation): - 0 == DERIVATION_EXPLICIT - an explicitely written COLLATE clause + 0 == DERIVATION_EXPLICIT - an explicitly written COLLATE clause 1 == DERIVATION_NONE - a mix of two different collations 2 == DERIVATION_IMPLICIT - a column 3 == DERIVATION_COERCIBLE - a string constant @@ -482,7 +585,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) /* We do allow to use binary strings (like BLOBS) together with character strings. - Binaries have more precedance than a character + Binaries have more precedence than a character string of the same derivation. */ if (collation == &my_charset_bin) @@ -634,8 +737,8 @@ void Item_field::set_field(Field *field_par) { field=result_field=field_par; // for easy coding with fields maybe_null=field->maybe_null(); - max_length=field_par->field_length; decimals= field->decimals(); + max_length= field_par->representation_length(); table_name= *field_par->table_name; field_name= field_par->field_name; db_name= field_par->table->s->db; @@ -743,6 +846,7 @@ String *Item_field::val_str(String *str) return field->val_str(str,&str_value); } + double Item_field::val_real() { DBUG_ASSERT(fixed == 1); @@ -751,6 +855,7 @@ double Item_field::val_real() return field->val_real(); } + longlong Item_field::val_int() { DBUG_ASSERT(fixed == 1); @@ -760,6 +865,14 @@ longlong Item_field::val_int() } +my_decimal *Item_field::val_decimal(my_decimal *decimal_value) +{ + if ((null_value= field->is_null())) + return 0; + return field->val_decimal(decimal_value); +} + + String *Item_field::str_result(String *str) { if ((null_value=result_field->is_null())) @@ -814,6 +927,40 @@ longlong Item_field::val_int_result() } +my_decimal *Item_field::val_decimal_result(my_decimal *decimal_value) +{ + if ((null_value= result_field->is_null())) + return 0; + return result_field->val_decimal(decimal_value); +} + + +bool Item_field::val_bool_result() +{ + if ((null_value= result_field->is_null())) + return FALSE; + switch (result_field->result_type()) + { + case INT_RESULT: + return result_field->val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *val= result_field->val_decimal(&decimal_value); + if (val) + return !my_decimal_is_zero(val); + return 0; + } + case REAL_RESULT: + case STRING_RESULT: + return result_field->val_real() != 0.0; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } +} + + bool Item_field::eq(const Item *item, bool binary_cmp) const { if (item->type() != FIELD_ITEM) @@ -872,10 +1019,17 @@ Item_int::Item_int(const char *str_arg, uint length) value= my_strtoll10(str_arg, &end_ptr, &error); max_length= (uint) (end_ptr - str_arg); name= (char*) str_arg; + unsigned_flag= value > 0; fixed= 1; } +my_decimal *Item_int::val_decimal(my_decimal *decimal_value) +{ + int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value); + return decimal_value; +} + String *Item_int::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor @@ -916,7 +1070,98 @@ void Item_uint::print(String *str) } -String *Item_real::val_str(String *str) +Item_decimal::Item_decimal(const char *str_arg, uint length, + CHARSET_INFO *charset) +{ + str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value); + name= (char*) str_arg; + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + +Item_decimal::Item_decimal(longlong val, bool unsig) +{ + int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(double val, int precision, int scale) +{ + double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg, + uint decimal_par, uint length) +{ + my_decimal2decimal(val_arg, &decimal_value); + name= (char*) str; + decimals= (uint8) decimal_par; + max_length= length; + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(my_decimal *value_par) +{ + my_decimal2decimal(value_par, &decimal_value); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(value_par); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(const char *bin, int precision, int scale) +{ + binary2my_decimal(E_DEC_FATAL_ERROR, bin, &decimal_value, precision, scale); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +longlong Item_decimal::val_int() +{ + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result); + return result; +} + +double Item_decimal::val_real() +{ + double result; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result); + return result; +} + +String *Item_decimal::val_str(String *result) +{ + result->set_charset(&my_charset_bin); + my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result); + return result; +} + +void Item_decimal::print(String *str) +{ + my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value); + str->append(str_value); +} + + +String *Item_float::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor DBUG_ASSERT(fixed == 1); @@ -925,6 +1170,15 @@ String *Item_real::val_str(String *str) } +my_decimal *Item_float::val_decimal(my_decimal *decimal_value) +{ + // following assert is redundant, because fixed=1 assigned in constructor + DBUG_ASSERT(fixed == 1); + double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); + return (decimal_value); +} + + void Item_string::print(String *str) { str->append('_'); @@ -934,8 +1188,20 @@ void Item_string::print(String *str) str->append('\''); } + +my_decimal *Item_string::val_decimal(my_decimal *decimal_value) +{ + /* following assert is redundant, because fixed=1 assigned in constructor */ + DBUG_ASSERT(fixed == 1); + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); + return (decimal_value); +} + + bool Item_null::eq(const Item *item, bool binary_cmp) const { return item->type() == type(); } + + double Item_null::val_real() { // following assert is redundant, because fixed=1 assigned in constructor @@ -959,6 +1225,11 @@ String *Item_null::val_str(String *str) return 0; } +my_decimal *Item_null::val_decimal(my_decimal *decimal_value) +{ + return 0; +} + Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs) { @@ -1005,7 +1276,6 @@ void Item_param::set_null() { DBUG_ENTER("Item_param::set_null"); /* These are cleared after each execution by reset() method */ - max_length= 0; null_value= 1; /* Because of NULL and string values we need to set max_length for each new @@ -1041,6 +1311,32 @@ void Item_param::set_double(double d) } +/* + Set decimal parameter value from string. + + SYNOPSIS + set_decimal() + str - character string + length - string length + + NOTE + as we use character strings to send decimal values in + binary protocol, we use str2my_decimal to convert it to + internal decimal value. +*/ +void Item_param::set_decimal(const char *str, ulong length) +{ + DBUG_ENTER("Item_param::set_decimal"); + + str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value); + state= DECIMAL_VALUE; + decimals= decimal_value.frac; + max_length= decimal_value.intg + decimals + 2; + maybe_null= 0; + DBUG_VOID_RETURN; +} + + /* Set parameter value from TIME value. @@ -1094,6 +1390,7 @@ bool Item_param::set_str(const char *str, ulong length) &dummy_errors)) DBUG_RETURN(TRUE); state= STRING_VALUE; + max_length= length; maybe_null= 0; /* max_length and decimals are set after charset conversion */ /* sic: str may be not null-terminated, don't add DBUG_PRINT here */ @@ -1133,7 +1430,7 @@ bool Item_param::set_longdata(const char *str, ulong length) RETURN 0 OK - 1 Out of memort + 1 Out of memory */ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) @@ -1179,6 +1476,15 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) DBUG_RETURN(1); break; } + case DECIMAL_RESULT: + { + const my_decimal *ent_value= (const my_decimal *)entry->value; + my_decimal2decimal(ent_value, &decimal_value); + state= DECIMAL_VALUE; + decimals= ent_value->frac; + max_length= ent_value->intg + decimals + 2; + break; + } default: DBUG_ASSERT(0); set_null(); @@ -1210,7 +1516,7 @@ void Item_param::reset() str_value.length(0); str_value_ptr.length(0); /* - We must prevent all charset conversions untill data has been written + We must prevent all charset conversions until data has been written to the binary log. */ str_value.set_charset(&my_charset_bin); @@ -1238,6 +1544,8 @@ int Item_param::save_in_field(Field *field, bool no_conversions) return field->store(value.integer); case REAL_VALUE: return field->store(value.real); + case DECIMAL_VALUE: + return field->store_decimal(&decimal_value); case TIME_VALUE: field->store_time(&value.time, value.time.time_type); return 0; @@ -1288,6 +1596,12 @@ double Item_param::val_real() return value.real; case INT_VALUE: return (double) value.integer; + case DECIMAL_VALUE: + { + double result; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result); + return result; + } case STRING_VALUE: case LONG_DATA_VALUE: { @@ -1318,6 +1632,12 @@ longlong Item_param::val_int() return (longlong) (value.real + (value.real > 0 ? 0.5 : -0.5)); case INT_VALUE: return value.integer; + case DECIMAL_VALUE: + { + longlong i; + my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i); + return i; + } case STRING_VALUE: case LONG_DATA_VALUE: { @@ -1336,6 +1656,36 @@ longlong Item_param::val_int() } +my_decimal *Item_param::val_decimal(my_decimal *dec) +{ + switch (state) { + case DECIMAL_VALUE: + return &decimal_value; + case REAL_VALUE: + double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec); + return dec; + case INT_VALUE: + int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec); + return dec; + case STRING_VALUE: + case LONG_DATA_VALUE: + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, dec); + return dec; + case TIME_VALUE: + { + longlong i= (longlong) TIME_to_ulonglong(&value.time); + int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec); + return dec; + } + case NULL_VALUE: + return 0; + default: + DBUG_ASSERT(0); + } + return 0; +} + + String *Item_param::val_str(String* str) { switch (state) { @@ -1348,6 +1698,11 @@ String *Item_param::val_str(String* str) case INT_VALUE: str->set(value.integer, &my_charset_bin); return str; + case DECIMAL_VALUE: + if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, + 0, 0, 0, str) <= 1) + return str; + return NULL; case TIME_VALUE: { if (str->reserve(MAX_DATE_STRING_REP_LENGTH)) @@ -1380,6 +1735,11 @@ const String *Item_param::query_val_str(String* str) const case REAL_VALUE: str->set(value.real, NOT_FIXED_DEC, &my_charset_bin); break; + case DECIMAL_VALUE: + if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, + 0, 0, 0, str) > 1) + return &my_null_string; + break; case TIME_VALUE: { char *buf, *ptr; @@ -1474,7 +1834,7 @@ void Item_param::print(String *str) } else { - char buffer[80]; + char buffer[STRING_BUFFER_USUAL_SIZE]; String tmp(buffer, sizeof(buffer), &my_charset_bin); const String *res; res= query_val_str(&tmp); @@ -1505,6 +1865,17 @@ String *Item_copy_string::val_str(String *str) } +my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value) +{ + // Item_copy_string is used without fix_fields call + if (null_value) + return 0; + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); + return (decimal_value); +} + + + int Item_copy_string::save_in_field(Field *field, bool no_conversions) { if (null_value) @@ -1548,6 +1919,24 @@ longlong Item_ref_null_helper::val_int() } +my_decimal *Item_ref_null_helper::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + my_decimal *val= (*ref)->val_decimal_result(decimal_value); + owner->was_null|= null_value= (*ref)->null_value; + return val; +} + + +bool Item_ref_null_helper::val_bool() +{ + DBUG_ASSERT(fixed == 1); + bool val= (*ref)->val_bool_result(); + owner->was_null|= null_value= (*ref)->null_value; + return val; +} + + String* Item_ref_null_helper::val_str(String* s) { DBUG_ASSERT(fixed == 1); @@ -1775,12 +2164,13 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) if (select_ref != not_found_item && !ambiguous_fields) { DBUG_ASSERT(*select_ref); - if (! (*select_ref)->fixed) + if (!select->ref_pointer_array[counter]) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), ref->name, "forward reference in item list"); return NULL; } + DBUG_ASSERT((*select_ref)->fixed); return (select->ref_pointer_array + counter); } if (group_by_ref) @@ -1939,7 +2329,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) { if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occured (e.g. ambigous names). */ + return TRUE; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); @@ -2003,7 +2393,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ - if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)) + if (!rf->fixed && + rf->fix_fields(thd, tables, reference) || rf->check_cols(1)) return TRUE; mark_as_dependent(thd, last, current_sel, rf); @@ -2024,7 +2415,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ - return rf->fix_fields(thd, tables, reference) || rf->check_cols(1); + return (!rf->fixed && + rf->fix_fields(thd, tables, reference) || rf->check_cols(1)); } } } @@ -2097,7 +2489,7 @@ void Item_field::cleanup() Item_ident::cleanup(); /* Even if this object was created by direct link to field in setup_wild() - it will be linked correctly next tyme by name of field and table alias. + it will be linked correctly next time by name of field and table alias. I.e. we can drop 'field'. */ field= result_field= 0; @@ -2271,9 +2663,17 @@ void Item_empty_string::make_field(Send_field *tmp_field) enum_field_types Item::field_type() const { - return ((result_type() == STRING_RESULT) ? MYSQL_TYPE_VARCHAR : - (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG : - FIELD_TYPE_DOUBLE); + switch (result_type()) + { + case STRING_RESULT: return MYSQL_TYPE_VARCHAR; + case INT_RESULT: return FIELD_TYPE_LONGLONG; + case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL; + case REAL_RESULT: return FIELD_TYPE_DOUBLE; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + return FIELD_TYPE_VAR_STRING; + }; } @@ -2326,6 +2726,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_DECIMAL: return new Field_decimal((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table, decimals, 0, unsigned_flag); + case MYSQL_TYPE_NEWDECIMAL: + return new Field_new_decimal((char*) 0, max_length - (decimals?1:0), + null_ptr, 0, + Field::NONE, name, table, decimals, 0, + unsigned_flag); case MYSQL_TYPE_TINY: return new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table, 0, unsigned_flag); @@ -2461,7 +2866,7 @@ int Item_null::save_in_field(Field *field, bool no_conversions) field Field where we want to store NULL RETURN VALUES - 0 ok + 0 OK 1 Field doesn't support NULL values */ @@ -2500,6 +2905,15 @@ int Item::save_in_field(Field *field, bool no_conversions) field->set_notnull(); error=field->store(nr); } + else if (result_type() == DECIMAL_RESULT) + { + my_decimal decimal_value; + my_decimal *value= val_decimal(&decimal_value); + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + error=field->store_decimal(value); + } else { longlong nr=val_int(); @@ -2541,9 +2955,18 @@ int Item_int::save_in_field(Field *field, bool no_conversions) return field->store(nr); } + +int Item_decimal::save_in_field(Field *field, bool no_conversions) +{ + field->set_notnull(); + return field->store_decimal(&decimal_value); +} + + Item_num *Item_uint::neg() { - return new Item_real(name, - ((double) value), 0, max_length); + Item_decimal *item= new Item_decimal(value, 0); + return item->neg(); } @@ -2552,7 +2975,7 @@ Item_num *Item_uint::neg() value is not a true double value (overflow) */ -Item_real::Item_real(const char *str_arg, uint length) +Item_float::Item_float(const char *str_arg, uint length) { int error; char *end_not_used; @@ -2574,7 +2997,7 @@ Item_real::Item_real(const char *str_arg, uint length) } -int Item_real::save_in_field(Field *field, bool no_conversions) +int Item_float::save_in_field(Field *field, bool no_conversions) { double nr= val_real(); if (null_value) @@ -2584,7 +3007,7 @@ int Item_real::save_in_field(Field *field, bool no_conversions) } -void Item_real::print(String *str) +void Item_float::print(String *str) { if (presentation) { @@ -2647,6 +3070,16 @@ longlong Item_hex_string::val_int() } +my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value) +{ + // following assert is redundant, because fixed=1 assigned in constructor + DBUG_ASSERT(fixed == 1); + ulonglong value= (ulonglong)val_int(); + int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value); + return (decimal_value); +} + + int Item_hex_string::save_in_field(Field *field, bool no_conversions) { int error; @@ -2736,6 +3169,7 @@ bool Item::send(Protocol *protocol, String *buffer) case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_BIT: + case MYSQL_TYPE_NEWDECIMAL: { String *res; if ((res=val_str(buffer))) @@ -2826,6 +3260,20 @@ bool Item_field::send(Protocol *protocol, String *buffer) } +Item_ref::Item_ref(Item **item, const char *table_name_par, + const char *field_name_par) + :Item_ident(NullS, table_name_par, field_name_par), result_field(0), + ref(item) +{ + /* + This constructor used to create some internals references over fixed items + */ + DBUG_ASSERT(ref); + if (*ref) + set_properties(); +} + + /* Resolve the name of a reference to a column reference. @@ -2896,7 +3344,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) Item **group_by_ref= NULL; if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel))) - return TRUE; /* Some error occured (e.g. ambigous names). */ + return TRUE; /* Some error occurred (e.g. ambiguous names). */ if (ref == not_found_item) /* This reference was not resolved. */ { @@ -2926,7 +3374,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) { if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occured (e.g. ambigous names). */ + return TRUE; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); @@ -3082,6 +3530,10 @@ void Item_ref::set_properties() maybe_null= (*ref)->maybe_null; decimals= (*ref)->decimals; collation.set((*ref)->collation); + /* + We have to remember if we refer to a sum function, to ensure that + split_sum_func() doesn't try to change the reference. + */ with_sum_func= (*ref)->with_sum_func; if ((*ref)->type() == FIELD_ITEM) alias_name_used= ((Item_ident *) (*ref))->alias_name_used; @@ -3154,6 +3606,106 @@ String *Item_ref::str_result(String* str) } +my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value) +{ + if (result_field) + { + if ((null_value= result_field->is_null())) + return 0; + return result_field->val_decimal(decimal_value); + } + return val_decimal(decimal_value); +} + + +bool Item_ref::val_bool_result() +{ + if (result_field) + { + if ((null_value= result_field->is_null())) + return 0; + switch (result_field->result_type()) + { + case INT_RESULT: + return result_field->val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *val= result_field->val_decimal(&decimal_value); + if (val) + return !my_decimal_is_zero(val); + return 0; + } + case REAL_RESULT: + case STRING_RESULT: + return result_field->val_real() != 0.0; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + } + return val_bool(); +} + + +double Item_ref::val_real() +{ + DBUG_ASSERT(fixed); + double tmp=(*ref)->val_result(); + null_value=(*ref)->null_value; + return tmp; +} + + +longlong Item_ref::val_int() +{ + DBUG_ASSERT(fixed); + longlong tmp=(*ref)->val_int_result(); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_ref::val_bool() +{ + DBUG_ASSERT(fixed); + bool tmp= (*ref)->val_bool_result(); + null_value= (*ref)->null_value; + return tmp; +} + + +String *Item_ref::val_str(String* tmp) +{ + DBUG_ASSERT(fixed); + tmp=(*ref)->str_result(tmp); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_ref::is_null() +{ + DBUG_ASSERT(fixed); + (void) (*ref)->val_int_result(); + return (*ref)->null_value; +} + + +bool Item_ref::get_date(TIME *ltime,uint fuzzydate) +{ + return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); +} + + +my_decimal *Item_ref::val_decimal(my_decimal *decimal_value) +{ + my_decimal *val= (*ref)->val_decimal(decimal_value); + null_value= (*ref)->null_value; + return val; +} + + void Item_ref_null_helper::print(String *str) { str->append("(", 18); @@ -3165,6 +3717,59 @@ void Item_ref_null_helper::print(String *str) } +double Item_direct_ref::val_real() +{ + double tmp=(*ref)->val_real(); + null_value=(*ref)->null_value; + return tmp; +} + + +longlong Item_direct_ref::val_int() +{ + longlong tmp=(*ref)->val_int(); + null_value=(*ref)->null_value; + return tmp; +} + + +String *Item_direct_ref::val_str(String* tmp) +{ + tmp=(*ref)->val_str(tmp); + null_value=(*ref)->null_value; + return tmp; +} + + +my_decimal *Item_direct_ref::val_decimal(my_decimal *decimal_value) +{ + my_decimal *tmp= (*ref)->val_decimal(decimal_value); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_direct_ref::val_bool() +{ + bool tmp= (*ref)->val_bool(); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_direct_ref::is_null() +{ + (void) (*ref)->val_int(); + return (*ref)->null_value; +} + + +bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate) +{ + return (null_value=(*ref)->get_date(ltime,fuzzydate)); +} + + void Item_null_helper::print(String *str) { str->append("(", 14); @@ -3389,6 +3994,9 @@ Item_result item_cmp_type(Item_result a,Item_result b) return INT_RESULT; else if (a == ROW_RESULT || b == ROW_RESULT) return ROW_RESULT; + if ((a == INT_RESULT || a == DECIMAL_RESULT) && + (b == INT_RESULT || b == DECIMAL_RESULT)) + return DECIMAL_RESULT; return REAL_RESULT; } @@ -3403,7 +4011,9 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) item->result_type()); char *name=item->name; // Alloced by sql_alloc - if (res_type == STRING_RESULT) + switch (res_type) + { + case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),&my_charset_bin),*result; @@ -3416,22 +4026,40 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) char *tmp_str= sql_strmake(result->ptr(), length); new_item= new Item_string(name, tmp_str, length, result->charset()); } + break; } - else if (res_type == INT_RESULT) + case INT_RESULT: { longlong result=item->val_int(); uint length=item->max_length; bool null_value=item->null_value; new_item= (null_value ? (Item*) new Item_null(name) : (Item*) new Item_int(name, result, length)); + break; } - else + case REAL_RESULT: { // It must REAL_RESULT double result= item->val_real(); uint length=item->max_length,decimals=item->decimals; bool null_value=item->null_value; new_item= (null_value ? (Item*) new Item_null(name) : (Item*) - new Item_real(name, result, decimals, length)); + new Item_float(name, result, decimals, length)); + break; + } + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *result= item->val_decimal(&decimal_value); + uint length= item->max_length, decimals= item->decimals; + bool null_value= item->null_value; + new_item= (null_value ? + (Item*) new Item_null(name) : + (Item*) new Item_decimal(name, result, length, decimals)); + break; + } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } if (new_item) thd->change_item_tree(ref, new_item); @@ -3462,6 +4090,16 @@ bool field_is_equal_to_item(Field *field,Item *item) } if (res_type == INT_RESULT) return 1; // Both where of type int + if (res_type == DECIMAL_RESULT) + { + my_decimal item_buf, *item_val, + field_buf, *field_val; + item_val= item->val_decimal(&item_buf); + if (item->null_value) + return 1; // This must be true + field_val= field->val_decimal(&field_buf); + return !my_decimal_cmp(item_val, field_val); + } double result= item->val_real(); if (item->null_value) return 1; @@ -3476,6 +4114,8 @@ Item_cache* Item_cache::get_cache(Item_result type) return new Item_cache_int(); case REAL_RESULT: return new Item_cache_real(); + case DECIMAL_RESULT: + return new Item_cache_decimal(); case STRING_RESULT: return new Item_cache_str(); case ROW_RESULT: @@ -3503,6 +4143,23 @@ void Item_cache_int::store(Item *item) { value= item->val_int_result(); null_value= item->null_value; + unsigned_flag= item->unsigned_flag; +} + + +String *Item_cache_int::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + str->set(value, default_charset()); + return str; +} + + +my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) +{ + DBUG_ASSERT(fixed == 1); + int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); + return decimal_val; } @@ -3513,6 +4170,69 @@ void Item_cache_real::store(Item *item) } +longlong Item_cache_real::val_int() +{ + DBUG_ASSERT(fixed == 1); + return (longlong) (value+(value > 0 ? 0.5 : -0.5)); +} + + +String* Item_cache_real::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + str->set(value, decimals, default_charset()); + return str; +} + + +my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) +{ + DBUG_ASSERT(fixed == 1); + double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); + return decimal_val; +} + + +void Item_cache_decimal::store(Item *item) +{ + my_decimal *val= item->val_decimal_result(&decimal_value); + if (val != &decimal_value) + my_decimal2decimal(val, &decimal_value); + null_value= item->null_value; +} + +double Item_cache_decimal::val_real() +{ + DBUG_ASSERT(fixed); + double res; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); + return res; +} + +longlong Item_cache_decimal::val_int() +{ + DBUG_ASSERT(fixed); + longlong res; + my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); + return res; +} + +String* Item_cache_decimal::val_str(String *str) +{ + DBUG_ASSERT(fixed); + my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE, + &decimal_value); + my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str); + return str; +} + +my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed); + return &decimal_value; +} + + void Item_cache_str::store(Item *item) { value_buff.set(buffer, sizeof(buffer), item->collation.collation); @@ -3534,7 +4254,6 @@ void Item_cache_str::store(Item *item) } } - double Item_cache_str::val_real() { DBUG_ASSERT(fixed == 1); @@ -3558,6 +4277,16 @@ longlong Item_cache_str::val_int() return (longlong)0; } +my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) +{ + DBUG_ASSERT(fixed == 1); + if (value) + string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); + else + decimal_val= 0; + return decimal_val; +} + bool Item_cache_row::allocate(uint num) { @@ -3646,7 +4375,53 @@ void Item_cache_row::bring_value() } -Item_type_holder::Item_type_holder(THD *thd, Item *item) +/* + Returns field for temporary table dependind on item type + + SYNOPSIS + get_holder_example_field() + thd - thread handler + item - pointer to item + table - empty table object + + NOTE + It is possible to return field for Item_func + items only if field type of this item is + date or time or datetime type. + also see function field_types_to_be_kept() from + field.cc + + RETURN + # - field + 0 - no field +*/ + +Field *get_holder_example_field(THD *thd, Item *item, TABLE *table) +{ + DBUG_ASSERT(table); + + Item_func *tmp_item= 0; + if (item->type() == Item::FIELD_ITEM) + return (((Item_field*) item)->field); + if (item->type() == Item::FUNC_ITEM) + tmp_item= (Item_func *) item; + else if (item->type() == Item::SUM_FUNC_ITEM) + { + Item_sum *item_sum= (Item_sum *) item; + if (item_sum->keep_field_type()) + { + if (item_sum->args[0]->type() == Item::FIELD_ITEM) + return (((Item_field*) item_sum->args[0])->field); + if (item_sum->args[0]->type() == Item::FUNC_ITEM) + tmp_item= (Item_func *) item_sum->args[0]; + } + } + return (tmp_item && field_types_to_be_kept(tmp_item->field_type()) ? + tmp_item->tmp_table_field(table) : 0); +} + + +Item_type_holder::Item_type_holder(THD *thd, Item *item, TABLE *table) :Item(thd, item), item_type(item->result_type()), orig_type(item_type) { @@ -3656,10 +4431,7 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) It is safe assign pointer on field, because it will be used just after all JOIN::prepare calls and before any SELECT execution */ - if (item->type() == Item::FIELD_ITEM) - field_example= ((Item_field*) item)->field; - else - field_example= 0; + field_example= get_holder_example_field(thd, item, table); max_length= real_length(item); maybe_null= item->maybe_null; collation.set(item->collation); @@ -3667,18 +4439,18 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) /* - STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT + STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT DECIMAL_RESULT ROW_RESULT should never appear in Item_type_holder::join_types, but it is included in following table just to make table full (there DBUG_ASSERT in function to catch ROW_RESULT) */ -static Item_result type_convertor[4][4]= -{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT}, - {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT}, - {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}, - {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}}; - +static Item_result type_convertor[5][5]= +{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT, STRING_RESULT}, + {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT, REAL_RESULT}, + {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT}, + {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}, + {STRING_RESULT, REAL_RESULT, DECIMAL_RESULT, ROW_RESULT, DECIMAL_RESULT}}; /* Values of 'from' field can be stored in 'to' field. @@ -3696,28 +4468,32 @@ static Item_result type_convertor[4][4]= inline bool is_attr_compatible(Item *from, Item *to) { return ((to->max_length >= from->max_length) && + ((to->result_type() != DECIMAL_RESULT && + to->result_type() != REAL_RESULT && + to->result_type() != INT_RESULT) || + (to->decimals >= from->decimals) && + ((to->max_length - to->decimals) >= + (from->max_length - from->decimals))) && (to->maybe_null || !from->maybe_null) && (to->result_type() != STRING_RESULT || from->result_type() != STRING_RESULT || - my_charset_same(from->collation.collation, - to->collation.collation))); + (from->collation.collation == to->collation.collation))); } -bool Item_type_holder::join_types(THD *thd, Item *item) +bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table) { uint32 new_length= real_length(item); bool use_new_field= 0, use_expression_type= 0; Item_result new_result_type= type_convertor[item_type][item->result_type()]; - bool item_is_a_field= item->type() == Item::FIELD_ITEM; - + Field *field= get_holder_example_field(thd, item, table); + bool item_is_a_field= field; /* Check if both items point to fields: in this case we can adjust column types of result table in the union smartly. */ if (field_example && item_is_a_field) { - Field *field= ((Item_field *)item)->field; /* Can 'field_example' field store data of the column? */ if ((use_new_field= (!field->field_cast_compatible(field_example->field_cast_type()) || @@ -3746,6 +4522,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item) if (use_new_field || (new_result_type != item_type) || (new_length > max_length) || (!maybe_null && item->maybe_null) || + ((new_result_type == REAL_RESULT || new_result_type == DECIMAL_RESULT) && + (decimals < item->decimals || + (max_length - decimals) < (new_length - item->decimals))) || (item_type == STRING_RESULT && collation.collation != item->collation.collation)) { @@ -3758,7 +4537,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) It is safe to assign a pointer to field here, because it will be used before any table is closed. */ - field_example= ((Item_field*) item)->field; + field_example= field; } old_cs= collation.collation->name; @@ -3773,8 +4552,20 @@ bool Item_type_holder::join_types(THD *thd, Item *item) return 1; } - max_length= max(max_length, new_length); - decimals= max(decimals, item->decimals); + if (new_result_type == DECIMAL_RESULT) + { + int intp1= new_length - item->decimals; + int intp2= max_length - decimals; + max_length= max(intp1, intp2); + decimals= max(decimals, item->decimals); + /* can't be overflow because it work only for decimals (no strings) */ + max_length+= decimals; + } + else + { + max_length= max(max_length, new_length); + decimals= max(decimals, item->decimals); + } maybe_null|= item->maybe_null; item_type= new_result_type; } @@ -3791,6 +4582,7 @@ uint32 Item_type_holder::real_length(Item *item) switch (item->result_type()) { case STRING_RESULT: + case DECIMAL_RESULT: return item->max_length; case REAL_RESULT: return 53; @@ -3816,6 +4608,11 @@ longlong Item_type_holder::val_int() return 0; } +my_decimal *Item_type_holder::val_decimal(my_decimal *) +{ + DBUG_ASSERT(0); // should never be called + return 0; +} String *Item_type_holder::val_str(String*) { diff --git a/sql/item.h b/sql/item.h index 6857b4acf82..ccbc00470e5 100644 --- a/sql/item.h +++ b/sql/item.h @@ -27,7 +27,7 @@ class Item_field; /* "Declared Type Collation" - A combination of collation and its deriviation. + A combination of collation and its derivation. */ enum Derivation @@ -45,7 +45,7 @@ enum Derivation MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value (i.e. constant). MY_COLL_ALLOW_CONV - allow any kind of conversion - (combintion of the above two) + (combination of the above two) MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE (e.g. when aggregating for comparison) MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV @@ -130,7 +130,7 @@ public: PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, - PARAM_ITEM, TRIGGER_FIELD_ITEM}; + PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -156,11 +156,11 @@ public: // alloc & destruct is done as start of select using sql_alloc Item(); /* - Constructor used by Item_field, Item_ref & agregate (sum) functions. + Constructor used by Item_field, Item_ref & aggregate (sum) functions. Used for duplicating lists in processing queries with temporary tables Also it used for Item_cond_and/Item_cond_or for creating - top AND/OR ctructure of WHERE clause to protect it of + top AND/OR structure of WHERE clause to protect it of optimisation changes in prepared statements */ Item(THD *thd, Item *item); @@ -193,40 +193,107 @@ public: virtual enum_field_types field_type() const; virtual enum Type type() const =0; /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ + /* + Return double precision floating point representation of item. + + SYNOPSIS + val_real() + + RETURN + In case of NULL value return 0.0 and set null_value flag to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ virtual double val_real()=0; + /* + Return integer representation of item. + + SYNOPSIS + val_int() + + RETURN + In case of NULL value return 0 and set null_value flag to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ virtual longlong val_int()=0; /* Return string representation of this item object. - The argument to val_str() is an allocated buffer this or any - nested Item object can use to store return value of this method. - This buffer should only be used if the item itself doesn't have an - own String buffer. In case when the item maintains it's own string - buffer, it's preferrable to return it instead to minimize number of - mallocs/memcpys. - The caller of this method can modify returned string, but only in - case when it was allocated on heap, (is_alloced() is true). This - allows the caller to efficiently use a buffer allocated by a child - without having to allocate a buffer of it's own. The buffer, given - to val_str() as agrument, belongs to the caller and is later used - by the caller at it's own choosing. - A few implications from the above: - - unless you return a string object which only points to your buffer - but doesn't manages it you should be ready that it will be - modified. - - even for not allocated strings (is_alloced() == false) the caller - can change charset (see Item_func_{typecast/binary}. XXX: is this - a bug? - - still you should try to minimize data copying and return internal - object whenever possible. + SYNOPSIS + val_str() + str an allocated buffer this or any nested Item object can use to + store return value of this method. + + NOTE + Buffer passed via argument should only be used if the item itself + doesn't have an own String buffer. In case when the item maintains + it's own string buffer, it's preferable to return it instead to + minimize number of mallocs/memcpys. + The caller of this method can modify returned string, but only in case + when it was allocated on heap, (is_alloced() is true). This allows + the caller to efficiently use a buffer allocated by a child without + having to allocate a buffer of it's own. The buffer, given to + val_str() as argument, belongs to the caller and is later used by the + caller at it's own choosing. + A few implications from the above: + - unless you return a string object which only points to your buffer + but doesn't manages it you should be ready that it will be + modified. + - even for not allocated strings (is_alloced() == false) the caller + can change charset (see Item_func_{typecast/binary}. XXX: is this + a bug? + - still you should try to minimize data copying and return internal + object whenever possible. + + RETURN + In case of NULL value return 0 (NULL pointer) and set null_value flag + to TRUE. + If value is not null null_value flag will be reset to FALSE. */ - virtual String *val_str(String*)=0; + virtual String *val_str(String *str)=0; + /* + Return decimal representation of item with fixed point. + + SYNOPSIS + val_decimal() + decimal_buffer buffer which can be used by Item for returning value + (but can be not) + + NOTE + Returned value should not be changed if it is not the same which was + passed via argument. + + RETURN + Return pointer on my_decimal (it can be other then passed via argument) + if value is not NULL (null_value flag will be reset to FALSE). + In case of NULL value it return 0 pointer and set null_value flag + to TRUE. + */ + virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0; + /* + Return boolean value of item. + + RETURN + FALSE value is false or NULL + TRUE value is true (not equal to 0) + */ + bool val_bool(); virtual Field *get_tmp_table_field() { return 0; } virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } + + /* + *result* family of methods is analog of *val* family (see above) but + return value of result_field of item if it is present. If Item have not + result field, it return val(). This methods set null_value flag in same + way as *val* methods do it. + */ virtual double val_result() { return val_real(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } + virtual my_decimal *val_decimal_result(my_decimal *val) + { return val_decimal(val); } + virtual bool val_bool_result() { return val_bool(); } + /* bit map of tables used by item */ virtual table_map used_tables() const { return (table_map) 0L; } /* @@ -287,14 +354,14 @@ public: virtual void top_level_item() {} /* set field of temporary table for Item which can be switched on temporary - table during query processing (groupping and so on) + table during query processing (grouping and so on) */ virtual void set_result_field(Field *field) {} virtual bool is_result_field() { return 0; } virtual bool is_bool_func() { return 0; } virtual void save_in_result_field(bool no_conversions) {} /* - set value of aggegate function in case of no rows for groupping were found + set value of aggregate function in case of no rows for grouping were found */ virtual void no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } @@ -368,6 +435,9 @@ public: Item *this_item(); Item *this_const_item() const; + bool fix_fields(THD *, struct st_table_list *, Item **); + void cleanup(); + inline uint get_offset() { return m_offset; @@ -377,37 +447,12 @@ public: // the item in the frame enum Type type() const; - inline double val_real() - { - Item *it= this_item(); - double ret= it->val_real(); - Item::null_value= it->null_value; - return ret; - } - - inline longlong val_int() - { - Item *it= this_item(); - longlong ret= it->val_int(); - Item::null_value= it->null_value; - return ret; - } - - inline String *val_str(String *sp) - { - Item *it= this_item(); - String *ret= it->val_str(sp); - Item::null_value= it->null_value; - return ret; - } - - inline bool is_null() - { - Item *it= this_item(); - bool ret= it->is_null(); - Item::null_value= it->null_value; - return ret; - } + double val_real(); + longlong val_int(); + String *val_str(String *sp); + my_decimal *val_decimal(my_decimal *); + inline bool is_null(); + void print(String *str); inline void make_field(Send_field *field) { @@ -432,14 +477,6 @@ public: return this_item()->save_in_field(field, no_conversions); } - void print(String *str) - { - str->reserve(m_name.length+8); - str->append(m_name.str, m_name.length); - str->append('@'); - str->qs_append(m_offset); - } - inline bool send(Protocol *protocol, String *str) { return this_item()->send(protocol, str); @@ -544,10 +581,13 @@ public: bool eq(const Item *item, bool binary_cmp) const; double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); String *val_str(String*); double val_result(); longlong val_int_result(); String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + bool val_bool_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); bool fix_fields(THD *, struct st_table_list *, Item **); @@ -600,12 +640,13 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); int save_safe_in_field(Field *field); bool send(Protocol *protocol, String *str); enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; } - // to prevent drop fixed flag (no need parent cleanup call) + /* to prevent drop fixed flag (no need parent cleanup call) */ void cleanup() {} bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } @@ -623,7 +664,8 @@ public: enum enum_item_param_state { NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE, - STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE + STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE, + DECIMAL_VALUE } state; /* @@ -637,6 +679,7 @@ public: Can not be declared inside the union as it's not a POD type. */ String str_value_ptr; + my_decimal decimal_value; union { longlong integer; @@ -688,6 +731,7 @@ public: double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal*); String *val_str(String*); bool get_time(TIME *tm); bool get_date(TIME *tm, uint fuzzydate); @@ -696,6 +740,7 @@ public: void set_null(); void set_int(longlong i, uint32 max_length_arg); void set_double(double i); + void set_decimal(const char *str, ulong length); bool set_str(const char *str, ulong length); bool set_longdata(const char *str, ulong length); void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg); @@ -746,6 +791,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } + my_decimal *val_decimal(my_decimal *); String *val_str(String*); int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } @@ -784,14 +830,52 @@ public: }; -class Item_real :public Item_num +/* decimal (fixed point) constant */ +class Item_decimal :public Item_num +{ +protected: + my_decimal decimal_value; +public: + Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset); + Item_decimal(const char *str, const my_decimal *val_arg, + uint decimal_par, uint length); + Item_decimal(my_decimal *value_par); + Item_decimal(longlong val, bool unsig); + Item_decimal(double val, int precision, int scale); + Item_decimal(const char *bin, int precision, int scale); + + enum Type type() const { return DECIMAL_ITEM; } + enum Item_result result_type () const { return DECIMAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + longlong val_int(); + double val_real(); + String *val_str(String*); + my_decimal *val_decimal(my_decimal *val) { return &decimal_value; } + int save_in_field(Field *field, bool no_conversions); + bool basic_const_item() const { return 1; } + Item *new_item() + { + return new Item_decimal(name, &decimal_value, decimals, max_length); + } + // to prevent drop fixed flag (no need parent cleanup call) + void cleanup() {} + void print(String *str); + Item_num *neg() + { + my_decimal_neg(&decimal_value); + unsigned_flag= !decimal_value.sign(); + return this; + } +}; + +class Item_float :public Item_num { char *presentation; public: double value; // Item_real() :value(0) {} - Item_real(const char *str_arg, uint length); - Item_real(const char *str,double val_arg,uint decimal_par,uint length) + Item_float(const char *str_arg, uint length); + Item_float(const char *str,double val_arg,uint decimal_par,uint length) :value(val_arg) { presentation= name=(char*) str; @@ -799,7 +883,8 @@ public: max_length=length; fixed= 1; } - Item_real(double value_par) :presentation(0), value(value_par) { fixed= 1; } + Item_float(double value_par) :presentation(0), value(value_par) { fixed= 1; } + int save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } @@ -810,37 +895,29 @@ public: return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - Item *new_item() { return new Item_real(name,value,decimals,max_length); } + Item *new_item() + { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } void print(String *str); }; -class Item_static_real_func :public Item_real +class Item_static_float_func :public Item_float { const char *func_name; public: - Item_static_real_func(const char *str, double val_arg, uint decimal_par, + Item_static_float_func(const char *str, double val_arg, uint decimal_par, uint length) - :Item_real(NullS, val_arg, decimal_par, length), func_name(str) + :Item_float(NullS, val_arg, decimal_par, length), func_name(str) {} void print(String *str) { str->append(func_name); } }; -class Item_float :public Item_real -{ -public: - Item_float(const char *str,uint length) :Item_real(str,length) - { - decimals=NOT_FIXED_DEC; - max_length=DBL_DIG+8; - } -}; - class Item_string :public Item { public: @@ -894,6 +971,7 @@ public: DBUG_ASSERT(fixed == 1); return (String*) &str_value; } + 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_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } @@ -932,7 +1010,7 @@ class Item_datetime :public Item_string { public: Item_datetime(const char *item_name): Item_string(item_name,"",0, - &my_charset_bin) + &my_charset_bin) { max_length=19;} enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } }; @@ -971,6 +1049,7 @@ public: longlong val_int(); bool basic_const_item() const { return 1; } String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } + 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_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } @@ -1033,54 +1112,25 @@ public: TODO we probably fix a superset of problems like in BUG#6658. Check this with Bar, and if we have a more broader set of problems like this. */ - Item_ref(Item **item, const char *table_name_par, const char *field_name_par) - :Item_ident(NullS, table_name_par, field_name_par), result_field(0), ref(item) - { - DBUG_ASSERT(item); - if (*item) - set_properties(); - } + Item_ref(Item **item, const char *table_name_par, const char *field_name_par); /* Constructor need to process subselect with temporary tables (see Item) */ Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const { return ref && (*ref)->eq(item, binary_cmp); } - double val_real() - { - DBUG_ASSERT(fixed); - double tmp=(*ref)->val_result(); - null_value=(*ref)->null_value; - return tmp; - } - longlong val_int() - { - DBUG_ASSERT(fixed); - longlong tmp=(*ref)->val_int_result(); - null_value=(*ref)->null_value; - return tmp; - } - String *val_str(String* tmp) - { - DBUG_ASSERT(fixed); - tmp=(*ref)->str_result(tmp); - null_value=(*ref)->null_value; - return tmp; - } - bool is_null() - { - DBUG_ASSERT(fixed); - (void) (*ref)->val_int_result(); - return (*ref)->null_value; - } - bool get_date(TIME *ltime,uint fuzzydate) - { - DBUG_ASSERT(fixed); - return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); - } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); + String *val_str(String* tmp); + bool is_null(); + bool get_date(TIME *ltime,uint fuzzydate); double val_result(); longlong val_int_result(); String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + bool val_bool_result(); bool send(Protocol *prot, String *tmp); void make_field(Send_field *field) { (*ref)->make_field(field); } bool fix_fields(THD *, struct st_table_list *, Item **); @@ -1121,33 +1171,13 @@ public: /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} - double val_real() - { - double tmp=(*ref)->val_real(); - null_value=(*ref)->null_value; - return tmp; - } - longlong val_int() - { - longlong tmp=(*ref)->val_int(); - null_value=(*ref)->null_value; - return tmp; - } - String *val_str(String* tmp) - { - tmp=(*ref)->val_str(tmp); - null_value=(*ref)->null_value; - return tmp; - } - bool is_null() - { - (void) (*ref)->val_int(); - return (*ref)->null_value; - } - bool get_date(TIME *ltime,uint fuzzydate) - { - return (null_value=(*ref)->get_date(ltime,fuzzydate)); - } + double val_real(); + longlong val_int(); + String *val_str(String* tmp); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); + bool is_null(); + bool get_date(TIME *ltime,uint fuzzydate); }; @@ -1164,6 +1194,8 @@ public: double val_real(); longlong val_int(); String* val_str(String* s); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); bool get_date(TIME *ltime, uint fuzzydate); void print(String *str); }; @@ -1174,7 +1206,8 @@ class Item_null_helper :public Item_ref_null_helper public: Item_null_helper(Item_in_subselect* master, Item *item, const char *table_name_par, const char *field_name_par) - :Item_ref_null_helper(master, &item, table_name_par, field_name_par), + :Item_ref_null_helper(master, (store= 0, &store), table_name_par, + field_name_par), store(item) { ref= &store; } void print(String *str); @@ -1243,6 +1276,7 @@ public: return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); void make_field(Send_field *field) { item->make_field(field); } void copy(); int save_in_field(Field *field, bool no_conversions); @@ -1291,6 +1325,15 @@ public: }; +class Item_decimal_buff :public Item_buff +{ + Item *item; + my_decimal value; +public: + Item_decimal_buff(Item *item_par); + bool cmp(void); +}; + class Item_field_buff :public Item_buff { char *buff; @@ -1453,24 +1496,23 @@ public: void print(String *str); }; + class Item_cache_int: public Item_cache { +protected: longlong value; public: Item_cache_int(): Item_cache(), value(0) {} - + void store(Item *item); double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } - String* val_str(String *str) - { - DBUG_ASSERT(fixed == 1); - str->set(value, default_charset()); - return str; - } + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return INT_RESULT; } }; + class Item_cache_real: public Item_cache { double value; @@ -1479,30 +1521,41 @@ public: void store(Item *item); double val_real() { DBUG_ASSERT(fixed == 1); return value; } - longlong val_int() - { - DBUG_ASSERT(fixed == 1); - return (longlong) (value+(value > 0 ? 0.5 : -0.5)); - } - String* val_str(String *str) - { - str->set(value, decimals, default_charset()); - return str; - } + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return REAL_RESULT; } }; + +class Item_cache_decimal: public Item_cache +{ +protected: + my_decimal decimal_value; +public: + Item_cache_decimal(): Item_cache() {} + + void store(Item *item); + double val_real(); + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type() const { return DECIMAL_RESULT; } +}; + + class Item_cache_str: public Item_cache { - char buffer[80]; + char buffer[STRING_BUFFER_USUAL_SIZE]; String *value, value_buff; public: Item_cache_str(): Item_cache(), value(0) { } - + void store(Item *item); double val_real(); longlong val_int(); String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; } + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return STRING_RESULT; } CHARSET_INFO *charset() const { return value->charset(); }; }; @@ -1547,6 +1600,12 @@ public: illegal_method_call((const char*)"val_str"); return 0; }; + my_decimal *val_decimal(my_decimal *val) + { + illegal_method_call((const char*)"val_decimal"); + return 0; + }; + enum Item_result result_type() const { return ROW_RESULT; } uint cols() { return item_count; } @@ -1579,14 +1638,15 @@ protected: Item_result orig_type; Field *field_example; public: - Item_type_holder(THD*, Item*); + Item_type_holder(THD*, Item*, TABLE *); Item_result result_type () const { return item_type; } enum Type type() const { return TYPE_HOLDER; } double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); String *val_str(String*); - bool join_types(THD *thd, Item *); + bool join_types(THD *thd, Item *, TABLE *); Field *example() { return field_example; } static uint32 real_length(Item *item); void cleanup() diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 66de26dba9a..7c77f7fa3bc 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -28,11 +28,21 @@ Item_buff *new_Item_buff(Item *item) if (item->type() == Item::FIELD_ITEM && !(((Item_field *) item)->field->flags & BLOB_FLAG)) return new Item_field_buff((Item_field *) item); - if (item->result_type() == STRING_RESULT) + switch (item->result_type()) + { + case STRING_RESULT: return new Item_str_buff((Item_field *) item); - if (item->result_type() == INT_RESULT) + case INT_RESULT: return new Item_int_buff((Item_field *) item); - return new Item_real_buff(item); + case REAL_RESULT: + return new Item_real_buff(item); + case DECIMAL_RESULT: + return new Item_decimal_buff(item); + case ROW_RESULT: + default: + DBUG_ASSERT(0); + return 0; + } } Item_buff::~Item_buff() {} @@ -107,6 +117,27 @@ bool Item_field_buff::cmp(void) } +Item_decimal_buff::Item_decimal_buff(Item *it) + :item(it) +{ + my_decimal_set_zero(&value); +} + + +bool Item_decimal_buff::cmp() +{ + my_decimal tmp; + my_decimal *ptmp= item->val_decimal(&tmp); + if (null_value != item->null_value || my_decimal_cmp(&value, ptmp) == 0) + { + null_value= item->null_value; + my_decimal2decimal(ptmp, &value); + return TRUE; + } + return FALSE; +} + + /***************************************************************************** ** Instansiate templates *****************************************************************************/ diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 96689bd0ac2..71a4e4dda53 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -31,6 +31,8 @@ static Item_result item_store_type(Item_result a,Item_result b) return STRING_RESULT; else if (a == REAL_RESULT || b == REAL_RESULT) return REAL_RESULT; + else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT) + return DECIMAL_RESULT; else return INT_RESULT; } @@ -51,7 +53,8 @@ static void agg_cmp_type(Item_result *type, Item **items, uint nitems) type[0]= item_cmp_type(type[0], items[i]->result_type()); } -static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) +static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, + const char *fname) { my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), c1.collation->name,c1.derivation_name(), @@ -104,7 +107,7 @@ Item_bool_func2* Le_creator::create(Item *a, Item *b) const longlong Item_func_not::val_int() { DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); + bool value= args[0]->val_bool(); null_value=args[0]->null_value; return ((!null_value && value == 0) ? 1 : 0); } @@ -116,11 +119,11 @@ longlong Item_func_not::val_int() longlong Item_func_not_all::val_int() { DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); + bool value= args[0]->val_bool(); /* - return TRUE if there was records in underlaying select in max/min - optimisation (ALL subquery) + return TRUE if there was records in underlying select in max/min + optimization (ALL subquery) */ if (empty_underlying_subquery()) return 1; @@ -147,7 +150,7 @@ void Item_func_not_all::print(String *str) /* Special NOP (No OPeration) for ALL subquery it is like Item_func_not_all - (return TRUE if underlaying sudquery do not return rows) but if subquery + (return TRUE if underlying subquery do not return rows) but if subquery returns some rows it return same value as argument (TRUE/FALSE). */ @@ -157,8 +160,8 @@ longlong Item_func_nop_all::val_int() longlong value= args[0]->val_int(); /* - return FALSE if there was records in underlaying select in max/min - optimisation (SAME/ANY subquery) + return FALSE if there was records in underlying select in max/min + optimization (SAME/ANY subquery) */ if (empty_underlying_subquery()) return 0; @@ -270,7 +273,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) owner= item; func= comparator_matrix[type] [test(owner->functype() == Item_func::EQUAL_FUNC)]; - if (type == ROW_RESULT) + switch(type) + { + case ROW_RESULT: { uint n= (*a)->cols(); if (n != (*b)->cols()) @@ -290,8 +295,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) } comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); } + break; } - else if (type == STRING_RESULT) + case STRING_RESULT: { /* We must set cmp_charset here as we may be called from for an automatic @@ -315,7 +321,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) func= &Arg_comparator::compare_e_binary_string; /* - As this is binary comparsion, mark all fields that they can't be + As this is binary compassion, mark all fields that they can't be transformed. Otherwise we would get into trouble with comparisons like: WHERE col= 'j' AND col LIKE BINARY 'j' @@ -325,14 +331,16 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) (*a)->transform(&Item::set_no_const_sub, (byte*) 0); (*b)->transform(&Item::set_no_const_sub, (byte*) 0); } + break; } - else if (type == INT_RESULT) + case INT_RESULT: { if (func == &Arg_comparator::compare_int_signed) { if ((*a)->unsigned_flag) - func= ((*b)->unsigned_flag)? &Arg_comparator::compare_int_unsigned : - &Arg_comparator::compare_int_unsigned_signed; + func= (((*b)->unsigned_flag)? + &Arg_comparator::compare_int_unsigned : + &Arg_comparator::compare_int_unsigned_signed); else if ((*b)->unsigned_flag) func= &Arg_comparator::compare_int_signed_unsigned; } @@ -341,6 +349,13 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) if ((*a)->unsigned_flag ^ (*b)->unsigned_flag) func= &Arg_comparator::compare_e_int_diff_signedness; } + break; + } + case DECIMAL_RESULT: + case REAL_RESULT: + break; + default: + DBUG_ASSERT(0); } return 0; } @@ -434,6 +449,24 @@ int Arg_comparator::compare_real() return -1; } +int Arg_comparator::compare_decimal() +{ + my_decimal value1; + my_decimal *val1= (*a)->val_decimal(&value1); + if (!(*a)->null_value) + { + my_decimal value2; + my_decimal *val2= (*b)->val_decimal(&value2); + if (!(*b)->null_value) + { + owner->null_value= 0; + return my_decimal_cmp(val1, val2); + } + } + owner->null_value= 1; + return -1; +} + int Arg_comparator::compare_e_real() { double val1= (*a)->val_real(); @@ -443,6 +476,16 @@ int Arg_comparator::compare_e_real() return test(val1 == val2); } +int Arg_comparator::compare_e_decimal() +{ + my_decimal value1, value2; + my_decimal *val1= (*a)->val_decimal(&value1); + my_decimal *val2= (*b)->val_decimal(&value2); + if ((*a)->null_value || (*b)->null_value) + return test((*a)->null_value && (*b)->null_value); + return test(my_decimal_cmp(val1, val2) == 0); +} + int Arg_comparator::compare_int_signed() { longlong val1= (*a)->val_int(); @@ -776,6 +819,8 @@ longlong Item_func_strcmp::val_int() void Item_func_interval::fix_length_and_dec() { + use_decimal_comparison= (row->el(0)->result_type() == DECIMAL_RESULT) || + (row->el(0)->result_type() == INT_RESULT); if (row->cols() > 8) { bool consts=1; @@ -786,10 +831,41 @@ void Item_func_interval::fix_length_and_dec() } if (consts && - (intervals=(double*) sql_alloc(sizeof(double)*(row->cols()-1)))) + (intervals= + (interval_range*) sql_alloc(sizeof(interval_range)*(row->cols()-1)))) { - for (uint i=1 ; i < row->cols(); i++) - intervals[i-1]= row->el(i)->val_real(); + if (use_decimal_comparison) + { + for (uint i=1 ; i < row->cols(); i++) + { + Item *el= row->el(i); + interval_range *range= intervals + (i-1); + if ((el->result_type() == DECIMAL_RESULT) || + (el->result_type() == INT_RESULT)) + { + range->type= DECIMAL_RESULT; + range->dec.init(); + my_decimal *dec= el->val_decimal(&range->dec); + if (dec != &range->dec) + { + range->dec= *dec; + range->dec.fix_buffer_pointer(); + } + } + else + { + range->type= REAL_RESULT; + range->dbl= el->val_real(); + } + } + } + else + { + for (uint i=1 ; i < row->cols(); i++) + { + intervals[i-1].dbl= row->el(i)->val_real(); + } + } } } maybe_null= 0; @@ -812,6 +888,11 @@ longlong Item_func_interval::val_int() { DBUG_ASSERT(fixed == 1); double value= row->el(0)->val_real(); + my_decimal dec_buf, *dec= NULL; + if (use_decimal_comparison) + { + dec= row->el(0)->val_decimal(&dec_buf); + } uint i; if (row->el(0)->null_value) @@ -824,18 +905,37 @@ longlong Item_func_interval::val_int() while (start != end) { uint mid= (start + end + 1) / 2; - if (intervals[mid] <= value) + interval_range *range= intervals + mid; + my_bool cmp_result; + if (dec && range->type == DECIMAL_RESULT) + cmp_result= my_decimal_cmp(&range->dec, dec) <= 0; + else + cmp_result= (range->dbl <= value); + if (cmp_result) start= mid; else end= mid - 1; } - return (value < intervals[start]) ? 0 : start + 1; + interval_range *range= intervals+start; + return ((dec && range->type == DECIMAL_RESULT) ? + my_decimal_cmp(dec, &range->dec) < 0 : + value < range->dbl) ? 0 : start + 1; } for (i=1 ; i < row->cols() ; i++) { - if (row->el(i)->val_real() > value) - return i-1; + Item *el= row->el(i); + if (use_decimal_comparison && + ((el->result_type() == DECIMAL_RESULT) || + (el->result_type() == INT_RESULT))) + { + my_decimal e_dec_buf, *e_dec= row->el(i)->val_decimal(&e_dec_buf); + if (my_decimal_cmp(e_dec, dec) > 0) + return i-1; + } + else + if (row->el(i)->val_real() > value) + return i-1; } return i-1; } @@ -847,7 +947,7 @@ void Item_func_between::fix_length_and_dec() /* As some compare functions are generated after sql_yacc, - we have to check for out of memory conditons here + we have to check for out of memory conditions here */ if (!args[0] || !args[1] || !args[2]) return; @@ -857,7 +957,7 @@ void Item_func_between::fix_length_and_dec() return; /* - Make a special case of compare with date/time and longlong fields. + Make a special ease of compare with date/time and longlong fields. They are compared as integers, so for const item this time-consuming conversion can be done only once, not for every single comparison */ @@ -926,6 +1026,24 @@ longlong Item_func_between::val_int() null_value= value >= a; } } + else if (cmp_type == DECIMAL_RESULT) + { + my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf), + a_buf, *a_dec, b_buf, *b_dec; + if ((null_value=args[0]->null_value)) + return 0; /* purecov: inspected */ + 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); + + if (args[1]->null_value && args[2]->null_value) + null_value=1; + else if (args[1]->null_value) + null_value= (my_decimal_cmp(dec, b_dec) <= 0); + else + null_value= (my_decimal_cmp(dec, a_dec) >= 0); + } else { double value= args[0]->val_real(),a,b; @@ -965,14 +1083,26 @@ void Item_func_ifnull::fix_length_and_dec() { maybe_null=args[1]->maybe_null; - max_length=max(args[0]->max_length,args[1]->max_length); - decimals=max(args[0]->decimals,args[1]->decimals); + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= (max(args[0]->max_length - args[0]->decimals, + args[1]->max_length - args[1]->decimals) + + decimals); agg_result_type(&cached_result_type, args, 2); - if (cached_result_type == STRING_RESULT) + switch (cached_result_type) + { + case STRING_RESULT: agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); - else if (cached_result_type != REAL_RESULT) + break; + case DECIMAL_RESULT: + case REAL_RESULT: + break; + case INT_RESULT: decimals= 0; - + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } cached_field_type= args[0]->field_type(); if (cached_field_type != args[1]->field_type()) cached_field_type= Item_func::field_type(); @@ -1020,6 +1150,24 @@ Item_func_ifnull::val_int() return value; } + +my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + my_decimal *value= args[0]->val_decimal(decimal_value); + if (!args[0]->null_value) + { + null_value= 0; + return value; + } + value= args[1]->val_decimal(decimal_value); + if ((null_value= args[1]->null_value)) + return 0; + return value; +} + + + String * Item_func_ifnull::val_str(String *str) { @@ -1043,8 +1191,10 @@ void Item_func_if::fix_length_and_dec() { maybe_null=args[1]->maybe_null || args[2]->maybe_null; - max_length=max(args[1]->max_length,args[2]->max_length); - decimals=max(args[1]->decimals,args[2]->decimals); + decimals= max(args[1]->decimals, args[2]->decimals); + max_length= (max(args[1]->max_length - args[1]->decimals, + args[2]->max_length - args[2]->decimals) + + decimals); enum Item_result arg1_type=args[1]->result_type(); enum Item_result arg2_type=args[2]->result_type(); bool null1=args[1]->const_item() && args[1]->null_value; @@ -1080,7 +1230,7 @@ double Item_func_if::val_real() { DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_int() ? args[1] : args[2]; + Item *arg= args[0]->val_bool() ? args[1] : args[2]; double value= arg->val_real(); null_value=arg->null_value; return value; @@ -1090,7 +1240,7 @@ longlong Item_func_if::val_int() { DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_int() ? args[1] : args[2]; + Item *arg= args[0]->val_bool() ? args[1] : args[2]; longlong value=arg->val_int(); null_value=arg->null_value; return value; @@ -1100,7 +1250,7 @@ String * Item_func_if::val_str(String *str) { DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_int() ? args[1] : args[2]; + Item *arg= args[0]->val_bool() ? args[1] : args[2]; String *res=arg->val_str(str); if (res) res->set_charset(collation.collation); @@ -1109,6 +1259,17 @@ Item_func_if::val_str(String *str) } +my_decimal * +Item_func_if::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + Item *arg= args[0]->val_bool() ? args[1] : args[2]; + my_decimal *value= arg->val_decimal(decimal_value); + null_value= arg->null_value; + return value; +} + + void Item_func_nullif::fix_length_and_dec() { @@ -1125,6 +1286,7 @@ Item_func_nullif::fix_length_and_dec() } } + /* nullif () returns NULL if arguments are equal, else it returns the first argument. @@ -1178,6 +1340,22 @@ Item_func_nullif::val_str(String *str) } +my_decimal * +Item_func_nullif::val_decimal(my_decimal * decimal_value) +{ + DBUG_ASSERT(fixed == 1); + my_decimal *res; + if (!cmp.compare()) + { + null_value=1; + return 0; + } + res= args[0]->val_decimal(decimal_value); + null_value= args[0]->null_value; + return res; +} + + bool Item_func_nullif::is_null() { @@ -1193,14 +1371,16 @@ Item_func_nullif::is_null() Item *Item_func_case::find_item(String *str) { - String *first_expr_str,*tmp; + String *first_expr_str, *tmp; + my_decimal *first_expr_dec, first_expr_dec_val; longlong first_expr_int; double first_expr_real; - + /* These will be initialized later */ LINT_INIT(first_expr_str); LINT_INIT(first_expr_int); LINT_INIT(first_expr_real); + LINT_INIT(first_expr_dec); if (first_expr_num != -1) { @@ -1221,9 +1401,14 @@ Item *Item_func_case::find_item(String *str) if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; + case DECIMAL_RESULT: + first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val); + if (args[first_expr_num]->null_value) + return else_expr_num != -1 ? args[else_expr_num] : 0; + break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -1235,7 +1420,7 @@ Item *Item_func_case::find_item(String *str) if (first_expr_num == -1) { // No expression between CASE and the first WHEN - if (args[i]->val_int()) + if (args[i]->val_bool()) return args[i+1]; continue; } @@ -1253,9 +1438,16 @@ Item *Item_func_case::find_item(String *str) if (args[i]->val_real() == first_expr_real && !args[i]->null_value) return args[i+1]; break; + case DECIMAL_RESULT: + { + my_decimal value; + if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0) + return args[i+1]; + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -1320,6 +1512,27 @@ double Item_func_case::val_real() return res; } + +my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + char buff[MAX_FIELD_WIDTH]; + String dummy_str(buff, sizeof(buff), default_charset()); + Item *item= find_item(&dummy_str); + my_decimal *res; + + if (!item) + { + null_value=1; + return 0; + } + + res= item->val_decimal(decimal_value); + null_value= item->null_value; + return res; +} + + void Item_func_case::fix_length_and_dec() { Item **agg; @@ -1358,7 +1571,7 @@ void Item_func_case::fix_length_and_dec() agg_cmp_type(&cmp_type, agg, nagg); if ((cmp_type == STRING_RESULT) && agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV)) - return; + return; } if (else_expr_num == -1 || args[else_expr_num]->maybe_null) @@ -1453,20 +1666,45 @@ double Item_func_coalesce::val_real() } +my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + null_value= 0; + for (uint i= 0; i < arg_count; i++) + { + my_decimal *res= args[i]->val_decimal(decimal_value); + if (!args[i]->null_value) + return res; + } + null_value=1; + return 0; +} + + void Item_func_coalesce::fix_length_and_dec() { - max_length= 0; - decimals= 0; agg_result_type(&cached_result_type, args, arg_count); - for (uint i=0 ; i < arg_count ; i++) + switch (cached_result_type) { - set_if_bigger(max_length,args[i]->max_length); - set_if_bigger(decimals,args[i]->decimals); - } - if (cached_result_type == STRING_RESULT) + case STRING_RESULT: + count_only_length(); + decimals= NOT_FIXED_DEC; agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV); - else if (cached_result_type != REAL_RESULT) + break; + case DECIMAL_RESULT: + count_decimal_length(); + break; + case REAL_RESULT: + count_real_length(); + break; + case INT_RESULT: + count_only_length(); decimals= 0; + break; + case ROW_RESULT: + defaullt: + DBUG_ASSERT(0); + } } /**************************************************************************** @@ -1483,11 +1721,24 @@ static int cmp_double(void *cmp_arg, double *a,double *b) return *a < *b ? -1 : *a == *b ? 0 : 1; } -static int cmp_row(void *cmp_arg, cmp_item_row* a, cmp_item_row* b) +static int cmp_row(void *cmp_arg, cmp_item_row *a, cmp_item_row *b) { return a->compare(b); } + +static int cmp_decimal(void *cmp_arg, my_decimal *a, my_decimal *b) +{ + /* + We need call of fixing buffer pointer, because fast sort just copy + decimal buffers in memory and pointers left pointing on old buffer place + */ + a->fix_buffer_pointer(); + b->fix_buffer_pointer(); + return my_decimal_cmp(a, b); +} + + int in_vector::find(Item *item) { byte *result=get_value(item); @@ -1530,7 +1781,11 @@ void in_string::set(uint pos,Item *item) String *str=((String*) base)+pos; String *res=item->val_str(str); if (res && res != str) + { + if (res->uses_buffer_owned_by(str)) + res->copy(); *str= *res; + } if (!str->charset()) { CHARSET_INFO *cs; @@ -1608,17 +1863,47 @@ byte *in_double::get_value(Item *item) return (byte*) &tmp; } -cmp_item* cmp_item::get_comparator(Item *item) + +in_decimal::in_decimal(uint elements) + :in_vector(elements, sizeof(my_decimal),(qsort2_cmp) cmp_decimal, 0) +{} + + +void in_decimal::set(uint pos, Item *item) { - switch (item->result_type()) { + /* as far as 'item' is constant, we can store reference on my_decimal */ + my_decimal *dec= ((my_decimal *)base) + pos; + dec->len= DECIMAL_BUFF_LENGTH; + dec->fix_buffer_pointer(); + my_decimal *res= item->val_decimal(dec); + if (res != dec) + my_decimal2decimal(res, dec); +} + + +byte *in_decimal::get_value(Item *item) +{ + my_decimal *result= item->val_decimal(&val); + if (item->null_value) + return 0; + return (byte *)result; +} + + +cmp_item* cmp_item::get_comparator(Item_result type, + CHARSET_INFO *cs) +{ + switch (type) { case STRING_RESULT: - return new cmp_item_sort_string(item->collation.collation); + return new cmp_item_sort_string(cs); case INT_RESULT: return new cmp_item_int; case REAL_RESULT: return new cmp_item_real; case ROW_RESULT: return new cmp_item_row; + case DECIMAL_RESULT: + return new cmp_item_decimal; default: DBUG_ASSERT(0); break; @@ -1677,7 +1962,9 @@ void cmp_item_row::store_value(Item *item) for (uint i=0; i < n; i++) { if (!comparators[i]) - if (!(comparators[i]= cmp_item::get_comparator(item->el(i)))) + if (!(comparators[i]= + cmp_item::get_comparator(item->el(i)->result_type(), + item->el(i)->collation.collation))) break; // new failed comparators[i]->store_value(item->el(i)); item->null_value|= item->el(i)->null_value; @@ -1748,6 +2035,36 @@ int cmp_item_row::compare(cmp_item *c) } +void cmp_item_decimal::store_value(Item *item) +{ + my_decimal *val= item->val_decimal(&value); + if (val != &value) + my_decimal2decimal(val, &value); +} + + +int cmp_item_decimal::cmp(Item *arg) +{ + my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf); + if (arg->null_value) + return 1; + return my_decimal_cmp(&value, tmp); +} + + +int cmp_item_decimal::compare(cmp_item *c) +{ + cmp_item_decimal *cmp= (cmp_item_decimal *)c; + return my_decimal_cmp(&value, &cmp->value); +} + + +cmp_item* cmp_item_decimal::make_same() +{ + return new cmp_item_decimal(); +} + + bool Item_func_in::nulls_in_row() { Item **arg,**arg_end; @@ -1803,6 +2120,9 @@ void Item_func_in::fix_length_and_dec() case ROW_RESULT: array= new in_row(arg_count-1, args[0]); break; + case DECIMAL_RESULT: + array= new in_decimal(arg_count - 1); + break; default: DBUG_ASSERT(0); return; @@ -1824,7 +2144,7 @@ void Item_func_in::fix_length_and_dec() } else { - in_item= cmp_item::get_comparator(args[0]); + in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation); if (cmp_type == STRING_RESULT) in_item->cmp_charset= cmp_collation.collation; } @@ -1999,7 +2319,7 @@ bool Item_cond::walk(Item_processor processor, byte *arg) DESCRIPTION The function recursively applies the transform method with the - same transformer to each member item of the codition list. + same transformer to each member item of the condition list. If the call of the method for a member item returns a new item the old item is substituted for a new one. After this the transform method is applied to the root node @@ -2025,6 +2345,35 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg) } +/* + Move SUM items out from item tree and replace with reference + + SYNOPSIS + split_sum_func() + thd Thread handler + ref_pointer_array Pointer to array of reference fields + fields All fields in select + + NOTES + This function is run on all expression (SELECT list, WHERE, HAVING etc) + that have or refer (HAVING) to a SUM expression. + + The split is done to get an unique item for each SUM function + so that we can easily find and calculate them. + (Calculation done by update_sum_func() and copy_sum_funcs() in + sql_select.cc) + + All found SUM items are added FIRST in the fields list and + we replace the item with a reference. + + We also replace all functions without side effects (like RAND() or UDF's) + that uses columns as arguments. + For functions with side effects, we just remember any fields referred + by the function to ensure that we get a copy of the field value for the + first accepted row. This ensures that we can do things like + SELECT a*SUM(b) FROM t1 WHERE a=1 +*/ + void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array, List &fields) { @@ -2034,16 +2383,27 @@ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array, const_item_cache=1; while ((item=li++)) { - if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) + /* with_sum_func is set for items that contains a SUM expression */ + if (item->type() != SUM_FUNC_ITEM && + (item->with_sum_func || + (item->used_tables() & PSEUDO_TABLE_BITS))) item->split_sum_func(thd, ref_pointer_array, fields); - else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) + else if (item->type() == SUM_FUNC_ITEM || + (item->used_tables() && item->type() != REF_ITEM)) { + /* + Replace item with a reference so that we can easily calculate + it (in case of sum functions) or copy it (in case of fields) + + The test above is to ensure we don't do a reference for things + that are constants or are not yet calculated as in: + SELECT RAND() as r1, SUM(a) as r2 FROM t1 HAVING r1 > 1 AND r2 > 0 + */ Item **ref= li.ref(); uint el= fields.elements; ref_pointer_array[el]= item; Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name); fields.push_front(item); - ref_pointer_array[el]= item; thd->change_item_tree(ref, new_item); } item->update_used_tables(); @@ -2112,7 +2472,7 @@ void Item_cond::neg_arguments(THD *thd) /* - Evalution of AND(expr, expr, expr ...) + Evaluation of AND(expr, expr, expr ...) NOTES: abort_if_null is set for AND expressions for which we don't care if the @@ -2137,7 +2497,7 @@ longlong Item_cond_and::val_int() null_value= 0; while ((item=li++)) { - if (item->val_int() == 0) + if (!item->val_bool()) { if (abort_on_null || !(null_value= item->null_value)) return 0; // return FALSE @@ -2155,7 +2515,7 @@ longlong Item_cond_or::val_int() null_value=0; while ((item=li++)) { - if (item->val_int() != 0) + if (item->val_bool()) { null_value=0; return 1; @@ -2394,7 +2754,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) DBUG_ASSERT(fixed == 0); if ((!args[0]->fixed && args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) || - (!args[1]->fixed && + (!args[1]->fixed && args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1)) return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; @@ -2768,7 +3128,7 @@ longlong Item_cond_xor::val_int() /* Apply NOT transformation to the item and return a new one. - SYNPOSIS + SYNOPSIS neg_transformer() thd thread handler @@ -2946,10 +3306,10 @@ uint Item_equal::members() SYNOPSIS contains() - field field whose occurence is to be checked + field field whose occurrence is to be checked DESCRIPTION - The function checks whether field is occured in the Item_equal object + The function checks whether field is occurred in the Item_equal object RETURN VALUES 1 if nultiple equality contains a reference to field @@ -2977,7 +3337,7 @@ bool Item_equal::contains(Field *field) item multiple equality whose members are to be joined DESCRIPTION - The function actually merges two multiple equalitis. + The function actually merges two multiple equalities. After this operation the Item_equal object additionally contains the field items of another item of the type Item_equal. If the optional constant items are not equal the cond_false flag is @@ -3114,7 +3474,8 @@ longlong Item_equal::val_int() void Item_equal::fix_length_and_dec() { Item *item= const_item ? const_item : get_first(); - eval_item= cmp_item::get_comparator(item); + eval_item= cmp_item::get_comparator(item->result_type(), + item->collation.collation); if (item->result_type() == STRING_RESULT) eval_item->cmp_charset= cmp_collation.collation; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a156322e13c..717bcbca7d5 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -67,6 +67,7 @@ public: int compare_string(); // compare args[0] & args[1] int compare_binary_string(); // compare args[0] & args[1] int compare_real(); // compare args[0] & args[1] + int compare_decimal(); // compare args[0] & args[1] int compare_int_signed(); // compare args[0] & args[1] int compare_int_signed_unsigned(); int compare_int_unsigned_signed(); @@ -75,11 +76,12 @@ public: int compare_e_string(); // compare args[0] & args[1] int compare_e_binary_string(); // compare args[0] & args[1] int compare_e_real(); // compare args[0] & args[1] + int compare_e_decimal(); // compare args[0] & args[1] int compare_e_int(); // compare args[0] & args[1] int compare_e_int_diff_signedness(); int compare_e_row(); // compare args[0] & args[1] - static arg_cmp_func comparator_matrix [4][2]; + static arg_cmp_func comparator_matrix [5][2]; friend class Item_func; }; @@ -215,7 +217,7 @@ class Item_bool_rowready_func2 :public Item_bool_func2 public: Item_bool_rowready_func2(Item *a, Item *b) :Item_bool_func2(a, b) { - allowed_arg_cols= a->cols(); + allowed_arg_cols= 0; // Fetch this value from first argument } Item *neg_transformer(THD *thd); virtual Item *negated_item(); @@ -269,7 +271,7 @@ public: class Item_func_not_all :public Item_func_not { - /* allow to check presence od values in max/min optimisation */ + /* allow to check presence of values in max/min optimization */ Item_sum_hybrid *test_sum_item; Item_maxmin_subselect *test_sub_item; @@ -421,37 +423,67 @@ public: }; +struct interval_range +{ + Item_result type; + double dbl; + my_decimal dec; +}; + class Item_func_interval :public Item_int_func { Item_row *row; - double *intervals; + my_bool use_decimal_comparison; + interval_range *intervals; public: Item_func_interval(Item_row *a) - :Item_int_func(a),row(a),intervals(0) { allowed_arg_cols= a->cols(); } + :Item_int_func(a),row(a),intervals(0) + { + allowed_arg_cols= 0; // Fetch this value from first argument + } longlong val_int(); void fix_length_and_dec(); const char *func_name() const { return "interval"; } }; -class Item_func_ifnull :public Item_func +class Item_func_coalesce :public Item_func { +protected: enum Item_result cached_result_type; - enum_field_types cached_field_type; - bool field_type_defined; + Item_func_coalesce(Item *a, Item *b) + :Item_func(a, b), cached_result_type(INT_RESULT) + {} public: - Item_func_ifnull(Item *a,Item *b) - :Item_func(a,b), cached_result_type(INT_RESULT) + Item_func_coalesce(List &list) + :Item_func(list),cached_result_type(INT_RESULT) {} double val_real(); longlong val_int(); - String *val_str(String *str); + String *val_str(String *); + my_decimal *val_decimal(my_decimal *); + void fix_length_and_dec(); enum Item_result result_type () const { return cached_result_type; } + const char *func_name() const { return "coalesce"; } + table_map not_null_tables() const { return 0; } +}; + + +class Item_func_ifnull :public Item_func_coalesce +{ +protected: + enum_field_types cached_field_type; + bool field_type_defined; +public: + Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {} + double val_real(); + longlong val_int(); + String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum_field_types field_type() const; void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } Field *tmp_table_field(TABLE *table); - table_map not_null_tables() const { return 0; } }; @@ -465,6 +497,7 @@ public: double val_real(); longlong val_int(); 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,struct st_table_list *tlist, Item **ref) { @@ -488,6 +521,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "nullif"; } @@ -497,23 +531,6 @@ public: }; -class Item_func_coalesce :public Item_func -{ - enum Item_result cached_result_type; -public: - Item_func_coalesce(List &list) - :Item_func(list),cached_result_type(INT_RESULT) - {} - double val_real(); - longlong val_int(); - String *val_str(String *); - void fix_length_and_dec(); - enum Item_result result_type () const { return cached_result_type; } - const char *func_name() const { return "coalesce"; } - table_map not_null_tables() const { return 0; } -}; - - class Item_func_case :public Item_func { int first_expr_num, else_expr_num; @@ -526,7 +543,7 @@ public: Item_func_case(List &list, Item *first_expr_arg, Item *else_expr_arg) :Item_func(), first_expr_num(-1), else_expr_num(-1), cached_result_type(INT_RESULT) - { + { ncases= list.elements; if (first_expr_arg) { @@ -543,6 +560,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec(); table_map not_null_tables() const { return 0; } enum Item_result result_type () const { return cached_result_type; } @@ -583,7 +601,7 @@ public: class in_string :public in_vector { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmp; public: in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs); @@ -610,6 +628,16 @@ public: byte *get_value(Item *item); }; +class in_decimal :public in_vector +{ + my_decimal val; +public: + in_decimal(uint elements); + void set(uint pos, Item *item); + byte *get_value(Item *item); +}; + + /* ** Classes for easy comparing of non const items */ @@ -624,7 +652,7 @@ public: virtual int cmp(Item *item)= 0; // for optimized IN with row virtual int compare(cmp_item *item)= 0; - static cmp_item* get_comparator(Item *); + static cmp_item* get_comparator(Item_result type, CHARSET_INFO *cs); virtual cmp_item *make_same()= 0; virtual void store_value_by_template(cmp_item *tmpl, Item *item) { @@ -645,7 +673,7 @@ public: class cmp_item_sort_string :public cmp_item_string { protected: - char value_buff[80]; + char value_buff[STRING_BUFFER_USUAL_SIZE]; String value; public: cmp_item_sort_string(CHARSET_INFO *cs): @@ -657,7 +685,7 @@ public: } int cmp(Item *arg) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff, sizeof(buff), cmp_charset), *res; if (!(res= arg->val_str(&tmp))) return 1; /* Can't be right */ @@ -711,6 +739,18 @@ public: cmp_item *make_same(); }; + +class cmp_item_decimal :public cmp_item +{ + my_decimal value; +public: + void store_value(Item *item); + int cmp(Item *arg); + int compare(cmp_item *c); + cmp_item *make_same(); +}; + + class cmp_item_row :public cmp_item { cmp_item **comparators; @@ -780,7 +820,7 @@ class Item_func_in :public Item_int_func Item_func_in(List &list) :Item_int_func(list), array(0), in_item(0), have_null(0) { - allowed_arg_cols= args[0]->cols(); + allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); void fix_length_and_dec(); @@ -993,26 +1033,26 @@ public: /* - The class Item_equal is used to represent conjuctions of equality + The class Item_equal is used to represent conjunctions of equality predicates of the form field1 = field2, and field=const in where conditions and on expressions. All equality predicates of the form field1=field2 contained in a - conjuction are substituted for a sequence of items of this class. - An item of this class Item_equal(f1,f2,...fk) respresents a + conjunction are substituted for a sequence of items of this class. + An item of this class Item_equal(f1,f2,...fk) represents a multiple equality f1=f2=...=fk. - If a conjuction contains predicates f1=f2 and f2=f3, a new item of + If a conjunction contains predicates f1=f2 and f2=f3, a new item of this class is created Item_equal(f1,f2,f3) representing the multiple equality f1=f2=f3 that substitutes the above equality predicates in - the conjuction. - A conjuction of the predicates f2=f1 and f3=f1 and f3=f2 will be + the conjunction. + A conjunction of the predicates f2=f1 and f3=f1 and f3=f2 will be substituted for the item representing the same multiple equality f1=f2=f3. - An item Item_equal(f1,f2) can appear instead of a conjuction of + An item Item_equal(f1,f2) can appear instead of a conjunction of f2=f1 and f1=f2, or instead of just the predicate f1=f2. - An item of the class Item_equal inherites equalities from outer + An item of the class Item_equal inherits equalities from outer conjunctive levels. Suppose we have a where condition of the following form: @@ -1023,7 +1063,7 @@ public: f1=f3 will be substituted for Item_equal(f1,f2,f3,f4,f5); An object of the class Item_equal can contain an optional constant - item c. Thenit represents a multiple equality of the form + item c. Then it represents a multiple equality of the form c=f1=...=fk. Objects of the class Item_equal are used for the following: @@ -1041,7 +1081,7 @@ public: 3. An object Item_equal(t1.f1,...,tk.fk) is used to optimize the selected execution plan for the query: if table ti is accessed before the table tj then in any predicate P in the where condition - the occurence of tj.fj is substituted for ti.fi. This can allow + the occurrence of tj.fj is substituted for ti.fi. This can allow an evaluation of the predicate at an earlier step. When feature 1 is supported they say that join transitive closure @@ -1172,7 +1212,7 @@ public: /* - XOR is Item_cond, not an Item_int_func bevause we could like to + XOR is Item_cond, not an Item_int_func because we could like to optimize (a XOR b) later on. It's low prio, though */ @@ -1189,7 +1229,7 @@ public: }; -/* Some usefull inline functions */ +/* Some useful inline functions */ inline Item *and_conds(Item *a, Item *b) { diff --git a/sql/item_create.cc b/sql/item_create.cc index 9fb44658dd5..6bd5c0c9a52 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -289,7 +289,7 @@ Item *create_func_period_diff(Item* a, Item *b) Item *create_func_pi(void) { - return new Item_static_real_func("pi()", M_PI, 6, 8); + return new Item_static_float_func("pi()", M_PI, 6, 8); } Item *create_func_pow(Item* a, Item *b) @@ -454,7 +454,7 @@ Item *create_load_file(Item* a) } -Item *create_func_cast(Item *a, Cast_target cast_type, int len, +Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec, CHARSET_INFO *cs) { Item *res; @@ -467,6 +467,9 @@ Item *create_func_cast(Item *a, Cast_target cast_type, int len, case ITEM_CAST_DATE: res= new Item_date_typecast(a); break; case ITEM_CAST_TIME: res= new Item_time_typecast(a); break; case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break; + case ITEM_CAST_DECIMAL: + res= new Item_decimal_typecast(a, (len>0) ? len : 10, dec ? dec : 2); + break; case ITEM_CAST_CHAR: res= new Item_char_typecast(a, len, cs ? cs : current_thd->variables.collation_connection); diff --git a/sql/item_create.h b/sql/item_create.h index 1be33fef257..0a9af144ec0 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -28,7 +28,8 @@ Item *create_func_bit_length(Item* a); Item *create_func_coercibility(Item* a); Item *create_func_ceiling(Item* a); Item *create_func_char_length(Item* a); -Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs); +Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec, + CHARSET_INFO *cs); Item *create_func_connection_id(void); Item *create_func_conv(Item* a, Item *b, Item *c); Item *create_func_cos(Item* a); diff --git a/sql/item_func.cc b/sql/item_func.cc index 9d98c5cfa1b..a4c1110da32 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -194,6 +194,11 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, } if ((*arg)->type() == FIELD_ITEM) ((Item_field *)(*arg))->no_const_subst= 1; + /* + We do not check conv->fixed, because Item_func_conv_charset which can + be return by safe_charset_converter can't be fixed at creation, also + it do not need tables (second argument) for name resolving + */ *arg= conv; conv->fix_fields(thd, 0, arg); } @@ -308,10 +313,23 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) We can't yet set item to *arg as fix_fields may change *arg We shouldn't call fix_fields() twice, so check 'fixed' field first */ - if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) || - (*arg)->check_cols(allowed_arg_cols)) + if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg))) return TRUE; /* purecov: inspected */ item= *arg; + + if (allowed_arg_cols) + { + if (item->check_cols(allowed_arg_cols)) + return 1; + } + else + { + /* we have to fetch allowed_arg_cols from first argument */ + DBUG_ASSERT(arg == args); // it is first argument + allowed_arg_cols= item->cols(); + DBUG_ASSERT(allowed_arg_cols); // Can't be 0 any more + } + if (item->maybe_null) maybe_null=1; @@ -343,6 +361,7 @@ bool Item_func::walk (Item_processor processor, byte *argument) } + /* Transform an Item_func object with a transformer callback function @@ -389,15 +408,17 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array, for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++) { Item *item=* arg; - if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) + if (item->type() != SUM_FUNC_ITEM && + (item->with_sum_func || + (item->used_tables() & PSEUDO_TABLE_BITS))) item->split_sum_func(thd, ref_pointer_array, fields); - else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) + else if (item->type() == SUM_FUNC_ITEM || + (item->used_tables() && item->type() != REF_ITEM)) { uint el= fields.elements; ref_pointer_array[el]= item; Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name); fields.push_front(item); - ref_pointer_array[el]= item; thd->change_item_tree(arg, new_item); } } @@ -502,15 +523,26 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) case STRING_RESULT: res= make_string_field(t_arg); break; + case DECIMAL_RESULT: + res= new Field_new_decimal(max_length + (decimals?1:0), maybe_null, + name, t_arg, decimals); + break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } return res; } +my_decimal *Item_func::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed); + int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value); + return decimal_value; +} + String *Item_real_func::val_str(String *str) { @@ -523,38 +555,97 @@ String *Item_real_func::val_str(String *str) } -String *Item_num_func::val_str(String *str) -{ - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong nr=val_int(); - if (null_value) - return 0; /* purecov: inspected */ - if (!unsigned_flag) - str->set(nr,&my_charset_bin); - else - str->set((ulonglong) nr,&my_charset_bin); - } - else - { - double nr= val_real(); - if (null_value) - return 0; /* purecov: inspected */ - str->set(nr,decimals,&my_charset_bin); - } - return str; -} - - void Item_func::fix_num_length_and_dec() { - decimals=0; + decimals= 0; for (uint i=0 ; i < arg_count ; i++) - set_if_bigger(decimals,args[i]->decimals); - max_length=float_length(decimals); + { + set_if_bigger(decimals, args[i]->decimals); + } + max_length= float_length(decimals); } + +void Item_func_numhybrid::fix_num_length_and_dec() +{} + + +/* + Set max_length/decimals of function if function is fixed point and + result length/precision depends on argument ones + + SYNOPSIS + Item_func::count_decimal_length() +*/ + +void Item_func::count_decimal_length() +{ + uint32 length= 0; + decimals= 0; + for (uint i=0 ; i < arg_count ; i++) + { + set_if_bigger(decimals, args[i]->decimals); + set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); + } + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; +} + + +/* + Set max_length of if it is maximum length of its arguments + + SYNOPSIS + Item_func::count_only_length() +*/ + +void Item_func::count_only_length() +{ + max_length= 0; + for (uint i=0 ; i < arg_count ; i++) + set_if_bigger(max_length, args[i]->max_length); +} + + +/* + Set max_length/decimals of function if function is floating point and + result length/precision depends on argument ones + + SYNOPSIS + Item_func::count_real_length() +*/ + +void Item_func::count_real_length() +{ + uint32 length= 0; + decimals= 0; + max_length= 0; + for (uint i=0 ; i < arg_count ; i++) + { + if (decimals != NOT_FIXED_DEC) + { + set_if_bigger(decimals, args[i]->decimals); + set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); + } + set_if_bigger(max_length, args[i]->max_length); + } + if (decimals != NOT_FIXED_DEC) + { + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; + } +} + + + void Item_func::signal_divide_by_null() { THD *thd= current_thd; @@ -585,45 +676,221 @@ String *Item_int_func::val_str(String *str) return str; } + /* - Change from REAL_RESULT (default) to INT_RESULT if both arguments are - integers + Check arguments here to determine result's type for function with two + arguments. + + SYNOPSIS + Item_num_op::find_num_type() */ void Item_num_op::find_num_type(void) { - if (args[0]->result_type() == INT_RESULT && - args[1]->result_type() == INT_RESULT) + DBUG_ENTER("Item_num_op::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + DBUG_ASSERT(arg_count == 2); + Item_result r0= args[0]->result_type(); + Item_result r1= args[1]->result_type(); + + if (r0 == REAL_RESULT || r1 == REAL_RESULT || + r0 == STRING_RESULT || r1 ==STRING_RESULT) { + count_real_length(); + max_length= float_length(decimals); + hybrid_type= REAL_RESULT; + } + else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT) + { + hybrid_type= DECIMAL_RESULT; + result_precision(); + } + else if (r0 == INT_RESULT && r1 == INT_RESULT) + { + decimals= 0; hybrid_type=INT_RESULT; unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag; + result_precision(); } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + DBUG_VOID_RETURN; } -String *Item_num_op::val_str(String *str) + +/* + Set result type of function if it (type) is depends only on first argument + + SYNOPSIS + Item_func_num1::find_num_type() +*/ +void Item_func_num1::find_num_type() +{ + DBUG_ENTER("Item_func_num1::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + switch(hybrid_type= args[0]->result_type()) + { + case INT_RESULT: + unsigned_flag=args[0]->unsigned_flag; + hybrid_type= INT_RESULT; + break; + case STRING_RESULT: + case REAL_RESULT: + hybrid_type= REAL_RESULT; + max_length= float_length(decimals); + break; + case DECIMAL_RESULT: + hybrid_type= DECIMAL_RESULT; + break; + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + DBUG_VOID_RETURN; +} + + +void Item_func_num1::fix_num_length_and_dec() +{ + decimals= args[0]->decimals; + max_length= args[0]->max_length; +} + + +void Item_func_numhybrid::fix_length_and_dec() +{ + fix_num_length_and_dec(); + find_num_type(); +} + + +String *Item_func_numhybrid::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) + switch (hybrid_type) { - longlong nr=val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_value))) + return 0; + my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val); + my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); + break; + } + case INT_RESULT: + { + longlong nr= int_op(); if (null_value) return 0; /* purecov: inspected */ if (!unsigned_flag) str->set(nr,&my_charset_bin); else str->set((ulonglong) nr,&my_charset_bin); + break; } - else + case REAL_RESULT: { - double nr= val_real(); + double nr=real_op(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals,&my_charset_bin); + break; + } + default: + DBUG_ASSERT(0); } return str; } +double Item_func_numhybrid::val_real() +{ + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) + { + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_value))) + return 0.0; + double result; + my_decimal2double(E_DEC_FATAL_ERROR, val, &result); + return result; + } + case INT_RESULT: + return (double)int_op(); + case REAL_RESULT: + return real_op(); + default: + DBUG_ASSERT(0); + } + return 0.0; +} + + +longlong Item_func_numhybrid::val_int() +{ + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) + { + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_value))) + return 0; + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); + return result; + } + case INT_RESULT: + return int_op(); + case REAL_RESULT: + return (longlong)real_op(); + default: + DBUG_ASSERT(0); + } + return 0; +} + + +my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) +{ + my_decimal *val= decimal_value; + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) + { + case DECIMAL_RESULT: + val= decimal_op(decimal_value); + break; + case INT_RESULT: + { + longlong result= int_op(); + int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value); + break; + } + case REAL_RESULT: + { + double result= int_op(); + double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value); + break; + } + case STRING_RESULT: + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + return val; +} + + void Item_func_signed::print(String *str) { str->append("cast(", 5); @@ -642,26 +909,83 @@ void Item_func_unsigned::print(String *str) } -double Item_func_plus::val_real() +String *Item_decimal_typecast::val_str(String *str) +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, &tmp_buf); + my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str); + return str; +} + + +double Item_decimal_typecast::val_real() +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + double res; + my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res); + return res; +} + + +longlong Item_decimal_typecast::val_int() +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + longlong res; + my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res); + return res; +} + + +my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) +{ + my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf); + my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec); + return dec; +} + + +double Item_func_plus::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real() + args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; return value; } -longlong Item_func_plus::val_int() + +longlong Item_func_plus::int_op() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int()+args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; - return value; - } - return (longlong) Item_func_plus::val_real(); + longlong value=args[0]->val_int()+args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; +} + + +my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + my_decimal value2, *val2= args[1]->val_decimal(&value2); + if ((null_value= args[1]->null_value) || + my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) + return 0; + return decimal_value; +} + +/* + Set precision of results for additive operations (+ and -) + + SYNOPSIS + Item_func_additive_op::result_precision() +*/ +void Item_func_additive_op::result_precision() +{ + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= (max(args[0]->max_length - args[0]->decimals, + args[1]->max_length - args[1]->decimals) + + decimals + 1); } @@ -679,53 +1003,80 @@ void Item_func_minus::fix_length_and_dec() } -double Item_func_minus::val_real() +double Item_func_minus::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real() - args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; return value; } -longlong Item_func_minus::val_int() + +longlong Item_func_minus::int_op() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int() - args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; - return value; - } - return (longlong) Item_func_minus::val_real(); + longlong value=args[0]->val_int() - args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; } -double Item_func_mul::val_real() +my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + my_decimal value2, *val2= args[1]->val_decimal(&value2); + if ((null_value= args[1]->null_value) || + my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) + return 0; + return decimal_value; +} + + +double Item_func_mul::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real() * args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0.0; /* purecov: inspected */ + return 0.0; return value; } -longlong Item_func_mul::val_int() + +longlong Item_func_mul::int_op() { DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int()*args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; /* purecov: inspected */ - return value; - } - return (longlong) Item_func_mul::val_real(); + longlong value=args[0]->val_int()*args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; } -double Item_func_div::val_real() +my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + my_decimal value2, *val2= args[1]->val_decimal(&value2); + if ((null_value= args[1]->null_value) || + my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) + return 0; + return decimal_value; +} + + +void Item_func_mul::result_precision() +{ + decimals= args[0]->decimals + args[1]->decimals; + max_length= ((args[0]->max_length - args[0]->decimals) + + (args[1]->max_length - args[1]->decimals) + + decimals); +} + + +double Item_func_div::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); @@ -741,34 +1092,66 @@ double Item_func_div::val_real() } -longlong Item_func_div::val_int() +my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) + my_decimal value1, *val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + my_decimal value2, *val2= args[1]->val_decimal(&value2); + if ((null_value= args[1]->null_value)) + return 0; + switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, + val1, val2, DECIMAL_DIV_SCALE_INCREASE)) { - longlong value=args[0]->val_int(); - longlong val2=args[1]->val_int(); - if ((null_value= args[0]->null_value || args[1]->null_value)) - return 0; - if (val2 == 0) - { - signal_divide_by_null(); - return 0; - } - return value/val2; + case E_DEC_TRUNCATED: + case E_DEC_OK: + return decimal_value; + case E_DEC_DIV_ZERO: + signal_divide_by_null(); + default: + return 0; } - return (longlong) Item_func_div::val_real(); +} + + +void Item_func_div::result_precision() +{ + decimals= (args[0]->decimals + args[0]->decimals + + DECIMAL_DIV_SCALE_INCREASE); + max_length= ((args[0]->max_length - args[0]->decimals) + + (args[1]->max_length - args[1]->decimals) + + decimals); } void Item_func_div::fix_length_and_dec() { - decimals=max(args[0]->decimals,args[1]->decimals)+2; - set_if_smaller(decimals, NOT_FIXED_DEC); - max_length=args[0]->max_length - args[0]->decimals + decimals; - uint tmp=float_length(decimals); - set_if_smaller(max_length,tmp); - maybe_null=1; + DBUG_ENTER("Item_func_div::fix_length_and_dec"); + Item_num_op::fix_length_and_dec(); + switch(hybrid_type) + { + case REAL_RESULT: + { + decimals=max(args[0]->decimals,args[1]->decimals)+2; + set_if_smaller(decimals, NOT_FIXED_DEC); + max_length=args[0]->max_length - args[0]->decimals + decimals; + uint tmp=float_length(decimals); + set_if_smaller(max_length,tmp); + break; + } + case INT_RESULT: + hybrid_type= DECIMAL_RESULT; + DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); + result_precision(); + break; + case DECIMAL_RESULT: + result_precision(); + break; + default: + DBUG_ASSERT(0); + } + maybe_null= 1; // devision by zero + DBUG_VOID_RETURN; } @@ -791,30 +1174,28 @@ longlong Item_func_int_div::val_int() } +String *Item_func_int_div::val_str(String*str) +{ + longlong nr= val_int(); + if (null_value) + return 0; /* purecov: inspected */ + if (!unsigned_flag) + str->set(nr,&my_charset_bin); + else + str->set((ulonglong) nr,&my_charset_bin); + return str; +} + + void Item_func_int_div::fix_length_and_dec() { - find_num_type(); max_length=args[0]->max_length - args[0]->decimals; maybe_null=1; + unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag; } -double Item_func_mod::val_real() -{ - DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); - double val2= args[1]->val_real(); - if ((null_value= args[0]->null_value || args[1]->null_value)) - return 0.0; /* purecov: inspected */ - if (val2 == 0.0) - { - signal_divide_by_null(); - return 0.0; - } - return fmod(value,val2); -} - -longlong Item_func_mod::val_int() +longlong Item_func_mod::int_op() { DBUG_ASSERT(fixed == 1); longlong value= args[0]->val_int(); @@ -829,52 +1210,96 @@ longlong Item_func_mod::val_int() return value % val2; } -void Item_func_mod::fix_length_and_dec() -{ - Item_num_op::fix_length_and_dec(); -} - - -double Item_func_neg::val_real() +double Item_func_mod::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); - null_value=args[0]->null_value; + double val2= args[1]->val_real(); + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0.0; /* purecov: inspected */ + if (val2 == 0.0) + { + signal_divide_by_null(); + return 0.0; + } + return fmod(value,val2); +} + + +my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + my_decimal value2, *val2= args[1]->val_decimal(&value2); + if ((null_value= args[1]->null_value)) + return 0; + switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, + val1, val2)) + { + case E_DEC_TRUNCATED: + case E_DEC_OK: + return decimal_value; + case E_DEC_DIV_ZERO: + signal_divide_by_null(); + default: + return 0; + } +} + + +void Item_func_mod::result_precision() +{ + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= max(args[0]->max_length, args[1]->max_length); +} + + +double Item_func_neg::real_op() +{ + double value= args[0]->val_real(); + null_value= args[0]->null_value; return -value; } -longlong Item_func_neg::val_int() +longlong Item_func_neg::int_op() { - DBUG_ASSERT(fixed == 1); - longlong value=args[0]->val_int(); - null_value=args[0]->null_value; + longlong value= args[0]->val_int(); + null_value= args[0]->null_value; return -value; } -void Item_func_neg::fix_length_and_dec() +my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value) { - enum Item_result arg_result= args[0]->result_type(); - enum Item::Type arg_type= args[0]->type(); - decimals=args[0]->decimals; - max_length=args[0]->max_length; - hybrid_type= REAL_RESULT; - - /* - We need to account for added '-' in the following cases: - A) argument is a real or integer positive constant - in this case - argument's max_length is set to actual number of bytes occupied, and not - maximum number of bytes real or integer may require. Note that all - constants are non negative so we don't need to account for removed '-'. - B) argument returns a string. - */ - if (arg_result == STRING_RESULT || - (arg_type == REAL_ITEM && ((Item_real*)args[0])->value >= 0) || - (arg_type == INT_ITEM && ((Item_int*)args[0])->value > 0)) - max_length++; + my_decimal val, *value= args[0]->val_decimal(&val); + if (!(null_value= args[0]->null_value)) + { + my_decimal2decimal(value, decimal_value); + my_decimal_neg(decimal_value); + } + return decimal_value; +} - if (args[0]->result_type() == INT_RESULT) + +void Item_func_neg::fix_num_length_and_dec() +{ + decimals= args[0]->decimals; + /* 1 add because sign can appear */ + max_length= args[0]->max_length + 1; + unsigned_flag= 0; +} + + +void Item_func_signproc::fix_length_and_dec() +{ + DBUG_ENTER("Item_func_signproc::fix_length_and_dec"); + Item_func_num1::fix_length_and_dec(); + if (hybrid_type == INT_RESULT && + args[0]->type() == INT_ITEM && + ((ulonglong) ((Item_uint*) args[0])->value >= + (ulonglong) LONGLONG_MIN)) { /* If this is in integer context keep the context as integer @@ -886,42 +1311,47 @@ void Item_func_neg::fix_length_and_dec() (This is needed because the lex parser doesn't anymore handle signed integers) */ - if (args[0]->type() != INT_ITEM || - ((ulonglong) ((Item_uint*) args[0])->value <= - (ulonglong) LONGLONG_MIN)) - hybrid_type= INT_RESULT; + hybrid_type= DECIMAL_RESULT; + DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); } + DBUG_VOID_RETURN; } -double Item_func_abs::val_real() +double Item_func_abs::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); - null_value=args[0]->null_value; + null_value= args[0]->null_value; return fabs(value); } -longlong Item_func_abs::val_int() +longlong Item_func_abs::int_op() { - DBUG_ASSERT(fixed == 1); - longlong value=args[0]->val_int(); - null_value=args[0]->null_value; + longlong value= args[0]->val_int(); + null_value= args[0]->null_value; return value >= 0 ? value : -value; } +my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + if (!(null_value= args[0]->null_value)) + { + my_decimal2decimal(value, decimal_value); + if (decimal_value->sign()) + my_decimal_neg(decimal_value); + } + return decimal_value; +} + + void Item_func_abs::fix_length_and_dec() { - decimals=args[0]->decimals; - max_length=args[0]->max_length; - hybrid_type= REAL_RESULT; - if (args[0]->result_type() == INT_RESULT) - { - hybrid_type= INT_RESULT; + Item_func_num1::fix_length_and_dec(); + if (hybrid_type == INT_RESULT) unsigned_flag= 1; - } } @@ -1122,42 +1552,148 @@ void Item_func_integer::fix_length_and_dec() decimals=0; } -longlong Item_func_ceiling::val_int() +void Item_func_int_val::fix_num_length_and_dec() { - DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); - null_value=args[0]->null_value; + max_length= args[0]->max_length - (args[0]->decimals ? + args[0]->decimals + 1 : + 0) + 2; + uint tmp= float_length(decimals); + set_if_smaller(max_length,tmp); + decimals= 0; +} + + +void Item_func_int_val::find_num_type() +{ + DBUG_ENTER("Item_func_int_val::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + switch(hybrid_type= args[0]->result_type()) + { + case STRING_RESULT: + case REAL_RESULT: + hybrid_type= REAL_RESULT; + max_length= float_length(decimals); + break; + case INT_RESULT: + case DECIMAL_RESULT: + /* + -2 because in most high position can't be used any digit for longlong + and one position for increasing value during operation + */ + if ((args[0]->max_length - args[0]->decimals) >= + (DECIMAL_LONGLONG_DIGITS - 2)) + { + hybrid_type= DECIMAL_RESULT; + } + else + { + unsigned_flag= args[0]->unsigned_flag; + hybrid_type= INT_RESULT; + } + break; + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + + DBUG_VOID_RETURN; +} + + +longlong Item_func_ceiling::int_op() +{ + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; return (longlong) ceil(value); } -longlong Item_func_floor::val_int() + +double Item_func_ceiling::real_op() { - DBUG_ASSERT(fixed == 1); - // the volatile's for BUG #3051 to calm optimizer down (because of gcc's bug) + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ volatile double value= args[0]->val_real(); - null_value=args[0]->null_value; + null_value= args[0]->null_value; + return ceil(value); +} + + +my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + if ((null_value= args[0]->null_value)) + return 0; + if (my_decimal_ceiling(E_DEC_FATAL_ERROR, value, decimal_value) > 1) + return 0; + return decimal_value; +} + + +longlong Item_func_floor::int_op() +{ + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; return (longlong) floor(value); } -void Item_func_round::fix_length_and_dec() + +double Item_func_floor::real_op() { - max_length=args[0]->max_length; - decimals=args[0]->decimals; + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; + return floor(value); +} + + +my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + if ((null_value= args[0]->null_value)) + return 0; + if (my_decimal_floor(E_DEC_FATAL_ERROR, value, decimal_value) > 1) + return 0; + return decimal_value; +} + + +void Item_func_round::fix_num_length_and_dec() +{ + max_length= args[0]->max_length; + decimals= NOT_FIXED_DEC; if (args[1]->const_item()) { int tmp=(int) args[1]->val_int(); if (tmp < 0) decimals=0; else - decimals=min(tmp,NOT_FIXED_DEC); + decimals=min(tmp, NOT_FIXED_DEC); } } -double Item_func_round::val_real() +double Item_func_round::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); int dec=(int) args[1]->val_int(); + if (dec > 0) + decimals= dec; // to get correct output uint abs_dec=abs(dec); double tmp; /* @@ -1184,6 +1720,58 @@ double Item_func_round::val_real() } +longlong Item_func_round::int_op() +{ + longlong value= args[0]->val_int(); + int dec=(int) args[1]->val_int(); + decimals= 0; + uint abs_dec; + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0; + if (dec >= 0) + return value; // integer have not digits after point + + abs_dec= -dec; + double tmp; + /* + tmp2 is here to avoid return the value with 80 bit precision + This will fix that the test round(0.1,1) = round(0.1,1) is true + */ + volatile double tmp2; + + tmp= (abs_dec < array_elements(log_10) ? + log_10[abs_dec] : pow(10.0, (double) abs_dec)); + + if (truncate) + { + if (unsigned_flag) + tmp2= floor(((double)((ulonglong)value))/tmp)*tmp; + else if (value >= 0) + tmp2= floor(((double)value)/tmp)*tmp; + else + tmp2= ceil(((double)value)/tmp)*tmp; + } + else + tmp2= rint(((double)value)/tmp)*tmp; + return (longlong)tmp2; +} + + +my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + int dec=(int) args[1]->val_int(); + if (dec > 0) + decimals= dec; // to get correct output + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0; + if (my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate, + decimal_value) > 1) + return 0; + return decimal_value; +} + + bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) { @@ -1274,10 +1862,8 @@ void Item_func_min_max::fix_length_and_dec() for (uint i=0 ; i < arg_count ; i++) { - if (max_length < args[i]->max_length) - max_length=args[i]->max_length; - if (decimals < args[i]->decimals) - decimals=args[i]->decimals; + set_if_bigger(max_length, args[i]->max_length); + set_if_bigger(decimals, args[i]->decimals); if (!args[i]->maybe_null) maybe_null=0; cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); @@ -1302,6 +1888,14 @@ String *Item_func_min_max::val_str(String *str) str->set((ulonglong) nr,&my_charset_bin); return str; } + case DECIMAL_RESULT: + { + my_decimal dec_buf, *dec_val= val_decimal(&dec_buf); + if (null_value) + return 0; + my_decimal2string(E_DEC_FATAL_ERROR, dec_val, 0, 0, 0, str); + return str; + } case REAL_RESULT: { double nr= val_real(); @@ -1340,7 +1934,7 @@ String *Item_func_min_max::val_str(String *str) } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); return 0; } @@ -1393,6 +1987,40 @@ longlong Item_func_min_max::val_int() return value; } + +my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) +{ + DBUG_ASSERT(fixed == 1); + my_decimal tmp_buf, *tmp, *res= NULL; + null_value=1; + for (uint i=0; i < arg_count ; i++) + { + if (null_value) + { + res= args[i]->val_decimal(dec); + null_value= args[i]->null_value; + } + else + { + tmp= args[i]->val_decimal(&tmp_buf); + if (args[i]->null_value) + continue; + if ((my_decimal_cmp(tmp, res) * cmp_sign) < 0) + { + if (tmp == &tmp_buf) + { + my_decimal2decimal(tmp, dec); + res= dec; + } + else + res= tmp; + } + } + } + return res; +} + + longlong Item_func_length::val_int() { DBUG_ASSERT(fixed == 1); @@ -1516,6 +2144,21 @@ longlong Item_func_field::val_int() return (longlong) (i); } } + else if (cmp_type == DECIMAL_RESULT) + { + my_decimal dec_arg_buf, *dec_arg, + dec_buf, *dec= args[0]->val_decimal(&dec_buf); + if (args[0]->is_null()) + return 0; + for (uint i=1; i < arg_count; i++) + { + dec_arg= args[i]->val_decimal(&dec_arg_buf); + if (args[i]->is_null()) + continue; + if (!my_decimal_cmp(dec_arg, dec)) + return (longlong) (i); + } + } else { double val= args[0]->val_real(); @@ -1759,7 +2402,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg != arg_end ; arg++,i++) { - if (!(*arg)->fixed && + if (!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) DBUG_RETURN(1); // we can't assign 'item' before, because fix_fields() can change arg @@ -1775,7 +2418,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, Moreover, some arguments can represent a numeric input which doesn't effect the result character set and collation. There is no a general rule for UDF. Everything depends on - the particular user definted function. + the particular user defined function. */ if (item->collation.collation->state & MY_CS_BINSORT) func->collation.set(&my_charset_bin); @@ -1786,7 +2429,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, const_item_cache&=item->const_item(); f_args.arg_type[i]=item->result_type(); } - //TODO: why all folowing memory is not allocated with 1 call of sql_alloc? + //TODO: why all following memory is not allocated with 1 call of sql_alloc? if (!(buffers=new String[arg_count]) || !(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) || !(f_args.lengths= (ulong*) sql_alloc(arg_count * sizeof(long))) || @@ -1886,6 +2529,7 @@ bool udf_handler::get_arguments() f_args.args[i]=0; switch (f_args.arg_type[i]) { case STRING_RESULT: + case DECIMAL_RESULT: { String *res=args[i]->val_str(&buffers[str_count++]); if (!(args[i]->null_value)) @@ -1913,7 +2557,7 @@ bool udf_handler::get_arguments() break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -1958,6 +2602,31 @@ String *udf_handler::val_str(String *str,String *save_str) } +my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf) +{ + char buf[DECIMAL_MAX_STR_LENGTH+1], *end; + ulong res_length= DECIMAL_MAX_STR_LENGTH; + + if (get_arguments()) + { + *null_value=1; + return 0; + } + char *(*func)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)= + (char* (*)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)) + u_d->func; + + char *res= func(&initid, &f_args, buf, &res_length, &is_null, &error); + if (is_null || error) + { + *null_value= 1; + return 0; + } + buf[res_length]= 0; + str2my_decimal(E_DEC_FATAL_ERROR, buf, dec_buf, &end); + return dec_buf; +} + double Item_func_udf_float::val_real() { @@ -2004,6 +2673,59 @@ String *Item_func_udf_int::val_str(String *str) return str; } + +longlong Item_func_udf_decimal::val_int() +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + if (null_value) + return 0; + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); + return result; +} + + +double Item_func_udf_decimal::val_real() +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + if (null_value) + return 0.0; + double result; + my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); + return result; +} + + +my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf) +{ + DBUG_ASSERT(fixed == 1); + DBUG_ENTER("Item_func_udf_decimal::val_decimal"); + DBUG_PRINT("info",("result_type: %d arg_count: %d", + args[0]->result_type(), arg_count)); + + DBUG_RETURN(udf.val_decimal(&null_value, dec_buf)); +} + + +String *Item_func_udf_decimal::val_str(String *str) +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + if (null_value) + return 0; + if (str->length() < DECIMAL_MAX_STR_LENGTH) + str->length(DECIMAL_MAX_STR_LENGTH); + my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf); + my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str); + return str; +} + + +void Item_func_udf_decimal::fix_length_and_dec() +{ + fix_num_length_and_dec(); +} + + /* Default max_length is max argument length */ void Item_func_udf_str::fix_length_and_dec() @@ -2364,20 +3086,17 @@ longlong Item_func_release_lock::val_int() longlong Item_func_last_insert_id::val_int() { + THD *thd= current_thd; DBUG_ASSERT(fixed == 1); if (arg_count) { - longlong value=args[0]->val_int(); - current_thd->insert_id(value); - null_value=args[0]->null_value; - return value; - } - else - { - Item *it= get_system_var(current_thd, OPT_SESSION, "last_insert_id", 14, - "last_insert_id()"); - return it->val_int(); + longlong value= args[0]->val_int(); + thd->insert_id(value); + null_value= args[0]->null_value; + return value; // Avoid side effect of insert_id() } + thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + return thd->insert_id(); } /* This function is just used to test speed of different functions */ @@ -2403,7 +3122,7 @@ longlong Item_func_benchmark::val_int() break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); return 0; } @@ -2569,6 +3288,8 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, entry->value[length]= 0; // Store end \0 } memcpy(entry->value,ptr,length); + if (type == DECIMAL_RESULT) + ((my_decimal*)entry->value)->fix_buffer_pointer(); entry->length= length; entry->type=type; entry->collation.set(cs, dv); @@ -2584,7 +3305,7 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, /* Get the value of a variable as a double */ -double user_var_entry::val(my_bool *null_value) +double user_var_entry::val_real(my_bool *null_value) { if ((*null_value= (value == 0))) return 0.0; @@ -2594,6 +3315,12 @@ double user_var_entry::val(my_bool *null_value) return *(double*) value; case INT_RESULT: return (double) *(longlong*) value; + case DECIMAL_RESULT: + { + double result; + my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result); + return result; + } case STRING_RESULT: return my_atof(value); // This is null terminated case ROW_RESULT: @@ -2616,6 +3343,12 @@ longlong user_var_entry::val_int(my_bool *null_value) return (longlong) *(double*) value; case INT_RESULT: return *(longlong*) value; + case DECIMAL_RESULT: + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 1, &result); + return result; + } case STRING_RESULT: { int error; @@ -2644,6 +3377,9 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, case INT_RESULT: str->set(*(longlong*) value, &my_charset_bin); break; + case DECIMAL_RESULT: + my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str); + break; case STRING_RESULT: if (str->copy(value, length, collation.collation)) str= 0; // EOM error @@ -2654,16 +3390,43 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, return(str); } +/* Get the value of a variable as a decimal */ + +my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) +{ + if ((*null_value= (value == 0))) + return 0; + + switch (type) { + case REAL_RESULT: + double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val); + break; + case INT_RESULT: + int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) value, 0, val); + break; + case DECIMAL_RESULT: + val= (my_decimal *)value; + break; + case STRING_RESULT: + str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val); + break; + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; + } + return(val); +} + /* This functions is invoked on SET @variable or @variable:= expression. - Evaluete (and check expression), store results. + Evaluate (and check expression), store results. SYNOPSYS Item_func_set_user_var::check() NOTES - For now it always return OK. All problem with value evalueting - will be catched by thd->net.report_error check in sql_set_variables(). + For now it always return OK. All problem with value evaluating + will be caught by thd->net.report_error check in sql_set_variables(). RETURN FALSE OK. @@ -2690,9 +3453,14 @@ Item_func_set_user_var::check() save_result.vstr= args[0]->val_str(&value); break; } + case DECIMAL_RESULT: + { + save_result.vdec= args[0]->val_decimal(&decimal_buff); + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -2711,7 +3479,7 @@ Item_func_set_user_var::check() the value method used by the user RETURN - 0 Ok + 0 OK 1 EOM Error */ @@ -2748,9 +3516,20 @@ Item_func_set_user_var::update() args[0]->collation.derivation); break; } + case DECIMAL_RESULT: + { + if (!save_result.vdec) // Null value + res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin, + DERIVATION_NONE); + else + res= update_hash((void*) save_result.vdec, + sizeof(my_decimal), DECIMAL_RESULT, + &my_charset_bin, DERIVATION_NONE); + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -2763,7 +3542,7 @@ double Item_func_set_user_var::val_real() DBUG_ASSERT(fixed == 1); check(); update(); // Store expression - return entry->val(&null_value); + return entry->val_real(&null_value); } longlong Item_func_set_user_var::val_int() @@ -2783,6 +3562,15 @@ String *Item_func_set_user_var::val_str(String *str) } +my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed == 1); + check(); + update(); // Store expression + return entry->val_decimal(&null_value, val); +} + + void Item_func_set_user_var::print(String *str) { str->append("(@", 2); @@ -2819,7 +3607,16 @@ double Item_func_get_user_var::val_real() DBUG_ASSERT(fixed == 1); if (!var_entry) return 0.0; // No such variable - return (var_entry->val(&null_value)); + return (var_entry->val_real(&null_value)); +} + + +my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec) +{ + DBUG_ASSERT(fixed == 1); + if (!var_entry) + return 0; + return var_entry->val_decimal(&null_value, dec); } @@ -2850,7 +3647,7 @@ longlong Item_func_get_user_var::val_int() RETURN 0 OK - 1 Failed to put appropiate record into binary log + 1 Failed to put appropriate record into binary log */ @@ -2874,8 +3671,8 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, that it gets into the binlog (if it didn't, the slave could be influenced by a variable of the same name previously set by another thread). - We create it like if it had been explicitely set with SET before. - The 'new' mimicks what sql_yacc.yy does when 'SET @a=10;'. + We create it like if it had been explicitly set with SET before. + The 'new' mimics what sql_yacc.yy does when 'SET @a=10;'. sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION' in dispatch_command()). Instead of building a one-element list to pass to sql_set_variables(), we could instead manually call check() and update(); @@ -2906,7 +3703,7 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, uint size; /* First we need to store value of var_entry, when the next situation - appers: + appears: > set @a:=1; > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1); We have to write to binlog value @a= 1; @@ -2968,7 +3765,13 @@ void Item_func_get_user_var::fix_length_and_dec() case STRING_RESULT: max_length= MAX_BLOB_WIDTH; break; + case DECIMAL_RESULT: + max_length= DECIMAL_MAX_LENGTH; + decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1); + break; case ROW_RESULT: // Keep compiler happy + default: + DBUG_ASSERT(0); break; } } @@ -3129,9 +3932,7 @@ void Item_func_match::init_search(bool no_order) if (join_key && !no_order) flags|=FT_SORTED; - ft_handler=table->file->ft_init_ext(flags, key, - (byte*) ft_tmp->ptr(), - ft_tmp->length()); + ft_handler=table->file->ft_init_ext(flags, key, ft_tmp); if (join_key) table->file->ft_handler=ft_handler; @@ -3173,12 +3974,12 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) } /* Check that all columns come from the same table. - We've already checked that columns in MATCH are fields so + We've already checked that columns in MATCH are fields so PARAM_TABLE_BIT can only appear from AGAINST argument. */ if ((used_tables_cache & ~PARAM_TABLE_BIT) != item->used_tables()) key=NO_SUCH_KEY; - + if (key == NO_SUCH_KEY && !(flags & FT_BOOL)) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); @@ -3527,7 +4328,7 @@ const char * Item_func_sp::func_name() const { THD *thd= current_thd; - /* Calculate length to avoud reallocation of string for sure */ + /* Calculate length to avoid reallocation of string for sure */ uint len= ((m_name->m_db.length + m_name->m_name.length)*2 + //characters*quoting 2 + // ` and ` @@ -3556,13 +4357,18 @@ Item_func_sp::execute(Item **itp) #endif if (! m_sp) - m_sp= sp_find_function(thd, m_name); + m_sp= sp_find_function(thd, m_name, TRUE); // cache only if (! m_sp) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); DBUG_RETURN(-1); } +#ifndef EMBEDDED_LIBRARY + my_bool nsok= thd->net.no_send_ok; + thd->net.no_send_ok= TRUE; +#endif + #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_procedure_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0)) @@ -3578,7 +4384,7 @@ Item_func_sp::execute(Item **itp) #endif /* - We don't need to surpress sending of ok packet here (by setting + We don't need to suppress sending of OK packet here (by setting thd->net.no_send_ok to true), because we are not allowing statements in functions now. */ @@ -3588,6 +4394,9 @@ Item_func_sp::execute(Item **itp) sp_restore_security_context(thd, m_sp, &save_ctx); #endif +#ifndef EMBEDDED_LIBRARY + thd->net.no_send_ok= nsok; +#endif DBUG_RETURN(res); } @@ -3598,7 +4407,7 @@ Item_func_sp::field_type() const DBUG_ENTER("Item_func_sp::field_type"); if (! m_sp) - m_sp= sp_find_function(current_thd, m_name); + m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only if (m_sp) { DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns)); @@ -3616,7 +4425,7 @@ Item_func_sp::result_type() const DBUG_PRINT("info", ("m_sp = %p", m_sp)); if (! m_sp) - m_sp= sp_find_function(current_thd, m_name); + m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only if (m_sp) { DBUG_RETURN(m_sp->result()); @@ -3631,7 +4440,7 @@ Item_func_sp::fix_length_and_dec() DBUG_ENTER("Item_func_sp::fix_length_and_dec"); if (! m_sp) - m_sp= sp_find_function(current_thd, m_name); + m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only if (! m_sp) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); @@ -3651,9 +4460,13 @@ Item_func_sp::fix_length_and_dec() decimals= 0; max_length= 21; break; + case DECIMAL_RESULT: + // TODO: where to find real precision and scale? + decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1); + max_length= DECIMAL_MAX_LENGTH; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } diff --git a/sql/item_func.h b/sql/item_func.h index fb8d77d5b83..20f70fce575 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -32,6 +32,10 @@ class Item_func :public Item_result_field { protected: Item **args, *tmp_arg[2]; + /* + Allowed numbers of columns in result (usually 1, which means scalar value) + 0 means get this number from first argument + */ uint allowed_arg_cols; public: uint arg_count; @@ -129,7 +133,10 @@ public: void print(String *str); void print_op(String *str); void print_args(String *str, uint from); - void fix_num_length_and_dec(); + virtual void fix_num_length_and_dec(); + void count_only_length(); + void count_real_length(); + void count_decimal_length(); inline bool get_arg0_date(TIME *ltime, uint fuzzy_date) { return (null_value=args[0]->get_date(ltime, fuzzy_date)); @@ -144,7 +151,9 @@ public: Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg); Item *get_tmp_table_item(THD *thd); - + + my_decimal *val_decimal(my_decimal *); + bool agg_arg_collations(DTCollation &c, Item **items, uint nitems, uint flags= 0); bool agg_arg_collations_for_comparison(DTCollation &c, @@ -168,49 +177,70 @@ public: longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); } enum Item_result result_type () const { return REAL_RESULT; } - void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); } + void fix_length_and_dec() + { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } }; -class Item_num_func :public Item_func +class Item_func_numhybrid: public Item_func { - protected: +protected: Item_result hybrid_type; public: - Item_num_func(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) {} - Item_num_func(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {} - String *val_str(String*str); - longlong val_int() - { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); } + Item_func_numhybrid(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) + {} + Item_func_numhybrid(Item *a,Item *b) + :Item_func(a,b),hybrid_type(REAL_RESULT) + {} + enum Item_result result_type () const { return hybrid_type; } - void fix_length_and_dec() { fix_num_length_and_dec(); } + void fix_length_and_dec(); + void fix_num_length_and_dec(); + virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */ + + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*str); + + virtual longlong int_op()= 0; + virtual double real_op()= 0; + virtual my_decimal *decimal_op(my_decimal *)= 0; bool is_null() { (void) val_real(); return null_value; } }; - -class Item_num_op :public Item_func +/* function where type of result detected by first argument */ +class Item_func_num1: public Item_func_numhybrid +{ +public: + Item_func_num1(Item *a) :Item_func_numhybrid(a) {} + Item_func_num1(Item *a, Item *b) :Item_func_numhybrid(a, b) {} + + void fix_num_length_and_dec(); + void find_num_type(); +}; + + +/* Base class for operations like '+', '-', '*' */ +class Item_num_op :public Item_func_numhybrid { - protected: - Item_result hybrid_type; public: - Item_num_op(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {} - String *val_str(String*str); + Item_num_op(Item *a,Item *b) :Item_func_numhybrid(a, b) {} + virtual void result_precision()= 0; void print(String *str) { print_op(str); } - enum Item_result result_type () const { return hybrid_type; } - void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); } - void find_num_type(void); - bool is_null() { (void) val_real(); return null_value; } + void find_num_type(); }; class Item_int_func :public Item_func { public: - Item_int_func() :Item_func() { max_length=21; } - Item_int_func(Item *a) :Item_func(a) { max_length=21; } - Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; } - Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; } - Item_int_func(List &list) :Item_func(list) { max_length=21; } + Item_int_func() :Item_func() { max_length= 21; } + Item_int_func(Item *a) :Item_func(a) { max_length= 21; } + Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length= 21; } + Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) + { max_length= 21; } + Item_int_func(List &list) :Item_func(list) { max_length= 21; } Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {} double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); @@ -253,22 +283,51 @@ public: }; -class Item_func_plus :public Item_num_op +class Item_decimal_typecast :public Item_func { + my_decimal decimal_value; public: - Item_func_plus(Item *a,Item *b) :Item_num_op(a,b) {} - const char *func_name() const { return "+"; } + Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a) + { + max_length= len + 2; + decimals= dec; + } + String *val_str(String *str); double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal*); + enum Item_result result_type () const { return DECIMAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } + void fix_length_and_dec() {}; }; -class Item_func_minus :public Item_num_op + +class Item_func_additive_op :public Item_num_op { public: - Item_func_minus(Item *a,Item *b) :Item_num_op(a,b) {} + Item_func_additive_op(Item *a,Item *b) :Item_num_op(a,b) {} + void result_precision(); +}; + + +class Item_func_plus :public Item_func_additive_op +{ +public: + Item_func_plus(Item *a,Item *b) :Item_func_additive_op(a,b) {} + const char *func_name() const { return "+"; } + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); +}; + +class Item_func_minus :public Item_func_additive_op +{ +public: + Item_func_minus(Item *a,Item *b) :Item_func_additive_op(a,b) {} const char *func_name() const { return "-"; } - double val_real(); - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); }; @@ -278,8 +337,10 @@ class Item_func_mul :public Item_num_op public: Item_func_mul(Item *a,Item *b) :Item_num_op(a,b) {} const char *func_name() const { return "*"; } - double val_real(); - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); + void result_precision(); }; @@ -287,22 +348,27 @@ class Item_func_div :public Item_num_op { public: Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {} - double val_real(); - longlong val_int(); + longlong int_op() { DBUG_ASSERT(0); } + double real_op(); + my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "/"; } void fix_length_and_dec(); + void result_precision(); }; -class Item_func_int_div :public Item_num_op +class Item_func_int_div :public Item_func { public: - Item_func_int_div(Item *a,Item *b) :Item_num_op(a,b) - { hybrid_type=INT_RESULT; } + Item_func_int_div(Item *a,Item *b) :Item_func(a,b) + {} double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } longlong val_int(); + String *val_str(String*str); const char *func_name() const { return "DIV"; } void fix_length_and_dec(); + void print(String *str) { print_op(str); } + enum Item_result result_type () const { return INT_RESULT; } }; @@ -310,37 +376,47 @@ class Item_func_mod :public Item_num_op { public: Item_func_mod(Item *a,Item *b) :Item_num_op(a,b) {} - double val_real(); - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "%"; } + void result_precision(); +}; + + +class Item_func_signproc :public Item_func_num1 +{ +public: + Item_func_signproc(Item *a) :Item_func_num1(a) {} + Item_func_signproc(Item *a, Item *b) :Item_func_num1(a, b) {} void fix_length_and_dec(); }; -class Item_func_neg :public Item_num_func +class Item_func_neg :public Item_func_signproc { public: - Item_func_neg(Item *a) :Item_num_func(a) {} - double val_real(); - longlong val_int(); + Item_func_neg(Item *a) :Item_func_signproc(a) {} + double real_op(); + longlong int_op(); + my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "-"; } - void fix_length_and_dec(); + void fix_num_length_and_dec(); }; -class Item_func_abs :public Item_num_func +class Item_func_abs :public Item_func_num1 { public: - Item_func_abs(Item *a) :Item_num_func(a) {} + Item_func_abs(Item *a) :Item_func_num1(a) {} + double real_op(); + longlong int_op(); + my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "abs"; } - double val_real(); - longlong val_int(); - enum Item_result result_type () const - { return args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT; } void fix_length_and_dec(); }; -// A class to handle logaritmic and trigometric functions +// A class to handle logarithmic and trigonometric functions class Item_dec_func :public Item_real_func { @@ -487,34 +563,49 @@ public: }; -class Item_func_ceiling :public Item_func_integer +class Item_func_int_val :public Item_func_num1 { - Item_func_ceiling(); /* Never called */ public: - Item_func_ceiling(Item *a) :Item_func_integer(a) {} - const char *func_name() const { return "ceiling"; } - longlong val_int(); + Item_func_int_val(Item *a) :Item_func_num1(a) {} + void fix_num_length_and_dec(); + void find_num_type(); }; -class Item_func_floor :public Item_func_integer + +class Item_func_ceiling :public Item_func_int_val { public: - Item_func_floor(Item *a) :Item_func_integer(a) {} + Item_func_ceiling(Item *a) :Item_func_int_val(a) {} + const char *func_name() const { return "ceiling"; } + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); +}; + + +class Item_func_floor :public Item_func_int_val +{ +public: + Item_func_floor(Item *a) :Item_func_int_val(a) {} const char *func_name() const { return "floor"; } - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); }; /* This handles round and truncate */ -class Item_func_round :public Item_real_func +class Item_func_round :public Item_func_num1 { bool truncate; public: - Item_func_round(Item *a,Item *b,bool trunc_arg) - :Item_real_func(a,b),truncate(trunc_arg) {} + Item_func_round(Item *a, Item *b, bool trunc_arg) + :Item_func_num1(a,b), truncate(trunc_arg) {} const char *func_name() const { return truncate ? "truncate" : "round"; } - double val_real(); - void fix_length_and_dec(); + double real_op(); + longlong int_op(); + my_decimal *decimal_op(my_decimal *); + void fix_num_length_and_dec(); }; @@ -550,7 +641,8 @@ class Item_func_units :public Item_real_func :Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {} double val_real(); const char *func_name() const { return name; } - void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); } + void fix_length_and_dec() + { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } }; @@ -565,6 +657,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec(); enum Item_result result_type () const { return cmp_type; } table_map not_null_tables() const { return 0; } @@ -751,7 +844,11 @@ public: Item_func_last_insert_id(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "last_insert_id"; } - void fix_length_and_dec() { if (arg_count) max_length= args[0]->max_length; } + void fix_length_and_dec() + { + if (arg_count) + max_length= args[0]->max_length; + } }; class Item_func_benchmark :public Item_int_func @@ -805,6 +902,14 @@ class Item_func_udf_float :public Item_udf_func DBUG_ASSERT(fixed == 1); return (longlong) Item_func_udf_float::val_real(); } + my_decimal *val_decimal(my_decimal *dec_buf) + { + double res=val_real(); + if (null_value) + return NULL; + double2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); + return dec_buf; + } double val_real(); String *val_str(String *str); void fix_length_and_dec() { fix_num_length_and_dec(); } @@ -821,7 +926,22 @@ public: double val_real() { return (double) Item_func_udf_int::val_int(); } String *val_str(String *str); enum Item_result result_type () const { return INT_RESULT; } - void fix_length_and_dec() { decimals=0; max_length=21; } + void fix_length_and_dec() { decimals= 0; max_length= 21; } +}; + + +class Item_func_udf_decimal :public Item_udf_func +{ +public: + Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_decimal(udf_func *udf_arg, List &list) + :Item_udf_func(udf_arg,list) {} + longlong val_int(); + double val_real(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String *str); + enum Item_result result_type () const { return DECIMAL_RESULT; } + void fix_length_and_dec(); }; @@ -848,6 +968,14 @@ public: return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err_not_used) : (longlong) 0; } + my_decimal *val_decimal(my_decimal *dec_buf) + { + String *res=val_str(&str_value); + if (!res) + return NULL; + string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); + return dec_buf; + } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); }; @@ -872,6 +1000,15 @@ public: }; +class Item_func_udf_decimal :public Item_int_func +{ +public: + Item_func_udf_decimal(udf_func *udf_arg) :Item_int_func() {} + Item_func_udf_decimal(udf_func *udf_arg, List &list) :Item_int_func(list) {} + my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } +}; + + class Item_func_udf_str :public Item_func { public: @@ -930,7 +1067,7 @@ class Item_master_pos_wait :public Item_int_func }; -/* Handling of user definiable variables */ +/* Handling of user definable variables */ class user_var_entry; @@ -941,11 +1078,13 @@ class Item_func_set_user_var :public Item_func user_var_entry *entry; char buffer[MAX_FIELD_WIDTH]; String value; + my_decimal decimal_buff; union { longlong vint; double vreal; String *vstr; + my_decimal *vdec; } save_result; String save_buff; @@ -957,6 +1096,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); bool update_hash(void *ptr, uint length, enum Item_result type, CHARSET_INFO *cs, Derivation dv); bool check(); @@ -982,6 +1122,7 @@ public: LEX_STRING get_name() { return name; } double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal*); String *val_str(String* str); void fix_length_and_dec(); void print(String *str); @@ -1091,7 +1232,8 @@ public: enum Cast_target { ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT, - ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR + ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR, + ITEM_CAST_DECIMAL }; @@ -1157,6 +1299,22 @@ public: return d; } + my_decimal *val_decimal(my_decimal *dec_buf) + { + Item *it; + my_decimal *result; + + if (execute(&it)) + { + null_value= 1; + return NULL; + } + result= it->val_decimal(dec_buf); + null_value= it->null_value; + return result; + } + + String *val_str(String *str) { Item *it; diff --git a/sql/item_row.cc b/sql/item_row.cc index 62f31186b09..08c682afa85 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -84,21 +84,25 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) return FALSE; } + void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array, List &fields) { Item **arg, **arg_end; for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++) { - if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM) - (*arg)->split_sum_func(thd, ref_pointer_array, fields); - else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM) + Item *item= *arg; + if (item->type() != SUM_FUNC_ITEM && + (item->with_sum_func || + (item->used_tables() & PSEUDO_TABLE_BITS))) + item->split_sum_func(thd, ref_pointer_array, fields); + else if (item->type() == SUM_FUNC_ITEM || + (item->used_tables() && item->type() != REF_ITEM)) { uint el= fields.elements; - ref_pointer_array[el]=*arg; + ref_pointer_array[el]= *arg; Item *new_item= new Item_ref(ref_pointer_array + el, 0, (*arg)->name); fields.push_front(*arg); - ref_pointer_array[el]= *arg; thd->change_item_tree(arg, new_item); } } diff --git a/sql/item_row.h b/sql/item_row.h index 64bd5cbbb44..e6b23eebb49 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -56,6 +56,11 @@ public: illegal_method_call((const char*)"val_str"); return 0; }; + my_decimal *val_decimal(my_decimal *) + { + illegal_method_call((const char*)"val_decimal"); + return 0; + }; bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); table_map used_tables() const { return used_tables_cache; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index f9843692b7b..55185a5f75b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -49,6 +49,8 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, uint nr_of_decimals(const char *str) { + if (strchr(str,'e') || strchr(str,'E')) + return NOT_FIXED_DEC; if ((str=strchr(str,'.'))) { const char *start= ++str; @@ -1776,15 +1778,17 @@ String *Item_func_elt::val_str(String *str) void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array, List &fields) { - if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) + if (item->type() != SUM_FUNC_ITEM && + (item->with_sum_func || + (item->used_tables() & PSEUDO_TABLE_BITS))) item->split_sum_func(thd, ref_pointer_array, fields); - else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) + else if (item->type() == SUM_FUNC_ITEM || + (item->used_tables() && item->type() != REF_ITEM)) { uint el= fields.elements; - ref_pointer_array[el]=item; + ref_pointer_array[el]= item; Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name); fields.push_front(item); - ref_pointer_array[el]= item; thd->change_item_tree(&item, new_item); } Item_str_func::split_sum_func(thd, ref_pointer_array, fields); @@ -1800,7 +1804,7 @@ void Item_func_make_set::fix_length_and_dec() for (uint i=0 ; i < arg_count ; i++) max_length+=args[i]->max_length; - + used_tables_cache|= item->used_tables(); not_null_tables_cache&= item->not_null_tables(); const_item_cache&= item->const_item(); @@ -2189,6 +2193,7 @@ String *Item_func_conv::val_str(String *str) return 0; } null_value=0; + unsigned_flag= !(from_base < 0); if (from_base < 0) dec= my_strntoll(res->charset(),res->ptr(),res->length(),-from_base,&endptr,&err); else @@ -2643,18 +2648,13 @@ String *Item_func_quote::val_str(String *str) for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++) new_length+= get_esc_bit(escmask, (uchar) *from); - /* - We have to use realloc() instead of alloc() as we want to keep the - old result in arg - */ - if (arg->realloc(new_length)) + if (tmp_value.alloc(new_length)) goto null; /* - As 'arg' and 'str' may be the same string, we must replace characters - from the end to the beginning + We replace characters from the end to the beginning */ - to= (char*) arg->ptr() + new_length - 1; + to= (char*) tmp_value.ptr() + new_length - 1; *to--= '\''; for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--) { @@ -2682,10 +2682,10 @@ String *Item_func_quote::val_str(String *str) } } *to= '\''; - arg->length(new_length); - str->set_charset(collation.collation); + tmp_value.length(new_length); + tmp_value.set_charset(collation.collation); null_value= 0; - return arg; + return &tmp_value; null: null_value= 1; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index e322e5616a1..dc50c9a4ccd 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -397,8 +397,7 @@ public: bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { DBUG_ASSERT(fixed == 0); - return (!item->fixed && - item->fix_fields(thd, tlist, &item) || + return ((!item->fixed && item->fix_fields(thd, tlist, &item)) || item->check_cols(1) || Item_func::fix_fields(thd, tlist, ref)); } @@ -596,6 +595,7 @@ public: class Item_func_quote :public Item_str_func { + String tmp_value; public: Item_func_quote(Item *a) :Item_str_func(a) {} const char *func_name() const { return "quote"; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d6d58adaf7c..8d392232f02 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -53,7 +53,7 @@ void Item_subselect::init(st_select_lex *select_lex, { DBUG_ENTER("Item_subselect::init"); - DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex)); + DBUG_PRINT("enter", ("select_lex: 0x%x", (ulong) select_lex)); unit= select_lex->master_unit(); if (unit->item) @@ -143,7 +143,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) res= engine->prepare(); - // all transformetion is done (used by prepared statements) + // all transformation is done (used by prepared statements) changed= 1; if (!res) @@ -246,7 +246,7 @@ void Item_subselect::update_used_tables() { if (!engine->uncacheable()) { - // did all used tables become ststic? + // did all used tables become static? if (!(used_tables_cache & ~engine->upper_select_const_tables())) const_item_cache= 1; } @@ -292,7 +292,7 @@ Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param, const_item_cache= parent->get_const_item_cache(); /* - this subquery alwais creates during preparation, so we can assign + this subquery always creates during preparation, so we can assign thd here */ thd= thd_param; @@ -356,7 +356,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) !(select_lex->item_list.head()->type() == FIELD_ITEM || select_lex->item_list.head()->type() == REF_ITEM) && /* - switch off this optimisation for prepare statement, + switch off this optimization for prepare statement, because we do not rollback this changes TODO: make rollback for it, or special name resolving mode in 5.0. */ @@ -374,7 +374,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) } substitution= select_lex->item_list.head(); /* - as far as we moved content to upper leven, field which depend of + as far as we moved content to upper level, field which depend of 'upper' select is not really dependent => we remove this dependence */ substitution->walk(&Item::remove_dependence_processor, @@ -494,7 +494,7 @@ longlong Item_singlerow_subselect::val_int() } } -String *Item_singlerow_subselect::val_str (String *str) +String *Item_singlerow_subselect::val_str(String *str) { if (!exec() && !value->null_value) { @@ -509,10 +509,41 @@ String *Item_singlerow_subselect::val_str (String *str) } +my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value) +{ + if (!exec() && !value->null_value) + { + null_value= 0; + return value->val_decimal(decimal_value); + } + else + { + reset(); + return 0; + } +} + + +bool Item_singlerow_subselect::val_bool() +{ + if (!exec() && !value->null_value) + { + null_value= 0; + return value->val_bool(); + } + else + { + reset(); + return 0; + } +} + + Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): Item_subselect() { DBUG_ENTER("Item_exists_subselect::Item_exists_subselect"); + bool val_bool(); init(select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; null_value= 0; //can't be NULL @@ -622,6 +653,32 @@ String *Item_exists_subselect::val_str(String *str) return str; } + +my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + return 0; + } + int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); + return decimal_value; +} + + +bool Item_exists_subselect::val_bool() +{ + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + return 0; + } + return value; +} + + double Item_in_subselect::val_real() { DBUG_ASSERT(fixed == 1); @@ -752,7 +809,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, /* Item_sum_(max|min) can't substitute other item => we can use 0 as - reference + reference, also Item_sum_(max|min) can't be fixed after creation, so + we do not check item->fixed */ if (item->fix_fields(thd, join->tables_list, 0)) goto err; @@ -774,7 +832,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, // left expression belong to outer select SELECT_LEX *current= thd->lex->current_select, *up; thd->lex->current_select= up= current->return_after_parsing(); - if (!left_expr->fixed && + if (!left_expr->fixed && left_expr->fix_fields(thd, up->get_table_list(), &left_expr)) { thd->lex->current_select= current; @@ -803,7 +861,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, thd->lex->current_select= current; /* - As far as Item_ref_in_optimizer do not substitude itself on fix_fields + As far as Item_ref_in_optimizer do not substitute itself on fix_fields we can use same item for all selects. */ expr= new Item_direct_ref((Item**)optimizer->get_cache(), @@ -840,6 +898,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, */ select_lex->having= join->having= and_items(join->having, item); select_lex->having_fix_field= 1; + /* + we do not check join->having->fixed, because Item_and (from and_items) + or comparison function (from func->create) can't be fixed after creation + */ tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; if (tmp) @@ -871,6 +933,11 @@ Item_in_subselect::single_value_transformer(JOIN *join, new Item_cond_and(having, join->having) : having); select_lex->having_fix_field= 1; + /* + we do not check join->having->fixed, because Item_and (from + and_items) or comparison function (from func->create) can't be + fixed after creation + */ tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; if (tmp) @@ -887,6 +954,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, argument (reference) to fix_fields() */ select_lex->where= join->conds= and_items(join->conds, item); + /* + we do not check join->conds->fixed, because Item_and can't be fixed + after creation + */ if (join->conds->fix_fields(thd, join->tables_list, 0)) goto err; } @@ -908,6 +979,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, item= new Item_cond_or(new Item_func_isnull(left_expr), item); select_lex->having= join->having= item; select_lex->having_fix_field= 1; + /* + we do not check join->having->fixed, because comparison function + (from func->create) can't be fixed after creation + */ tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; if (tmp) @@ -982,7 +1057,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) goto err; } - // we will refer to apper level cache array => we have to save it in PS + // we will refer to upper level cache array => we have to save it in PS optimizer->keep_top_level_cache(); thd->lex->current_select= current; @@ -995,10 +1070,14 @@ Item_in_subselect::row_value_transformer(JOIN *join) List_iterator_fast li(select_lex->item_list); for (uint i= 0; i < n; i++) { + DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); + if (select_lex->ref_pointer_array[i]-> + check_cols(left_expr->el(i)->cols())) + goto err; Item *func= new Item_ref_null_helper(this, - select_lex->ref_pointer_array+i, - (char *) "", - (char *) ""); + select_lex->ref_pointer_array+i, + (char *) "", + (char *) ""); func= eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> addr(i), @@ -1019,6 +1098,10 @@ Item_in_subselect::row_value_transformer(JOIN *join) */ select_lex->having= join->having= and_items(join->having, item); select_lex->having_fix_field= 1; + /* + join->having can't be fixed after creation, so we do not check + join->having->fixed + */ if (join->having->fix_fields(thd, join->tables_list, 0)) { select_lex->having_fix_field= 0; @@ -1034,6 +1117,10 @@ Item_in_subselect::row_value_transformer(JOIN *join) argument (reference) to fix_fields() */ select_lex->where= join->conds= and_items(join->conds, item); + /* + join->conds can't be fixed after creation, so we do not check + join->conds->fixed + */ if (join->conds->fix_fields(thd, join->tables_list, 0)) goto err; } @@ -1117,6 +1204,7 @@ void subselect_single_select_engine::cleanup() DBUG_ENTER("subselect_single_select_engine::cleanup"); prepared= optimized= executed= 0; join= 0; + result->cleanup(); DBUG_VOID_RETURN; } @@ -1125,6 +1213,7 @@ void subselect_union_engine::cleanup() { DBUG_ENTER("subselect_union_engine::cleanup"); unit->reinit_exec_mechanism(); + result->cleanup(); DBUG_VOID_RETURN; } @@ -1132,6 +1221,10 @@ void subselect_union_engine::cleanup() void subselect_uniquesubquery_engine::cleanup() { DBUG_ENTER("subselect_uniquesubquery_engine::cleanup"); + /* + subselect_uniquesubquery_engine have not 'result' assigbed, so we do not + cleanup() it + */ DBUG_VOID_RETURN; } @@ -1415,13 +1508,15 @@ int subselect_indexsubquery_engine::exec() uint subselect_single_select_engine::cols() { - return select_lex->item_list.elements; + DBUG_ASSERT(select_lex->join); // should be called after fix_fields() + return select_lex->join->fields_list.elements; } uint subselect_union_engine::cols() { - return unit->first_select()->item_list.elements; + DBUG_ASSERT(unit->is_prepared()); // should be called after fix_fields() + return unit->types.elements; } @@ -1521,7 +1616,7 @@ void subselect_indexsubquery_engine::print(String *str) str->append(" on ", 4); str->append(key_info->name); if (check_null) - str->append(" chicking NULL", 14); + str->append(" checking NULL", 14); if (cond) { str->append(" where ", 7); @@ -1533,7 +1628,7 @@ void subselect_indexsubquery_engine::print(String *str) /* change select_result object of engine - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object @@ -1555,7 +1650,7 @@ bool subselect_single_select_engine::change_result(Item_subselect *si, /* change select_result object of engine - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object @@ -1578,7 +1673,7 @@ bool subselect_union_engine::change_result(Item_subselect *si, /* change select_result emulation, never should be called - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object @@ -1599,7 +1694,7 @@ bool subselect_uniquesubquery_engine::change_result(Item_subselect *si, /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_single_select_engine::no_tables() RETURN @@ -1615,7 +1710,7 @@ bool subselect_single_select_engine::no_tables() /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_union_engine::no_tables() RETURN @@ -1636,7 +1731,7 @@ bool subselect_union_engine::no_tables() /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_uniquesubquery_engine::no_tables() RETURN diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 53fe21a9bb6..4661fae81da 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -142,6 +142,8 @@ public: double val_real(); longlong val_int (); String *val_str (String *); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); enum Item_result result_type() const; void fix_length_and_dec(); @@ -155,7 +157,7 @@ public: friend class select_singlerow_subselect; }; -/* used in static ALL/ANY optimisation */ +/* used in static ALL/ANY optimization */ class select_max_min_finder_subselect; class Item_maxmin_subselect :public Item_singlerow_subselect { @@ -193,6 +195,8 @@ public: longlong val_int(); double val_real(); String *val_str(String*); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); void fix_length_and_dec(); void print(String *str); @@ -294,7 +298,7 @@ public: virtual int prepare()= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; virtual int exec()= 0; - virtual uint cols()= 0; /* return number of columnss in select */ + virtual uint cols()= 0; /* return number of columns in select */ virtual uint8 uncacheable()= 0; /* query is uncacheable */ enum Item_result type() { return res_type; } virtual void exclude()= 0; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 29837c3afbd..2ecc1eb083c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -124,6 +124,16 @@ Item *Item_sum::get_tmp_table_item(THD *thd) return sum_item; } + +my_decimal *Item_sum::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed); + DBUG_ASSERT(decimal_value); + int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value); + return decimal_value; +} + + bool Item_sum::walk (Item_processor processor, byte *argument) { if (arg_count) @@ -139,6 +149,32 @@ bool Item_sum::walk (Item_processor processor, byte *argument) } +Field *Item_sum::create_tmp_field(bool group, TABLE *table, + uint convert_blob_length) +{ + switch (result_type()) { + case REAL_RESULT: + return new Field_double(max_length,maybe_null,name,table,decimals); + case INT_RESULT: + return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag); + case STRING_RESULT: + if (max_length > 255 && convert_blob_length) + return new Field_varstring(convert_blob_length, maybe_null, + name, table, + collation.collation); + return make_string_field(table); + case DECIMAL_RESULT: + return new Field_new_decimal(max_length - (decimals?1:0), + maybe_null, name, table, decimals); + case ROW_RESULT: + default: + // This case should never be choosen + DBUG_ASSERT(0); + return 0; + } +} + + String * Item_sum_num::val_str(String *str) { @@ -151,6 +187,17 @@ Item_sum_num::val_str(String *str) } +my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + double nr= val_real(); + if (null_value) + return 0; + double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); + return (decimal_value); +} + + String * Item_sum_int::val_str(String *str) { @@ -184,8 +231,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1)) return TRUE; - if (decimals < args[i]->decimals) - decimals=args[i]->decimals; + set_if_bigger(decimals, args[i]->decimals); maybe_null |= args[i]->maybe_null; } result_field=0; @@ -198,6 +244,29 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } +Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) + :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), + hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), + used_table_cache(item->used_table_cache), was_values(item->was_values) +{ + switch (hybrid_type) + { + case INT_RESULT: + sum_int= item->sum_int; + break; + case DECIMAL_RESULT: + my_decimal2decimal(&item->sum_dec, &sum_dec); + break; + case REAL_RESULT: + sum= item->sum; + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + collation.set(item->collation); +} + bool Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { @@ -217,20 +286,29 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) item->fix_fields(thd, tables, args) || (item= args[0])->check_cols(1)) return TRUE; - - hybrid_type= item->result_type(); - if (hybrid_type == INT_RESULT) - { - max_length=20; - } - else if (hybrid_type == REAL_RESULT) - { - max_length=float_length(decimals); - }else - { - max_length=item->max_length; - } decimals=item->decimals; + + switch (hybrid_type= item->result_type()) + { + case INT_RESULT: + max_length= 20; + sum_int= 0; + break; + case DECIMAL_RESULT: + max_length= item->max_length; + my_decimal_set_zero(&sum_dec); + break; + case REAL_RESULT: + max_length= float_length(decimals); + sum= 0.0; + break; + case STRING_RESULT: + max_length= item->max_length; + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + }; /* MIN/MAX can return NULL for empty set indepedent of the used column */ maybe_null= 1; unsigned_flag=item->unsigned_flag; @@ -252,6 +330,19 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ** reset and add of sum_func ***********************************************************************/ +Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item) + :Item_sum_num(thd, item), hybrid_type(item->hybrid_type), + curr_dec_buff(item->curr_dec_buff) +{ + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal2decimal(item->dec_buffs, dec_buffs); + my_decimal2decimal(item->dec_buffs + 1, dec_buffs + 1); + } + else + sum= item->sum; +} + Item *Item_sum_sum::copy_or_same(THD* thd) { return new (thd->mem_root) Item_sum_sum(thd, this); @@ -260,30 +351,128 @@ Item *Item_sum_sum::copy_or_same(THD* thd) void Item_sum_sum::clear() { - null_value=1; sum=0.0; + DBUG_ENTER("Item_sum_sum::clear"); + null_value=1; + if (hybrid_type == DECIMAL_RESULT) + { + curr_dec_buff= 0; + my_decimal_set_zero(dec_buffs); + } + else + sum= 0.0; + DBUG_VOID_RETURN; +} + + +void Item_sum_sum::fix_length_and_dec() +{ + DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); + maybe_null=null_value=1; + decimals= args[0]->decimals; + switch (args[0]->result_type()) + { + case REAL_RESULT: + case STRING_RESULT: + hybrid_type= REAL_RESULT; + sum= 0.0; + break; + case INT_RESULT: + case DECIMAL_RESULT: + /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */ + max_length= min(args[0]->max_length + DECIMAL_LONGLONG_DIGITS, + DECIMAL_MAX_LENGTH); + curr_dec_buff= 0; + hybrid_type= DECIMAL_RESULT; + my_decimal_set_zero(dec_buffs); + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s (%d, %d)", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"), + max_length, + (int)decimals)); + DBUG_VOID_RETURN; } bool Item_sum_sum::add() { - sum+= args[0]->val_real(); - if (!args[0]->null_value) - null_value= 0; - return 0; + DBUG_ENTER("Item_sum_sum::add"); + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), + val, dec_buffs + curr_dec_buff); + curr_dec_buff^= 1; + null_value= 0; + } + } + else + { + sum+= args[0]->val_real(); + if (!args[0]->null_value) + null_value= 0; + } + DBUG_RETURN(0); +} + + +longlong Item_sum_sum::val_int() +{ + DBUG_ASSERT(fixed == 1); + if (hybrid_type == DECIMAL_RESULT) + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag, + &result); + return result; + } + return Item_sum_num::val_int(); } double Item_sum_sum::val_real() { DBUG_ASSERT(fixed == 1); + if (hybrid_type == DECIMAL_RESULT) + my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum); return sum; } +String *Item_sum_sum::val_str(String*str) +{ + if (hybrid_type == DECIMAL_RESULT) + { + if (null_value) + return NULL; + my_decimal_round(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, decimals, + FALSE, dec_buffs + curr_dec_buff); + my_decimal2string(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, + 0, 0, 0, str); + return str; + } + return Item_sum_num::val_str(str); +} + + +my_decimal *Item_sum_sum::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(hybrid_type == DECIMAL_RESULT); + return(dec_buffs + curr_dec_buff); +} + /* Item_sum_sum_distinct */ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) - :Item_sum_num(item), sum(0.0), tree(0) + :Item_sum_sum(item), tree(0) { /* quick_group is an optimizer hint, which means that GROUP BY can be @@ -297,12 +486,24 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *original) - :Item_sum_num(thd, original), sum(0.0), tree(0) + :Item_sum_sum(thd, original), tree(0), dec_bin_buff(original->dec_bin_buff) { quick_group= 0; } +void Item_sum_sum_distinct::fix_length_and_dec() +{ + Item_sum_sum::fix_length_and_dec(); + if (hybrid_type == DECIMAL_RESULT) + { + dec_bin_buff= (byte *) + sql_alloc(my_decimal_get_binary_size(args[0]->max_length, + args[0]->decimals)); + } +} + + Item * Item_sum_sum_distinct::copy_or_same(THD *thd) { @@ -320,10 +521,11 @@ C_MODE_END bool Item_sum_sum_distinct::setup(THD *thd) { + DBUG_ENTER("Item_sum_sum_distinct::setup"); SELECT_LEX *select_lex= thd->lex->current_select; /* what does it mean??? */ if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) - return 1; + DBUG_RETURN(1); DBUG_ASSERT(tree == 0); /* setup can not be called twice */ @@ -337,17 +539,25 @@ bool Item_sum_sum_distinct::setup(THD *thd) TODO: if underlying item result fits in 4 bytes we can take advantage of it and have tree of long/ulong. It gives 10% performance boost */ - static uint key_length= sizeof(double); - tree= new Unique(simple_raw_key_cmp, &key_length, key_length, + uint *key_length_ptr= (uint *)thd->alloc(sizeof(uint)); + *key_length_ptr= ((hybrid_type == DECIMAL_RESULT) ? + my_decimal_get_binary_size(args[0]->max_length, + args[0]->decimals) : + sizeof(double)); + tree= new Unique(simple_raw_key_cmp, key_length_ptr, *key_length_ptr, thd->variables.max_heap_table_size); - return tree == 0; + DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree, + *key_length_ptr)); + DBUG_RETURN(tree == 0); } void Item_sum_sum_distinct::clear() { + DBUG_ENTER("Item_sum_sum_distinct::clear"); DBUG_ASSERT(tree); /* we always have a tree */ null_value= 1; tree->reset(); + DBUG_VOID_RETURN; } void Item_sum_sum_distinct::cleanup() @@ -360,25 +570,71 @@ void Item_sum_sum_distinct::cleanup() bool Item_sum_sum_distinct::add() { - /* args[0]->val_real() may reset args[0]->null_value */ - double val= args[0]->val_real(); - if (!args[0]->null_value) + DBUG_ENTER("Item_sum_sum_distinct::add"); + if (hybrid_type == DECIMAL_RESULT) { - DBUG_ASSERT(tree); - null_value= 0; - if (val) - return tree->unique_add(&val); + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + DBUG_ASSERT(tree); + null_value= 0; + my_decimal2binary(E_DEC_FATAL_ERROR, val, dec_bin_buff, + args[0]->max_length, args[0]->decimals); + DBUG_RETURN(tree->unique_add(dec_bin_buff)); + } } - return 0; + else + { + /* args[0]->val() may reset args[0]->null_value */ + double val= args[0]->val_real(); + if (!args[0]->null_value) + { + DBUG_ASSERT(tree); + null_value= 0; + DBUG_PRINT("info", ("real: %lg, tree 0x%lx", val, (ulong)tree)); + if (val) + DBUG_RETURN(tree->unique_add(&val)); + } + else + DBUG_PRINT("info", ("real: NULL")); + } + DBUG_RETURN(0); +} + + +void Item_sum_sum_distinct::add_real(double val) +{ + DBUG_ENTER("Item_sum_sum_distinct::add_real"); + sum+= val; + DBUG_PRINT("info", ("sum %lg, val %lg", sum, val)); + DBUG_VOID_RETURN; +} + + +void Item_sum_sum_distinct::add_decimal(byte *val) +{ + binary2my_decimal(E_DEC_FATAL_ERROR, val, &tmp_dec, + args[0]->max_length, args[0]->decimals); + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), + &tmp_dec, dec_buffs + curr_dec_buff); + curr_dec_buff^= 1; } C_MODE_START -static int sum_sum_distinct(void *element, element_count num_of_dups, - void *item_sum_sum_distinct) +static int sum_sum_distinct_real(void *element, element_count num_of_dups, + void *item_sum_sum_distinct) { ((Item_sum_sum_distinct *) - (item_sum_sum_distinct))->add(* (double *) element); + (item_sum_sum_distinct))->add_real(* (double *) element); + return 0; +} + +static int sum_sum_distinct_decimal(void *element, element_count num_of_dups, + void *item_sum_sum_distinct) +{ + ((Item_sum_sum_distinct *) + (item_sum_sum_distinct))->add_decimal((byte *)element); return 0; } @@ -386,16 +642,86 @@ C_MODE_END double Item_sum_sum_distinct::val_real() { + DBUG_ENTER("Item_sum_sum_distinct::val"); /* We don't have a tree only if 'setup()' hasn't been called; this is the case of sql_select.cc:return_zero_rows. */ - sum= 0.0; - if (tree) - tree->walk(sum_sum_distinct, (void *) this); - return sum; + if (hybrid_type == DECIMAL_RESULT) + { + /* Item_sum_sum_distinct::val_decimal do not use argument */ + my_decimal *val= val_decimal(0); + if (!null_value) + my_decimal2double(E_DEC_FATAL_ERROR, val, &sum); + } + else + { + sum= 0.0; + DBUG_PRINT("info", ("tree 0x%lx", (ulong)tree)); + if (tree) + tree->walk(sum_sum_distinct_real, (void *) this); + } + DBUG_RETURN(sum); } + +my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake) +{ + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal_set_zero(dec_buffs); + curr_dec_buff= 0; + if (tree) + tree->walk(sum_sum_distinct_decimal, (void *)this); + } + else + { + double real= val_real(); + double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs + curr_dec_buff); + } + return(dec_buffs + curr_dec_buff); +} + + +longlong Item_sum_sum_distinct::val_int() +{ + longlong i; + if (hybrid_type == DECIMAL_RESULT) + { + /* Item_sum_sum_distinct::val_decimal do not use argument */ + my_decimal *val= val_decimal(0); + if (!null_value) + my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &i); + } + else + i= (longlong) val_real(); + return i; +} + + +String *Item_sum_sum_distinct::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + if (hybrid_type == DECIMAL_RESULT) + { + /* Item_sum_sum_distinct::val_decimal do not use argument */ + my_decimal *val= val_decimal(0); + if (null_value) + return 0; + my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val); + my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); + } + else + { + double nr= val_real(); + if (null_value) + return 0; + str->set(nr, decimals, &my_charset_bin); + } + return str; +} + + /* end of Item_sum_sum_distinct */ Item *Item_sum_count::copy_or_same(THD* thd) @@ -442,6 +768,20 @@ void Item_sum_count::cleanup() /* Avgerage */ +void Item_sum_avg::fix_length_and_dec() +{ + Item_sum_sum::fix_length_and_dec(); + maybe_null=null_value=1; + decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC); + if (hybrid_type == DECIMAL_RESULT) + { + f_scale= args[0]->decimals; + max_length= DECIMAL_MAX_LENGTH + (f_scale ? 1 : 0); + f_precision= DECIMAL_MAX_LENGTH; + dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale); + } +} + Item *Item_sum_avg::copy_or_same(THD* thd) { @@ -449,21 +789,43 @@ Item *Item_sum_avg::copy_or_same(THD* thd) } +Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, + uint convert_blob_len) +{ + if (hybrid_type == DECIMAL_RESULT) + { + if (group) + return new Field_string(dec_bin_size + sizeof(longlong), + 0, name, table, &my_charset_bin); + else + return new Field_new_decimal(f_precision, + maybe_null, name, table, f_scale); + } + else + { + if (group) + return new Field_string(sizeof(double)+sizeof(longlong), + 0, name,table,&my_charset_bin); + else + return new Field_double(max_length, maybe_null, name, table, decimals); + } +} + + void Item_sum_avg::clear() { - sum=0.0; count=0; + Item_sum_sum::clear(); + count=0; } bool Item_sum_avg::add() { - double nr= args[0]->val_real(); + if (Item_sum_sum::add()) + return TRUE; if (!args[0]->null_value) - { - sum+=nr; count++; - } - return 0; + return FALSE; } double Item_sum_avg::val_real() @@ -474,11 +836,46 @@ double Item_sum_avg::val_real() null_value=1; return 0.0; } - null_value=0; - return sum/ulonglong2double(count); + return Item_sum_sum::val_real() / ulonglong2double(count); } +my_decimal *Item_sum_avg::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed == 1); + if (!count) + { + null_value=1; + return NULL; + } + my_decimal sum, cnt; + const my_decimal *sum_dec= Item_sum_sum::val_decimal(&sum); + int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); + my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4); + return val; +} + + +String *Item_sum_avg::val_str(String *str) +{ + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *dec_val= val_decimal(&value); + if (null_value) + return NULL; + my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value); + my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str); + return str; + } + double nr= val_real(); + if (null_value) + return NULL; + str->set(nr, decimals, &my_charset_bin); + return str; +} + + + /* Standard deviation */ @@ -500,26 +897,140 @@ Item *Item_sum_std::copy_or_same(THD* thd) Variance */ + +Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): + Item_sum_num(thd, item), hybrid_type(item->hybrid_type), + cur_dec(item->cur_dec), count(item->count) +{ + if (hybrid_type == DECIMAL_RESULT) + { + memcpy(dec_sum, item->dec_sum, sizeof(item->dec_sum)); + memcpy(dec_sqr, item->dec_sqr, sizeof(item->dec_sqr)); + for (int i=0; i<2; i++) + { + dec_sum[i].fix_buffer_pointer(); + dec_sqr[i].fix_buffer_pointer(); + } + } + else + { + sum= item->sum; + sum_sqr= item->sum_sqr; + } +} + + +void Item_sum_variance::fix_length_and_dec() +{ + DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); + maybe_null=null_value=1; + decimals= args[0]->decimals + 4; + switch (args[0]->result_type()) + { + case REAL_RESULT: + case STRING_RESULT: + hybrid_type= REAL_RESULT; + sum= 0.0; + break; + case INT_RESULT: + case DECIMAL_RESULT: + /* SUM result can't be longer than length(arg)*2 + digits_after_the_point_to_add*/ + max_length= args[0]->max_length*2 + 4; + cur_dec= 0; + hybrid_type= DECIMAL_RESULT; + my_decimal_set_zero(dec_sum); + my_decimal_set_zero(dec_sqr); + f_scale0= args[0]->decimals; + f_precision0= DECIMAL_MAX_LENGTH / 2; + f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1); + f_precision1= DECIMAL_MAX_LENGTH; + dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0); + dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1); + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s (%d, %d)", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"), + max_length, + (int)decimals)); + DBUG_VOID_RETURN; +} + + Item *Item_sum_variance::copy_or_same(THD* thd) { return new (thd->mem_root) Item_sum_variance(thd, this); } +Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, + uint convert_blob_len) +{ + if (hybrid_type == DECIMAL_RESULT) + { + if (group) + return new Field_string(dec_bin_size0+dec_bin_size1+sizeof(longlong), + 0, name,table,&my_charset_bin); + else + return new Field_new_decimal(DECIMAL_MAX_LENGTH, + maybe_null, name, table, f_scale1 + 4); + } + else + { + if (group) + return new Field_string(sizeof(double)*2+sizeof(longlong), + 0, name,table,&my_charset_bin); + else + return new Field_double(max_length, maybe_null,name,table,decimals); + } +} + + void Item_sum_variance::clear() { - sum=sum_sqr=0.0; + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal_set_zero(dec_sum); + my_decimal_set_zero(dec_sqr); + cur_dec= 0; + } + else + sum=sum_sqr=0.0; count=0; } bool Item_sum_variance::add() { - double nr= args[0]->val_real(); - if (!args[0]->null_value) + if (hybrid_type == DECIMAL_RESULT) { - sum+=nr; - sum_sqr+=nr*nr; - count++; + my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf); + my_decimal sqr_buf; + if (!args[0]->null_value) + { + count++; + int next_dec= cur_dec ^ 1; + my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr+next_dec, + dec_sqr+cur_dec, &sqr_buf); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sum+next_dec, + dec_sum+cur_dec, dec); + cur_dec= next_dec; + } + } + else + { + double nr= args[0]->val_real(); + if (!args[0]->null_value) + { + sum+=nr; + sum_sqr+=nr*nr; + count++; + } } return 0; } @@ -533,16 +1044,77 @@ double Item_sum_variance::val_real() return 0.0; } null_value=0; + if (hybrid_type == DECIMAL_RESULT) + { + double result; + my_decimal dec_buf, *dec= Item_sum_variance::val_decimal(&dec_buf); + my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); + return result; + } /* Avoid problems when the precision isn't good enough */ double tmp=ulonglong2double(count); double tmp2=(sum_sqr - sum*sum/tmp)/tmp; return tmp2 <= 0.0 ? 0.0 : tmp2; } + +my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) +{ + DBUG_ASSERT(fixed ==1 ); + if (hybrid_type == REAL_RESULT) + { + double result= Item_sum_variance::val_real(); + if (null_value) + return 0; + double2my_decimal(E_DEC_FATAL_ERROR, result, dec_buf); + return dec_buf; + } + if (!count) + { + null_value= 1; + return 0; + } + null_value= 0; + my_decimal count_buf, sum_sqr_buf; + int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf); + my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf, + dec_sum+cur_dec, dec_sum+cur_dec); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2); + my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2); + return dec_buf; +} + void Item_sum_variance::reset_field() { - double nr= args[0]->val_real(); char *res=result_field->ptr; + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *arg_dec= args[0]->val_decimal(&value); + if (args[0]->null_value) + { + my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, + res, f_precision0, f_scale0); + my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, + res+dec_bin_size0, f_precision1, f_scale1); + res+= dec_bin_size0 + dec_bin_size1; + longlong tmp=0; + int8store(res,tmp); + } + else + { + my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, + res, f_precision0, f_scale0); + my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec); + my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum, + res+dec_bin_size0, f_precision1, f_scale1); + res+= dec_bin_size0 + dec_bin_size1; + longlong tmp=1; + int8store(res,tmp); + } + return; + } + double nr= args[0]->val_real(); if (args[0]->null_value) bzero(res,sizeof(double)*2+sizeof(longlong)); @@ -558,10 +1130,33 @@ void Item_sum_variance::reset_field() void Item_sum_variance::update_field() { - double nr,old_nr,old_sqr; longlong field_count; char *res=result_field->ptr; + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *arg_val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + binary2my_decimal(E_DEC_FATAL_ERROR, res, + dec_sum+1, f_precision0, f_scale0); + binary2my_decimal(E_DEC_FATAL_ERROR, res+dec_bin_size0, + dec_sqr+1, f_precision1, f_scale1); + field_count= sint8korr(res + (dec_bin_size0 + dec_bin_size1)); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sum, arg_val, dec_sum+1); + my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum+1, arg_val, arg_val); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr, dec_sqr+1, dec_sum+1); + field_count++; + my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum, + res, f_precision0, f_scale0); + my_decimal2binary(E_DEC_FATAL_ERROR, dec_sqr, + res+dec_bin_size0, f_precision1, f_scale1); + res+= dec_bin_size0 + dec_bin_size1; + int8store(res, field_count); + } + return; + } + double nr,old_nr,old_sqr; float8get(old_nr, res); float8get(old_sqr, res+sizeof(double)); field_count=sint8korr(res+sizeof(double)*2); @@ -582,9 +1177,20 @@ void Item_sum_variance::update_field() void Item_sum_hybrid::clear() { - sum= 0.0; - sum_int= 0; - value.length(0); + switch (hybrid_type) + { + case INT_RESULT: + sum_int= 0; + break; + case DECIMAL_RESULT: + my_decimal_set_zero(&sum_dec); + break; + case REAL_RESULT: + sum= 0.0; + break; + default: + value.length(0); + } null_value= 1; } @@ -606,6 +1212,9 @@ double Item_sum_hybrid::val_real() if (unsigned_flag) return ulonglong2double(sum_int); return (double) sum_int; + case DECIMAL_RESULT: + my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum); + return sum; case REAL_RESULT: return sum; case ROW_RESULT: @@ -622,9 +1231,47 @@ longlong Item_sum_hybrid::val_int() DBUG_ASSERT(fixed == 1); if (null_value) return 0; - if (hybrid_type == INT_RESULT) + switch (hybrid_type) + { + case INT_RESULT: return sum_int; - return (longlong) Item_sum_hybrid::val_real(); + case DECIMAL_RESULT: + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result); + return sum_int; + } + default: + return (longlong) Item_sum_hybrid::val_real(); + } +} + + +my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + switch (hybrid_type) { + case STRING_RESULT: + string2my_decimal(E_DEC_FATAL_ERROR, &value, val); + break; + case REAL_RESULT: + double2my_decimal(E_DEC_FATAL_ERROR, sum, val); + break; + case DECIMAL_RESULT: + val= &sum_dec; + break; + case INT_RESULT: + int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val); + break; + case ROW_RESULT: + default: + // This case should never be choosen + DBUG_ASSERT(0); + break; + } + return val; // Keep compiler happy } @@ -640,6 +1287,9 @@ Item_sum_hybrid::val_str(String *str) case REAL_RESULT: str->set(sum,decimals, &my_charset_bin); break; + case DECIMAL_RESULT: + my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str); + return str; case INT_RESULT: if (unsigned_flag) str->set((ulonglong) sum_int, &my_charset_bin); @@ -713,6 +1363,17 @@ bool Item_sum_min::add() } } break; + case DECIMAL_RESULT: + { + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value && + (null_value || (my_decimal_cmp(&sum_dec, val) > 0))) + { + my_decimal2decimal(val, &sum_dec); + null_value= 0; + } + } + break; case REAL_RESULT: { double nr= args[0]->val_real(); @@ -766,6 +1427,17 @@ bool Item_sum_max::add() } } break; + case DECIMAL_RESULT: + { + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value && + (null_value || (my_decimal_cmp(val, &sum_dec) > 0))) + { + my_decimal2decimal(val, &sum_dec); + null_value= 0; + } + } + break; case REAL_RESULT: { double nr= args[0]->val_real(); @@ -867,7 +1539,9 @@ void Item_sum_num::reset_field() void Item_sum_hybrid::reset_field() { - if (hybrid_type == STRING_RESULT) + switch(hybrid_type) + { + case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),result_field->charset()),*res; @@ -883,8 +1557,9 @@ void Item_sum_hybrid::reset_field() result_field->set_notnull(); result_field->store(res->ptr(),res->length(),tmp.charset()); } + break; } - else if (hybrid_type == INT_RESULT) + case INT_RESULT: { longlong nr=args[0]->val_int(); @@ -899,8 +1574,9 @@ void Item_sum_hybrid::reset_field() result_field->set_notnull(); } result_field->store(nr); + break; } - else // REAL_RESULT + case REAL_RESULT: { double nr= args[0]->val_real(); @@ -915,14 +1591,46 @@ void Item_sum_hybrid::reset_field() result_field->set_notnull(); } result_field->store(nr); + break; + } + case DECIMAL_RESULT: + { + my_decimal value, *arg_dec= args[0]->val_decimal(&value); + + if (maybe_null) + { + if (args[0]->null_value) + result_field->set_null(); + else + result_field->set_notnull(); + } + if (!args[0]->null_value) + result_field->store_decimal(arg_dec); + break; + } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } } void Item_sum_sum::reset_field() { - double nr= args[0]->val_real(); // Nulls also return 0 - float8store(result_field->ptr,nr); + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *arg_val= args[0]->val_decimal(&value); + if (args[0]->null_value) + result_field->reset(); + else + result_field->store_decimal(arg_val); + } + else + { + DBUG_ASSERT(hybrid_type == REAL_RESULT); + double nr= args[0]->val_real(); // Nulls also return 0 + float8store(result_field->ptr, nr); + } if (args[0]->null_value) result_field->set_null(); else @@ -949,17 +1657,40 @@ void Item_sum_count::reset_field() void Item_sum_avg::reset_field() { - double nr= args[0]->val_real(); char *res=result_field->ptr; - - if (args[0]->null_value) - bzero(res,sizeof(double)+sizeof(longlong)); + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *arg_dec= args[0]->val_decimal(&value); + if (args[0]->null_value) + { + my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, + res, f_precision, f_scale); + res+= dec_bin_size; + longlong tmp=0; + int8store(res,tmp); + } + else + { + my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, + res, f_precision, f_scale); + res+= dec_bin_size; + longlong tmp=1; + int8store(res,tmp); + } + } else { - float8store(res,nr); - res+=sizeof(double); - longlong tmp=1; - int8store(res,tmp); + double nr= args[0]->val_real(); + + if (args[0]->null_value) + bzero(res,sizeof(double)+sizeof(longlong)); + else + { + float8store(res,nr); + res+=sizeof(double); + longlong tmp=1; + int8store(res,tmp); + } } } @@ -983,17 +1714,39 @@ void Item_sum_bit::update_field() void Item_sum_sum::update_field() { - double old_nr,nr; - char *res=result_field->ptr; - - float8get(old_nr,res); - nr= args[0]->val_real(); - if (!args[0]->null_value) + if (hybrid_type == DECIMAL_RESULT) { - old_nr+=nr; - result_field->set_notnull(); + my_decimal value, *arg_val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + if (!result_field->is_null()) + { + my_decimal field_value, + *field_val= result_field->val_decimal(&field_value); + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val); + result_field->store_decimal(dec_buffs); + } + else + { + result_field->store_decimal(arg_val); + result_field->set_notnull(); + } + } + } + else + { + double old_nr,nr; + char *res=result_field->ptr; + + float8get(old_nr,res); + nr= args[0]->val_real(); + if (!args[0]->null_value) + { + old_nr+=nr; + result_field->set_notnull(); + } + float8store(res,old_nr); } - float8store(res,old_nr); } @@ -1017,32 +1770,59 @@ void Item_sum_count::update_field() void Item_sum_avg::update_field() { - double nr,old_nr; longlong field_count; char *res=result_field->ptr; - - float8get(old_nr,res); - field_count=sint8korr(res+sizeof(double)); - - nr= args[0]->val_real(); - if (!args[0]->null_value) + if (hybrid_type == DECIMAL_RESULT) { - old_nr+=nr; - field_count++; + my_decimal value, *arg_val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + binary2my_decimal(E_DEC_FATAL_ERROR, res, + dec_buffs + 1, f_precision, f_scale); + field_count= sint8korr(res + dec_bin_size); + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1); + field_count++; + my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs, + res, f_precision, f_scale); + res+= dec_bin_size; + int8store(res, field_count); + } + } + else + { + double nr, old_nr; + + float8get(old_nr, res); + field_count= sint8korr(res + sizeof(double)); + + nr= args[0]->val_real(); + if (!args[0]->null_value) + { + old_nr+= nr; + field_count++; + } + float8store(res,old_nr); + res+= sizeof(double); + int8store(res, field_count); } - float8store(res,old_nr); - res+=sizeof(double); - int8store(res,field_count); } void Item_sum_hybrid::update_field() { - if (hybrid_type == STRING_RESULT) + switch (hybrid_type) + { + case STRING_RESULT: min_max_update_str_field(); - else if (hybrid_type == INT_RESULT) + break; + case INT_RESULT: min_max_update_int_field(); - else + break; + case DECIMAL_RESULT: + min_max_update_decimal_field(); + break; + default: min_max_update_real_field(); + } } @@ -1112,41 +1892,119 @@ Item_sum_hybrid::min_max_update_int_field() } -Item_avg_field::Item_avg_field(Item_sum_avg *item) +void +Item_sum_hybrid::min_max_update_decimal_field() +{ + /* TODO: optimize: do not get result_field in case of args[0] is NULL */ + my_decimal old_val, nr_val; + const my_decimal *old_nr= result_field->val_decimal(&old_val); + const my_decimal *nr= args[0]->val_decimal(&nr_val); + if (!args[0]->null_value) + { + if (result_field->is_null(0)) + old_nr=nr; + else + { + bool res= my_decimal_cmp(old_nr, nr) > 0; + /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */ + if ((cmp_sign > 0) ^ (!res)) + old_nr=nr; + } + result_field->set_notnull(); + } + else if (result_field->is_null(0)) + result_field->set_null(); + result_field->store_decimal(old_nr); +} + + +Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item) { name=item->name; decimals=item->decimals; max_length=item->max_length; field=item->result_field; maybe_null=1; + hybrid_type= res_type; + if (hybrid_type == DECIMAL_RESULT) + { + f_scale= item->f_scale; + f_precision= item->f_precision; + dec_bin_size= item->dec_bin_size; + } } double Item_avg_field::val_real() { // fix_fields() never calls for this Item - double nr; - longlong count; - float8get(nr,field->ptr); - char *res=(field->ptr+sizeof(double)); - count=sint8korr(res); - - if (!count) + if (hybrid_type == DECIMAL_RESULT) { - null_value=1; - return 0.0; + my_decimal value, *dec_val= val_decimal(&value); + if (null_value) + return 0.0; + double d; + my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d); + return d; + } + else + { + double nr; + longlong count; + float8get(nr,field->ptr); + char *res=(field->ptr+sizeof(double)); + count=sint8korr(res); + + if (!count) + { + null_value=1; + return 0.0; + } + null_value=0; + return nr/(double) count; } - null_value=0; - return nr/(double) count; } +longlong Item_avg_field::val_int() +{ + return (longlong)val_real(); +} + + +my_decimal *Item_avg_field::val_decimal(my_decimal * val) +{ + // fix_fields() never calls for this Item + longlong count= sint8korr(field->ptr + dec_bin_size); + if ((null_value= !count)) + return NULL; + + my_decimal dec_count, dec_field; + binary2my_decimal(E_DEC_FATAL_ERROR, + field->ptr, &dec_field, f_precision, f_scale); + int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); + my_decimal_div(E_DEC_FATAL_ERROR, val, &dec_field, &dec_count, 4); + return val; +} + + String *Item_avg_field::val_str(String *str) { // fix_fields() never calls for this Item - double nr= Item_avg_field::val_real(); - if (null_value) - return 0; - str->set(nr,decimals, &my_charset_bin); + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *dec_val= val_decimal(&value); + if (null_value) + return NULL; + my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value); + my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str); + } + else + { + double nr= Item_avg_field::val_real(); + if (null_value) + return 0; + str->set(nr, decimals, &my_charset_bin); + } return str; } @@ -1169,11 +2027,29 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item) max_length=item->max_length; field=item->result_field; maybe_null=1; + if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT) + { + f_scale0= item->f_scale0; + f_precision0= item->f_precision0; + dec_bin_size0= item->dec_bin_size0; + f_scale1= item->f_scale1; + f_precision1= item->f_precision1; + dec_bin_size1= item->dec_bin_size1; + } } double Item_variance_field::val_real() { // fix_fields() never calls for this Item + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal dec_buf, *dec_val= val_decimal(&dec_buf); + if (null_value) + return 0.0; + double d; + my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d); + return d; + } double sum,sum_sqr; longlong count; float8get(sum,field->ptr); @@ -1201,6 +2077,28 @@ String *Item_variance_field::val_str(String *str) return str; } + +my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf) +{ + // fix_fields() never calls for this Item + longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1); + if ((null_value= !count)) + return 0; + + my_decimal dec_count, dec_sum, dec_sqr, tmp; + int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); + binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr, + &dec_sum, f_precision0, f_scale0); + binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0, + &dec_sqr, f_precision1, f_scale1); + my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, 2); + my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_sum, &dec_count, 2); + return dec_buf; +} + + /**************************************************************************** ** COUNT(DISTINCT ...) ****************************************************************************/ @@ -1597,6 +2495,58 @@ Item *Item_sum_udf_int::copy_or_same(THD* thd) } +String *Item_sum_udf_decimal::val_str(String *str) +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + if (null_value) + return 0; + if (str->length() < DECIMAL_MAX_STR_LENGTH) + str->length(DECIMAL_MAX_STR_LENGTH); + my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf); + my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str); + return str; +} + + +double Item_sum_udf_decimal::val_real() +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + if (null_value) + return 0.0; + double result; + my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); + return result; +} + + +longlong Item_sum_udf_decimal::val_int() +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + if (null_value) + return 0; + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); + return result; +} + + +my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf) +{ + DBUG_ASSERT(fixed == 1); + DBUG_ENTER("Item_func_udf_decimal::val_decimal"); + DBUG_PRINT("info",("result_type: %d arg_count: %d", + args[0]->result_type(), arg_count)); + + DBUG_RETURN(udf.val_decimal(&null_value, dec_buf)); +} + + +Item *Item_sum_udf_decimal::copy_or_same(THD* thd) +{ + return new (thd->mem_root) Item_sum_udf_decimal(thd, this); +} + + longlong Item_sum_udf_int::val_int() { DBUG_ASSERT(fixed == 1); @@ -2037,7 +2987,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) for (i=0 ; i < arg_count ; i++) { - if ((!args[i]->fixed && + if ((!args[i]->fixed && args[i]->fix_fields(thd, tables, args + i)) || args[i]->check_cols(1)) return TRUE; diff --git a/sql/item_sum.h b/sql/item_sum.h index 7866a9ae913..d759f5607c3 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -78,6 +78,7 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } + my_decimal *val_decimal(my_decimal *); virtual const char *func_name() const { return "?"; } virtual Item *result_item(Field *field) { return new Item_field(field);} @@ -92,6 +93,9 @@ public: virtual bool setup(THD *thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); + virtual int scale() { return decimals; } + virtual Field *create_tmp_field(bool group, TABLE *table, + uint convert_blob_length); bool walk (Item_processor processor, byte *argument); }; @@ -112,6 +116,7 @@ public: return (longlong) val_real(); /* Real as default */ } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void reset_field(); }; @@ -132,17 +137,24 @@ public: class Item_sum_sum :public Item_sum_num { +protected: + Item_result hybrid_type; double sum; - void fix_length_and_dec() { maybe_null=null_value=1; } + my_decimal dec_buffs[2]; + uint curr_dec_buff; + void fix_length_and_dec(); - public: - Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {} - Item_sum_sum(THD *thd, Item_sum_sum *item) - :Item_sum_num(thd, item), sum(item->sum) {} +public: + Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {} + Item_sum_sum(THD *thd, Item_sum_sum *item); enum Sumfunctype sum_func () const {return SUM_FUNC;} void clear(); bool add(); double val_real(); + longlong val_int(); + String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return hybrid_type; } void reset_field(); void update_field(); void no_rows_in_result() {} @@ -159,29 +171,35 @@ class Item_sum_sum :public Item_sum_num class Unique; -class Item_sum_sum_distinct :public Item_sum_num +class Item_sum_sum_distinct :public Item_sum_sum { - double sum; Unique *tree; + byte *dec_bin_buff; + my_decimal tmp_dec; private: Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item); public: Item_sum_sum_distinct(Item *item_par); ~Item_sum_sum_distinct() {} - + bool setup(THD *thd); void clear(); void cleanup(); bool add(); double val_real(); + my_decimal *val_decimal(my_decimal *); + longlong val_int(); + String *val_str(String *str); - inline void add(double val) { sum+= val; } + void add_real(double val); + void add_decimal(byte *val); enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } void reset_field() {} // not used void update_field() {} // not used const char *func_name() const { return "sum_distinct"; } Item *copy_or_same(THD* thd); virtual void no_rows_in_result() {} + void fix_length_and_dec(); }; @@ -304,44 +322,51 @@ class Item_avg_field :public Item_result_field { public: Field *field; - Item_avg_field(Item_sum_avg *item); + Item_result hybrid_type; + uint f_precision, f_scale; + uint dec_bin_size; + Item_avg_field(Item_result res_type, Item_sum_avg *item); enum Type type() const { return FIELD_AVG_ITEM; } double val_real(); - longlong val_int() - { /* can't be fix_fields()ed */ return (longlong) val_real(); } + longlong val_int(); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } String *val_str(String*); - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; -class Item_sum_avg :public Item_sum_num +class Item_sum_avg :public Item_sum_sum { - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } - - double sum; +public: ulonglong count; + uint f_precision, f_scale; + uint dec_bin_size; - public: - Item_sum_avg(Item *item_par) :Item_sum_num(item_par), sum(0.0), count(0) {} + Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {} Item_sum_avg(THD *thd, Item_sum_avg *item) - :Item_sum_num(thd, item), sum(item->sum), count(item->count) {} + :Item_sum_sum(thd, item), count(item->count) {} + void fix_length_and_dec(); enum Sumfunctype sum_func () const {return AVG_FUNC;} void clear(); bool add(); double val_real(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String *str); void reset_field(); void update_field(); Item *result_item(Field *field) - { return new Item_avg_field(this); } + { return new Item_avg_field(hybrid_type, this); } void no_rows_in_result() {} const char *func_name() const { return "avg"; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; class Item_sum_variance; @@ -350,15 +375,25 @@ class Item_variance_field :public Item_result_field { public: Field *field; + Item_result hybrid_type; + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; Item_variance_field(Item_sum_variance *item); enum Type type() const {return FIELD_VARIANCE_ITEM; } double val_real(); longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val_real(); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; @@ -376,23 +411,27 @@ public: class Item_sum_variance : public Item_sum_num { - double sum, sum_sqr; - ulonglong count; - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } + void fix_length_and_dec(); - public: - Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {} - Item_sum_variance(THD *thd, Item_sum_variance *item): - Item_sum_num(thd, item), sum(item->sum), sum_sqr(item->sum_sqr), - count(item->count) {} +public: + Item_result hybrid_type; + double sum, sum_sqr; + my_decimal dec_sum[2], dec_sqr[2]; + int cur_dec; + ulonglong count; + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; + + Item_sum_variance(Item *item_par) :Item_sum_num(item_par), hybrid_type(REAL_RESULT), + cur_dec(0),count(0) + {} + Item_sum_variance(THD *thd, Item_sum_variance *item); enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } void clear(); bool add(); double val_real(); + my_decimal *val_decimal(my_decimal *); void reset_field(); void update_field(); Item *result_item(Field *field) @@ -400,6 +439,8 @@ class Item_sum_variance : public Item_sum_num void no_rows_in_result() {} const char *func_name() const { return "variance"; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); + enum Item_result result_type () const { return hybrid_type; } }; class Item_sum_std; @@ -410,6 +451,7 @@ public: Item_std_field(Item_sum_std *item); enum Type type() const { return FIELD_STD_ITEM; } double val_real(); + enum Item_result result_type () const { return REAL_RESULT; } }; /* @@ -429,16 +471,18 @@ class Item_sum_std :public Item_sum_variance { return new Item_std_field(this); } const char *func_name() const { return "std"; } Item *copy_or_same(THD* thd); + enum Item_result result_type () const { return REAL_RESULT; } }; // This class is a string or number function depending on num_func class Item_sum_hybrid :public Item_sum { - protected: +protected: String value,tmp_value; double sum; longlong sum_int; + my_decimal sum_dec; Item_result hybrid_type; enum_field_types hybrid_field_type; int cmp_sign; @@ -449,15 +493,10 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par), sum(0.0), sum_int(0), hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG), - cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(&my_charset_bin); } - Item_sum_hybrid(THD *thd, Item_sum_hybrid *item): - Item_sum(thd, item), value(item->value), - sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type), - hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign), - used_table_cache(item->used_table_cache), + cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(item->collation); } + { collation.set(&my_charset_bin); } + Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -465,6 +504,7 @@ class Item_sum_hybrid :public Item_sum void clear(); double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); void make_const() { used_table_cache=0; } @@ -475,6 +515,7 @@ class Item_sum_hybrid :public Item_sum void min_max_update_str_field(); void min_max_update_real_field(); void min_max_update_int_field(); + void min_max_update_decimal_field(); void cleanup(); bool any_value() { return was_values; } void no_rows_in_result(); @@ -523,7 +564,7 @@ public: void reset_field(); void update_field(); void fix_length_and_dec() - { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; } + { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; } }; @@ -661,6 +702,23 @@ public: Item *copy_or_same(THD* thd); }; +class Item_sum_udf_decimal :public Item_udf_sum +{ +public: + Item_sum_udf_decimal(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_decimal(udf_func *udf_arg, List &list) + :Item_udf_sum(udf_arg,list) {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) + :Item_udf_sum(thd, item) {} + String *val_str(String *); + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return DECIMAL_RESULT; } + void fix_length_and_dec() { fix_num_length_and_dec(); } + Item *copy_or_same(THD* thd); +}; + #else /* Dummy functions to get sql_yacc.cc compiled */ class Item_sum_udf_float :public Item_sum_num @@ -694,6 +752,22 @@ public: }; +class Item_sum_udf_decimal :public Item_sum_num +{ + public: + Item_sum_udf_decimal(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg, List &list) :Item_sum_num() {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) + :Item_sum_num(thd, item) {} + enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } + my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } + void clear() {} + bool add() { return 0; } + void update_field() {} +}; + + class Item_sum_udf_str :public Item_sum_num { public: diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 917018463e5..ab511ae2883 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -315,7 +315,9 @@ public: }; -/* This can't be a Item_str_func, because the val() functions are special */ +/* + This can't be a Item_str_func, because the val_real() functions are special +*/ class Item_date :public Item_func { diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc index 88e0cbbc0e6..c1a19d71d04 100644 --- a/sql/item_uniq.cc +++ b/sql/item_uniq.cc @@ -20,3 +20,9 @@ #endif #include "mysql_priv.h" + +Field *Item_sum_unique_users::create_tmp_field(bool group, TABLE *table, + uint convert_blob_length) +{ + return new Field_long(9,maybe_null,name,table,1); +} diff --git a/sql/item_uniq.h b/sql/item_uniq.h index e74c09ca3c4..602474f7581 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -57,4 +57,5 @@ public: return new Item_sum_unique_users(thd, this); } void print(String *str) { str->append("0.0", 3); } + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; diff --git a/sql/lex.h b/sql/lex.h index 871d1d99750..7b03950b35a 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -99,6 +99,7 @@ static SYMBOL symbols[] = { { "CASCADE", SYM(CASCADE)}, { "CASCADED", SYM(CASCADED)}, { "CASE", SYM(CASE_SYM)}, + { "CHAIN", SYM(CHAIN_SYM)}, { "CHANGE", SYM(CHANGE)}, { "CHANGED", SYM(CHANGED)}, { "CHAR", SYM(CHAR_SYM)}, @@ -385,6 +386,7 @@ static SYMBOL symbols[] = { { "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)}, { "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)}, { "RELAY_THREAD", SYM(RELAY_THREAD)}, + { "RELEASE", SYM(RELEASE_SYM)}, { "RELOAD", SYM(RELOAD)}, { "RENAME", SYM(RENAME)}, { "REPAIR", SYM(REPAIR)}, diff --git a/sql/log.cc b/sql/log.cc index 6c97581d144..7d6854b6fb4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1346,7 +1346,7 @@ bool MYSQL_LOG::write(Log_event* event_info) if (thd) { - /* NOTE: CHARSET AND TZ REPL WILL BE REWRITTEN SHORTLY */ +#if MYSQL_VERSION_ID < 50003 /* To make replication of charsets working in 4.1 we are writing values of charset related variables before every statement in the binlog, @@ -1375,9 +1375,15 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u", if (e.write(file)) goto err; } +#endif /* We use the same ONE_SHOT trick for making replication of time zones working in 4.1. Again in 5.0 we have better means for doing this. + + TODO: we should do like we now do with charsets (no more ONE_SHOT; + logging in each event in a compact format). Dmitri says we can do: + if (time_zone_used) write the timezone to binlog (in a format to be + defined). */ if (thd->time_zone_used && thd->variables.time_zone != global_system_variables.time_zone) diff --git a/sql/log_event.cc b/sql/log_event.cc index 5ee034d785e..d2a0e8642f9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -953,7 +953,13 @@ void Query_log_event::pack_info(Protocol *protocol) bool Query_log_event::write(IO_CACHE* file) { - uchar buf[QUERY_HEADER_LEN+1+4+1+8+1+1+FN_REFLEN+5], *start, *start_of_status; + uchar buf[QUERY_HEADER_LEN+ + 1+4+ // code of flags2 and flags2 + 1+8+ // code of sql_mode and sql_mode + 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog + 1+4+ // code of autoinc and the 2 autoinc variables + 1+6 // code of charset and charset + ], *start, *start_of_status; ulong event_length; if (!query) @@ -1048,9 +1054,15 @@ bool Query_log_event::write(IO_CACHE* file) int2store(start+2, auto_increment_offset); start+= 4; } + if (charset_inited) + { + *(start++)= Q_CHARSET_CODE; + memcpy(start, charset, 6); + start+= 6; + } /* Here there could be code like - if (command-line-option-which-says-"log_this_variable") + if (command-line-option-which-says-"log_this_variable" && inited) { *(start++)= Q_THIS_VARIABLE_CODE; int4store(start, this_variable); @@ -1095,7 +1107,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, thread_id(thd_arg->thread_id), /* save the original thread id; we already know the server id */ slave_proxy_id(thd_arg->variables.pseudo_thread_id), - flags2_inited(1), sql_mode_inited(1), flags2(0), + flags2_inited(1), sql_mode_inited(1), charset_inited(1), sql_mode(thd_arg->variables.sql_mode), auto_increment_increment(thd_arg->variables.auto_increment_increment), auto_increment_offset(thd_arg->variables.auto_increment_offset) @@ -1104,7 +1116,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, time(&end_time); exec_time = (ulong) (end_time - thd->start_time); catalog_len = (catalog) ? (uint32) strlen(catalog) : 0; - status_vars_len= 1+4+1+8+1+1+catalog_len+1; + /* status_vars_len is set just before writing the event */ db_len = (db) ? (uint32) strlen(db) : 0; /* If we don't use flags2 for anything else than options contained in @@ -1114,7 +1126,12 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, we will probably want to reclaim the 29 bits. So we need the &. */ flags2= 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); + int2store(charset, thd_arg->variables.character_set_client->number); + int2store(charset+2, thd_arg->variables.collation_connection->number); + int2store(charset+4, thd_arg->variables.collation_server->number); DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode)); } #endif /* MYSQL_CLIENT */ @@ -1129,7 +1146,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, const Format_description_log_event *description_event) :Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS), db(NullS), catalog_len(0), status_vars_len(0), - flags2_inited(0), sql_mode_inited(0) + flags2_inited(0), sql_mode_inited(0), charset_inited(0), + auto_increment_increment(1), auto_increment_offset(1) { ulong data_len; uint32 tmp; @@ -1156,8 +1174,6 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET); db_len = (uint)buf[Q_DB_LEN_OFFSET]; error_code = uint2korr(buf + Q_ERR_CODE_OFFSET); - /* If auto_increment is not set by query_event, they should not be used */ - auto_increment_increment= auto_increment_offset= 1; /* 5.0 format starts here. @@ -1216,6 +1232,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, auto_increment_offset= uint2korr(pos+2); pos+= 4; break; + case Q_CHARSET_CODE: + { + charset_inited= 1; + memcpy(charset, pos, 6); + pos+= 6; + break; + } default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ @@ -1348,6 +1371,27 @@ void Query_log_event::print(FILE* file, bool short_form, last_event_info->auto_increment_offset= auto_increment_offset; } + if (likely(charset_inited)) + { + if (unlikely(!last_event_info->charset_inited)) /* first Query event */ + { + last_event_info->charset_inited= 1; + last_event_info->charset[0]= ~charset[0]; // force a difference to force write + } + if (unlikely(bcmp(last_event_info->charset, charset, 6))) + { + fprintf(file,"SET " + "@@session.character_set_client=%d," + "@@session.collation_connection=%d," + "@@session.collation_server=%d" + ";\n", + uint2korr(charset), + uint2korr(charset+2), + uint2korr(charset+4)); + memcpy(last_event_info->charset, charset, 6); + } + } + my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fputs(";\n", file); } @@ -1400,34 +1444,64 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) thd->variables.pseudo_thread_id= thread_id; // for temp tables mysql_log.write(thd,COM_QUERY,"%s",thd->query); DBUG_PRINT("query",("%s",thd->query)); - - if (flags2_inited) - /* - all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must - take their value from flags2. - */ - thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG); - /* - else, we are in a 3.23/4.0 binlog; we previously received a - Rotate_log_event which reset thd->options and sql_mode, so nothing to do. - */ - - /* - We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a - slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not - force us to ignore the dir too. Imagine you are a ring of machines, and - one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE - on this machine; you don't want it to propagate elsewhere (you don't want - all slaves to start ignoring the dirs). - */ - if (sql_mode_inited) - thd->variables.sql_mode= - (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) | - (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE)); if (ignored_error_code((expected_error= error_code)) || !check_expected_error(thd,rli,expected_error)) + { + if (flags2_inited) + /* + all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must + take their value from flags2. + */ + thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG); + /* + else, we are in a 3.23/4.0 binlog; we previously received a + Rotate_log_event which reset thd->options and sql_mode etc, so nothing to do. + */ + /* + We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a + slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not + force us to ignore the dir too. Imagine you are a ring of machines, and + one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE + on this machine; you don't want it to propagate elsewhere (you don't want + all slaves to start ignoring the dirs). + */ + if (sql_mode_inited) + thd->variables.sql_mode= + (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) | + (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE)); + if (charset_inited) + { + if (rli->cached_charset_compare(charset)) + { + /* Verify that we support the charsets found in the event. */ + if (!(thd->variables.character_set_client= + get_charset(uint2korr(charset), MYF(MY_WME))) || + !(thd->variables.collation_connection= + get_charset(uint2korr(charset+2), MYF(MY_WME))) || + !(thd->variables.collation_server= + get_charset(uint2korr(charset+4), MYF(MY_WME)))) + { + /* + We updated the thd->variables with nonsensical values (0), and the + thread is not guaranteed to terminate now (as it may be configured + to ignore EE_UNKNOWN_CHARSET);if we're going to execute a next + statement we'll have a new charset info with it, so no problem to + have stored 0 in thd->variables. But we invalidate cached + charset to force a check next time (otherwise if next time + charset is unknown again we won't detect it). + */ + rli->cached_charset_invalidate(); + goto compare_errors; + } + thd->update_charset(); // for the charset change to take effect + } + } + + /* Execute the query (note that we bypass dispatch_command()) */ mysql_parse(thd, thd->query, q_len); + + } else { /* @@ -1452,6 +1526,8 @@ START SLAVE; . Query: '%s'", expected_error, thd->query); } goto end; } + +compare_errors: /* If we expected a non-zero error code, and we don't get the same error @@ -1666,12 +1742,7 @@ bool Start_log_event_v3::write(IO_CACHE* file) int Start_log_event_v3::exec_event(struct st_relay_log_info* rli) { DBUG_ENTER("Start_log_event_v3::exec_event"); - /* - If the I/O thread has not started, mi->old_format is BINLOG_FORMAT_CURRENT - (that's what the MASTER_INFO constructor does), so the test below is not - perfect at all. - */ - switch (rli->relay_log.description_event_for_exec->binlog_version) + switch (binlog_version) { case 3: case 4: @@ -2789,14 +2860,24 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) rli->group_master_log_name, (ulong) rli->group_master_log_pos)); /* - Reset thd->options and sql_mode, because this could be the signal of a - master's downgrade from 5.0 to 4.0. + Reset thd->options and sql_mode etc, because this could be the signal of + a master's downgrade from 5.0 to 4.0. However, no need to reset description_event_for_exec: indeed, if the next master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next master is 4.0 then the events are in the slave's format (conversion). */ set_slave_thread_options(thd); thd->variables.sql_mode= global_system_variables.sql_mode; + thd->variables.auto_increment_increment= + thd->variables.auto_increment_offset= 1; + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.collation_server= + global_system_variables.collation_server; + thd->update_charset(); + rli->cached_charset_invalidate(); } pthread_mutex_unlock(&rli->data_lock); pthread_cond_broadcast(&rli->data_cond); @@ -3018,6 +3099,16 @@ void User_var_log_event::pack_info(Protocol* protocol) buf= my_malloc(val_offset + 22, MYF(MY_WME)); event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf; break; + case DECIMAL_RESULT: + { + buf= my_malloc(val_offset + DECIMAL_MAX_STR_LENGTH, MYF(MY_WME)); + String str(buf+val_offset, DECIMAL_MAX_STR_LENGTH, &my_charset_bin); + my_decimal dec; + binary2my_decimal(E_DEC_FATAL_ERROR, val+2, &dec, val[0], val[1]); + my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str); + event_len= str.length() + val_offset; + break; + } case STRING_RESULT: /* 15 is for 'COLLATE' and other chars */ buf= my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, MYF(MY_WME)); @@ -3086,7 +3177,7 @@ bool User_var_log_event::write(IO_CACHE* file) char buf[UV_NAME_LEN_SIZE]; char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE]; - char buf2[8], *pos= buf2; + char buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2; uint buf1_length; ulong event_length; @@ -3101,8 +3192,6 @@ bool User_var_log_event::write(IO_CACHE* file) { buf1[1]= type; int4store(buf1 + 2, charset_number); - int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len); - buf1_length= 10; switch (type) { case REAL_RESULT: @@ -3111,6 +3200,16 @@ bool User_var_log_event::write(IO_CACHE* file) case INT_RESULT: int8store(buf2, *(longlong*) val); break; + case DECIMAL_RESULT: + { + my_decimal *dec= (my_decimal *)val; + dec->fix_buffer_pointer(); + buf2[0]= (char)(dec->intg + dec->frac); + buf2[1]= (char)dec->frac; + decimal2bin((decimal*)val, buf2+2, buf2[0], buf2[1]); + val_len= decimal_bin_size(buf2[0], buf2[1]) + 2; + break; + } case STRING_RESULT: pos= val; break; @@ -3119,6 +3218,8 @@ bool User_var_log_event::write(IO_CACHE* file) DBUG_ASSERT(1); return 0; } + int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len); + buf1_length= 10; } /* Length of the whole event */ @@ -3166,6 +3267,23 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las longlong10_to_str(uint8korr(val), int_buf, -10); fprintf(file, ":=%s;\n", int_buf); break; + case DECIMAL_RESULT: + { + char str_buf[200]; + int str_len= sizeof(str_buf) - 1; + int precision= (int)val[0]; + int scale= (int)val[1]; + decimal_digit dec_buf[10]; + decimal dec; + dec.len= 10; + dec.buf= dec_buf; + + bin2decimal(val+2, &dec, precision, scale); + decimal2string(&dec, str_buf, &str_len, 0, 0, 0); + str_buf[str_len]= 0; + fprintf(file, "%s",str_buf); + break; + } case STRING_RESULT: { /* @@ -3242,7 +3360,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) switch (type) { case REAL_RESULT: float8get(real_val, val); - it= new Item_real(real_val); + it= new Item_float(real_val); val= (char*) &real_val; // Pointer to value in native format val_len= 8; break; @@ -3252,6 +3370,14 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) val= (char*) &int_val; // Pointer to value in native format val_len= 8; break; + case DECIMAL_RESULT: + { + Item_decimal *dec= new Item_decimal(val+2, val[0], val[1]); + it= dec; + val= (char *)dec->val_decimal(NULL); + val_len= sizeof(my_decimal); + break; + } case STRING_RESULT: it= new Item_string(val, val_len, charset); break; diff --git a/sql/log_event.h b/sql/log_event.h index 64bb9d502e9..7f04582a32d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -232,6 +232,7 @@ struct sql_ex_info #define Q_SQL_MODE_CODE 1 #define Q_CATALOG_CODE 2 #define Q_AUTO_INCREMENT 3 +#define Q_CHARSET_CODE 4 /* Intvar event post-header */ @@ -401,11 +402,19 @@ typedef struct st_last_event_info bool sql_mode_inited; ulong sql_mode; /* must be same as THD.variables.sql_mode */ ulong auto_increment_increment, auto_increment_offset; + bool charset_inited; + char charset[6]; // 3 variables, each of them storable in 2 bytes st_last_event_info() - :flags2_inited(0), flags2(0), sql_mode_inited(0), sql_mode(0), - auto_increment_increment(1),auto_increment_offset(1) + :flags2_inited(0), sql_mode_inited(0), + auto_increment_increment(1),auto_increment_offset(1), charset_inited(0) { - db[0]= 0; /* initially, the db is unknown */ + /* + Currently we only use static LAST_EVENT_INFO objects, so zeroed at + program's startup, but these explicit bzero() is for the day someone + creates dynamic instances. + */ + bzero(db, sizeof(db)); + bzero(charset, sizeof(charset)); } } LAST_EVENT_INFO; #endif @@ -634,7 +643,7 @@ public: status_vars on disk is a sequence of pairs (code, value) where 'code' means 'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so its first byte is its length. For now the order of status vars is: - flags2 - sql_mode - catalog. + flags2 - sql_mode - catalog - autoinc - charset We should add the same thing to Load_log_event, but in fact LOAD DATA INFILE is going to be logged with a new type of event (logging of the plain text query), so Load_log_event would be frozen, so no need. The @@ -655,11 +664,13 @@ public: */ bool flags2_inited; bool sql_mode_inited; + bool charset_inited; uint32 flags2; /* In connections sql_mode is 32 bits now but will be 64 bits soon */ ulong sql_mode; ulong auto_increment_increment, auto_increment_offset; + char charset[6]; #ifndef MYSQL_CLIENT diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc new file mode 100644 index 00000000000..027b33f1d1c --- /dev/null +++ b/sql/my_decimal.cc @@ -0,0 +1,212 @@ +/* Copyright (C) 2004 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 */ +#include "mysql_priv.h" + +#ifndef MYSQL_CLIENT +/* + report result of decimal operation + + SYNOPSIS + decimal_operation_results() + result decimal library return code (E_DEC_* see include/decimal.h) + + return + result +*/ +int decimal_operation_results(int result) +{ + switch (result) + { + case E_DEC_OK: + break; +//TODO: fix error messages + case E_DEC_TRUNCATED: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED), + "", (long)-1); + break; + case E_DEC_OVERFLOW: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_WARN_DATA_OUT_OF_RANGE, + ER(ER_WARN_DATA_OUT_OF_RANGE), + "", (long)-1); + break; + case E_DEC_DIV_ZERO: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO)); + break; + case E_DEC_BAD_NUM: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + "decimal", "", "", (long)-1); + break; + case E_DEC_OOM: + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + break; + default: + DBUG_ASSERT(0); + } + return result; +} + + +/* + Converting decimal to string + + SYNOPSIS + my_decimal2string() + + return + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW + E_DEC_OOM +*/ + +int my_decimal2string(uint mask, const my_decimal *d, + int fixed_prec, int fixed_dec, + char filler, String *str) +{ + int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d)); + int result; + if (str->alloc(length)) + return check_result(mask, E_DEC_OOM); + char *sptr= (char *)str->ptr(); + int res= decimal2string((decimal *)d, sptr, + &length, fixed_prec, fixed_dec, + filler); + result= check_result(mask, res); + str->length(length); + return result; +} + + +/* + Convert from decimal to binary representation + + SYNOPSIS + my_decimal2binary() + mask error processing mask + d number for conversion + bin pointer to buffer where to write result + prec overall number of decimal digits + scale number of decimal digits after decimal point + + NOTE + Before conversion we round number if it need but produce truncation + error in this case + + RETURN + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW +*/ + +int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec, + int scale) +{ + int err1= E_DEC_OK, err2; + my_decimal rounded; + my_decimal2decimal(d, &rounded); + decimal_optimize_fraction(&rounded); + if (scale < rounded.frac) + { + err1= E_DEC_TRUNCATED; + /* decimal_round can return only E_DEC_TRUNCATED */ + decimal_round(&rounded, &rounded, scale, HALF_UP); + } + err2= decimal2bin(&rounded, bin, prec, scale); + if (!err2) + err2= err1; + return check_result(mask, err2); +} + + +/* + Convert string for decimal when string can be in some multibyte charset + + SYNOPSIS + str2my_decimal() + mask error processing mask + from string to process + length length of given string + charset charset of given string + decimal_value buffer for result storing + + RESULT + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW + E_DEC_BAD_NUM + E_DEC_OOM +*/ +int str2my_decimal(uint mask, const char *from, uint length, + CHARSET_INFO *charset, my_decimal *decimal_value) +{ + char *end; + int err; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + if (charset->mbminlen > 1) + { + uint dummy_errors; + tmp.copy(from, length, charset, &my_charset_latin1, &dummy_errors); + from= tmp.ptr(); + length= tmp.length(); + charset= &my_charset_bin; + } + my_decimal_set_zero(decimal_value); + err= string2decimal((char *)from, (decimal *)decimal_value, &end); + if ((end-from) != length && !err) + err= E_DEC_TRUNCATED; + check_result(mask, err); + return err; +} + + +#ifndef DBUG_OFF +/* routines for debugging print */ + +/* print decimal */ +void +print_decimal(const my_decimal *dec) +{ + fprintf(DBUG_FILE, + "\nDecimal: sign: %d intg: %d frac: %d \n\ +%09d,%09d,%09d,%09d,%09d,%09d,%09d,%09d\n", + dec->sign(), dec->intg, dec->frac, + dec->buf[0], dec->buf[1], dec->buf[2], dec->buf[3], + dec->buf[4], dec->buf[5], dec->buf[6], dec->buf[7]); +} + + +/* print decimal with its binary representation */ +void +print_decimal_buff(const my_decimal *dec, const byte* ptr, int length) +{ + print_decimal(dec); + fprintf(DBUG_FILE, "Record: "); + for(int i= 0; i < length; i++) + { + fprintf(DBUG_FILE, "%02X ", (uint)((uchar *)ptr)[i]); + } + fprintf(DBUG_FILE, "\n"); +} +#endif + + +#endif /*MYSQL_CLIENT*/ diff --git a/sql/my_decimal.h b/sql/my_decimal.h new file mode 100644 index 00000000000..63d3fb7e2e5 --- /dev/null +++ b/sql/my_decimal.h @@ -0,0 +1,332 @@ +/* Copyright (C) 2004 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 */ + +/* + It is interface module to fixed precision decimals library. + + Most functions use 'uint mask' as parameter, if during operation error + which fit in this mask is detected then it will be processed automatically + here. (errors are E_DEC_* constants, see include/decimal.h) + + Most function are just inline wrappers around library calls +*/ + +#ifndef my_decimal_h +#define my_decimal_h + +C_MODE_START +#include +C_MODE_END + +#define DECIMAL_LONGLONG_DIGITS 22 +#define DECIMAL_LONG_DIGITS 10 +#define DECIMAL_LONG3_DIGITS 8 + +/* number of digits on which we increase scale of devision result */ +#define DECIMAL_DIV_SCALE_INCREASE 5 + +/* maximum length of buffer in our big digits (uint32) */ +#define DECIMAL_BUFF_LENGTH 8 +/* + maximum guaranteed length of number in decimal digits (number of our + digits * number of decimal digits in one our big digit - number of decimal + digits in one our big digit decreased on 1 (because we always put decimal + point on the border of our big digits)) +*/ +#define DECIMAL_MAX_LENGTH ((8 * 9) - 8) +/* + maximum length of string representation (number of maximum decimal + digits + 1 position for sign + 1 position for decimal point) +*/ +#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_LENGTH + 2) +/* + maximum size of packet length +*/ +#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_LENGTH + + +inline uint my_decimal_size(uint precision, uint scale) +{ + /* + Always allocate more space to allow library to put decimal point + where it want + */ + return decimal_size(precision, scale) + 1; +} + + +/* my_decimal class limits 'decimal' type to what we need in MySQL */ +/* It internally all necessary space iside the instance so no extra */ +/* memory is needed. One should call fix_buffer_pointer() function */ +/* when he moves my_decimal objects in memory */ +class my_decimal :public decimal +{ + decimal_digit buffer[DECIMAL_BUFF_LENGTH]; + +public: + + void init() + { + len= DECIMAL_BUFF_LENGTH; + buf= buffer; +#if !defined(HAVE_purify) && !defined(DBUG_OFF) + for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) + buffer[i]= i; +#endif + } + my_decimal() + { + init(); + } + void fix_buffer_pointer() { buf= buffer; } + + bool sign() const { return decimal::sign; } + void sign(bool s) { decimal::sign= s; } +}; + + +#ifndef DBUG_OFF +void print_decimal(const my_decimal *dec); +void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length); +#endif + +#ifndef MYSQL_CLIENT +int decimal_operation_results(int result); +#else +inline int decimal_operation_results(int result) +{ + return result; +} +#endif /*MYSQL_CLIENT*/ + +inline int check_result(uint mask, int result) +{ + if (result & mask) + decimal_operation_results(result); + return result; +} + + +inline +int my_decimal_string_length(const my_decimal *d) +{ + return decimal_string_size(d); +} + + +inline +int my_decimal_max_length(const my_decimal *d) +{ + /* -1 because we do not count \0 */ + return decimal_string_size(d) - 1; +} + + +inline +int my_decimal_get_binary_size(uint precision, uint scale) +{ + return decimal_bin_size((int)precision, (int)scale); +} + + +inline +void my_decimal2decimal(const my_decimal *from, my_decimal *to) +{ + *to= *from; + to->fix_buffer_pointer(); +} + + +int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec, + int scale); + + +inline +int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec, + int scale) +{ + return check_result(mask, bin2decimal((char *)bin, (decimal *)d, prec, + scale)); +} + + +inline +int my_decimal_set_zero(my_decimal *d) +{ + decimal_make_zero(((decimal *)d)); + return 0; +} + + +inline +bool my_decimal_is_zero(const my_decimal *decimal_value) +{ + return decimal_is_zero((decimal *)decimal_value); +} + + +inline +int my_decimal_round(uint mask, const my_decimal *from, int scale, + bool truncate, my_decimal *to) +{ + return check_result(mask, decimal_round((decimal *)from, to, scale, + (truncate ? TRUNCATE : HALF_UP))); +} + + +inline +int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) +{ + return check_result(mask, decimal_round((decimal *)from, to, 0, FLOOR)); +} + + +inline +int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) +{ + return check_result(mask, decimal_round((decimal *)from, to, 0, CEILING)); +} + + +#ifndef MYSQL_CLIENT +int my_decimal2string(uint mask, const my_decimal *d, int fixed_prec, + int fixed_dec, char filler, String *str); +#endif + +inline +int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag, + longlong *l) +{ + my_decimal rounded; + /* decimal_round can return only E_DEC_TRUNCATED */ + decimal_round((decimal*)d, &rounded, 0, HALF_UP); + return check_result(mask, (unsigned_flag ? + decimal2ulonglong(&rounded, (ulonglong *)l) : + decimal2longlong(&rounded, l))); +} + + +inline +int my_decimal2double(uint mask, const my_decimal *d, double *result) +{ + return check_result(mask, decimal2double((decimal *)d, result)); +} + + +inline +int str2my_decimal(uint mask, const char *str, my_decimal *d, + char **end= 0) +{ + /* set it to 0 to avoid junk in value in case of error of conversion */ + my_decimal_set_zero(d); + return check_result(mask, string2decimal((char *)str, (decimal *)d, end)); +} + + +int str2my_decimal(uint mask, const char *from, uint length, + CHARSET_INFO *charset, my_decimal *decimal_value); + + +#ifdef MYSQL_SERVER +inline +int string2my_decimal(uint mask, const String *str, my_decimal *d) +{ + return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d); +} +#endif + + +inline +int double2my_decimal(uint mask, double val, my_decimal *d) +{ + return check_result(mask, double2decimal(val, (decimal *)d)); +} + + +inline +int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) +{ + return check_result(mask, (unsigned_flag ? + ulonglong2decimal((ulonglong)i, d) : + longlong2decimal(i, d))); +} + + +inline +int my_decimal_neg(st_decimal *arg) +{ + decimal_neg(arg); + return 0; +} + + +inline +int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result(mask, decimal_add((decimal *)a, (decimal *)b, res)); +} + + +inline +int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result(mask, decimal_sub((decimal *)a, (decimal *)b, res)); +} + + +inline +int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result(mask, decimal_mul((decimal *)a, (decimal *)b, res)); +} + + +inline +int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b, int div_scale_inc) +{ + return check_result(mask, decimal_div((decimal *)a, (decimal *)b, res, + div_scale_inc)); +} + + +inline +int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result(mask, decimal_mod((decimal *)a, (decimal *)b, res)); +} + + +/* Returns -1 if ab and 0 if a==b */ +inline +int my_decimal_cmp(const my_decimal *a, const my_decimal *b) +{ + return decimal_cmp((decimal *)a, (decimal *)b); +} + +inline +void max_my_decimal(my_decimal *to, int precision, int frac) +{ + DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH); + max_decimal(precision, frac, (decimal *)to); +} + +#endif /*my_decimal_h*/ + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index bd0e1455eb2..fdcf061ab7a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -285,6 +285,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2) #define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2) #define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2) +/* + Replication uses 8 bytes to store SQL_MODE in the binary log. The day you + use strictly more than 64 bits by adding one more define above, you should + contact the replication team because the replication code should then be + updated (to store more bytes on disk). +*/ #define RAID_BLOCK_SIZE 1024 @@ -337,6 +343,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); #define WEEK_YEAR 2 #define WEEK_FIRST_WEEKDAY 4 +#define STRING_BUFFER_USUAL_SIZE 80 + enum enum_parsing_place { NO_MATTER, @@ -401,9 +409,13 @@ inline THD *_current_thd(void) } #define current_thd _current_thd() +typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, + uint key_length, + ulonglong *engine_data); #include "sql_string.h" #include "sql_list.h" #include "sql_map.h" +#include "my_decimal.h" #include "handler.h" #include "parse_file.h" #include "table.h" @@ -412,6 +424,7 @@ inline THD *_current_thd(void) #include "sql_udf.h" class user_var_entry; #include "item.h" +extern my_decimal decimal_zero; typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); /* sql_parse.cc */ void free_items(Item *item); @@ -446,6 +459,7 @@ Item *negate_expression(THD *thd, Item *expr); struct Query_cache_query_flags { unsigned int client_long_flag:1; + unsigned int client_protocol_41:1; uint character_set_client_num; uint character_set_results_num; uint collation_connection_num; @@ -714,7 +728,6 @@ bool mysql_do(THD *thd, List &values); /* sql_analyse.h */ bool append_escaped(String *to_str, String *from_str); -bool append_escaped(String *to_str, char *from, uint from_len); /* sql_show.cc */ bool mysqld_show_open_tables(THD *thd,const char *wild); @@ -1323,7 +1336,7 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) table->null_row= 0; table->status= STATUS_NO_RECORD; table->keys_in_use_for_query= table->s->keys_in_use; - table->maybe_null= test(table->outer_join= table_list->outer_join); + table->maybe_null= table_list->outer_join; table->tablenr= tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9b39f51fc5b..668ef033414 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -261,11 +261,12 @@ bool opt_large_files= sizeof(my_off_t) > 4; bool opt_help= 0; bool opt_verbose= 0; -arg_cmp_func Arg_comparator::comparator_matrix[4][2] = +arg_cmp_func Arg_comparator::comparator_matrix[5][2] = {{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string}, {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real}, {&Arg_comparator::compare_int_signed, &Arg_comparator::compare_e_int}, - {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}}; + {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}, + {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}}; /* Global variables */ @@ -291,6 +292,7 @@ my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster; #ifdef HAVE_NDBCLUSTER_DB const char *opt_ndbcluster_connectstring= 0; my_bool opt_ndb_shm, opt_ndb_optimized_node_selection; +ulong opt_ndb_cache_check_time= 0; #endif my_bool opt_readonly, use_temp_pool, relay_log_purge; my_bool opt_sync_bdb_logs, opt_sync_frm; @@ -371,6 +373,7 @@ const char *sql_mode_str="OFF"; const char *in_left_expr_name= ""; /* name of additional condition */ const char *in_additional_cond= ""; +my_decimal decimal_zero; /* classes for comparation parsing/processing */ Eq_creator eq_creator; Ne_creator ne_creator; @@ -2383,6 +2386,7 @@ static int init_common_variables(const char *conf_file_name, int argc, char **argv, const char **groups) { umask(((~my_umask) & 0666)); + my_decimal_set_zero(&decimal_zero); // set decimal_zero constant; tzset(); // Set tzname max_system_variables.pseudo_thread_id= (ulong)~0; @@ -3375,39 +3379,34 @@ int main(int argc, char **argv) return 0; } } - else if (argc >= 4) + else if (argc == 4 || argc == 5) { - const char *defaults_file = "--defaults-file"; - const char *service = "--local-service"; - char extra_opt[FN_REFLEN] = ""; + /* + This may seem strange, because we handle --local-service while + preserving 4.1's behavior of allowing any one other argument that is + passed to the service on startup. (The assumption is that this is + --defaults-file=file, but that was not enforced in 4.1, so we don't + enforce it here.) + */ + char *extra_opt= NULL; char *account_name = NULL; - char *option; int index; for (index = 3; index < argc; index++) { - option= argv[index]; - /* - Install an optional service with optional config file - mysqld --install-manual mysqldopt --defaults-file=c:\miguel\my.ini - */ - if (strncmp(option, defaults_file, strlen(defaults_file)) == 0) - { - strmov(extra_opt, option); - } - else - /* - Install an optional service as local service - mysqld --install-manual mysqldopt --local-service - */ - if (strncmp(option, service, strlen(service)) == 0) + if (strncmp(argv[index], "--local-service", 15) == 0) { account_name=(char*)malloc(27); strmov(account_name, "NT AUTHORITY\\LocalService\0"); } + else + { + extra_opt= argv[index]; + } } - if (!default_service_handling(argv, argv[2], argv[2], file_path, extra_opt, account_name)) - return 0; + if (argc != 5 || account_name) + if (!default_service_handling(argv, argv[2], argv[2], file_path, extra_opt, account_name)) + return 0; } else if (argc == 1 && Service.IsService(MYSQL_SERVICENAME)) { @@ -4174,9 +4173,9 @@ enum options_mysqld OPT_INNODB, OPT_ISAM, OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT, OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, - OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, + OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME, OPT_SKIP_SAFEMALLOC, - OPT_TEMP_POOL, OPT_TX_ISOLATION, + OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE, OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS, OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, OPT_SAFE_USER_CREATE, OPT_SQL_MODE, @@ -4251,7 +4250,11 @@ enum options_mysqld OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE, OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE, - OPT_SYNC_FRM, OPT_SYNC_BINLOG, OPT_BDB_NOSYNC, + OPT_SYNC_FRM, OPT_SYNC_BINLOG, + OPT_SYNC_REPLICATION, + OPT_SYNC_REPLICATION_SLAVE_ID, + OPT_SYNC_REPLICATION_TIMEOUT, + OPT_BDB_NOSYNC, OPT_ENABLE_SHARED_MEMORY, OPT_SHARED_MEMORY_BASE_NAME, OPT_OLD_PASSWORDS, @@ -4363,6 +4366,10 @@ Disable with --skip-bdb (will save memory).", {"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.", (gptr*) &default_collation_name, (gptr*) &default_collation_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"completion-type", OPT_COMPLETION_TYPE, "Default completion type.", + (gptr*) &global_system_variables.completion_type, + (gptr*) &max_system_variables.completion_type, 0, GET_ULONG, + REQUIRED_ARG, 0, 0, 2, 0, 1, 0}, {"concurrent-insert", OPT_CONCURRENT_INSERT, "Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.", (gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert, @@ -4698,6 +4705,10 @@ Disable with --skip-ndbcluster (will save memory).", (gptr*) &opt_ndb_optimized_node_selection, (gptr*) &opt_ndb_optimized_node_selection, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + { "ndb_cache_check_time", OPT_NDB_CACHE_CHECK_TIME, + "A dedicated thread is created to update cached commit count value at the given interval.", + (gptr*) &opt_ndb_cache_check_time, (gptr*) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG, + 0, 0, LONG_TIMEOUT, 0, 1, 0}, #endif {"new", 'n', "Use very new possible 'unsafe' functions.", (gptr*) &global_system_variables.new_mode, @@ -5443,6 +5454,23 @@ The minimum value for this variable is 4096.", (gptr*) &sync_binlog_period, (gptr*) &sync_binlog_period, 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0}, +#ifdef DOES_NOTHING_YET + {"sync-replication", OPT_SYNC_REPLICATION, + "Enable synchronous replication", + (gptr*) &global_system_variables.sync_replication, + (gptr*) &global_system_variables.sync_replication, + 0, GET_ULONG, REQUIRED_ARG, 0, 0, 1, 0, 1, 0}, + {"sync-replication-slave-id", OPT_SYNC_REPLICATION_SLAVE_ID, + "Synchronous replication is wished for this slave", + (gptr*) &global_system_variables.sync_replication_slave_id, + (gptr*) &global_system_variables.sync_replication_slave_id, + 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0}, + {"sync-replication-timeout", OPT_SYNC_REPLICATION_TIMEOUT, + "Synchronous replication timeout", + (gptr*) &global_system_variables.sync_replication_timeout, + (gptr*) &global_system_variables.sync_replication_timeout, + 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, +#endif {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default", (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e5799bfd509..ceb9f97bbbc 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3611,7 +3611,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, if (!value) // IS NULL or IS NOT NULL { - if (field->table->outer_join) // Can't use a key on this + if (field->table->maybe_null) // Can't use a key on this DBUG_RETURN(0); if (!maybe_null) // Not null field DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0); diff --git a/sql/procedure.cc b/sql/procedure.cc index 420a4f6262b..a31b93da358 100644 --- a/sql/procedure.cc +++ b/sql/procedure.cc @@ -41,6 +41,34 @@ static struct st_procedure_def { { "analyse",proc_analyse_init } // Analyse a result }; + +my_decimal *Item_proc_string::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return 0; + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); + return (decimal_value); +} + + +my_decimal *Item_proc_int::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return 0; + int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value); + return (decimal_value); +} + + +my_decimal *Item_proc_real::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return 0; + double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); + return (decimal_value); +} + + /***************************************************************************** ** Setup handling of procedure ** Return 0 if everything is ok diff --git a/sql/procedure.h b/sql/procedure.h index 33c1288c88e..4e5bf8a2f4b 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -71,6 +71,7 @@ public: s->set(value,decimals,default_charset()); return s; } + my_decimal *val_decimal(my_decimal *); unsigned int size_of() { return sizeof(*this);} }; @@ -89,6 +90,7 @@ public: double val_real() { return (double) value; } longlong val_int() { return value; } String *val_str(String *s) { s->set(value, default_charset()); return s; } + my_decimal *val_decimal(my_decimal *); unsigned int size_of() { return sizeof(*this);} }; @@ -122,6 +124,7 @@ public: { return null_value ? (String*) 0 : (String*) &str_value; } + my_decimal *val_decimal(my_decimal *); unsigned int size_of() { return sizeof(*this);} }; diff --git a/sql/protocol.cc b/sql/protocol.cc index c61a3eb9f7c..cfd7a955951 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -753,6 +753,7 @@ bool Protocol_simple::store(const char *from, uint length, DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || + field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL || (field_types[field_pos] >= MYSQL_TYPE_ENUM && field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); field_pos++; @@ -769,6 +770,7 @@ bool Protocol_simple::store(const char *from, uint length, DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || + field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL || (field_types[field_pos] >= MYSQL_TYPE_ENUM && field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); field_pos++; @@ -831,6 +833,26 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) } +bool Protocol_simple::store_decimal(const my_decimal *d) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); + field_pos++; +#endif + int buf_size= my_decimal_string_length(d); + char *buff= (char *)my_alloca(buf_size); + String str(buff, buf_size, &my_charset_bin); + if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str)) + { + my_afree(buff); + return TRUE; + } + my_afree(buff); + return net_store_data(str.ptr(), str.length()); +} + + bool Protocol_simple::store(float from, uint32 decimals, String *buffer) { #ifndef DEBUG_OFF @@ -1045,6 +1067,24 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag) return 0; } +bool Protocol_prep::store_decimal(const my_decimal *d) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); + field_pos++; +#endif + int buf_size= my_decimal_string_length(d); + char *buff= (char *)my_alloca(buf_size); + String str(buff, buf_size, &my_charset_bin); + if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str)) + { + my_afree(buff); + return TRUE; + } + my_afree(buff); + return store(str.ptr(), str.length(), str.charset()); +} bool Protocol_prep::store(float from, uint32 decimals, String *buffer) { diff --git a/sql/protocol.h b/sql/protocol.h index fddd3ceba94..ad2593d3ab7 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -82,6 +82,7 @@ public: virtual bool store_short(longlong from)=0; virtual bool store_long(longlong from)=0; virtual bool store_longlong(longlong from, bool unsigned_flag)=0; + virtual bool store_decimal(const my_decimal *)=0; virtual bool store(const char *from, uint length, CHARSET_INFO *cs)=0; virtual bool store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0; @@ -107,6 +108,7 @@ public: virtual bool store_short(longlong from); virtual bool store_long(longlong from); virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store_decimal(const my_decimal *); virtual bool store(const char *from, uint length, CHARSET_INFO *cs); virtual bool store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); @@ -137,6 +139,7 @@ public: virtual bool store_short(longlong from); virtual bool store_long(longlong from); virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store_decimal(const my_decimal *); virtual bool store(const char *from,uint length, CHARSET_INFO *cs); virtual bool store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); diff --git a/sql/set_var.cc b/sql/set_var.cc index 7a528467e24..6fb44ae3ea3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -100,6 +100,8 @@ static int check_pseudo_thread_id(THD *thd, set_var *var); static bool set_log_bin(THD *thd, set_var *var); static void fix_low_priority_updates(THD *thd, enum_var_type type); static void fix_tx_isolation(THD *thd, enum_var_type type); +static int check_completion_type(THD *thd, set_var *var); +static void fix_completion_type(THD *thd, enum_var_type type); static void fix_net_read_timeout(THD *thd, enum_var_type type); static void fix_net_write_timeout(THD *thd, enum_var_type type); static void fix_net_retry_count(THD *thd, enum_var_type type); @@ -149,6 +151,10 @@ sys_var_character_set_database sys_character_set_database("character_set_databas sys_var_character_set_client sys_character_set_client("character_set_client"); sys_var_character_set_connection sys_character_set_connection("character_set_connection"); sys_var_character_set_results sys_character_set_results("character_set_results"); +sys_var_thd_ulong sys_completion_type("completion_type", + &SV::completion_type, + check_completion_type, + fix_completion_type); sys_var_collation_connection sys_collation_connection("collation_connection"); sys_var_collation_database sys_collation_database("collation_database"); sys_var_collation_server sys_collation_server("collation_server"); @@ -352,6 +358,14 @@ sys_var_thd_storage_engine sys_storage_engine("storage_engine", &SV::table_type); #ifdef HAVE_REPLICATION sys_var_sync_binlog_period sys_sync_binlog_period("sync_binlog", &sync_binlog_period); +sys_var_thd_ulong sys_sync_replication("sync_replication", + &SV::sync_replication); +sys_var_thd_ulong sys_sync_replication_slave_id( + "sync_replication_slave_id", + &SV::sync_replication_slave_id); +sys_var_thd_ulong sys_sync_replication_timeout( + "sync_replication_timeout", + &SV::sync_replication_timeout); #endif sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm); sys_var_long_ptr sys_table_cache_size("table_cache", @@ -399,6 +413,7 @@ sys_var_thd_bool sys_ndb_use_exact_count("ndb_use_exact_count", &SV::ndb_use_exact_count); sys_var_thd_bool sys_ndb_use_transactions("ndb_use_transactions", &SV::ndb_use_transactions); +sys_var_long_ptr sys_ndb_cache_check_time("ndb_cache_check_time", &ndb_cache_check_time); #endif /* Time/date/datetime formats */ @@ -532,6 +547,7 @@ sys_var *sys_variables[]= &sys_collation_connection, &sys_collation_database, &sys_collation_server, + &sys_completion_type, &sys_concurrent_insert, &sys_connect_timeout, &sys_date_format, @@ -640,6 +656,9 @@ sys_var *sys_variables[]= &sys_storage_engine, #ifdef HAVE_REPLICATION &sys_sync_binlog_period, + &sys_sync_replication, + &sys_sync_replication_slave_id, + &sys_sync_replication_timeout, #endif &sys_sync_frm, &sys_table_cache_size, @@ -670,6 +689,7 @@ sys_var *sys_variables[]= &sys_ndb_force_send, &sys_ndb_use_exact_count, &sys_ndb_use_transactions, + &sys_ndb_cache_check_time, #endif &sys_unique_checks, &sys_updatable_views_with_limit, @@ -708,6 +728,7 @@ struct show_var_st init_vars[]= { {sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS}, {sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS}, {sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS}, + {sys_completion_type.name, (char*) &sys_completion_type, SHOW_SYS}, {sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS}, {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS}, {"datadir", mysql_real_data_home, SHOW_CHAR}, @@ -849,6 +870,7 @@ struct show_var_st init_vars[]= { {sys_ndb_force_send.name, (char*) &sys_ndb_force_send, SHOW_SYS}, {sys_ndb_use_exact_count.name,(char*) &sys_ndb_use_exact_count, SHOW_SYS}, {sys_ndb_use_transactions.name,(char*) &sys_ndb_use_transactions, SHOW_SYS}, + {sys_ndb_cache_check_time.name,(char*) &sys_ndb_cache_check_time, SHOW_SYS}, #endif {sys_net_buffer_length.name,(char*) &sys_net_buffer_length, SHOW_SYS}, {sys_net_read_timeout.name, (char*) &sys_net_read_timeout, SHOW_SYS}, @@ -907,6 +929,9 @@ struct show_var_st init_vars[]= { {sys_storage_engine.name, (char*) &sys_storage_engine, SHOW_SYS}, #ifdef HAVE_REPLICATION {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS}, + {sys_sync_replication.name, (char*) &sys_sync_replication, SHOW_SYS}, + {sys_sync_replication_slave_id.name, (char*) &sys_sync_replication_slave_id,SHOW_SYS}, + {sys_sync_replication_timeout.name, (char*) &sys_sync_replication_timeout,SHOW_SYS}, #endif {sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS}, #ifdef HAVE_TZNAME @@ -1122,6 +1147,21 @@ static void fix_tx_isolation(THD *thd, enum_var_type type) thd->variables.tx_isolation); } +static void fix_completion_type(THD *thd __attribute__(unused), + enum_var_type type __attribute__(unused)) {} + +static int check_completion_type(THD *thd, set_var *var) +{ + longlong val= var->value->val_int(); + if (val < 0 || val > 2) + { + char buf[64]; + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, llstr(val, buf)); + return 1; + } + return 0; +} + /* If we are changing the thread variable, we have to copy it to NET too @@ -1499,7 +1539,7 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type, bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; const char *value; String str(buff, sizeof(buff), system_charset_info), *res; @@ -1536,7 +1576,7 @@ err: bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) { bool not_used; - char buff[80], *error= 0; + char buff[STRING_BUFFER_USUAL_SIZE], *error= 0; uint error_len= 0; String str(buff, sizeof(buff), system_charset_info), *res; @@ -1747,7 +1787,7 @@ bool sys_var_thd_date_time_format::update(THD *thd, set_var *var) bool sys_var_thd_date_time_format::check(THD *thd, set_var *var) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String str(buff,sizeof(buff), system_charset_info), *res; DATE_TIME_FORMAT *format; @@ -1851,7 +1891,7 @@ bool sys_var_collation::check(THD *thd, set_var *var) if (var->value->result_type() == STRING_RESULT) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String str(buff,sizeof(buff), system_charset_info), *res; if (!(res=var->value->val_str(&str))) { @@ -1885,7 +1925,7 @@ bool sys_var_character_set::check(THD *thd, set_var *var) if (var->value->result_type() == STRING_RESULT) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String str(buff,sizeof(buff), system_charset_info), *res; if (!(res=var->value->val_str(&str))) { @@ -2024,9 +2064,15 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type) } } -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool sys_var_character_set_server::check(THD *thd, set_var *var) { + /* + To be perfect we should fail even if we are a 5.0.3 slave, a 4.1 master, + and user wants to change our global character set variables. Because + replicating a 4.1 assumes those are not changed. But that's not easy to + do. + */ if ((var->type == OPT_GLOBAL) && (mysql_bin_log.is_open() || active_mi->slave_running || active_mi->rli.slave_running)) @@ -2131,7 +2177,7 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type) } } -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool sys_var_collation_server::check(THD *thd, set_var *var) { if ((var->type == OPT_GLOBAL) && @@ -2936,7 +2982,7 @@ int set_var::check(THD *thd) return 0; } - if ((!value->fixed && + if ((!value->fixed && value->fix_fields(thd, 0, &value)) || value->check_cols(1)) return -1; if (var->check_update_type(value->result_type())) @@ -3075,7 +3121,7 @@ int set_var_password::update(THD *thd) bool sys_var_thd_storage_engine::check(THD *thd, set_var *var) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; const char *value; String str(buff, sizeof(buff), &my_charset_latin1), *res; diff --git a/sql/set_var.h b/sql/set_var.h index 8514b518660..3104fd38976 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -564,7 +564,7 @@ class sys_var_character_set_server :public sys_var_character_set public: sys_var_character_set_server(const char *name_arg) : sys_var_character_set(name_arg) {} -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool check(THD *thd, set_var *var); #endif void set_default(THD *thd, enum_var_type type); @@ -602,7 +602,7 @@ class sys_var_collation_server :public sys_var_collation { public: sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {} -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool check(THD *thd, set_var *var); #endif bool update(THD *thd, set_var *var); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7826be85679..030949e15d1 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5094,7 +5094,7 @@ ER_SP_BADSELECT 0A000 ER_SP_BADRETURN 42000 eng "RETURN is only allowed in a FUNCTION" ER_SP_BADSTATEMENT 0A000 - eng "Statements like SELECT, INSERT, UPDATE (and others) are not allowed in a FUNCTION" + eng "LOCK and UNLOCK tables are not allowed in stored procedures" ER_UPDATE_LOG_DEPRECATED_IGNORED 42000 eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored" ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000 diff --git a/sql/slave.cc b/sql/slave.cc index 0c5ebe0744a..f3ab4b21832 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -660,13 +660,14 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, pthread_cond_t* term_cond, volatile uint *slave_running) { + DBUG_ENTER("terminate_slave_thread"); if (term_lock) { pthread_mutex_lock(term_lock); if (!*slave_running) { pthread_mutex_unlock(term_lock); - return ER_SLAVE_NOT_RUNNING; + DBUG_RETURN(ER_SLAVE_NOT_RUNNING); } } DBUG_ASSERT(thd != 0); @@ -678,6 +679,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, while (*slave_running) // Should always be true { + DBUG_PRINT("loop", ("killing slave thread")); KICK_SLAVE(thd); /* There is a small chance that slave thread might miss the first @@ -689,7 +691,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, } if (term_lock) pthread_mutex_unlock(term_lock); - return 0; + DBUG_RETURN(0); } @@ -1418,13 +1420,20 @@ not always make sense; please check the manual before using it)."; values of these 2 are never used (new connections don't use them). We don't test equality of global collation_database either as it's is going to be deprecated (made read-only) in 4.1 very soon. - We don't do it for <3.23.57 because masters <3.23.50 hang on - SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). + The test is only relevant if master < 5.0.3 (we'll test only if it's older + than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores + charset info in each binlog event. + We don't do it for 3.23 because masters <3.23.50 hang on + SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we + test only if master is 4.x. */ - if (strncmp(mi->rli.relay_log.description_event_for_queue->server_version, - "3.23.57",7) < 0) + + /* redundant with rest of code but safer against later additions */ + if (*mysql->server_version == '3') goto err; - if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) && + + if ((*mysql->server_version == '4') && + !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -1447,8 +1456,12 @@ be equal for replication to work"; such check will broke everything for them. (And now everything will work for them because by default both their master and slave will have 'SYSTEM' time zone). + + TODO: when the new replication of timezones is sorted out with Dmitri, + change >= '4' to == '4'. */ - if (!mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && + if ((*mysql->server_version >= '4') && + !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -2527,6 +2540,7 @@ st_relay_log_info::st_relay_log_info() bzero((char*) &info_file, sizeof(info_file)); bzero((char*) &cache_buf, sizeof(cache_buf)); + cached_charset_invalidate(); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST); @@ -2755,6 +2769,7 @@ void set_slave_thread_options(THD* thd) { thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) | OPTION_AUTO_IS_NULL; + thd->variables.completion_type= 0; } /* @@ -3078,6 +3093,24 @@ bool st_relay_log_info::is_until_satisfied() } +void st_relay_log_info::cached_charset_invalidate() +{ + /* Full of zeroes means uninitialized. */ + bzero(cached_charset, sizeof(cached_charset)); +} + + +bool st_relay_log_info::cached_charset_compare(char *charset) +{ + if (bcmp(cached_charset, charset, sizeof(cached_charset))) + { + memcpy(cached_charset, charset, sizeof(cached_charset)); + return 1; + } + return 0; +} + + static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) { /* @@ -3722,6 +3755,8 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions")); pthread_cond_broadcast(&rli->data_cond); rli->ignore_log_space_limit= 0; /* don't need any lock */ + /* we die so won't remember charset - re-update them on next thread start */ + rli->cached_charset_invalidate(); rli->save_temporary_tables = thd->temporary_tables; /* diff --git a/sql/slave.h b/sql/slave.h index e0816fd45a7..598ff0a7845 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -291,6 +291,8 @@ typedef struct st_relay_log_info UNTIL_LOG_NAMES_CMP_UNKNOWN= -2, UNTIL_LOG_NAMES_CMP_LESS= -1, UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1 } until_log_names_cmp_result; + + char cached_charset[6]; st_relay_log_info(); ~st_relay_log_info(); @@ -334,6 +336,14 @@ typedef struct st_relay_log_info return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos : group_relay_log_pos); } + /* + Last charset (6 bytes) seen by slave SQL thread is cached here; it helps + the thread save 3 get_charset() per Query_log_event if the charset is not + changing from event to event (common situation). + When the 6 bytes are equal to 0 is used to mean "cache is invalidated". + */ + void cached_charset_invalidate(); + bool cached_charset_compare(char *charset); } RELAY_LOG_INFO; diff --git a/sql/sp.cc b/sql/sp.cc index 84b126e5ecd..46b08c3e847 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -854,13 +854,14 @@ sp_show_status_procedure(THD *thd, const char *wild) ******************************************************************************/ sp_head * -sp_find_function(THD *thd, sp_name *name) +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)); - if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name))) + if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) && + !cache_only) { if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK) sp= NULL; @@ -963,7 +964,7 @@ sp_function_exists(THD *thd, sp_name *name) byte * -sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first) +sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first) { LEX_STRING *lsp= (LEX_STRING *)ptr; *plen= lsp->length; @@ -972,37 +973,36 @@ sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first) void -sp_add_fun_to_lex(LEX *lex, sp_name *fun) +sp_add_to_hash(HASH *h, sp_name *fun) { - if (! hash_search(&lex->spfuns, - (byte *)fun->m_qname.str, fun->m_qname.length)) + if (! hash_search(h, (byte *)fun->m_qname.str, fun->m_qname.length)) { LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING)); ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length); ls->length= fun->m_qname.length; - my_hash_insert(&lex->spfuns, (byte *)ls); + my_hash_insert(h, (byte *)ls); } } void -sp_merge_funs(LEX *dst, LEX *src) +sp_merge_hash(HASH *dst, HASH *src) { - for (uint i=0 ; i < src->spfuns.records ; i++) + for (uint i=0 ; i < src->records ; i++) { - LEX_STRING *ls= (LEX_STRING *)hash_element(&src->spfuns, i); + LEX_STRING *ls= (LEX_STRING *)hash_element(src, i); - if (! hash_search(&dst->spfuns, (byte *)ls->str, ls->length)) - my_hash_insert(&dst->spfuns, (byte *)ls); + if (! hash_search(dst, (byte *)ls->str, ls->length)) + my_hash_insert(dst, (byte *)ls); } } int -sp_cache_functions(THD *thd, LEX *lex) +sp_cache_routines(THD *thd, LEX *lex, int type) { - HASH *h= &lex->spfuns; + HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs); int ret= 0; for (uint i=0 ; i < h->records ; i++) @@ -1011,7 +1011,9 @@ sp_cache_functions(THD *thd, LEX *lex) sp_name name(*ls); name.m_qname= *ls; - if (! sp_cache_lookup(&thd->sp_func_cache, &name)) + if (! sp_cache_lookup((type == TYPE_ENUM_FUNCTION ? + &thd->sp_func_cache : &thd->sp_proc_cache), + &name)) { sp_head *sp; LEX *oldlex= thd->lex; @@ -1027,11 +1029,23 @@ sp_cache_functions(THD *thd, LEX *lex) name.m_name.str+= 1; name.m_name.length= name.m_qname.length - name.m_db.length - 1; - if (db_find_routine(thd, TYPE_ENUM_FUNCTION, &name, &sp) - == SP_OK) + if (db_find_routine(thd, type, &name, &sp) == SP_OK) { - sp_cache_insert(&thd->sp_func_cache, sp); - ret= sp_cache_functions(thd, newlex); + if (type == TYPE_ENUM_FUNCTION) + sp_cache_insert(&thd->sp_func_cache, sp); + else + sp_cache_insert(&thd->sp_proc_cache, sp); + ret= sp_cache_routines(thd, newlex, TYPE_ENUM_FUNCTION); + if (!ret) + { + sp_merge_hash(&lex->spfuns, &newlex->spfuns); + ret= sp_cache_routines(thd, newlex, TYPE_ENUM_PROCEDURE); + } + if (!ret) + { + sp_merge_hash(&lex->spprocs, &newlex->spprocs); + sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs); + } delete newlex; thd->lex= oldlex; if (ret) @@ -1041,9 +1055,6 @@ sp_cache_functions(THD *thd, LEX *lex) { delete newlex; thd->lex= oldlex; - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", ls->str); - ret= 1; - break; } } } diff --git a/sql/sp.h b/sql/sp.h index 152c59d0d02..6290324bb86 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -56,7 +56,7 @@ int sp_show_status_procedure(THD *thd, const char *wild); sp_head * -sp_find_function(THD *thd, sp_name *name); +sp_find_function(THD *thd, sp_name *name, bool cache_only = 0); int sp_create_function(THD *thd, sp_head *sp); @@ -77,14 +77,15 @@ bool sp_function_exists(THD *thd, sp_name *name); -// This is needed since we have to read the functions before we -// do anything else. +/* + * For precaching of functions and procedures + */ void -sp_add_fun_to_lex(LEX *lex, sp_name *fun); +sp_add_to_hash(HASH *h, sp_name *fun); void -sp_merge_funs(LEX *dst, LEX *src); +sp_merge_hash(HASH *dst, HASH *src); int -sp_cache_functions(THD *thd, LEX *lex); +sp_cache_routines(THD *thd, LEX *lex, int type); // diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 3f2969768c5..075aef9d286 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -23,6 +23,7 @@ #include "sp.h" #include "sp_pcontext.h" #include "sp_rcontext.h" +#include "sp_cache.h" Item_result sp_map_result_type(enum enum_field_types type) @@ -36,6 +37,8 @@ sp_map_result_type(enum enum_field_types type) case MYSQL_TYPE_INT24: return INT_RESULT; case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return DECIMAL_RESULT; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: return REAL_RESULT; @@ -127,7 +130,7 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) else { DBUG_PRINT("info", ("INT_RESULT: %d", i)); - it= new Item_int(it->val_int()); + it= new Item_int(i); } break; } @@ -147,13 +150,80 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) uint8 decimals= it->decimals; uint32 max_length= it->max_length; DBUG_PRINT("info", ("REAL_RESULT: %g", d)); - it= new Item_real(it->val_real()); + it= new Item_float(d); it->decimals= decimals; it->max_length= max_length; } break; } - default: + case DECIMAL_RESULT: + { + switch (it->result_type()) + { + case DECIMAL_RESULT: + { + my_decimal value, *val= it->val_decimal(&value); + if (it->null_value) + it= new Item_null(); + else + it= new Item_decimal(val); + break; + } + case INT_RESULT: + { + longlong val= it->val_int(); + if (it->null_value) + it= new Item_null(); + else + it= new Item_decimal(val, (int)it->max_length, + (bool)it->unsigned_flag); + break; + } + case REAL_RESULT: + { + double val= it->val_real(); + if (it->null_value) + it= new Item_null(); + else + it= new Item_decimal(val, (int)it->max_length, + (int)it->decimals); + break; + } + case STRING_RESULT: + { + char buffer[MAX_FIELD_WIDTH]; + String tmp(buffer, sizeof(buffer), it->collation.collation); + String *val= it->val_str(&tmp); + if (it->null_value) + it= new Item_null(); + else + it= new Item_decimal(val->ptr(), val->length(), val->charset()); + break; + } + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } +#ifndef DBUG_OFF + if (it->null_value) + { + DBUG_PRINT("info", ("DECIMAL_RESULT: null")); + } + else + { + my_decimal value, *val= it->val_decimal(&value); + int len; + char *buff= + (char *)my_alloca(len= my_decimal_string_length(val) + 3); + String str(buff, len, &my_charset_bin); + my_decimal2string(0, val, 0, 0, 0, &str); + DBUG_PRINT("info", ("DECIMAL_RESULT: %s", str.ptr())); + my_afree(buff); + } +#endif + break; + } + case STRING_RESULT: { char buffer[MAX_FIELD_WIDTH]; String tmp(buffer, sizeof(buffer), it->collation.collation); @@ -172,6 +242,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) } break; } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } } @@ -259,11 +332,14 @@ sp_head::sp_head() :Item_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE), m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE) { + extern byte * + sp_table_key(const byte *ptr, uint *plen, my_bool first); DBUG_ENTER("sp_head::sp_head"); state= INITIALIZED; m_backpatch.empty(); m_lex.empty(); + hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); DBUG_VOID_RETURN; } @@ -424,10 +500,10 @@ sp_head::~sp_head() void sp_head::destroy() { - DBUG_ENTER("sp_head::destroy"); - DBUG_PRINT("info", ("name: %s", m_name.str)); sp_instr *i; LEX *lex; + DBUG_ENTER("sp_head::destroy"); + DBUG_PRINT("info", ("name: %s", m_name.str)); for (uint ip = 0 ; (i = get_instr(ip)) ; ip++) delete i; @@ -439,6 +515,8 @@ sp_head::destroy() if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left delete lex; } + if (m_sptabs.array.buffer) + hash_free(&m_sptabs); DBUG_VOID_RETURN; } @@ -732,6 +810,10 @@ sp_head::execute_procedure(THD *thd, List *args) static_cast(fi); suv= new Item_func_set_user_var(guv->get_name(), item); + /* + we do not check suv->fixed, bacause it can't be fixed after + creation + */ suv->fix_fields(thd, NULL, &item); suv->fix_length_and_dec(); suv->check(); @@ -799,48 +881,10 @@ sp_head::restore_lex(THD *thd) oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); // Collect some data from the sub statement lex. - sp_merge_funs(oldlex, sublex); -#ifdef NOT_USED_NOW - // QQ We're not using this at the moment. - if (sublex.sql_command == SQLCOM_CALL) - { - // It would be slightly faster to keep the list sorted, but we need - // an "insert before" method to do that. - char *proc= sublex.udf.name.str; - - List_iterator_fast li(m_calls); - char **it; - - while ((it= li++)) - if (my_strcasecmp(system_charset_info, proc, *it) == 0) - break; - if (! it) - m_calls.push_back(&proc); - - } + sp_merge_hash(&oldlex->spfuns, &sublex->spfuns); + sp_merge_hash(&oldlex->spprocs, &sublex->spprocs); // Merge used tables - // QQ ...or just open tables in thd->open_tables? - // This is not entirerly clear at the moment, but for now, we collect - // tables here. - for (sl= sublex.all_selects_list ; - sl ; - sl= sl->next_select()) - { - for (TABLE_LIST *tables= sl->get_table_list() ; - tables ; - tables= tables->next) - { - List_iterator_fast li(m_tables); - char **tb; - - while ((tb= li++)) - if (my_strcasecmp(system_charset_info, tables->table_name, *tb) == 0) - break; - if (! tb) - m_tables.push_back(&tables->table_name); - } - } -#endif + sp_merge_table_list(thd, &m_sptabs, sublex->query_tables, sublex); if (! sublex->sp_lex_in_use) delete sublex; thd->lex= oldlex; @@ -1864,3 +1908,242 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ + +/* + * Table merge hash table + * + */ +typedef struct st_sp_table +{ + LEX_STRING qname; + bool temp; + TABLE_LIST *table; +} SP_TABLE; + +byte * +sp_table_key(const byte *ptr, uint *plen, my_bool first) +{ + SP_TABLE *tab= (SP_TABLE *)ptr; + *plen= tab->qname.length; + return (byte *)tab->qname.str; +} + +/* + * Merge the table list into the hash table. + * If the optional lex is provided, it's used to check and set + * the flag for creation of a temporary table. + */ +bool +sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table, + LEX *lex_for_tmp_check) +{ + for (; table ; table= table->next_global) + if (!table->derived && + (!table->select_lex || + !(table->select_lex->options & OPTION_SCHEMA_TABLE))) + { + char tname[64+1+64+1+64+1]; // db.table.alias\0 + uint tlen, alen; + SP_TABLE *tab; + + tlen= table->db_length; + memcpy(tname, table->db, tlen); + tname[tlen++]= '.'; + memcpy(tname+tlen, table->table_name, table->table_name_length); + tlen+= table->table_name_length; + tname[tlen++]= '.'; + alen= strlen(table->alias); + memcpy(tname+tlen, table->alias, alen); + tlen+= alen; + tname[tlen]= '\0'; + + if ((tab= (SP_TABLE *)hash_search(h, (byte *)tname, tlen))) + { + if (tab->table->lock_type < table->lock_type) + tab->table= table; // Use the table with the highest lock type + } + else + { + if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) + return FALSE; + tab->qname.length= tlen; + tab->qname.str= (char *)thd->strmake(tname, tab->qname.length); + if (!tab->qname.str) + return FALSE; + if (lex_for_tmp_check && + lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && + lex_for_tmp_check->query_tables == table && + lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) + tab->temp= TRUE; + tab->table= table; + my_hash_insert(h, (byte *)tab); + } + } + return TRUE; +} + +void +sp_merge_routine_tables(THD *thd, LEX *lex) +{ + uint i; + + for (i= 0 ; i < lex->spfuns.records ; i++) + { + sp_head *sp; + LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spfuns, i); + sp_name name(*ls); + + name.m_qname= *ls; + if ((sp= sp_cache_lookup(&thd->sp_func_cache, &name))) + sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs); + } + for (i= 0 ; i < lex->spprocs.records ; i++) + { + sp_head *sp; + LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spprocs, i); + sp_name name(*ls); + + name.m_qname= *ls; + if ((sp= sp_cache_lookup(&thd->sp_proc_cache, &name))) + sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs); + } +} + +void +sp_merge_table_hash(HASH *hdst, HASH *hsrc) +{ + for (uint i=0 ; i < hsrc->records ; i++) + { + SP_TABLE *tabdst; + SP_TABLE *tabsrc= (SP_TABLE *)hash_element(hsrc, i); + + if (! (tabdst= (SP_TABLE *)hash_search(hdst, + tabsrc->qname.str, + tabsrc->qname.length))) + { + my_hash_insert(hdst, (byte *)tabsrc); + } + else + { + if (tabdst->table->lock_type < tabsrc->table->lock_type) + tabdst->table= tabsrc->table; // Use the highest lock type + } + } +} + +TABLE_LIST * +sp_hash_to_table_list(THD *thd, HASH *h) +{ + uint i; + TABLE_LIST *tables= NULL; + DBUG_ENTER("sp_hash_to_table_list"); + + for (i=0 ; i < h->records ; i++) + { + SP_TABLE *stab= (SP_TABLE *)hash_element(h, i); + if (stab->temp) + continue; + TABLE_LIST *table, *otable= stab->table; + + if (! (table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST)))) + return NULL; + table->db= otable->db; + table->db_length= otable->db_length; + table->alias= otable->alias; + table->table_name= otable->table_name; + table->table_name_length= otable->table_name_length; + table->lock_type= otable->lock_type; + table->updating= otable->updating; + table->force_index= otable->force_index; + table->ignore_leaves= otable->ignore_leaves; + table->derived= otable->derived; + table->schema_table= otable->schema_table; + table->select_lex= otable->select_lex; + table->cacheable_table= otable->cacheable_table; + table->use_index= otable->use_index; + table->ignore_index= otable->ignore_index; + table->option= otable->option; + + table->next_global= tables; + tables= table; + } + DBUG_RETURN(tables); +} + +bool +sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("sp_open_and_lock_tables"); + bool ret; + + thd->in_lock_tables= 1; + thd->options|= OPTION_TABLE_LOCK; + if (simple_open_n_lock_tables(thd, tables)) + { + thd->options&= ~(ulong)(OPTION_TABLE_LOCK); + ret= FALSE; + } + else + { +#if 0 + // QQ What about this? +#ifdef HAVE_QUERY_CACHE + if (thd->variables.query_cache_wlock_invalidate) + query_cache.invalidate_locked_for_write(first_table); // QQ first_table? +#endif /* HAVE_QUERY_CACHE */ +#endif + thd->locked_tables= thd->lock; + thd->lock= 0; + ret= TRUE; + } + thd->in_lock_tables= 0; + DBUG_RETURN(ret); +} + +void +sp_unlock_tables(THD *thd) +{ + thd->lock= thd->locked_tables; + thd->locked_tables= 0; + close_thread_tables(thd); // Free tables + if (thd->options & OPTION_TABLE_LOCK) + { +#if 0 + // QQ What about this? + end_active_trans(thd); +#endif + thd->options&= ~(ulong)(OPTION_TABLE_LOCK); + } + if (thd->global_read_lock) + unlock_global_read_lock(thd); +} + +/* + * Simple function for adding an explicetly named (systems) table to + * the global table list, e.g. "mysql", "proc". + * + */ +TABLE_LIST * +sp_add_to_query_tables(THD *thd, LEX *lex, + const char *db, const char *name, + thr_lock_type locktype) +{ + TABLE_LIST *table; + + if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST)))) + { + my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST)); + return NULL; + } + table->db_length= strlen(db); + table->db= thd->strmake(db, table->db_length); + table->table_name_length= strlen(name); + table->table_name= thd->strmake(name, table->table_name_length); + table->alias= thd->strdup(name); + table->lock_type= locktype; + table->select_lex= lex->current_select; // QQ? + table->cacheable_table= 1; + + lex->add_to_query_tables(table); + return table; +} diff --git a/sql/sp_head.h b/sql/sp_head.h index c4d2068661c..5df9c753048 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -92,11 +92,6 @@ public: uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value st_sp_chistics *m_chistics; ulong m_sql_mode; // For SHOW CREATE -#if NOT_USED_NOW - // QQ We're not using this at the moment. - List m_calls; // Called procedures. - List m_tables; // Used tables. -#endif LEX_STRING m_qname; // db.name LEX_STRING m_db; LEX_STRING m_name; @@ -108,6 +103,7 @@ public: LEX_STRING m_definer_host; longlong m_created; longlong m_modified; + HASH m_sptabs; /* Merged table lists */ // Pointers set during parsing uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end, *m_body_begin; @@ -897,4 +893,22 @@ void sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ +bool +sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table, + LEX *lex_for_tmp_check = 0); +void +sp_merge_routine_tables(THD *thd, LEX *lex); +void +sp_merge_table_hash(HASH *hdst, HASH *hsrc); +TABLE_LIST * +sp_hash_to_table_list(THD *thd, HASH *h); +bool +sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables); +void +sp_unlock_tables(THD *thd); +TABLE_LIST * +sp_add_to_query_tables(THD *thd, LEX *lex, + const char *db, const char *name, + thr_lock_type locktype); + #endif /* _SP_HEAD_H_ */ diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 609882b84c6..0c6c8c5aa70 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -249,14 +249,20 @@ sp_cursor::fetch(THD *thd, List *vars) it= new Item_int(s); break; case REAL_RESULT: - it= new Item_real(s, strlen(s)); + it= new Item_float(s, strlen(s)); break; - default: + case DECIMAL_RESULT: + it= new Item_decimal(s, strlen(s), thd->db_charset); + break; + case STRING_RESULT: { uint len= strlen(s); it= new Item_string(thd->strmake(s, len), len, thd->db_charset); break; } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } thd->spcont->set_item(pv->offset, it); } diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 3f97cab1511..c2eea524cac 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -59,8 +59,11 @@ int compare_ulonglong2(void* cmp_arg __attribute__((unused)), return compare_ulonglong(s,t); } -bool append_escaped(String *to_str, String *from_str); -bool append_escaped(String *to_str, char *from, uint from_len); +int compare_decimal2(int* len, const char *s, const char *t) +{ + return memcmp(s, t, *len); +} + Procedure * proc_analyse_init(THD *thd, ORDER *param, select_result *result, @@ -142,6 +145,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, } if (item->result_type() == REAL_RESULT) *f_info++ = new field_real(item, pc); + if (item->result_type() == DECIMAL_RESULT) + *f_info++= new field_decimal(item, pc); if (item->result_type() == STRING_RESULT) *f_info++ = new field_str(item, pc); } @@ -263,7 +268,7 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num) } else // ulonglong is as big as bigint in MySQL { - if ((check_ulonglong(num, info->integers) == REAL_NUM)) + if ((check_ulonglong(num, info->integers) == DECIMAL_NUM)) return 0; ev_info->ullval = (ulonglong) max(ev_info->ullval, info->ullval); ev_info->max_dval = (double) max(ev_info->max_dval, info->dval); @@ -451,6 +456,80 @@ void field_real::add() } // field_real::add +void field_decimal::add() +{ + my_decimal dec_buf, *dec= item->val_decimal(&dec_buf); + uint length, zero_count, decs; + TREE_ELEMENT *element; + + if (item->null_value) + { + nulls++; + return; + } + + length= my_decimal_string_length(dec); + + if (room_in_tree) + { + char buf[DECIMAL_MAX_FIELD_SIZE]; + my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf, + item->max_length, item->decimals); + if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg))) + { + room_in_tree = 0; // Remove tree, out of RAM ? + delete_tree(&tree); + } + /* + if element->count == 1, this element can be found only once from tree + if element->count == 2, or more, this element is already in tree + */ + else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements) + { + room_in_tree = 0; // Remove tree, too many elements + delete_tree(&tree); + } + } + + if (!found) + { + found = 1; + min_arg = max_arg = sum[0] = *dec; + min_arg.fix_buffer_pointer(); + max_arg.fix_buffer_pointer(); + sum[0].fix_buffer_pointer(); + my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec); + cur_sum= 0; + min_length = max_length = length; + } + else + { + int next_cur_sum= cur_sum ^ 1; + my_decimal sqr_buf; + + my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec); + my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec); + my_decimal_add(E_DEC_FATAL_ERROR, + sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf); + cur_sum= next_cur_sum; + if (length < min_length) + min_length = length; + if (length > max_length) + max_length = length; + if (my_decimal_cmp(dec, &min_arg) < 0) + { + min_arg= *dec; + min_arg.fix_buffer_pointer(); + } + if (my_decimal_cmp(dec, &max_arg) > 0) + { + max_arg= *dec; + max_arg.fix_buffer_pointer(); + } + } +} + + void field_longlong::add() { char buff[MAX_FIELD_WIDTH]; @@ -888,6 +967,70 @@ void field_ulonglong::get_opt_type(String *answer, } //field_ulonglong::get_opt_type +void field_decimal::get_opt_type(String *answer, + ha_rows total_rows __attribute__((unused))) +{ + my_decimal zero; + char buff[MAX_FIELD_WIDTH]; + + my_decimal_set_zero(&zero); + my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0); + + sprintf(buff, "DECIMAL(%d, %d)", + (int)(max_length - (item->decimals ? 1 : 0)), item->decimals); + if (is_unsigned) + strcat(buff, " UNSIGNED"); + answer->append(buff, (uint) strlen(buff)); +} + + +String *field_decimal::get_min_arg(String *str) +{ + my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str); + return str; +} + + +String *field_decimal::get_max_arg(String *str) +{ + my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str); + return str; +} + + +String *field_decimal::avg(String *s, ha_rows rows) +{ + if (!(rows - nulls)) + { + s->set((double) 0.0, 1,my_thd_charset); + return s; + } + my_decimal num, avg_val; + int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num); + my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, 0); + my_decimal2string(E_DEC_FATAL_ERROR, &avg_val, 0, 0, '0', s); + return s; +} + + +String *field_decimal::std(String *s, ha_rows rows) +{ + if (!(rows - nulls)) + { + s->set((double) 0.0, 1,my_thd_charset); + return s; + } + my_decimal num, std_val, sum2, sum2d; + int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num); + my_decimal_mul(E_DEC_FATAL_ERROR, &sum2, sum+cur_sum, sum+cur_sum); + my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0); + my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &std_val); + my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0); + my_decimal2string(E_DEC_FATAL_ERROR, &std_val, 0, 0, '0', s); + return s; +} + + int collect_string(String *element, element_count count __attribute__((unused)), TREE_INFO *info) @@ -922,6 +1065,28 @@ int collect_real(double *element, element_count count __attribute__((unused)), } // collect_real +int collect_decimal(char *element, element_count count, + TREE_INFO *info) +{ + char buff[DECIMAL_MAX_STR_LENGTH]; + String s(buff, sizeof(buff),&my_charset_bin); + + if (info->found) + info->str->append(','); + else + info->found = 1; + my_decimal dec; + binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec, + info->item->max_length, info->item->decimals); + + info->str->append('\''); + my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s); + info->str->append(s); + info->str->append('\''); + return 0; +} + + int collect_longlong(longlong *element, element_count count __attribute__((unused)), TREE_INFO *info) @@ -1023,12 +1188,12 @@ uint check_ulonglong(const char *str, uint length) bigger = LONG_NUM; } else if (length > ulonglong_len) - return REAL_NUM; + return DECIMAL_NUM; else { cmp = ulonglong_str; smaller = LONG_NUM; - bigger = REAL_NUM; + bigger = DECIMAL_NUM; } while (*cmp && *cmp++ == *str++) ; return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger; @@ -1087,38 +1252,3 @@ bool append_escaped(String *to_str, String *from_str) } return 0; } - -bool append_escaped(String *to_str, char *from, uint from_len) -{ - char *end, c; - - if (to_str->realloc(to_str->length() + from_len)) - return 1; - - end= from + from_len; - - for (; from < end; from++) - { - c= *from; - switch (c) { - case '\0': - c= '0'; - break; - case '\032': - c= 'Z'; - break; - case '\\': - case '\'': - break; - default: - goto normal_character; - } - if (to_str->append('\\')) - return 1; - - normal_character: - if (to_str->append(c)) - return 1; - } - return 0; -} diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 3d1cffecaef..a0f0df9b43b 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -61,6 +61,7 @@ int compare_longlong2(void* cmp_arg __attribute__((unused)), int compare_ulonglong(const ulonglong *s, const ulonglong *t); int compare_ulonglong2(void* cmp_arg __attribute__((unused)), const ulonglong *s, const ulonglong *t); +int compare_decimal2(int* len, const char *s, const char *t); Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List &field_list); void free_string(String*); @@ -143,6 +144,36 @@ public: }; +int collect_decimal(char *element, element_count count, + TREE_INFO *info); + +class field_decimal :public field_info +{ + my_decimal min_arg, max_arg; + my_decimal sum[2], sum_sqr[2]; + int cur_sum; + int bin_size; +public: + field_decimal(Item* a, analyse* b) :field_info(a,b) + { + bin_size= my_decimal_get_binary_size(a->max_length, a->decimals); + init_tree(&tree, 0, 0, bin_size, (qsort_cmp2)compare_decimal2, + 0, 0, (void *)&bin_size); + }; + + void add(); + void get_opt_type(String*, ha_rows); + String *get_min_arg(String *); + String *get_max_arg(String *); + String *avg(String *s, ha_rows rows); + friend int collect_decimal(char *element, element_count count, + TREE_INFO *info); + tree_walk_action collect_enum() + { return (tree_walk_action) collect_decimal; } + String *std(String *s, ha_rows rows); +}; + + int collect_real(double *element, element_count count, TREE_INFO *info); class field_real: public field_info diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3fb2fac5b27..eef86921012 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -31,7 +31,6 @@ TABLE *unused_tables; /* Used by mysql_test */ HASH open_cache; /* Used by mysql_test */ -HASH assign_cache; static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, const char *name, const char *alias, @@ -497,58 +496,58 @@ void close_temporary(TABLE *table,bool delete_table) void close_temporary_tables(THD *thd) { TABLE *table,*next; - char *query, *end; - uint query_buf_size; - bool found_user_tables = 0; + char *query, *name_in_query, *end; + uint greatest_key_length= 0; if (!thd->temporary_tables) return; + /* + We write a DROP TEMPORARY TABLE for each temp table left, so that our + replication slave can clean them up. Not one multi-table DROP TABLE binlog + event: this would cause problems if slave uses --replicate-*-table. + */ LINT_INIT(end); - query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS + /* We'll re-use always same buffer so make it big enough for longest name */ for (table=thd->temporary_tables ; table ; table=table->next) - /* - We are going to add 4 ` around the db/table names, so 1 does not look - enough; indeed it is enough, because table->key_length is greater (by 8, - because of server_id and thread_id) than db||table. - */ - query_buf_size+= table->s->key_length+1; + greatest_key_length= max(greatest_key_length, table->s->key_length); - if ((query = alloc_root(thd->mem_root, query_buf_size))) + if ((query = alloc_root(thd->mem_root, greatest_key_length+50))) // Better add "if exists", in case a RESET MASTER has been done - end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "); + name_in_query= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `"); for (table=thd->temporary_tables ; table ; table=next) { - if (query) // we might be out of memory, but this is not fatal + /* + In we are OOM for 'query' this is not fatal. We skip temporary tables + not created directly by the user. + */ + if (query && mysql_bin_log.is_open() && (table->s->table_name[0] != '#')) { - // skip temporary tables not created directly by the user - if (table->s->table_name[0] != '#') - found_user_tables = 1; - end = strxmov(end,"`",table->s->db,"`.`", - table->s->table_name,"`,", NullS); + /* + Here we assume table_cache_key always starts + with \0 terminated db name + */ + end = strxmov(name_in_query, table->s->db, "`.`", + table->s->table_name, "`", NullS); + Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE); + /* + Imagine the thread had created a temp table, then was doing a SELECT, and + the SELECT was killed. Then it's not clever to mark the statement above as + "killed", because it's not really a statement updating data, and there + are 99.99% chances it will succeed on slave. And, if thread is + killed now, it's not clever either. + If a real update (one updating a persistent table) was killed on the + master, then this real update will be logged with error_code=killed, + rightfully causing the slave to stop. + */ + qinfo.error_code= 0; + mysql_bin_log.write(&qinfo); } next=table->next; close_temporary(table); } - if (query && found_user_tables && mysql_bin_log.is_open()) - { - /* The -1 is to remove last ',' */ - thd->clear_error(); - Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0, FALSE); - /* - Imagine the thread had created a temp table, then was doing a SELECT, and - the SELECT was killed. Then it's not clever to mark the statement above as - "killed", because it's not really a statement updating data, and there - are 99.99% chances it will succeed on slave. - If a real update (one updating a persistent table) was killed on the - master, then this real update will be logged with error_code=killed, - rightfully causing the slave to stop. - */ - qinfo.error_code= 0; - mysql_bin_log.write(&qinfo); - } thd->temporary_tables=0; } @@ -854,7 +853,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->outer_join= table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= table->force_index= 0; table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= share->keys_in_use; table->used_keys= share->keys_for_keyread; @@ -919,10 +918,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { if (table->s->key_length == key_length && !memcmp(table->s->table_cache_key,key,key_length) && - !my_strcasecmp(system_charset_info, table->alias, alias) && - table->query_id != thd->query_id) + !my_strcasecmp(system_charset_info, table->alias, alias)) { - table->query_id=thd->query_id; + if (table->query_id != thd->query_id) + table->query_id=thd->query_id; DBUG_PRINT("info",("Using locked table")); goto reset; } @@ -1078,7 +1077,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->outer_join= table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= table->force_index= 0; table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= table->s->keys_in_use; table->insert_values= 0; @@ -1150,7 +1149,6 @@ bool reopen_table(TABLE *table,bool locked) tmp.tablenr= table->tablenr; tmp.used_fields= table->used_fields; tmp.const_table= table->const_table; - tmp.outer_join= table->outer_join; tmp.null_row= table->null_row; tmp.maybe_null= table->maybe_null; tmp.status= table->status; @@ -2120,13 +2118,31 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, table_list->alias, name, item_name, (ulong) ref)); if (table_list->field_translation) { - DBUG_ASSERT(ref != 0 && table_list->view != 0); - uint num= table_list->view->select_lex.item_list.elements; + uint num; + if (table_list->schema_table_reformed) + { + num= thd->lex->current_select->item_list.elements; + } + else + { + DBUG_ASSERT(ref != 0 && table_list->view != 0); + num= table_list->view->select_lex.item_list.elements; + } Field_translator *trans= table_list->field_translation; for (uint i= 0; i < num; i ++) { if (!my_strcasecmp(system_charset_info, trans[i].name, name)) { + if (table_list->schema_table_reformed) + { + /* + Translation table items are always Item_fields + and fixed already('mysql_schema_table' function). + So we can return ->field. It is used only for + 'show & where' commands. + */ + DBUG_RETURN(((Item_field*) (trans[i].item))->field); + } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_grants_view && check_grant_column(thd, &table_list->grant, @@ -2152,6 +2168,8 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, thd->change_item_tree(ref, item_ref); else if (item_ref) *ref= item_ref; + if (!(*ref)->fixed) + (*ref)->fix_fields(thd, 0, ref); } DBUG_RETURN((Field*) view_ref_found); } @@ -2758,6 +2776,20 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, thd->allow_sum_func= allow_sum_func; thd->where="field list"; + /* + To prevent fail on forward lookup we fill it with zerows, + then if we got pointer on zero after find_item_in_list we will know + that it is forward lookup. + + There is other way to solve problem: fill array with pointers to list, + but it will be slower. + + TODO: remove it when (if) we made one list for allfields and + ref_pointer_array + */ + if (ref_pointer_array) + bzero(ref_pointer_array, sizeof(Item *) * fields.elements); + Item **ref= ref_pointer_array; while ((item= it++)) { @@ -3358,7 +3390,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) if (cond_and->list.elements) { COND *on_expr= cond_and; - on_expr->fix_fields(thd, 0, &on_expr); + if (!on_expr->fixed) + on_expr->fix_fields(thd, 0, &on_expr); if (!embedded->outer_join) // Not left join { *conds= and_conds(*conds, cond_and); @@ -3367,7 +3400,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { - if ((*conds)->fix_fields(thd, tables, conds)) + if (!(*conds)->fixed && + (*conds)->fix_fields(thd, tables, conds)) goto err_no_arena; } } @@ -3379,8 +3413,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (embedded->on_expr && !embedded->on_expr->fixed) { - if (embedded->on_expr->fix_fields(thd, tables, - &embedded->on_expr)) + if (!embedded->on_expr->fixed && + embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr)) goto err_no_arena; } } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index c08d3eae0e1..e38e417e6df 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -777,6 +777,8 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) bzero(&flags, QUERY_CACHE_FLAGS_SIZE); flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? 1 : 0); + flags.client_protocol_41= (thd->client_capabilities & CLIENT_PROTOCOL_41 ? + 1 : 0); flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= @@ -912,12 +914,12 @@ end: int Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) { + ulonglong engine_data; Query_cache_query *query; Query_cache_block *first_result_block, *result_block; Query_cache_block_table *block_table, *block_table_end; ulong tot_length; Query_cache_query_flags flags; - bool check_tables; DBUG_ENTER("Query_cache::send_result_to_client"); if (query_cache_size == 0 || thd->variables.query_cache_type == 0) @@ -974,6 +976,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) bzero(&flags, QUERY_CACHE_FLAGS_SIZE); flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? 1 : 0); + flags.client_protocol_41= (thd->client_capabilities & CLIENT_PROTOCOL_41 ? + 1 : 0); flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= (thd->variables.character_set_results ? @@ -1023,7 +1027,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) goto err_unlock; } - check_tables= query->tables_type() & HA_CACHE_TBL_ASKTRANSACT; // Check access; block_table= query_block->table(0); block_table_end= block_table+query_block->n_tables; @@ -1084,19 +1087,30 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) goto err_unlock; // Parse query } #endif /*!NO_EMBEDDED_ACCESS_CHECKS*/ - if (check_tables && !ha_caching_allowed(thd, table->db(), - table->key_length(), - table->type())) + engine_data= table->engine_data(); + if (table->callback() && + !(*table->callback())(thd, table->db(), + table->key_length(), + &engine_data)) { DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s", table_list.db, table_list.alias)); BLOCK_UNLOCK_RD(query_block); - thd->lex->safe_to_cache_query= 0; // Don't try to cache this + if (engine_data != table->engine_data()) + { + DBUG_PRINT("qcache", + ("Handler require invalidation queries of %s.%s %lld-%lld", + table_list.db, table_list.alias, + engine_data, table->engine_data())); + invalidate_table(table->db(), table->key_length()); + } + else + thd->lex->safe_to_cache_query= 0; // Don't try to cache this goto err_unlock; // Parse query } else - DBUG_PRINT("qcache", ("handler allow caching (%d) %s,%s", - check_tables, table_list.db, table_list.alias)); + DBUG_PRINT("qcache", ("handler allow caching %s,%s", + table_list.db, table_list.alias)); } move_to_query_list_end(query_block); hits++; @@ -2124,7 +2138,9 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, if (!insert_table(tables_used->table->s->key_length, tables_used->table->s->table_cache_key, block_table, tables_used->db_length, - tables_used->table->file->table_cache_type())) + tables_used->table->file->table_cache_type(), + tables_used->callback_func, + tables_used->engine_data)) break; if (tables_used->table->s->db_type == DB_TYPE_MRG_MYISAM) @@ -2140,9 +2156,13 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, uint key_length= filename_2_table_key(key, table->table->filename, &db_length); (++block_table)->n= ++n; + /* + There are not callback function for for MyISAM, and engine data + */ if (!insert_table(key_length, key, block_table, db_length, - tables_used->table->file->table_cache_type())) + tables_used->table->file->table_cache_type(), + 0, 0)) goto err; } } @@ -2169,7 +2189,9 @@ err: my_bool Query_cache::insert_table(uint key_len, char *key, Query_cache_block_table *node, - uint32 db_length, uint8 cache_type) + uint32 db_length, uint8 cache_type, + qc_engine_callback callback, + ulonglong engine_data) { DBUG_ENTER("Query_cache::insert_table"); DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d", @@ -2179,6 +2201,23 @@ Query_cache::insert_table(uint key_len, char *key, hash_search(&tables, (byte*) key, key_len)); + if (table_block && + table_block->table()->engine_data() != engine_data) + { + DBUG_PRINT("qcache", + ("Handler require invalidation queries of %s.%s %lld-%lld", + table_block->table()->db(), + table_block->table()->table(), + engine_data, + table_block->table()->engine_data())); + /* + as far as we delete all queries with this table, table block will be + deleted, too + */ + invalidate_table(table_block); + table_block= 0; + } + if (table_block == 0) { DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)", @@ -2209,6 +2248,8 @@ Query_cache::insert_table(uint key_len, char *key, header->table(db + db_length + 1); header->key_length(key_len); header->type(cache_type); + header->callback(callback); + header->engine_data(engine_data); } Query_cache_block_table *list_root = table_block->table(0); @@ -2729,9 +2770,11 @@ my_bool Query_cache::ask_handler_allowance(THD *thd, for (; tables_used; tables_used= tables_used->next_global) { TABLE *table= tables_used->table; - if (!ha_caching_allowed(thd, table->s->table_cache_key, - table->s->key_length, - table->file->table_cache_type())) + handler *handler= table->file; + if (!handler->register_query_cache_table(thd, table->s->table_cache_key, + table->s->key_length, + &tables_used->callback_func, + &tables_used->engine_data)) { DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s", tables_used->db, tables_used->alias)); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 93d89aeae4f..e7116c7718a 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -146,6 +146,10 @@ struct Query_cache_table char *tbl; uint32 key_len; uint8 table_type; + /* unique for every engine reference */ + qc_engine_callback callback_func; + /* data need by some engines */ + ulonglong engine_data_buff; inline char *db() { return (char *) data(); } inline char *table() { return tbl; } @@ -154,6 +158,10 @@ struct Query_cache_table inline void key_length(uint32 len) { key_len= len; } inline uint8 type() { return table_type; } inline void type(uint8 t) { table_type= t; } + inline qc_engine_callback callback() { return callback_func; } + inline void callback(qc_engine_callback fn){ callback_func= fn; } + inline ulonglong engine_data() { return engine_data_buff; } + inline void engine_data(ulonglong data) { engine_data_buff= data; } inline gptr data() { return (gptr)(((byte*)this)+ @@ -282,7 +290,9 @@ protected: TABLE_COUNTER_TYPE tables); my_bool insert_table(uint key_len, char *key, Query_cache_block_table *node, - uint32 db_length, uint8 cache_type); + uint32 db_length, uint8 cache_type, + qc_engine_callback callback, + ulonglong engine_data); void unlink_table(Query_cache_block_table *node); Query_cache_block *get_free_block (ulong len, my_bool not_less, ulong min); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c9545a0141e..32c9e2a50f7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1303,6 +1303,14 @@ bool select_singlerow_subselect::send_data(List &items) } +void select_max_min_finder_subselect::cleanup() +{ + DBUG_ENTER("select_max_min_finder_subselect::cleanup"); + cache= 0; + DBUG_VOID_RETURN; +} + + bool select_max_min_finder_subselect::send_data(List &items) { DBUG_ENTER("select_max_min_finder_subselect::send_data"); @@ -1332,6 +1340,9 @@ bool select_max_min_finder_subselect::send_data(List &items) case STRING_RESULT: op= &select_max_min_finder_subselect::cmp_str; break; + case DECIMAL_RESULT: + op= &select_max_min_finder_subselect::cmp_decimal; + break; case ROW_RESULT: // This case should never be choosen DBUG_ASSERT(0); @@ -1373,6 +1384,26 @@ bool select_max_min_finder_subselect::cmp_int() val1 < val2); } +bool select_max_min_finder_subselect::cmp_decimal() +{ + String *val1, *val2, buf1, buf2; + Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + /* + as far as both operand is Item_cache buf1 & buf2 will not be used, + but added for safety + */ + my_decimal cval, *cvalue= cache->val_decimal(&cval); + my_decimal mval, *mvalue= maxmin->val_decimal(&mval); + if (fmax) + return (cache->null_value && !maxmin->null_value) || + (!cache->null_value && !maxmin->null_value && + my_decimal_cmp(cvalue, mvalue) > 0) ; + else + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + my_decimal_cmp(cvalue,mvalue) < 0); +} + bool select_max_min_finder_subselect::cmp_str() { String *val1, *val2, buf1, buf2; @@ -1439,6 +1470,8 @@ int select_dumpvar::prepare(List &list, SELECT_LEX_UNIT *u) /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) + Item_func_set_user_var can't be fixed after creation, so we do not + check xx->fixed */ xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first, 0); diff --git a/sql/sql_class.h b/sql/sql_class.h index 8e6204ab3a3..b04ad449ba3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -408,6 +408,7 @@ struct system_variables ulong table_type; ulong tmp_table_size; ulong tx_isolation; + ulong completion_type; /* Determines which non-standard SQL behaviour should be enabled */ ulong sql_mode; /* check of key presence in updatable view */ @@ -430,6 +431,11 @@ struct system_variables my_bool low_priority_updates; my_bool new_mode; my_bool query_cache_wlock_invalidate; +#ifdef HAVE_REPLICATION + ulong sync_replication; + ulong sync_replication_slave_id; + ulong sync_replication_timeout; +#endif /* HAVE_REPLICATION */ #ifdef HAVE_INNOBASE_DB my_bool innodb_table_locks; #endif /* HAVE_INNOBASE_DB */ @@ -1025,6 +1031,8 @@ public: sp_rcontext *spcont; // SP runtime context sp_cache *sp_proc_cache; sp_cache *sp_func_cache; + bool shortcut_make_view; /* Don't do full mysql_make_view() + during pre-opening of tables. */ /* If we do a purge of binary logs, log index info of the threads @@ -1509,9 +1517,11 @@ public: select_max_min_finder_subselect(Item_subselect *item, bool mx) :select_subselect(item), cache(0), fmax(mx) {} + void cleanup(); bool send_data(List &items); bool cmp_real(); bool cmp_int(); + bool cmp_decimal(); bool cmp_str(); }; @@ -1585,9 +1595,10 @@ class user_var_entry ulong length, update_query_id, used_query_id; Item_result type; - double val(my_bool *null_value); + double val_real(my_bool *null_value); longlong val_int(my_bool *null_value); String *val_str(my_bool *null_value, String *str, uint decimals); + my_decimal *val_decimal(my_bool *null_value, my_decimal *result); DTCollation collation; }; @@ -1616,9 +1627,11 @@ public: ~Unique(); inline bool unique_add(void *ptr) { + DBUG_ENTER("unique_add"); + DBUG_PRINT("info", ("tree %u - %u", tree.elements_in_tree, max_elements)); if (tree.elements_in_tree > max_elements && flush()) - return 1; - return !tree_insert(&tree, ptr, 0, tree.custom_arg); + DBUG_RETURN(1); + DBUG_RETURN(!tree_insert(&tree, ptr, 0, tree.custom_arg)); } bool get(TABLE *table); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index bed65f90c00..c01728e68d5 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -165,16 +165,21 @@ exit: else { if (!thd->fill_derived_tables()) + { delete derived_result; + derived_result= NULL; + } orig_table_list->derived_result= derived_result; orig_table_list->table= table; orig_table_list->table_name= (char*) table->s->table_name; + orig_table_list->table_name_length= strlen((char*)table->s->table_name); table->derived_select_number= first_select->select_number; table->s->tmp_table= TMP_TABLE; #ifndef NO_EMBEDDED_ACCESS_CHECKS table->grant.privilege= SELECT_ACL; #endif orig_table_list->db= (char *)""; + orig_table_list->db_length= 0; // Force read of table stats in the optimizer table->file->info(HA_STATUS_VARIABLE); /* Add new temporary table to list of open derived tables */ diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index c9c21d82568..dd2ac3c013b 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -409,8 +409,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; - if (cond && ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) + if (cond && ((!cond->fixed && + cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) goto err0; table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it @@ -495,7 +495,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, for (key_len=0 ; (item=it_ke++) ; key_part++) { // 'item' can be changed by fix_fields() call - if ((!item->fixed && + if ((!item->fixed && item->fix_fields(thd, tables, it_ke.ref())) || (item= *it_ke.ref())->check_cols(1)) goto err; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4cb62d5e9d7..fa6f1e05dc6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1811,13 +1811,13 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) is the same table (Bug #6034). Do the preparation after the select phase in select_insert::prepare2(). */ - if (info.ignore || info.handle_duplicates != DUP_ERROR) - table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); table->file->start_bulk_insert((ha_rows) 0); } restore_record(table,s->default_values); // Get empty record table->next_number_field=table->found_next_number_field; thd->cuted_fields=0; + if (info.ignore || info.handle_duplicates != DUP_ERROR) + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); thd->no_trans_update= 0; thd->abort_on_warning= (!info.ignore && (thd->variables.sql_mode & @@ -1847,14 +1847,9 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) int select_insert::prepare2(void) { DBUG_ENTER("select_insert::prepare2"); - if (thd->lex->current_select->options & OPTION_BUFFER_RESULT) - { - if (info.ignore || info.handle_duplicates != DUP_ERROR) - table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); table->file->start_bulk_insert((ha_rows) 0); - } - return 0; + DBUG_RETURN(0); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 43e82ff57c9..30c657c3b79 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -40,10 +40,6 @@ sys_var_long_ptr trg_new_row_fake_var(0, 0); #define yySkip() lex->ptr++ #define yyLength() ((uint) (lex->ptr - lex->tok_start)-1) -#if MYSQL_VERSION_ID < 32300 -#define FLOAT_NUM REAL_NUM -#endif - pthread_key(LEX*,THR_LEX); /* Longest standard keyword name */ @@ -115,9 +111,14 @@ void lex_free(void) void lex_start(THD *thd, uchar *buf,uint length) { LEX *lex= thd->lex; + DBUG_ENTER("lex_start"); + + lex->thd= lex->unit.thd= thd; + lex->buf= lex->ptr= buf; + lex->end_of_query= buf+length; + lex->unit.init_query(); lex->unit.init_select(); - lex->thd= lex->unit.thd= thd; lex->select_lex.init_query(); lex->value_list.empty(); lex->update_list.empty(); @@ -150,8 +151,6 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->empty_field_list_on_rset= 0; lex->select_lex.select_number= 1; lex->next_state=MY_LEX_START; - lex->buf= lex->ptr= buf; - lex->end_of_query=buf+length; lex->yylineno = 1; lex->in_comment=0; lex->length=0; @@ -173,11 +172,15 @@ void lex_start(THD *thd, uchar *buf,uint length) if (lex->spfuns.records) my_hash_reset(&lex->spfuns); + if (lex->spprocs.records) + my_hash_reset(&lex->spprocs); + if (lex->sptabs.records) + my_hash_reset(&lex->sptabs); + DBUG_VOID_RETURN; } void lex_end(LEX *lex) { - lex->select_lex.expr_list.delete_elements(); // If error when parsing sql-varargs x_free(lex->yacc_yyss); x_free(lex->yacc_yyvs); } @@ -334,7 +337,8 @@ static char *get_text(LEX *lex) continue; } #endif - if (*str == '\\' && str+1 != end) + if (!(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) && + *str == '\\' && str+1 != end) { switch(*++str) { case 'n': @@ -433,12 +437,12 @@ inline static uint int_token(const char *str,uint length) else if (length < signed_longlong_len) return LONG_NUM; else if (length > signed_longlong_len) - return REAL_NUM; + return DECIMAL_NUM; else { cmp=signed_longlong_str+1; smaller=LONG_NUM; // If <= signed_longlong_str - bigger=REAL_NUM; + bigger=DECIMAL_NUM; } } else @@ -454,10 +458,10 @@ inline static uint int_token(const char *str,uint length) else if (length > longlong_len) { if (length > unsigned_longlong_len) - return REAL_NUM; + return DECIMAL_NUM; cmp=unsigned_longlong_str; smaller=ULONGLONG_NUM; - bigger=REAL_NUM; + bigger=DECIMAL_NUM; } else { @@ -795,7 +799,7 @@ int yylex(void *arg, void *yythd) return(FLOAT_NUM); } yylval->lex_str=get_token(lex,yyLength()); - return(REAL_NUM); + return(DECIMAL_NUM); case MY_LEX_HEX_NUMBER: // Found x'hexstring' yyGet(); // Skip ' diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6ed5fb247dc..5d232d60e79 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -67,7 +67,7 @@ enum enum_sql_command { SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, - SQLCOM_COMMIT, SQLCOM_SAVEPOINT, + SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, @@ -416,6 +416,7 @@ public: void print(String *str); ulong init_prepare_fake_select_lex(THD *thd); + inline bool is_prepared() { return prepared; } bool change_result(select_subselect *result, select_subselect *old_result); void set_limit(st_select_lex *values, st_select_lex *sl); @@ -718,6 +719,7 @@ typedef struct st_lex uint8 create_view_check; bool drop_if_exists, drop_temporary, local_file, one_shot_set; bool in_comment, ignore_space, verbose, no_write_to_binlog; + bool tx_chain, tx_release; /* special JOIN::prepare mode: changing of query is prohibited */ bool view_prepare_mode; bool safe_to_cache_query; @@ -746,6 +748,8 @@ typedef struct st_lex bool all_privileges; sp_pcontext *spcont; HASH spfuns; /* Called functions */ + HASH spprocs; /* Called procedures */ + HASH sptabs; /* Merged table lists */ st_sp_chistics sp_chistics; bool only_view; /* used for SHOW CREATE TABLE/VIEW */ /* @@ -766,14 +770,21 @@ typedef struct st_lex st_lex() :result(0), sql_command(SQLCOM_END) { - extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first); - hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_spfuns_key, 0, 0); + extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first); + extern byte *sp_table_key(const byte *ptr, uint *plen, my_bool first); + hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0); + hash_init(&spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0); + hash_init(&sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); } ~st_lex() { if (spfuns.array.buffer) hash_free(&spfuns); + if (spprocs.array.buffer) + hash_free(&spprocs); + if (sptabs.array.buffer) + hash_free(&sptabs); } inline void uncacheable(uint8 cause) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4a6b8f2af01..7fa43eebd7f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -65,6 +65,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc); #endif static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); +static bool check_multi_update_lock(THD *thd); static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(THD *thd, const char **filename_ptr, @@ -133,6 +134,28 @@ static bool end_active_trans(THD *thd) DBUG_RETURN(error); } +static bool begin_trans(THD *thd) +{ + int error=0; + if (thd->locked_tables) + { + thd->lock=thd->locked_tables; + thd->locked_tables=0; // Will be automatically closed + close_thread_tables(thd); // Free tables + } + if (end_active_trans(thd)) + error= -1; + else + { + LEX *lex= thd->lex; + thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | + OPTION_BEGIN); + thd->server_status|= SERVER_STATUS_IN_TRANS; + if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) + error= ha_start_consistent_snapshot(thd); + } + return error; +} #ifdef HAVE_REPLICATION inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) @@ -689,6 +712,8 @@ static int check_connection(THD *thd) DBUG_PRINT("info", ("New connection received on %s", vio_description(net->vio))); + vio_in_addr(net->vio,&thd->remote.sin_addr); + if (!thd->host) // If TCP/IP connection { char ip[30]; @@ -733,7 +758,6 @@ static int check_connection(THD *thd) DBUG_PRINT("info",("Host: %s",thd->host)); thd->host_or_ip= thd->host; thd->ip= 0; - bzero((char*) &thd->remote, sizeof(struct sockaddr)); } vio_keepalive(net->vio, TRUE); ulong pkt_len= 0; @@ -1264,6 +1288,127 @@ err: DBUG_RETURN(error); } +/* + Ends the current transaction and (maybe) begin the next + First uint4 in packet is completion type + Remainder is savepoint name (if required) + + SYNOPSIS + mysql_endtrans() + thd Current thread + completion Completion type + savepoint_name Savepoint when doing ROLLBACK_SAVEPOINT_NAME + or RELEASE_SAVEPOINT_NAME + release (OUT) indicator for release operation + + RETURN + 0 - OK +*/ + +enum enum_mysql_completiontype { + ROLLBACK_RELEASE=-2, + COMMIT_RELEASE=-1, + COMMIT=0, + ROLLBACK=1, + SAVEPOINT_NAME_ROLLBACK=2, + SAVEPOINT_NAME_RELEASE=4, + COMMIT_AND_CHAIN=6, + ROLLBACK_AND_CHAIN=7, +}; + +int mysql_endtrans(THD *thd, enum enum_mysql_completiontype completion, + char *savepoint_name) +{ + bool do_release= 0; + int res= 0; + LEX *lex= thd->lex; + DBUG_ENTER("mysql_endtrans"); + + switch (completion) { + case COMMIT: + /* + We don't use end_active_trans() here to ensure that this works + even if there is a problem with the OPTION_AUTO_COMMIT flag + (Which of course should never happen...) + */ + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + if (!(res= ha_commit(thd))) + send_ok(thd); + break; + case COMMIT_RELEASE: + do_release= 1; + case COMMIT_AND_CHAIN: + res= end_active_trans(thd); + if (!res && completion == COMMIT_AND_CHAIN) + res= begin_trans(thd); + if (!res) + send_ok(thd); + break; + case ROLLBACK_RELEASE: + do_release= 1; + case ROLLBACK: + case ROLLBACK_AND_CHAIN: + { + bool warn= 0; + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + if (!ha_rollback(thd)) + { + /* + If a non-transactional table was updated, warn; don't warn if this is a + slave thread (because when a slave thread executes a ROLLBACK, it has + been read from the binary log, so it's 100% sure and normal to produce + error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the + slave SQL thread, it would not stop the thread but just be printed in + the error log; but we don't want users to wonder why they have this + message in the error log, so we don't send it. + */ + warn= (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && + !thd->slave_thread; + } + else + res= -1; + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + if (!res && (completion == ROLLBACK_AND_CHAIN)) + res= begin_trans(thd); + + if (!res) + { + if (warn) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARNING_NOT_COMPLETE_ROLLBACK, + ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); + send_ok(thd); + } + break; + } + case SAVEPOINT_NAME_ROLLBACK: + if (!(res=ha_rollback_to_savepoint(thd, savepoint_name))) + { + if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARNING_NOT_COMPLETE_ROLLBACK, + ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); + send_ok(thd); + } + break; + case SAVEPOINT_NAME_RELEASE: + if (!(res=ha_release_savepoint_name(thd, savepoint_name))) + send_ok(thd); + break; + default: + res= -1; + my_error(ER_UNKNOWN_COM_ERROR, MYF(0)); + DBUG_RETURN(-1); + } + + if (res < 0) + my_error(thd->killed_errno(), MYF(0)); + else if ((res == 0) && do_release) + thd->killed= THD::KILL_CONNECTION; + + DBUG_RETURN(res); +} #ifndef EMBEDDED_LIBRARY @@ -2014,6 +2159,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, } TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; table_list->schema_select_lex= sel; + table_list->schema_table_reformed= 1; DBUG_RETURN(0); } @@ -2080,12 +2226,20 @@ 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 */ TABLE_LIST *all_tables; /* most outer SELECT_LEX_UNIT of query */ SELECT_LEX_UNIT *unit= &lex->unit; + /* Locked closure of all tables */ + TABLE_LIST *locked_tables= NULL; + /* Saved variable value */ +#ifdef HAVE_INNOBASE_DB + my_bool old_innodb_table_locks= thd->variables.innodb_table_locks; +#endif DBUG_ENTER("mysql_execute_command"); thd->net.no_send_error= 0; @@ -2108,11 +2262,91 @@ mysql_execute_command(THD *thd) /* should be assigned after making first tables same */ all_tables= lex->query_tables; + thd->shortcut_make_view= 0; if (lex->sql_command != SQLCOM_CREATE_PROCEDURE && - lex->sql_command != SQLCOM_CREATE_SPFUNCTION) + lex->sql_command != SQLCOM_CREATE_SPFUNCTION && + lex->sql_command != SQLCOM_LOCK_TABLES && + lex->sql_command != SQLCOM_UNLOCK_TABLES) { - if (sp_cache_functions(thd, lex)) - DBUG_RETURN(-1); + while (1) + { + if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION)) + DBUG_RETURN(-1); + if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE)) + DBUG_RETURN(-1); + if (!thd->locked_tables && + lex->sql_command != SQLCOM_CREATE_TABLE && + lex->sql_command != SQLCOM_CREATE_VIEW) + { + MEM_ROOT *thdmemroot= NULL; + + sp_merge_routine_tables(thd, lex); + // QQ Preopen tables to find views and triggers. + // This means we open, close and open again, which sucks, but + // right now it's the easiest way to get it to work. A better + // solution will hopefully be found soon... + if (lex->sptabs.records || lex->query_tables) + { + uint procs, funs, tabs; + + if (thd->mem_root != thd->current_arena->mem_root) + { + thdmemroot= thd->mem_root; + thd->mem_root= thd->current_arena->mem_root; + } + if (!sp_merge_table_list(thd, &lex->sptabs, lex->query_tables)) + DBUG_RETURN(-1); + procs= lex->spprocs.records; + funs= lex->spfuns.records; + tabs= lex->sptabs.records; + + if ((locked_tables= sp_hash_to_table_list(thd, &lex->sptabs))) + { + // We don't want these updated now + uint ctmpdtabs= thd->status_var.created_tmp_disk_tables; + uint ctmptabs= thd->status_var.created_tmp_tables; + uint count; + + thd->shortcut_make_view= TRUE; + open_tables(thd, locked_tables, &count); + thd->shortcut_make_view= FALSE; + close_thread_tables(thd); + thd->status_var.created_tmp_disk_tables= ctmpdtabs; + thd->status_var.created_tmp_tables= ctmptabs; + thd->clear_error(); + mysql_reset_errors(thd); + locked_tables= NULL; + } + // A kludge: Decrease all temp. table's query ids to allow a + // second opening. + for (TABLE *table= thd->temporary_tables; table ; table=table->next) + table->query_id-= 1; + if (procs < lex->spprocs.records || + funs < lex->spfuns.records || + tabs < lex->sptabs.records) + { + if (thdmemroot) + thd->mem_root= thdmemroot; + continue; // Found more SPs or tabs, try again + } + } + if (lex->sptabs.records && + (lex->spfuns.records || lex->spprocs.records) && + sp_merge_table_list(thd, &lex->sptabs, lex->query_tables)) + { + if ((locked_tables= sp_hash_to_table_list(thd, &lex->sptabs))) + { +#ifdef HAVE_INNOBASE_DB + thd->variables.innodb_table_locks= FALSE; +#endif + sp_open_and_lock_tables(thd, locked_tables); + } + } + if (thdmemroot) + thd->mem_root= thdmemroot; + } + break; + } // while (1) } /* @@ -2127,6 +2361,22 @@ 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 @@ -2367,7 +2617,8 @@ mysql_execute_command(THD *thd) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); - if (it->check_cols(1) || it->fix_fields(lex->thd, 0, &it)) + if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) || + it->check_cols(1)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); goto error; @@ -3586,7 +3837,7 @@ unsent_create_error: { Item *it= (Item *)lex->value_list.head(); - if (it->fix_fields(lex->thd, 0, &it) || it->check_cols(1)) + if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1)) { my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -3633,74 +3884,23 @@ unsent_create_error: break; case SQLCOM_BEGIN: - if (thd->locked_tables) - { - thd->lock=thd->locked_tables; - thd->locked_tables=0; // Will be automatically closed - close_thread_tables(thd); // Free tables - } - if (end_active_trans(thd)) + if (begin_trans(thd)) goto error; else - { - thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | - OPTION_BEGIN); - thd->server_status|= SERVER_STATUS_IN_TRANS; - if (!(lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) || - !(res= ha_start_consistent_snapshot(thd))) - send_ok(thd); - } + send_ok(thd); break; case SQLCOM_COMMIT: - /* - We don't use end_active_trans() here to ensure that this works - even if there is a problem with the OPTION_AUTO_COMMIT flag - (Which of course should never happen...) - */ - { - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); - thd->server_status&= ~SERVER_STATUS_IN_TRANS; - if (!ha_commit(thd)) - { - send_ok(thd); - } - else + if (mysql_endtrans(thd, lex->tx_release ? COMMIT_RELEASE : + lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT, 0)) goto error; break; - } case SQLCOM_ROLLBACK: - thd->server_status&= ~SERVER_STATUS_IN_TRANS; - if (!ha_rollback(thd)) - { - /* - If a non-transactional table was updated, warn; don't warn if this is a - slave thread (because when a slave thread executes a ROLLBACK, it has - been read from the binary log, so it's 100% sure and normal to produce - error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the - slave SQL thread, it would not stop the thread but just be printed in - the error log; but we don't want users to wonder why they have this - message in the error log, so we don't send it. - */ - if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARNING_NOT_COMPLETE_ROLLBACK, - ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); - send_ok(thd); - } - else - res= TRUE; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + if (mysql_endtrans(thd, lex->tx_release ? ROLLBACK_RELEASE : + lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK, 0)) + goto error; break; case SQLCOM_ROLLBACK_TO_SAVEPOINT: - if (!ha_rollback_to_savepoint(thd, lex->savepoint_name)) - { - if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARNING_NOT_COMPLETE_ROLLBACK, - ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); - send_ok(thd); - } - else + if (mysql_endtrans(thd, SAVEPOINT_NAME_ROLLBACK, lex->savepoint_name)) goto error; break; case SQLCOM_SAVEPOINT: @@ -3709,6 +3909,10 @@ unsent_create_error: else goto error; break; + case SQLCOM_RELEASE_SAVEPOINT: + if (mysql_endtrans(thd, SAVEPOINT_NAME_RELEASE, lex->savepoint_name)) + goto error; + break; case SQLCOM_CREATE_PROCEDURE: case SQLCOM_CREATE_SPFUNCTION: { @@ -4143,11 +4347,30 @@ unsent_create_error: default: thd->row_count_func= -1; } - - DBUG_RETURN(res || thd->net.report_error); - + goto cleanup; + error: - DBUG_RETURN(TRUE); + 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; + } + + if (locked_tables) + { +#ifdef HAVE_INNOBASE_DB + thd->variables.innodb_table_locks= old_innodb_table_locks; +#endif + if (thd->locked_tables) + sp_unlock_tables(thd); + } + DBUG_RETURN(res || thd->net.report_error); } @@ -4606,19 +4829,21 @@ bool mysql_new_select(LEX *lex, bool move_down) { SELECT_LEX *select_lex; + DBUG_ENTER("mysql_new_select"); + if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX())) - return 1; + DBUG_RETURN(1); select_lex->select_number= ++lex->thd->select_number; select_lex->init_query(); select_lex->init_select(); select_lex->parent_lex= lex; if (move_down) { + SELECT_LEX_UNIT *unit; lex->subqueries= TRUE; /* first select_lex of subselect or derived table */ - SELECT_LEX_UNIT *unit; if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT())) - return 1; + DBUG_RETURN(1); unit->init_query(); unit->init_select(); @@ -4635,7 +4860,7 @@ mysql_new_select(LEX *lex, bool move_down) if (lex->current_select->order_list.first && !lex->current_select->braces) { my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY"); - return 1; + DBUG_RETURN(1); } select_lex->include_neighbour(lex->current_select); SELECT_LEX_UNIT *unit= select_lex->master_unit(); @@ -4647,7 +4872,7 @@ mysql_new_select(LEX *lex, bool move_down) fake SELECT_LEX for UNION processing */ if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX())) - return 1; + DBUG_RETURN(1); fake->include_standalone(unit, (SELECT_LEX_NODE**)&unit->fake_select_lex); fake->select_number= INT_MAX; @@ -4661,7 +4886,7 @@ mysql_new_select(LEX *lex, bool move_down) select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); lex->current_select= select_lex; select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; - return 0; + DBUG_RETURN(0); } /* @@ -4954,21 +5179,19 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, break; case FIELD_TYPE_NULL: break; - case FIELD_TYPE_DECIMAL: + case FIELD_TYPE_NEWDECIMAL: if (!length) { - if ((new_field->length= new_field->decimals)) - new_field->length++; - else + if (!(new_field->length= new_field->decimals)) new_field->length= 10; // Default length for DECIMAL } - if (new_field->length < MAX_FIELD_WIDTH) // Skip wrong argument - { - new_field->length+=sign_len; - if (new_field->decimals) - new_field->length++; - } - break; + new_field->pack_length= + my_decimal_get_binary_size(new_field->length, new_field->decimals); + if (new_field->length <= DECIMAL_MAX_LENGTH && + new_field->length >= new_field->decimals) + break; + my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); + DBUG_RETURN(1); case MYSQL_TYPE_VARCHAR: /* Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table @@ -5154,6 +5377,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, new_field->pack_length= (new_field->length + 7) / 8; break; } + case FIELD_TYPE_DECIMAL: + DBUG_ASSERT(0); /* Was obsolete */ } if (!(new_field->flags & BLOB_FLAG) && @@ -5955,6 +6180,56 @@ 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) { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a71b8148f8e..93197b1a2eb 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -332,6 +332,13 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len) *pos+= 8; } +static void set_param_decimal(Item_param *param, uchar **pos, ulong len) +{ + ulong length= get_param_length(pos, len); + param->set_decimal((char*)*pos, length); + *pos+= len; +} + #ifndef EMBEDDED_LIBRARY /* @@ -508,6 +515,12 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, param->item_type= Item::REAL_ITEM; param->item_result_type= REAL_RESULT; break; + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + param->set_param_func= set_param_decimal; + param->item_type= Item::DECIMAL_ITEM; + param->item_result_type= DECIMAL_RESULT; + break; case MYSQL_TYPE_TIME: param->set_param_func= set_param_time; param->item_type= Item::STRING_ITEM; @@ -1541,9 +1554,11 @@ static int check_prepared_statement(Prepared_statement *stmt, if (lex->sql_command != SQLCOM_CREATE_PROCEDURE && lex->sql_command != SQLCOM_CREATE_SPFUNCTION) { - /* the error is print inside */ - if (sp_cache_functions(thd, lex)) - DBUG_RETURN(1); + /* The error is printed inside */ + if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION)) + DBUG_RETURN(-1); + if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE)) + DBUG_RETURN(-1); } switch (sql_command) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 97570e7dc0f..08b1b3a34b3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -542,6 +542,10 @@ JOIN::optimize() } else if ((conds=new Item_cond_and(conds,having))) { + /* + Item_cond_and can't be fixed after creation, so we do not check + conds->fixed + */ conds->fix_fields(thd, tables_list, &conds); conds->change_ref_to_fields(thd, tables_list); conds->top_level_item(); @@ -1435,7 +1439,7 @@ JOIN::exec() curr_join->select_distinct=0; /* Each row is unique */ curr_join->join_free(0); /* Free quick selects */ - if (select_distinct && ! group_list) + if (curr_join->select_distinct && ! curr_join->group_list) { thd->proc_info="Removing duplicates"; if (curr_join->tmp_having) @@ -7213,7 +7217,8 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) if (conds) { conds= and_conds(conds, table->on_expr); - conds->fix_fields(join->thd, 0, &conds); + if (!conds->fixed) + conds->fix_fields(join->thd, 0, &conds); } else conds= table->on_expr; @@ -7432,6 +7437,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) 21)))) { cond=new_cond; + /* + Item_func_eq can't be fixed after creation so we do not check + cond->fixed, also it do not need tables so we use 0 as second + argument. + */ cond->fix_fields(thd, 0, &cond); } thd->insert_id(0); // Clear for next request @@ -7446,6 +7456,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2)))) { cond=new_cond; + /* + Item_func_eq can't be fixed after creation so we do not check + cond->fixed, also it do not need tables so we use 0 as second + argument. + */ cond->fix_fields(thd, 0, &cond); } } @@ -7641,8 +7656,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, else new_field= item->make_string_field(table); break; - case ROW_RESULT: - default: + case DECIMAL_RESULT: + new_field= new Field_new_decimal(item->max_length - (item->decimals?1:0), + maybe_null, + item->name, table, item->decimals); + break; + case ROW_RESULT: + default: // This case should never be choosen DBUG_ASSERT(0); new_field= 0; // to satisfy compiler (uninitialized variable) @@ -7693,47 +7713,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, { Item_sum *item_sum=(Item_sum*) item; bool maybe_null=item_sum->maybe_null; - switch (item_sum->sum_func()) { - case Item_sum::AVG_FUNC: /* Place for sum & count */ - if (group) - return new Field_string(sizeof(double)+sizeof(longlong), - 0, item->name,table,&my_charset_bin); - else - return new Field_double(item_sum->max_length,maybe_null, - item->name, table, item_sum->decimals); - case Item_sum::VARIANCE_FUNC: /* Place for sum & count */ - case Item_sum::STD_FUNC: - if (group) - return new Field_string(sizeof(double)*2+sizeof(longlong), - 0, item->name,table,&my_charset_bin); - else - return new Field_double(item_sum->max_length, maybe_null, - item->name,table,item_sum->decimals); - case Item_sum::UNIQUE_USERS_FUNC: - return new Field_long(9,maybe_null,item->name,table,1); - default: - switch (item_sum->result_type()) { - case REAL_RESULT: - return new Field_double(item_sum->max_length,maybe_null, - item->name,table,item_sum->decimals); - case INT_RESULT: - return new Field_longlong(item_sum->max_length,maybe_null, - item->name,table,item->unsigned_flag); - case STRING_RESULT: - if (item_sum->max_length > 255 && convert_blob_length) - return new Field_varstring(convert_blob_length, maybe_null, - item->name, table, - item->collation.collation); - return item_sum->make_string_field(table); - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - thd->fatal_error(); - return 0; - } - } - /* We never come here */ + Field *result= item_sum->create_tmp_field(group, table, convert_blob_length); + if (!result) + thd->fatal_error(); + return result; } case Item::FIELD_ITEM: case Item::DEFAULT_VALUE_ITEM: @@ -7751,6 +7734,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::PROC_ITEM: case Item::INT_ITEM: case Item::REAL_ITEM: + case Item::DECIMAL_ITEM: case Item::STRING_ITEM: case Item::REF_ITEM: case Item::NULL_ITEM: @@ -9181,7 +9165,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) tab->info="const row not found"; /* Mark for EXPLAIN that the row was not found */ pos->records_read=0.0; - if (!table->outer_join || error > 0) + if (!table->maybe_null || error > 0) DBUG_RETURN(error); } } @@ -9200,7 +9184,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) tab->info="unique row not found"; /* Mark for EXPLAIN that the row was not found */ pos->records_read=0.0; - if (!table->outer_join || error > 0) + if (!table->maybe_null || error > 0) DBUG_RETURN(error); } if (table->key_read) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e9126871045..c50d594a7aa 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -311,7 +311,9 @@ mysql_find_files(THD *thd,List *files, const char *db,const char *path, if (db && !(col_access & TABLE_ACLS)) { table_list.db= (char*) db; + table_list.db_length= strlen(db); table_list.table_name= file->name; + table_list.table_name_length= strlen(file->name); table_list.grant.privilege=col_access; if (check_grant(thd, TABLE_ACLS, &table_list, 1, UINT_MAX, 1)) continue; @@ -1786,7 +1788,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) enum enum_schema_tables schema_table_idx; thr_lock_type lock_type; List bases; + List_iterator_fast it(bases); COND *partial_cond; + int error= 1; DBUG_ENTER("get_all_tables"); LINT_INIT(end); @@ -1803,13 +1807,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (schema_table->process_table(thd, show_table_list, table, res, show_table_list->db, show_table_list->alias)) - { - DBUG_RETURN(1); - } + goto err; close_thread_tables(thd, 0, 0, old_open_tables); show_table_list->table= 0; - lex->all_selects_list= select_lex; - DBUG_RETURN(0); + error= 0; + goto err; } lex->all_selects_list= &sel; @@ -1822,14 +1824,14 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) /* information schema name always is first in list */ if (schema_db_add(thd, &bases, idx_field_vals.db_value, &with_i_schema)) - return 1; + goto err; if (mysql_find_files(thd, &bases, NullS, mysql_data_home, idx_field_vals.db_value, 1)) - return 1; + goto err; - List_iterator_fast it(bases); partial_cond= make_cond_for_info_schema(cond, tables); + it.rewind(); /* To get access to new elements in basis list */ while ((base_name= it++) || /* generate error for non existing database. @@ -1851,7 +1853,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (with_i_schema) // information schema table names { if (schema_tables_add(thd, &files, idx_field_vals.table_value)) - DBUG_RETURN(1); + goto err; } else { @@ -1860,7 +1862,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) len= FN_LEN - len; if (mysql_find_files(thd, &files, base_name, path, idx_field_vals.table_value, 0)) - DBUG_RETURN(1); + goto err; } List_iterator_fast it_files(files); @@ -1906,16 +1908,14 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) int res; TABLE *old_open_tables= thd->open_tables; if (make_table_list(thd, &sel, base_name, file_name)) - DBUG_RETURN(1); + goto err; TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first; show_table_list->lock_type= lock_type; res= open_and_lock_tables(thd, show_table_list); if (schema_table->process_table(thd, show_table_list, table, res, base_name, show_table_list->alias)) - { - DBUG_RETURN(1); - } + goto err; close_thread_tables(thd, 0, 0, old_open_tables); } } @@ -1927,8 +1927,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) with_i_schema= 0; } } + + error= 0; +err: lex->all_selects_list= select_lex; - DBUG_RETURN(0); + DBUG_RETURN(error); } @@ -2249,15 +2252,21 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[6]->store((const char*) pos, strlen((const char*) pos), cs); if (field->has_charset()) - table->field[8]->store((longlong) field->field_length/ + table->field[8]->store((longlong) field->representation_length()/ field->charset()->mbmaxlen); else - table->field[8]->store((longlong) field->field_length); - table->field[9]->store((longlong) field->field_length); + table->field[8]->store((longlong) field->representation_length()); + table->field[9]->store((longlong) field->representation_length()); { uint dec =field->decimals(); switch (field->type()) { + case FIELD_TYPE_NEWDECIMAL: + table->field[10]->store((longlong) field->field_length); + table->field[10]->set_notnull(); + table->field[11]->store((longlong) field->decimals()); + table->field[11]->set_notnull(); + break; case FIELD_TYPE_DECIMAL: { uint int_part=field->field_length - (dec ? dec + 1 : 0); @@ -2265,8 +2274,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[10]->set_notnull(); table->field[11]->store((longlong) field->decimals()); table->field[11]->set_notnull(); + break; } - break; case FIELD_TYPE_TINY: case FIELD_TYPE_SHORT: case FIELD_TYPE_LONG: @@ -2282,8 +2291,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[11]->store((longlong) dec); table->field[11]->set_notnull(); } + break; } - break; default: break; } @@ -2518,7 +2527,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) bzero((char*) &proc_tables,sizeof(proc_tables)); proc_tables.db= (char*) "mysql"; + proc_tables.db_length= 5; proc_tables.table_name= proc_tables.alias= (char*) "proc"; + proc_tables.table_name_length= 4; proc_tables.lock_type= TL_READ; if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ))) { @@ -3196,11 +3207,51 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) table_list->schema_table_name, table_list->alias); table_list->table_name= (char*) table->s->table_name; + table_list->table_name_length= strlen(table->s->table_name); table_list->table= table; table->next= thd->derived_tables; thd->derived_tables= table; table_list->select_lex->options |= OPTION_SCHEMA_TABLE; lex->safe_to_cache_query= 0; + + if (table_list->schema_table_reformed) // show command + { + SELECT_LEX *sel= lex->current_select; + uint i= 0; + Item *item; + Field_translator *transl; + + if (table_list->field_translation) + { + Field_translator *end= table_list->field_translation + + sel->item_list.elements; + for (transl= table_list->field_translation; transl < end; transl++) + { + if (!transl->item->fixed && + transl->item->fix_fields(thd, table_list, &transl->item)) + DBUG_RETURN(1); + } + DBUG_RETURN(0); + } + List_iterator_fast it(sel->item_list); + if (!(transl= + (Field_translator*)(thd->current_arena-> + alloc(sel->item_list.elements * + sizeof(Field_translator))))) + { + DBUG_RETURN(1); + } + while ((item= it++)) + { + char *name= item->name; + transl[i].item= item; + if (!item->fixed && item->fix_fields(thd, table_list, &transl[i].item)) + DBUG_RETURN(1); + transl[i++].name= name; + } + table_list->field_translation= transl; + } + DBUG_RETURN(0); } @@ -3233,8 +3284,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, information_schema_name.length, 0); make_lex_string(thd, &table, schema_table->table_name, strlen(schema_table->table_name), 0); - if (!sel->item_list.elements && /* Handle old syntax */ - schema_table->old_format(thd, schema_table) || + if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0), 0, 0, TL_READ, (List *) 0, (List *) 0)) diff --git a/sql/sql_string.h b/sql/sql_string.h index cb9db52c830..a5c7cf77630 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -210,6 +210,11 @@ public: { if (&s != this) { + /* + It is forbidden to do assignments like + some_string = substring_of_that_string + */ + DBUG_ASSERT(!s.uses_buffer_owned_by(this)); free(); Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length; alloced=0; @@ -343,4 +348,9 @@ public: /* Swap two string objects. Efficient way to exchange data without memcpy. */ void swap(String &s); + + inline bool uses_buffer_owned_by(const String *s) const + { + return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length); + } }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 88e840d1c4e..d7cefb3dceb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -777,6 +777,14 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, } sql_field->pack_flag= FIELDFLAG_NUMBER; break; + case FIELD_TYPE_NEWDECIMAL: + sql_field->pack_flag=(FIELDFLAG_NUMBER | + (sql_field->flags & UNSIGNED_FLAG ? 0 : + FIELDFLAG_DECIMAL) | + (sql_field->flags & ZEROFILL_FLAG ? + FIELDFLAG_ZEROFILL : 0) | + (sql_field->decimals << FIELDFLAG_DEC_SHIFT)); + break; case FIELD_TYPE_TIMESTAMP: /* We should replace old TIMESTAMP fields with their newer analogs */ if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD) @@ -2396,6 +2404,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, { strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table, reg_ext, NullS); + /* Resolve symlinks (for windows) */ + fn_format(src_path, src_path, "", "", MYF(MY_UNPACK_FILENAME)); if (access(src_path, F_OK)) { my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table); @@ -2424,6 +2434,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, { strxmov(dst_path, mysql_data_home, "/", db, "/", table_name, reg_ext, NullS); + fn_format(dst_path, dst_path, "", "", MYF(MY_UNPACK_FILENAME)); if (!access(dst_path, F_OK)) goto table_exists; } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 5968d13efde..b9e837b0d64 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -176,7 +176,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) trg_field; trg_field= trg_field->next_trg_field) { trg_field->setup_field(thd, table, lex->trg_chistics.event); - if (trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0)) + if (!trg_field->fixed && + trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0)) return 1; } diff --git a/sql/sql_udf.h b/sql/sql_udf.h index d1f99a6d232..51ea6d4d627 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -103,6 +103,7 @@ class udf_handler :public Sql_alloc *null_value=0; return tmp; } + my_decimal *val_decimal(my_bool *null_value, my_decimal *dec_buf); void clear() { is_null= 0; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 0a91eb4c0e1..29897c70023 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -153,6 +153,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, SELECT_LEX *sl, *first_select; select_result *tmp_result; bool is_union; + TABLE *empty_table= 0; DBUG_ENTER("st_select_lex_unit::prepare"); describe= test(additional_options & SELECT_DESCRIBE); @@ -249,13 +250,21 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, goto err; if (sl == first_select) { + /* + We need to create an empty table object. It is used + to create tmp_table fields in Item_type_holder. + The main reason of this is that we can't create + field object without table. + */ + DBUG_ASSERT(!empty_table); + empty_table= (TABLE*) thd->calloc(sizeof(TABLE)); types.empty(); List_iterator_fast it(sl->item_list); Item *item_tmp; while ((item_tmp= it++)) { /* Error's in 'new' will be detected after loop */ - types.push_back(new Item_type_holder(thd_arg, item_tmp)); + types.push_back(new Item_type_holder(thd_arg, item_tmp, empty_table)); } if (thd_arg->is_fatal_error) @@ -274,7 +283,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, Item *type, *item_tmp; while ((type= tp++, item_tmp= it++)) { - if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp)) + if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp, + empty_table)) DBUG_RETURN(TRUE); } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f9ad513ea6a..f9df1be2abd 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -120,7 +120,7 @@ int mysql_update(THD *thd, bool used_key_is_modified, transactional_table, log_delayed; int res; int error=0; - uint used_index= MAX_KEY; + uint used_index; #ifndef NO_EMBEDDED_ACCESS_CHECKS uint want_privilege; #endif @@ -264,7 +264,10 @@ int mysql_update(THD *thd, 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 + { used_key_is_modified=0; + used_index= MAX_KEY; + } if (used_key_is_modified || order) { /* @@ -498,7 +501,7 @@ int mysql_update(THD *thd, free_underlaid_joins(thd, select_lex); if (error < 0) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, (ulong) thd->cuted_fields); thd->row_count_func= @@ -1380,7 +1383,7 @@ err: bool multi_update::send_eof() { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; thd->proc_info="updating reference tables"; /* Does updates for the last n - 1 tables, returns 0 if ok */ diff --git a/sql/sql_view.cc b/sql/sql_view.cc index e2c4b1289fd..456f513dab0 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -556,6 +556,7 @@ my_bool mysql_make_view(File_parser *parser, TABLE_LIST *table) { DBUG_ENTER("mysql_make_view"); + DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name)); if (table->view) { @@ -612,7 +613,9 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local; lex_start(thd, (uchar*)table->query.str, table->query.length); view_select= &lex->select_lex; - view_select->select_number= ++thd->select_number; + /* Only if we're not in the pre-open phase */ + if (!thd->shortcut_make_view) + view_select->select_number= ++thd->select_number; old_lex->derived_tables|= DERIVED_VIEW; { ulong options= thd->options; @@ -657,27 +660,29 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) TABLE_LIST *view_tables_tail= 0; TABLE_LIST *tbl; + /* move SP to main LEX */ if (lex->spfuns.records) - { - /* move SP to main LEX */ - sp_merge_funs(old_lex, lex); - /* open mysq.proc for functions which are not in cache */ - if (old_lex->proc_table == 0 && - (old_lex->proc_table= - (TABLE_LIST*)thd->calloc(sizeof(TABLE_LIST))) != 0) - { - TABLE_LIST *table= old_lex->proc_table; - table->db= (char*)"mysql"; - table->db_length= 5; - table->table_name= table->alias= (char*)"proc"; - table->table_name_length= 4; - table->cacheable_table= 1; - old_lex->add_to_query_tables(table); - } - } + sp_merge_hash(&old_lex->spfuns, &lex->spfuns); + /* cleanup LEX */ if (lex->spfuns.array.buffer) hash_free(&lex->spfuns); + if (lex->spprocs.array.buffer) + hash_free(&lex->spprocs); + if (lex->sptabs.array.buffer) + hash_free(&lex->sptabs); + + /* If we're pre-opening tables to find SPs and tables we need + not go any further; doing so will cause an infinite loop. */ + if (thd->shortcut_make_view) + { + extern bool + sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table, + LEX *lex_for_tmp_check = 0); + + sp_merge_table_list(thd, &old_lex->sptabs, view_tables); + goto ok; + } /* check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index cc2443bd41b..c4649c57269 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -219,6 +219,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CASCADE %token CASCADED %token CAST_SYM +%token CHAIN_SYM %token CHARSET %token CHECKSUM_SYM %token CHECK_SYM @@ -238,6 +239,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CURRENT_USER %token DATABASES %token DATA_SYM +%token DECIMAL_NUM %token DECLARE_SYM %token DEFAULT %token DELAYED_SYM @@ -381,10 +383,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token RAID_CHUNKSIZE %token READ_SYM %token READS_SYM -%token REAL_NUM %token REDUNDANT_SYM %token REFERENCES %token REGEXP +%token RELEASE_SYM %token RELOAD %token RENAME %token REPEATABLE_SYM @@ -665,7 +667,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %right BINARY COLLATE_SYM %type - IDENT IDENT_QUOTED TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM + IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component key_cache_name @@ -690,7 +692,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct opt_ignore_leaves fulltext_options spatial_type union_option - start_transaction_opts + start_transaction_opts opt_chain opt_work_and_chain opt_release %type ULONG_NUM raid_types merge_insert_types @@ -777,7 +779,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); query verb_clause create change select do drop insert replace insert2 insert_values update delete truncate rename show describe load alter optimize keycache preload flush - reset purge begin commit rollback savepoint + reset purge begin commit rollback savepoint release slave master_def master_defs master_file_def slave_until_opts repair restore backup analyze check start checksum field_list field_list_item field_spec kill column_def key_def @@ -876,6 +878,7 @@ statement: | preload | prepare | purge + | release | rename | repair | replace @@ -1461,6 +1464,7 @@ call: lex->sql_command= SQLCOM_CALL; lex->spname= $2; lex->value_list.empty(); + sp_add_to_hash(&lex->spprocs, $2); } '(' sp_cparam_list ')' {} ; @@ -1866,36 +1870,21 @@ sp_proc_stmt: if (lex->sql_command != SQLCOM_SET_OPTION || ! lex->var_list.is_empty()) { - /* - Currently we can't handle queries inside a FUNCTION or - TRIGGER, because of the way table locking works. This is - unfortunate, and limits the usefulness of functions and - especially triggers a tremendously, but it's nothing we - can do about this at the moment. - */ - if (sp->m_type != TYPE_ENUM_PROCEDURE) - { - my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0)); - YYABORT; - } - else - { - sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(), - lex->spcont); + sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(), + lex->spcont); - /* Extract the query statement from the tokenizer: - The end is either lex->tok_end or tok->ptr. */ - if (lex->ptr - lex->tok_end > 1) - i->m_query.length= lex->ptr - sp->m_tmp_query; - else - i->m_query.length= lex->tok_end - sp->m_tmp_query; - i->m_query.str= strmake_root(YYTHD->mem_root, - (char *)sp->m_tmp_query, - i->m_query.length); - i->set_lex(lex); - sp->add_instr(i); - lex->sp_lex_in_use= TRUE; - } + /* Extract the query statement from the tokenizer: + The end is either lex->tok_end or tok->ptr. */ + if (lex->ptr - lex->tok_end > 1) + i->m_query.length= lex->ptr - sp->m_tmp_query; + else + i->m_query.length= lex->tok_end - sp->m_tmp_query; + i->m_query.str= strmake_root(YYTHD->mem_root, + (char *)sp->m_tmp_query, + i->m_query.length); + i->set_lex(lex); + sp->add_instr(i); + lex->sp_lex_in_use= TRUE; } sp->restore_lex(YYTHD); } @@ -1912,11 +1901,6 @@ sp_proc_stmt: { sp_instr_freturn *i; - if ($2->type() == Item::SUBSELECT_ITEM) - { /* QQ For now, just disallow subselects as values */ - my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0)); - YYABORT; - } i= new sp_instr_freturn(lex->sphead->instructions(), lex->spcont, $2, lex->sphead->m_returns); @@ -2655,6 +2639,7 @@ udf_func_type: udf_type: STRING_SYM {$$ = (int) STRING_RESULT; } | REAL {$$ = (int) REAL_RESULT; } + | DECIMAL_SYM {$$ = (int) DECIMAL_RESULT; } | INT_SYM {$$ = (int) INT_RESULT; }; field_list: @@ -2835,11 +2820,11 @@ type: | MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } | LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; } | DECIMAL_SYM float_options field_options - { $$=FIELD_TYPE_DECIMAL;} + { $$=FIELD_TYPE_NEWDECIMAL;} | NUMERIC_SYM float_options field_options - { $$=FIELD_TYPE_DECIMAL;} + { $$=FIELD_TYPE_NEWDECIMAL;} | FIXED_SYM float_options field_options - { $$=FIELD_TYPE_DECIMAL;} + { $$=FIELD_TYPE_NEWDECIMAL;} | ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary { $$=FIELD_TYPE_ENUM; } | SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary @@ -2901,8 +2886,8 @@ real_type: float_options: - /* empty */ {} - | '(' NUM ')' { Lex->length=$2.str; } + /* empty */ { Lex->dec=Lex->length= (char*)0; } + | '(' NUM ')' { Lex->length=$2.str; Lex->dec= (char*)0; } | precision {}; precision: @@ -3892,10 +3877,11 @@ select_into: select_from: FROM join_table_list where_clause group_clause having_clause opt_order_clause opt_limit_clause procedure_clause - | FROM DUAL_SYM /* oracle compatibility: oracle always requires FROM - clause, and DUAL is system table without fields. - Is "SELECT 1 FROM DUAL" any better than - "SELECT 1" ? Hmmm :) */ + | FROM DUAL_SYM opt_limit_clause + /* oracle compatibility: oracle always requires FROM clause, + and DUAL is system table without fields. + Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ? + Hmmm :) */ ; select_options: @@ -4029,14 +4015,15 @@ bool_test: bool_pri: bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); } | bool_pri IS not NULL_SYM { $$= new Item_func_isnotnull($1); } - | predicate BETWEEN_SYM bit_expr AND_SYM bool_pri - { $$= new Item_func_between($1,$3,$5); } - | predicate not BETWEEN_SYM bit_expr AND_SYM bool_pri - { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); } + | bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); } + | bool_pri comp_op predicate %prec EQ + { $$= (*$2)(0)->create($1,$3); } + | bool_pri comp_op all_or_any in_subselect %prec EQ + { $$= all_any_subquery_creator($1, $2, $3, $4); } | predicate ; predicate: - bit_expr IN_SYM '(' expr_list ')' + bit_expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | bit_expr not IN_SYM '(' expr_list ')' { $5->push_front($1); $$= negate_expression(YYTHD, new Item_func_in(*$5)); } @@ -4044,6 +4031,10 @@ predicate: { $$= new Item_in_subselect($1, $3); } | bit_expr not IN_SYM in_subselect { $$= negate_expression(YYTHD, new Item_in_subselect($1, $4)); } + | 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)); } | bit_expr SOUNDS_SYM LIKE bit_expr { $$= new Item_func_eq(new Item_func_soundex($1), new Item_func_soundex($4)); } @@ -4054,11 +4045,6 @@ predicate: | 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)); } - | bit_expr EQUAL_SYM bit_expr { $$= new Item_func_equal($1,$3); } - | bit_expr comp_op bit_expr %prec EQ - { $$= (*$2)(0)->create($1,$3); } - | bit_expr comp_op all_or_any in_subselect %prec EQ - { $$= all_any_subquery_creator($1, $2, $3, $4); } | bit_expr ; bit_expr: @@ -4183,13 +4169,15 @@ simple_expr: | ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); } | BINARY simple_expr %prec NEG { - $$= create_func_cast($2, ITEM_CAST_CHAR, -1, &my_charset_bin); + $$= create_func_cast($2, ITEM_CAST_CHAR, -1, 0, &my_charset_bin); } | CAST_SYM '(' expr AS cast_type ')' { + LEX *lex= Lex; $$= create_func_cast($3, $5, - Lex->length ? atoi(Lex->length) : -1, - Lex->charset); + lex->length ? atoi(lex->length) : -1, + lex->dec ? atoi(lex->dec) : 0, + lex->charset); } | CASE_SYM opt_expr WHEN_SYM when_list opt_else END { $$= new Item_func_case(* $4, $2, $5 ); } @@ -4197,6 +4185,7 @@ simple_expr: { $$= create_func_cast($3, $5, Lex->length ? atoi(Lex->length) : -1, + Lex->dec ? atoi(Lex->dec) : 0, Lex->charset); } | CONVERT_SYM '(' expr USING charset_name ')' @@ -4499,7 +4488,7 @@ simple_expr: sp_name *name= new sp_name($1, $3); name->init_qname(YYTHD); - sp_add_fun_to_lex(Lex, name); + sp_add_to_hash(&Lex->spfuns, name); if ($5) $$= new Item_func_sp(name, *$5); else @@ -4561,6 +4550,22 @@ simple_expr: $$ = new Item_sum_udf_int(udf); } break; + case DECIMAL_RESULT: + if (udf->type == UDFTYPE_FUNCTION) + { + if ($3 != NULL) + $$ = new Item_func_udf_decimal(udf, *$3); + else + $$ = new Item_func_udf_decimal(udf); + } + else + { + if ($3 != NULL) + $$ = new Item_sum_udf_decimal(udf, *$3); + else + $$ = new Item_sum_udf_decimal(udf); + } + break; default: YYABORT; } @@ -4570,7 +4575,7 @@ simple_expr: { sp_name *name= sp_name_current_db_new(YYTHD, $1); - sp_add_fun_to_lex(Lex, name); + sp_add_to_hash(&Lex->spfuns, name); if ($3) $$= new Item_func_sp(name, *$3); else @@ -4810,16 +4815,17 @@ in_sum_expr: }; cast_type: - BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; } - | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; } - | NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; } - | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->length= (char*)0; } - | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->length= (char*)0; } - | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->length= (char*)0; } + BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; } + | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; } + | NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; } + | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; } ; expr_list: @@ -5322,7 +5328,7 @@ ULONG_NUM: NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } - | REAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } + | DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | FLOAT_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } ; @@ -5330,7 +5336,7 @@ ulonglong_num: NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } | ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } | LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } - | REAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } + | DECIMAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } | FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } ; @@ -5876,6 +5882,9 @@ show: SHOW { LEX *lex=Lex; lex->wild=0; + lex->lock_option= TL_READ; + mysql_init_select(lex); + lex->current_select->parsing_place= SELECT_LIST; bzero((char*) &lex->create_info,sizeof(lex->create_info)); } show_param @@ -5883,7 +5892,7 @@ show: SHOW ; show_param: - DATABASES ext_select_item_list wild_and_where + DATABASES wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; @@ -5891,44 +5900,44 @@ show_param: if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA)) YYABORT; } - | opt_full TABLES ext_select_item_list opt_db wild_and_where + | opt_full TABLES opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_TABLES; - lex->select_lex.db= $4; + lex->select_lex.db= $3; if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES)) YYABORT; } - | TABLE_SYM STATUS_SYM ext_select_item_list opt_db wild_and_where + | TABLE_SYM STATUS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_TABLE_STATUS; - lex->select_lex.db= $4; + lex->select_lex.db= $3; if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES)) YYABORT; } - | OPEN_SYM TABLES ext_select_item_list opt_db wild_and_where + | OPEN_SYM TABLES opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_OPEN_TABLES; - lex->select_lex.db= $4; + lex->select_lex.db= $3; if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES)) YYABORT; } | ENGINE_SYM storage_engines { Lex->create_info.db_type= $2; } show_engine_param - | opt_full COLUMNS ext_select_item_list from_or_in table_ident opt_db wild_and_where + | opt_full COLUMNS from_or_in table_ident opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_FIELDS; - if ($6) - $5->change_db($6); - if (prepare_schema_table(YYTHD, lex, $5, SCH_COLUMNS)) + if ($5) + $4->change_db($5); + if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS)) YYABORT; } | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ @@ -5954,14 +5963,14 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; } opt_limit_clause_init - | keys_or_index ext_select_item_list from_or_in table_ident opt_db where_clause + | keys_or_index from_or_in table_ident opt_db where_clause { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_KEYS; - if ($5) - $4->change_db($5); - if (prepare_schema_table(YYTHD, lex, $4, SCH_STATISTICS)) + if ($4) + $3->change_db($4); + if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS)) YYABORT; } | COLUMN_SYM TYPES_SYM @@ -5993,7 +6002,7 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_WARNS;} | ERRORS opt_limit_clause_init { Lex->sql_command = SQLCOM_SHOW_ERRORS;} - | opt_var_type STATUS_SYM ext_select_item_list wild_and_where + | opt_var_type STATUS_SYM wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; @@ -6008,7 +6017,7 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_MUTEX_STATUS; } | opt_full PROCESSLIST_SYM { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;} - | opt_var_type VARIABLES ext_select_item_list wild_and_where + | opt_var_type VARIABLES wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; @@ -6017,7 +6026,7 @@ show_param: if (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES)) YYABORT; } - | charset ext_select_item_list wild_and_where + | charset wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; @@ -6025,7 +6034,7 @@ show_param: if (prepare_schema_table(YYTHD, lex, 0, SCH_CHARSETS)) YYABORT; } - | COLLATION_SYM ext_select_item_list wild_and_where + | COLLATION_SYM wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; @@ -6111,19 +6120,23 @@ show_param: lex->sql_command = SQLCOM_SHOW_CREATE_FUNC; lex->spname= $3; } - | PROCEDURE STATUS_SYM ext_select_item_list wild_and_where + | PROCEDURE STATUS_SYM wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_STATUS_PROC; + if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ)) + YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) YYABORT; } - | FUNCTION_SYM STATUS_SYM ext_select_item_list wild_and_where + | FUNCTION_SYM STATUS_SYM wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_STATUS_FUNC; + if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ)) + YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) YYABORT; }; @@ -6193,20 +6206,6 @@ wild_and_where: } ; -ext_select_item_list: - { - LEX *lex=Lex; - SELECT_LEX *sel= lex->current_select; - lex->lock_option= TL_READ; - mysql_init_select(lex); - lex->current_select->parsing_place= SELECT_LIST; - } - ext_select_item_list2; - -ext_select_item_list2: - /* empty */ {} - | select_item_list {}; - /* A Oracle compatible synonym for show */ describe: @@ -6582,9 +6581,9 @@ NUM_literal: NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); } | LONG_NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); } | ULONGLONG_NUM { $$ = new Item_uint($1.str, $1.length); } - | REAL_NUM + | DECIMAL_NUM { - $$= new Item_real($1.str, $1.length); + $$= new Item_decimal($1.str, $1.length, YYTHD->charset()); if (YYTHD->net.report_error) { YYABORT; @@ -6901,6 +6900,7 @@ keyword: | BTREE_SYM {} | CACHE_SYM {} | CASCADED {} + | CHAIN_SYM {} | CHANGED {} | CHARSET {} | CHECKSUM_SYM {} @@ -7440,7 +7440,14 @@ set_expr_or_default: lock: LOCK_SYM table_or_tables { - Lex->sql_command=SQLCOM_LOCK_TABLES; + LEX *lex= Lex; + + if (lex->sphead) + { + my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0)); + YYABORT; + } + lex->sql_command= SQLCOM_LOCK_TABLES; } table_lock_list {} @@ -7470,7 +7477,19 @@ lock_option: ; unlock: - UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; } + UNLOCK_SYM + { + LEX *lex= Lex; + + if (lex->sphead) + { + my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0)); + YYABORT; + } + lex->sql_command= SQLCOM_UNLOCK_TABLES; + } + table_or_tables + {} ; @@ -7854,25 +7873,66 @@ opt_work: | WORK_SYM {;} ; +opt_chain: + /* empty */ { $$= (Lex->thd->variables.completion_type == 1); } + | AND_SYM NO_SYM CHAIN_SYM { $$=0; } + | AND_SYM CHAIN_SYM { $$=1; } + ; + +opt_release: + /* empty */ { $$= (Lex->thd->variables.completion_type == 2); } + | RELEASE_SYM { $$=1; } + | NO_SYM RELEASE_SYM { $$=0; } + ; + +opt_work_and_chain: + opt_work opt_chain { $$=$2; } + ; + +opt_savepoint: + /* empty */ {} + | SAVEPOINT_SYM {} + ; + commit: - COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;}; + COMMIT_SYM opt_work_and_chain opt_release + { + Lex->sql_command= SQLCOM_COMMIT; + Lex->tx_chain= $2; + Lex->tx_release= $3; + } + ; rollback: - ROLLBACK_SYM - { - Lex->sql_command = SQLCOM_ROLLBACK; + ROLLBACK_SYM opt_work_and_chain opt_release + { + Lex->sql_command= SQLCOM_ROLLBACK; + Lex->tx_chain= $2; + Lex->tx_release= $3; } - | ROLLBACK_SYM TO_SYM SAVEPOINT_SYM ident + | ROLLBACK_SYM opt_work + TO_SYM opt_savepoint ident { Lex->sql_command = SQLCOM_ROLLBACK_TO_SAVEPOINT; - Lex->savepoint_name = $4.str; - }; + Lex->savepoint_name = $5.str; + } + ; + savepoint: SAVEPOINT_SYM ident { Lex->sql_command = SQLCOM_SAVEPOINT; Lex->savepoint_name = $2.str; - }; + } + ; + +release: + RELEASE_SYM SAVEPOINT_SYM ident + { + Lex->sql_command = SQLCOM_RELEASE_SAVEPOINT; + Lex->savepoint_name = $3.str; + } + ; /* UNIONS : glue selects together diff --git a/sql/table.h b/sql/table.h index 8240a3445ec..5ab1f900195 100644 --- a/sql/table.h +++ b/sql/table.h @@ -217,14 +217,18 @@ struct st_table { uint derived_select_number; int current_lock; /* Type of lock on table */ my_bool copy_blobs; /* copy_blobs when storing */ + + /* + 0 or JOIN_TYPE_{LEFT|RIGHT}. Currently this is only compared to 0. + If maybe_null !=0, this table is inner w.r.t. some outer join operation, + and null_row may be true. + */ + uint maybe_null; /* - Used in outer joins: if true, all columns are considered to have NULL - values, including columns declared as "not null". + If true, the current table row is considered to have all columns set to + NULL, including columns declared as "not null" (see maybe_null). */ my_bool null_row; - /* 0 or JOIN_TYPE_{LEFT|RIGHT}, same as TABLE_LIST::outer_join */ - my_bool outer_join; - my_bool maybe_null; /* true if (outer_join != 0) */ my_bool force_index; my_bool distinct,const_table,no_rows; my_bool key_read, no_keyread; @@ -356,6 +360,7 @@ typedef struct st_table_list st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ st_select_lex *schema_select_lex; + bool schema_table_reformed; /* link to select_lex where this table was used */ st_select_lex *select_lex; st_lex *view; /* link on VIEW lex for merging */ @@ -387,6 +392,10 @@ typedef struct st_table_list uint effective_algorithm; /* which algorithm was really used */ uint privilege_backup; /* place for saving privileges */ GRANT_INFO grant; + /* data need by some engines in query cache*/ + ulonglong engine_data; + /* call back function for asking handler about caching in query cache */ + qc_engine_callback callback_func; thr_lock_type lock_type; uint outer_join; /* Which join type */ uint shared; /* Used in multi-upd */ diff --git a/sql/unireg.h b/sql/unireg.h index eca540b61b9..8d88683241b 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -77,6 +77,8 @@ #define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3)) #define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2)) #define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1)) +#define PSEUDO_TABLE_BITS (PARAM_TABLE_BIT | OUTER_REF_TABLE_BIT | \ + RAND_TABLE_BIT) #define MAX_FIELDS 4096 /* Limit in the .frm file */ #define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD) diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 70c5ec633be..793c48bb988 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -277,7 +277,7 @@ static int my_strnncollsp_big5(CHARSET_INFO * cs __attribute__((unused)), if (!res && a_length != b_length) { const uchar *end; - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* @@ -295,7 +295,7 @@ static int my_strnncollsp_big5(CHARSET_INFO * cs __attribute__((unused)), for (end= a + a_length-length; a < end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } } return res; diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 50c66a63e97..916ef6d271b 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -169,7 +169,7 @@ static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)), res= 0; if (a_length != b_length) { - int swap= 0; + int swap= 1; /* Check the next not space character of the longer key. If it's < ' ', then it's smaller than the other key. @@ -187,7 +187,7 @@ static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)), for (end= a + a_length-length; a < end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } } return res; diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 6b47b537fb9..d4f9627ecf7 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -2638,7 +2638,7 @@ static int my_strnncollsp_gbk(CHARSET_INFO * cs __attribute__((unused)), if (!res && a_length != b_length) { const uchar *end; - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* @@ -2656,7 +2656,7 @@ static int my_strnncollsp_gbk(CHARSET_INFO * cs __attribute__((unused)), for (end= a + a_length-length; a < end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } } return res; diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c index 043645684cf..fdf9f4a6d91 100644 --- a/strings/ctype-latin1.c +++ b/strings/ctype-latin1.c @@ -617,7 +617,7 @@ static int my_strnncollsp_latin1_de(CHARSET_INFO *cs __attribute__((unused)), res= 0; if (a != a_end || b != b_end) { - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* @@ -635,7 +635,7 @@ static int my_strnncollsp_latin1_de(CHARSET_INFO *cs __attribute__((unused)), for ( ; a < a_end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } } return res; diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index e902730d65a..a9edb35d8a4 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -399,7 +399,7 @@ static int my_strnncollsp_mb_bin(CHARSET_INFO * cs __attribute__((unused)), res= 0; if (a_length != b_length) { - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* @@ -417,7 +417,7 @@ static int my_strnncollsp_mb_bin(CHARSET_INFO * cs __attribute__((unused)), for (end= a + a_length-length; a < end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } } return res; diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index e436d5f8702..a955435c251 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -162,7 +162,7 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length, res= 0; if (a_length != b_length) { - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* @@ -174,13 +174,13 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length, /* put shorter key in s */ a_length= b_length; a= b; - swap= -1; /* swap sign of result */ + swap= -1; /* swap sign of result */ res= -res; } for (end= a + a_length-length; a < end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } } return res; diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 22cc8d9818d..b0e2d1fcb1a 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -256,7 +256,7 @@ static int my_strnncollsp_sjis(CHARSET_INFO *cs __attribute__((unused)), if (!res && (a != a_end || b != b_end)) { - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* @@ -274,7 +274,7 @@ static int my_strnncollsp_sjis(CHARSET_INFO *cs __attribute__((unused)), for (; a < a_end ; a++) { if (*a != ' ') - return ((int) *a - (int) ' ') ^ swap; + return (*a < ' ') ? -swap : swap; } } return res; diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 9ba35e1c8ec..b6c54f1b375 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -593,7 +593,7 @@ int my_strnncollsp_tis620(CHARSET_INFO * cs __attribute__((unused)), } if (a_length != b_length) { - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* @@ -612,7 +612,7 @@ int my_strnncollsp_tis620(CHARSET_INFO * cs __attribute__((unused)), { if (*a != ' ') { - res= ((int) *a - (int) ' ') ^ swap; + res= (*a < ' ') ? -swap : swap; goto ret; } } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 0d45cceb64d..35f49a34c80 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -280,7 +280,7 @@ static int my_strnncollsp_ucs2(CHARSET_INFO *cs __attribute__((unused)), if (slen != tlen) { - int swap= 0; + int swap= 1; if (slen < tlen) { s= t; @@ -291,7 +291,7 @@ static int my_strnncollsp_ucs2(CHARSET_INFO *cs __attribute__((unused)), for ( ; s < se ; s+= 2) { if (s[0] || s[1] != ' ') - return (((int)s[0] << 8) + (int) s[1] - (int) ' ') ^ swap; + return (s[0] == 0 && s[1] < ' ') ? -swap : swap; } } return 0; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index e17e7587e85..4c90726e877 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2093,7 +2093,7 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs, if (slen != tlen) { - int swap= 0; + int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ if (slen < tlen) @@ -2117,7 +2117,7 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs, for ( ; s < se; s++) { if (*s != ' ') - return ((int)*s - (int) ' ') ^ swap; + return (*s < ' ') ? -swap : swap; } } return res; diff --git a/strings/decimal.c b/strings/decimal.c index 42e65c26ad1..da704280189 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -113,11 +113,16 @@ typedef longlong dec2; #define DIG_PER_DEC1 9 #define DIG_MASK 100000000 #define DIG_BASE 1000000000 +#define DIG_MAX 999999999 #define DIG_BASE2 LL(1000000000000000000) #define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1) static const dec1 powers10[DIG_PER_DEC1+1]={ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; static const int dig2bytes[DIG_PER_DEC1+1]={0, 1, 1, 2, 2, 3, 3, 4, 4, 4}; +static const dec1 frac_max[DIG_PER_DEC1-1]={ + 900000000, 990000000, 999000000, + 999900000, 999990000, 999999000, + 999999900, 999999990 }; #define sanity(d) DBUG_ASSERT((d)->len >0 && ((d)->buf[0] | \ (d)->buf[(d)->len-1] | 1)) @@ -189,44 +194,145 @@ static const int dig2bytes[DIG_PER_DEC1+1]={0, 1, 1, 2, 2, 3, 3, 4, 4, 4}; (to)=a; \ } while(0) +/* + Get maximum value for given precision and scale + + SYNOPSIS + max_decimal() + precision/scale - see decimal_bin_size() below + to - decimal where where the result will be stored + to->buf and to->len must be set. +*/ + +void max_decimal(int precision, int frac, decimal *to) +{ + int intpart; + dec1 *buf= to->buf; + DBUG_ASSERT(precision && precision >= frac); + + to->sign= 0; + if ((intpart= to->intg= (precision - frac))) + { + int firstdigits= intpart % DIG_PER_DEC1; + if (firstdigits) + *buf++= powers10[firstdigits] - 1; /* get 9 99 999 ... */ + for(intpart/= DIG_PER_DEC1; intpart; intpart--) + *buf++= DIG_MAX; + } + + if ((to->frac= frac)) + { + int lastdigits= frac % DIG_PER_DEC1; + for(frac/= DIG_PER_DEC1; frac; frac--) + *buf++= DIG_MAX; + if (lastdigits) + *buf= frac_max[lastdigits - 1]; + } +} + + +static dec1 *remove_leading_zeroes(decimal *from, int *intg_result) +{ + int intg= from->intg, i; + dec1 *buf0= from->buf; + i= ((intg - 1) % DIG_PER_DEC1) + 1; + while (intg > 0 && *buf0 == 0) + { + intg-= i; + i= DIG_PER_DEC1; + buf0++; + } + if (intg > 0) + { + for (i= (intg - 1) % DIG_PER_DEC1; *buf0 < powers10[i--]; intg--) ; + DBUG_ASSERT(intg > 0); + } + else + intg=0; + *intg_result= intg; + return buf0; +} + + +/* + Remove ending 0 digits from fraction part + + SYNOPSIS + decimal_optimize_fraction() + from number for processing +*/ + +void decimal_optimize_fraction(decimal *from) +{ + int frac= from->frac, i; + dec1 *buf0= from->buf + ROUND_UP(from->intg) + ROUND_UP(frac) - 1; + + if (frac == 0) + return; + + i= ((frac - 1) % DIG_PER_DEC1 + 1); + while (frac > 0 && *buf0 == 0) + { + frac-= i; + i= DIG_PER_DEC1; + buf0--; + } + if (frac > 0) + { + for (i= DIG_PER_DEC1 - ((frac - 1) % DIG_PER_DEC1); + *buf0 % powers10[i++] == 0; + frac--); + } + from->frac= frac; +} + + /* Convert decimal to its printable string representation SYNOPSIS decimal2string() - from - value to convert - to - points to buffer where string representation should be stored - *to_len - in: size of to buffer - out: length of the actually written string + from - value to convert + to - points to buffer where string representation + should be stored + *to_len - in: size of to buffer + out: length of the actually written string + fixed_precision - 0 if representation can be variable length and + fixed_decimals will not be checked in this case. + Put number as with fixed point position with this + number of digits (sign counted and decimal point is + counted) + fixed_decimals - number digits after point. + filler - character to fill gaps in case of fixed_precision > 0 RETURN VALUE E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW */ -int decimal2string(decimal *from, char *to, int *to_len) +int decimal2string(decimal *from, char *to, int *to_len, + int fixed_precision, int fixed_decimals, + char filler) { - int len, intg=from->intg, frac=from->frac, i; + int len, intg, frac=from->frac, i, intg_len, frac_len, fill; + /* number digits before decimal point */ + int fixed_intg= (fixed_precision ? + (fixed_precision - + (from->sign ? 1 : 0) - + (fixed_decimals ? 1 : 0) - + fixed_decimals) : + 0); int error=E_DEC_OK; char *s=to; dec1 *buf, *buf0=from->buf, tmp; DBUG_ASSERT(*to_len >= 2+from->sign); + DBUG_ASSERT(fixed_precision == 0 || + (fixed_precision < *to_len && + fixed_precision > ((from->sign ? 1 : 0) + + (fixed_decimals ? 1 : 0)))); /* removing leading zeroes */ - i=((intg-1) % DIG_PER_DEC1)+1; - while (intg > 0 && *buf0 == 0) - { - intg-=i; - i=DIG_PER_DEC1; - buf0++; - } - if (intg > 0) - { - for (i=(intg-1) % DIG_PER_DEC1; *buf0 < powers10[i--]; intg--) ; - DBUG_ASSERT(intg > 0); - } - else - intg=0; + buf0= remove_leading_zeroes(from, &intg); if (unlikely(intg+frac==0)) { intg=1; @@ -234,8 +340,23 @@ int decimal2string(decimal *from, char *to, int *to_len) buf0=&tmp; } - len= from->sign + intg + test(frac) + frac; - if (unlikely(len > --*to_len)) /* reserve one byte for \0 */ + intg_len= fixed_precision ? fixed_intg : (intg ? intg : 1); + frac_len= fixed_precision ? fixed_decimals : frac; + len= from->sign + intg_len + test(frac) + frac_len; + if (fixed_precision) + { + if (frac > fixed_decimals) + { + error= E_DEC_TRUNCATED; + frac= fixed_decimals; + } + if (intg > fixed_intg) + { + error= E_DEC_OVERFLOW; + intg= fixed_intg; + } + } + else if (unlikely(len > --*to_len)) /* reserve one byte for \0 */ { int i=len-*to_len; error= (frac && i <= frac + 1) ? E_DEC_TRUNCATED : E_DEC_OVERFLOW; @@ -247,7 +368,7 @@ int decimal2string(decimal *from, char *to, int *to_len) } else frac-=i; - len= from->sign + intg + test(frac) + frac; + len= from->sign + intg_len + test(frac) + frac_len; } *to_len=len; s[len]=0; @@ -257,7 +378,8 @@ int decimal2string(decimal *from, char *to, int *to_len) if (frac) { - char *s1=s+intg; + char *s1= s + intg_len; + fill= frac_len - frac; buf=buf0+ROUND_UP(intg); *s1++='.'; for (; frac>0; frac-=DIG_PER_DEC1) @@ -271,22 +393,352 @@ int decimal2string(decimal *from, char *to, int *to_len) x*=10; } } + for(; fill; fill--) + *s1++=filler; } - s+=intg; - for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1) + fill= intg_len - intg; + if (intg == 0) + fill--; /* symbol 0 before digital point */ + for(; fill; fill--) + *s++=filler; + if (intg) { - dec1 x=*--buf; - for (i=min(intg, DIG_PER_DEC1); i; i--) + s+=intg; + for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1) { - dec1 y=x/10; - *--s='0'+(uchar)(x-y*10); - x=y; + dec1 x=*--buf; + for (i=min(intg, DIG_PER_DEC1); i; i--) + { + dec1 y=x/10; + *--s='0'+(uchar)(x-y*10); + x=y; + } } } + else + *s= '0'; return error; } + +/* + Return bounds of decimal digits in the number + + SYNOPSIS + digits_bounds() + from - decimal number for processing + start_result - index (from 0 ) of first decimal digits will + be written by this address + end_result - index of position just after last decimal digit + be written by this address +*/ + +static void digits_bounds(decimal *from, int *start_result, int *end_result) +{ + int start, stop, i; + dec1 *buf_beg= from->buf; + dec1 *end= from->buf + ROUND_UP(from->intg) + ROUND_UP(from->frac); + dec1 *buf_end= end - 1; + + /* find non-zero digit from number begining */ + while (buf_beg < end && *buf_beg == 0) + buf_beg++; + + if (buf_beg >= end) + { + /* it is zero */ + *start_result= *end_result= 0; + return; + } + + /* find non-zero decimal digit from number begining */ + if (buf_beg == from->buf && from->intg) + { + start= DIG_PER_DEC1 - (i= ((from->intg-1) % DIG_PER_DEC1 + 1)); + i--; + } + else + { + i= DIG_PER_DEC1 - 1; + start= (buf_beg - from->buf) * DIG_PER_DEC1; + } + if (buf_beg < end) + for (; *buf_beg < powers10[i--]; start++) ; + *start_result= start; /* index of first decimal digit (from 0) */ + + /* find non-zero digit at the end */ + while (buf_end > buf_beg && *buf_end == 0) + buf_end--; + /* find non-zero decimal digit from the end */ + if (buf_end == end - 1 && from->frac) + { + stop= ((buf_end - from->buf) * DIG_PER_DEC1 + + (i= ((from->frac - 1) % DIG_PER_DEC1 + 1))); + i= DIG_PER_DEC1 - i + 1; + } + else + { + stop= (buf_end - from->buf + 1) * DIG_PER_DEC1; + i= 1; + } + for (; *buf_end % powers10[i++] == 0; stop--); + *end_result= stop; /* index of position after last decimal digit (from 0) */ +} + + +/* + Left shift for alignment of data in buffer + + SYNOPSIS + do_mini_left_shift() + dec pointer to decimal number which have to be shifted + shift number of decimal digits on which it should be shifted + beg/end bounds of decimal digits (see digits_bounds()) + + NOTE + Result fitting in the buffer should be garanted. + 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive) +*/ + +void do_mini_left_shift(decimal *dec, int shift, int beg, int last) +{ + dec1 *from= dec->buf + ROUND_UP(beg + 1) - 1; + dec1 *end= dec->buf + ROUND_UP(last) - 1; + int c_shift= DIG_PER_DEC1 - shift; + DBUG_ASSERT(from >= dec->buf); + DBUG_ASSERT(end < dec->buf + dec->len); + if (beg % DIG_PER_DEC1 < shift) + *(from - 1)= (*from) / powers10[c_shift]; + for(; from < end; from++) + *from= ((*from % powers10[c_shift]) * powers10[shift] + + (*(from + 1)) / powers10[c_shift]); + *from= (*from % powers10[c_shift]) * powers10[shift]; +} + + +/* + Right shift for alignment of data in buffer + + SYNOPSIS + do_mini_left_shift() + dec pointer to decimal number which have to be shifted + shift number of decimal digits on which it should be shifted + beg/end bounds of decimal digits (see digits_bounds()) + + NOTE + Result fitting in the buffer should be garanted. + 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive) +*/ + +void do_mini_right_shift(decimal *dec, int shift, int beg, int last) +{ + dec1 *from= dec->buf + ROUND_UP(last) - 1; + dec1 *end= dec->buf + ROUND_UP(beg + 1) - 1; + int c_shift= DIG_PER_DEC1 - shift; + DBUG_ASSERT(from < dec->buf + dec->len); + DBUG_ASSERT(end >= dec->buf); + if (DIG_PER_DEC1 - ((last - 1) % DIG_PER_DEC1 + 1) < shift) + *(from + 1)= (*from % powers10[shift]) * powers10[c_shift]; + for(; from > end; from--) + *from= (*from / powers10[shift] + + (*(from - 1) % powers10[shift]) * powers10[c_shift]); + *from= *from / powers10[shift]; +} + + +/* + Shift of decimal digits in given number (with rounding if it need) + + SYNOPSIS + decimal_shift() + dec number to be shifted + shift number of decimal positions + shift > 0 means shift to left shift + shift < 0 meand right shift + NOTE + In fact it is multipling on 10^shift. + RETURN + E_DEC_OK OK + E_DEC_OVERFLOW operation lead to overflow, number is untoched + E_DEC_TRUNCATED number was rounded to fit into buffer +*/ + +int decimal_shift(decimal *dec, int shift) +{ + /* index of first non zero digit (all indexes from 0) */ + int beg; + /* index of position after last decimal digit */ + int end; + /* index of digit position just after point */ + int point= ROUND_UP(dec->intg) * DIG_PER_DEC1; + /* new point position */ + int new_point= point + shift; + /* number of digits in result */ + int digits_int, digits_frac; + /* length of result and new fraction in big digits*/ + int new_len, new_frac_len; + /* return code */ + int err= E_DEC_OK; + int new_front; + + if (shift == 0) + return E_DEC_OK; + + digits_bounds(dec, &beg, &end); + + if (beg == end) + { + decimal_make_zero(dec); + return E_DEC_OK; + } + + digits_int= new_point - beg; + set_if_bigger(digits_int, 0); + digits_frac= end - new_point; + set_if_bigger(digits_frac, 0); + + if ((new_len= ROUND_UP(digits_int) + (new_frac_len= ROUND_UP(digits_frac))) > + dec->len) + { + int lack= new_len - dec->len; + int diff; + + if (new_frac_len < lack) + return E_DEC_OVERFLOW; /* lack more then we have in fraction */ + + /* cat off fraction part to allow new number to fit in our buffer */ + err= E_DEC_TRUNCATED; + new_frac_len-= lack; + diff= digits_frac - (new_frac_len * DIG_PER_DEC1); + /* Make rounding method as parameter? */ + decimal_round(dec, dec, end - point - diff, HALF_UP); + end-= diff; + digits_frac= new_frac_len * DIG_PER_DEC1; + + if (end <= beg) + { + /* + we lost all digits (they will be shifted out of buffer), so we can + just return 0 + */ + decimal_make_zero(dec); + return E_DEC_TRUNCATED; + } + } + + if (shift % DIG_PER_DEC1) + { + int l_mini_shift, r_mini_shift, mini_shift; + int do_left; + /* + Calculate left/right shift to align decimal digits inside our bug + digits correctly + */ + if (shift > 0) + { + l_mini_shift= shift % DIG_PER_DEC1; + r_mini_shift= DIG_PER_DEC1 - l_mini_shift; + /* + It is left shift so prefer left shift, but if we have not place from + left, we have to have it from right, because we checked length of + result + */ + do_left= l_mini_shift <= beg; + DBUG_ASSERT(do_left || (dec->len * DIG_PER_DEC1 - end) >= r_mini_shift); + } + else + { + r_mini_shift= (-shift) % DIG_PER_DEC1; + l_mini_shift= DIG_PER_DEC1 - r_mini_shift; + /* see comment above */ + do_left= !((dec->len * DIG_PER_DEC1 - end) >= r_mini_shift); + DBUG_ASSERT(!do_left || l_mini_shift <= beg); + } + if (do_left) + { + do_mini_left_shift(dec, l_mini_shift, beg, end); + mini_shift=- l_mini_shift; + } + else + { + do_mini_right_shift(dec, r_mini_shift, beg, end); + mini_shift= r_mini_shift; + } + new_point+= mini_shift; + /* + If number is shifted and correctly aligned in buffer we can + finish + */ + if (!(shift+= mini_shift) && (new_point - digits_int) < DIG_PER_DEC1) + { + dec->intg= digits_int; + dec->frac= digits_frac; + return err; /* already shifted as it should be */ + } + beg+= mini_shift; + end+= mini_shift; + } + + /* if new 'decimal front' is in first digit, we do not need move digits */ + if ((new_front= (new_point - digits_int)) >= DIG_PER_DEC1 || + new_front < 0) + { + /* need to move digits */ + int d_shift; + dec1 *to, *barier; + if (new_front > 0) + { + /* move left */ + d_shift= new_front / DIG_PER_DEC1; + to= dec->buf + (ROUND_UP(beg + 1) - 1 - d_shift); + barier= dec->buf + (ROUND_UP(end) - 1 - d_shift); + DBUG_ASSERT(to >= dec->buf); + DBUG_ASSERT(barier + d_shift < dec->buf + dec->len); + for(; to <= barier; to++) + *to= *(to + d_shift); + for(barier+= d_shift; to <= barier; to++) + *to= 0; + d_shift= -d_shift; + } + else + { + /* move right */ + d_shift= (1 - new_front) / DIG_PER_DEC1; + to= dec->buf + ROUND_UP(end) - 1 + d_shift; + barier= dec->buf + ROUND_UP(beg + 1) - 1 + d_shift; + DBUG_ASSERT(to < dec->buf + dec->len); + DBUG_ASSERT(barier - d_shift >= dec->buf); + for(; to >= barier; to--) + *to= *(to - d_shift); + for(barier-= d_shift; to >= barier; to--) + *to= 0; + } + d_shift*= DIG_PER_DEC1; + beg+= d_shift; + end+= d_shift; + new_point+= d_shift; + } + + /* + If there are gaps then fill ren with 0. + + Only one of following 'for' loops will work becouse beg <= end + */ + beg= ROUND_UP(beg + 1) - 1; + end= ROUND_UP(end) - 1; + DBUG_ASSERT(new_point >= 0); + new_point= ROUND_UP(new_point) - 1; + for(; new_point > end; new_point--) + dec->buf[new_point]= 0; + for(; new_point < beg; new_point++) + dec->buf[new_point]= 0; + dec->intg= digits_int; + dec->frac= digits_frac; + return err; +} + + /* Convert string to decimal @@ -309,7 +761,7 @@ int decimal2string(decimal *from, char *to, int *to_len) static int str2dec(char *from, decimal *to, char **end, my_bool fixed) { - char *s=from, *s1; + char *s=from, *s1, *endp; int i, intg, frac, error, intg1, frac1; dec1 x,*buf; LINT_INIT(error); @@ -328,15 +780,19 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) intg=s-s1; if (*s=='.') { - char *s2=s+1; - while (my_isdigit(&my_charset_latin1, *s2)) - s2++; - frac=s2-s-1; + endp= s+1; + while (my_isdigit(&my_charset_latin1, *endp)) + endp++; + frac= endp - s - 1; } else - frac=0; + { + frac= 0; + endp= s; + } + if (end) - *end=s1+intg+frac+test(frac); + *end= endp; if (frac+intg == 0) return E_DEC_BAD_NUM; @@ -405,10 +861,26 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) } if (i) *buf=x*powers10[DIG_PER_DEC1-i]; + if (*endp == 'e' || *endp == 'E') + { + long exp= strtol(endp + 1, &endp, 10); + + if (end) + *end= endp; + + if (exp > INT_MAX/2) + return E_DEC_OVERFLOW; + if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW) + return E_DEC_TRUNCATED; + + if(error != E_DEC_OVERFLOW) + error= decimal_shift(to, exp); + } return error; } + int string2decimal(char *from, decimal *to, char **end) { return str2dec(from, to, end, 0); @@ -590,7 +1062,7 @@ int decimal2bin(decimal *from, char *to, int precision, int frac) { dec1 mask=from->sign ? -1 : 0, *buf1=from->buf, *stop1; int error=E_DEC_OK, intg=precision-frac, - isize1, intg1, intg1x, from_intg=from->intg, + isize1, intg1, intg1x, from_intg, intg0=intg/DIG_PER_DEC1, frac0=frac/DIG_PER_DEC1, intg0x=intg-intg0*DIG_PER_DEC1, @@ -600,22 +1072,9 @@ int decimal2bin(decimal *from, char *to, int precision, int frac) isize0=intg0*sizeof(dec1)+dig2bytes[intg0x], fsize0=frac0*sizeof(dec1)+dig2bytes[frac0x], fsize1=frac1*sizeof(dec1)+dig2bytes[frac1x]; + char *orig_to= to; - /* removing leading zeroes */ - intg1=((from_intg-1) % DIG_PER_DEC1)+1; - while (from_intg > 0 && *buf1 == 0) - { - from_intg-=intg1; - intg1=DIG_PER_DEC1; - buf1++; - } - if (from_intg > 0) - { - for (intg1=(from_intg-1) % DIG_PER_DEC1; *buf1 < powers10[intg1--]; from_intg--) ; - DBUG_ASSERT(from_intg > 0); - } - else - from_intg=0; + buf1= remove_leading_zeroes(from, &from_intg); if (unlikely(from_intg+fsize1==0)) { @@ -703,6 +1162,7 @@ int decimal2bin(decimal *from, char *to, int precision, int frac) while (fsize0-- > fsize1) *to++=(uchar)mask; } + orig_to[0]^= 0x80; return error; } @@ -729,10 +1189,16 @@ int bin2decimal(char *from, decimal *to, int precision, int scale) intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1, intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1, intg1=intg0+(intg0x>0), frac1=frac0+(frac0x>0); - dec1 *buf=to->buf, mask=(*from <0) ? -1 : 0; + dec1 *buf=to->buf, mask=(*from <0) ? 0 : -1; char *stop; + char *d_copy; + int bin_size= decimal_bin_size(precision, scale); sanity(to); + d_copy= (char *)my_alloca(bin_size); + memcpy(d_copy, from, bin_size); + d_copy[0]^= 0x80; + from= d_copy; FIX_INTG_FRAC_ERROR(to->len, intg1, frac1, error); if (unlikely(error)) @@ -804,6 +1270,7 @@ int bin2decimal(char *from, decimal *to, int precision, int scale) *buf=(x ^ mask) * powers10[DIG_PER_DEC1 - frac0x]; buf++; } + my_afree(d_copy); return error; } @@ -861,7 +1328,9 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode { int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, frac1=ROUND_UP(from->frac), round_digit, - intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len; + intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len, + intg1=ROUND_UP(from->intg + + (((intg0 + frac0)>0) && (from->buf[0] == DIG_MAX))); dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0; sanity(to); @@ -888,12 +1357,17 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode return E_DEC_OK; } - if (to != from) + if (to != from || intg1>intg0) { - dec1 *end=buf0+intg0+min(frac1, frac0); - while (buf0 < end) - *buf1++ = *buf0++; - buf0=from->buf; + dec1 *p0= buf0+intg0+max(frac1, frac0); + dec1 *p1= buf1+intg1+max(frac1, frac0); + + to->buf[0]= 0; + while (buf0 < p0) + *(--p1) = *(--p0); + + intg0= intg1; + buf0=to->buf; buf1=to->buf; to->sign=from->sign; to->intg=min(intg0, len)*DIG_PER_DEC1; @@ -1446,9 +1920,9 @@ static int do_div_mod(decimal *from1, decimal *from2, while (dintg++ < 0) *buf0++=0; - len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1); + len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1) + 1; set_if_bigger(len1, 3); - if (!(tmp1=my_alloca(len1*sizeof(dec1)))) + if (!(tmp1=(dec1 *)my_alloca(len1*sizeof(dec1)))) return E_DEC_OOM; memcpy(tmp1, buf1, i*sizeof(dec1)); bzero(tmp1+i, (len1-i)*sizeof(dec1)); @@ -1668,7 +2142,7 @@ int decimal_mod(decimal *from1, decimal *from2, decimal *to) #ifdef MAIN -int full=0; +int full= 0; decimal a, b, c; char buf1[100], buf2[100], buf3[100]; @@ -1681,14 +2155,26 @@ void dump_decimal(decimal *d) printf("%09d} */ ", d->buf[i]); } -void print_decimal(decimal *d, char *orig) + +void check_result_code(int actual, int want) +{ + if (actual != want) + { + printf("\n^^^^^^^^^^^^^ mast return %d\n", want); + exit(1); + } +} + + +void print_decimal(decimal *d, char *orig, int actual, int want) { char s[100]; int slen=sizeof(s); if (full) dump_decimal(d); - decimal2string(d, s, &slen); + decimal2string(d, s, &slen, 0, 0, 0); printf("'%s'", s); + check_result_code(actual, want); if (orig && strcmp(orig, s)) { printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); @@ -1705,43 +2191,45 @@ void test_d2s() printf("==== decimal2string ====\n"); a.buf[0]=12345; a.intg=5; a.frac=0; a.sign=0; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); a.buf[1]=987000000; a.frac=3; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); a.sign=1; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); slen=8; - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); slen=5; - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); a.buf[0]=987000000; a.frac=3; a.intg=0; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); } -void test_s2d(char *s, char *orig) +void test_s2d(char *s, char *orig, int ex) { char s1[100]; + int res; sprintf(s1, "'%s'", s); - printf("len=%2d %-30s => res=%d ", a.len, s1, string2decimal(s, &a, 0)); - print_decimal(&a, orig); + printf("len=%2d %-30s => res=%d ", a.len, s1, + (res= string2decimal(s, &a, 0))); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_d2f(char *s) +void test_d2f(char *s, int ex) { char s1[100]; double x; @@ -1752,12 +2240,12 @@ void test_d2f(char *s) res=decimal2double(&a, &x); if (full) dump_decimal(&a); printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x); + check_result_code(res, ex); } -void test_d2b2d(char *str, int p, int s, char *orig) +void test_d2b2d(char *str, int p, int s, char *orig, int ex) { char s1[100], buf[100]; - double x; int res, i, size=decimal_bin_size(p, s); sprintf(s1, "'%s'", str); @@ -1772,20 +2260,20 @@ void test_d2b2d(char *str, int p, int s, char *orig) } res=bin2decimal(buf, &a, p, s); printf(" => res=%d ", res); - print_decimal(&a, orig); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_f2d(double from) +void test_f2d(double from, int ex) { int res; res=double2decimal(from, &a); printf("%-40.*f => res=%d ", DBL_DIG-2, from, res); - print_decimal(&a, 0); + print_decimal(&a, 0, res, ex); printf("\n"); } -void test_ull2d(ulonglong from, char *orig) +void test_ull2d(ulonglong from, char *orig, int ex) { char s[100]; int res; @@ -1793,11 +2281,11 @@ void test_ull2d(ulonglong from, char *orig) res=ulonglong2decimal(from, &a); longlong10_to_str(from,s,10); printf("%-40s => res=%d ", s, res); - print_decimal(&a, orig); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_ll2d(longlong from, char *orig) +void test_ll2d(longlong from, char *orig, int ex) { char s[100]; int res; @@ -1805,11 +2293,11 @@ void test_ll2d(longlong from, char *orig) res=longlong2decimal(from, &a); longlong10_to_str(from,s,-10); printf("%-40s => res=%d ", s, res); - print_decimal(&a, orig); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_d2ull(char *s, char *orig) +void test_d2ull(char *s, char *orig, int ex) { char s1[100]; ulonglong x; @@ -1820,6 +2308,7 @@ void test_d2ull(char *s, char *orig) if (full) dump_decimal(&a); longlong10_to_str(x,s1,10); printf("%-40s => res=%d %s\n", s, res, s1); + check_result_code(res, ex); if (orig && strcmp(orig, s1)) { printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); @@ -1827,7 +2316,7 @@ void test_d2ull(char *s, char *orig) } } -void test_d2ll(char *s, char *orig) +void test_d2ll(char *s, char *orig, int ex) { char s1[100]; longlong x; @@ -1838,6 +2327,7 @@ void test_d2ll(char *s, char *orig) if (full) dump_decimal(&a); longlong10_to_str(x,s1,-10); printf("%-40s => res=%d %s\n", s, res, s1); + check_result_code(res, ex); if (orig && strcmp(orig, s1)) { printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); @@ -1845,7 +2335,7 @@ void test_d2ll(char *s, char *orig) } } -void test_da(char *s1, char *s2, char *orig) +void test_da(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1854,11 +2344,11 @@ void test_da(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_add(&a, &b, &c); printf("%-40s => res=%d ", s, res); - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } -void test_ds(char *s1, char *s2, char *orig) +void test_ds(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1867,7 +2357,7 @@ void test_ds(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_sub(&a, &b, &c); printf("%-40s => res=%d ", s, res); - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } @@ -1887,7 +2377,7 @@ void test_dc(char *s1, char *s2, int orig) } } -void test_dm(char *s1, char *s2, char *orig) +void test_dm(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1896,11 +2386,11 @@ void test_dm(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_mul(&a, &b, &c); printf("%-40s => res=%d ", s, res); - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } -void test_dv(char *s1, char *s2, char *orig) +void test_dv(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1909,14 +2399,15 @@ void test_dv(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_div(&a, &b, &c, 5); printf("%-40s => res=%d ", s, res); + check_result_code(res, ex); if (res == E_DEC_DIV_ZERO) printf("E_DEC_DIV_ZERO"); else - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } -void test_md(char *s1, char *s2, char *orig) +void test_md(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1925,16 +2416,17 @@ void test_md(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_mod(&a, &b, &c); printf("%-40s => res=%d ", s, res); + check_result_code(res, ex); if (res == E_DEC_DIV_ZERO) printf("E_DEC_DIV_ZERO"); else - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } char *round_mode[]={"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; -void test_ro(char *s1, int n, decimal_round_mode mode, char *orig) +void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex) { char s[100]; int res; @@ -1942,11 +2434,69 @@ void test_ro(char *s1, int n, decimal_round_mode mode, char *orig) string2decimal(s1, &a, 0); res=decimal_round(&a, &b, n, mode); printf("%-40s => res=%d ", s, res); - print_decimal(&b, orig); + print_decimal(&b, orig, res, ex); printf("\n"); } -main() + +void test_mx(int precision, int frac, char *orig) +{ + char s[100]; + sprintf(s, "%d, %d", precision, frac); + max_decimal(precision, frac, &a); + printf("%-40s => ", s); + print_decimal(&a, orig, 0, 0); + printf("\n"); +} + + +void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex) +{ + char s[100]; + char s2[100]; + int slen= sizeof(s2); + int res; + + sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler); + string2decimal(s1, &a, 0); + res= decimal2string(&a, s2, &slen, prec, dec, filler); + printf("%-40s => res=%d '%s'", s, res, s2); + check_result_code(res, ex); + if (orig && strcmp(orig, s2)) + { + printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); + exit(1); + } + printf("\n"); +} + + +void test_sh(char *s1, int shift, char *orig, int ex) +{ + char s[100]; + int res; + sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift)); + string2decimal(s1, &a, 0); + res= decimal_shift(&a, shift); + printf("%-40s => res=%d ", s, res); + print_decimal(&a, orig, res, ex); + printf("\n"); +} + + +void test_fr(char *s1, char *orig) +{ + char s[100]; + sprintf(s, "'%s'", s1); + printf("%-40s => ", s); + string2decimal(s1, &a, 0); + decimal_optimize_fraction(&a); + print_decimal(&a, orig, 0, 0); + printf("\n"); +} + + +int main() { a.buf=(void*)buf1; a.len=sizeof(buf1)/sizeof(dec1); @@ -1959,142 +2509,145 @@ main() test_d2s(); printf("==== string2decimal ====\n"); - test_s2d("12345", "12345"); - test_s2d("12345.", "12345"); - test_s2d("123.45", "123.45"); - test_s2d("-123.45", "-123.45"); - test_s2d(".00012345000098765", ".00012345000098765"); - test_s2d(".12345000098765", ".12345000098765"); - test_s2d("-.000000012345000098765", "-.000000012345000098765"); - test_s2d("1234500009876.5", "1234500009876.5"); + test_s2d("12345", "12345", 0); + test_s2d("12345.", "12345", 0); + test_s2d("123.45", "123.45", 0); + test_s2d("-123.45", "-123.45", 0); + test_s2d(".00012345000098765", "0.00012345000098765", 0); + test_s2d(".12345000098765", "0.12345000098765", 0); + test_s2d("-.000000012345000098765", "-0.000000012345000098765", 0); + test_s2d("1234500009876.5", "1234500009876.5", 0); a.len=1; - test_s2d("123450000098765", "98765"); - test_s2d("123450.000098765", "123450"); + test_s2d("123450000098765", "98765", 2); + test_s2d("123450.000098765", "123450", 1); a.len=sizeof(buf1)/sizeof(dec1); + test_s2d("123E5", "12300000", 0); + test_s2d("123E-2", "1.23", 0); printf("==== decimal2double ====\n"); - test_d2f("12345"); - test_d2f("123.45"); - test_d2f("-123.45"); - test_d2f(".00012345000098765"); - test_d2f("1234500009876.5"); + test_d2f("12345", 0); + test_d2f("123.45", 0); + test_d2f("-123.45", 0); + test_d2f("0.00012345000098765", 0); + test_d2f("1234500009876.5", 0); printf("==== double2decimal ====\n"); - test_f2d(12345); - test_f2d(1.0/3); - test_f2d(-123.45); - test_f2d(0.00012345000098765); - test_f2d(1234500009876.5); + test_f2d(12345, 0); + test_f2d(1.0/3, 0); + test_f2d(-123.45, 0); + test_f2d(0.00012345000098765, 0); + test_f2d(1234500009876.5, 0); printf("==== ulonglong2decimal ====\n"); - test_ull2d(ULL(12345), "12345"); - test_ull2d(ULL(0), "0"); - test_ull2d(ULL(18446744073709551615), "18446744073709551615"); + test_ull2d(ULL(12345), "12345", 0); + test_ull2d(ULL(0), "0", 0); + test_ull2d(ULL(18446744073709551615), "18446744073709551615", 0); printf("==== decimal2ulonglong ====\n"); - test_d2ull("12345", "12345"); - test_d2ull("0", "0"); - test_d2ull("18446744073709551615", "18446744073709551615"); - test_d2ull("18446744073709551616", "18446744073"); - test_d2ull("-1", "0"); - test_d2ull("1.23", "1"); - test_d2ull("9999999999999999999999999.000", "9999999999999999"); + test_d2ull("12345", "12345", 0); + test_d2ull("0", "0", 0); + test_d2ull("18446744073709551615", "18446744073709551615", 0); + test_d2ull("18446744073709551616", "18446744073", 2); + test_d2ull("-1", "0", 2); + test_d2ull("1.23", "1", 1); + test_d2ull("9999999999999999999999999.000", "9999999999999999", 2); printf("==== longlong2decimal ====\n"); - test_ll2d(LL(-12345), "-12345"); - test_ll2d(LL(-1), "-1"); - test_ll2d(LL(-9223372036854775807), "-9223372036854775807"); - test_ll2d(ULL(9223372036854775808), "-9223372036854775808"); + test_ll2d(LL(-12345), "-12345", 0); + test_ll2d(LL(-1), "-1", 0); + test_ll2d(LL(-9223372036854775807), "-9223372036854775807", 0); + test_ll2d(ULL(9223372036854775808), "-9223372036854775808", 0); printf("==== decimal2longlong ====\n"); - test_d2ll("18446744073709551615", "18446744073"); - test_d2ll("-1", "-1"); - test_d2ll("-1.23", "-1"); - test_d2ll("-9223372036854775807", "-9223372036854775807"); - test_d2ll("-9223372036854775808", "-9223372036854775808"); - test_d2ll("9223372036854775808", "9223372036854775807"); + test_d2ll("18446744073709551615", "18446744073", 2); + test_d2ll("-1", "-1", 0); + test_d2ll("-1.23", "-1", 1); + test_d2ll("-9223372036854775807", "-9223372036854775807", 0); + test_d2ll("-9223372036854775808", "-9223372036854775808", 0); + test_d2ll("9223372036854775808", "9223372036854775807", 2); printf("==== do_add ====\n"); - test_da(".00012345000098765" ,"123.45", "123.45012345000098765"); - test_da(".1" ,".45", ".55"); - test_da("1234500009876.5" ,".00012345000098765", "1234500009876.50012345000098765"); - test_da("9999909999999.5" ,".555", "9999910000000.055"); - test_da("99999999" ,"1", "100000000"); - test_da("989999999" ,"1", "990000000"); - test_da("999999999" ,"1", "1000000000"); - test_da("12345" ,"123.45", "12468.45"); - test_da("-12345" ,"-123.45", "-12468.45"); - test_ds("-12345" ,"123.45", "-12468.45"); - test_ds("12345" ,"-123.45", "12468.45"); + test_da(".00012345000098765" ,"123.45", "123.45012345000098765", 0); + test_da(".1" ,".45", "0.55", 0); + test_da("1234500009876.5" ,".00012345000098765", "1234500009876.50012345000098765", 0); + test_da("9999909999999.5" ,".555", "9999910000000.055", 0); + test_da("99999999" ,"1", "100000000", 0); + test_da("989999999" ,"1", "990000000", 0); + test_da("999999999" ,"1", "1000000000", 0); + test_da("12345" ,"123.45", "12468.45", 0); + test_da("-12345" ,"-123.45", "-12468.45", 0); + test_ds("-12345" ,"123.45", "-12468.45", 0); + test_ds("12345" ,"-123.45", "12468.45", 0); printf("==== do_sub ====\n"); - test_ds(".00012345000098765", "123.45","-123.44987654999901235"); - test_ds("1234500009876.5", ".00012345000098765","1234500009876.49987654999901235"); - test_ds("9999900000000.5", ".555","9999899999999.945"); - test_ds("1111.5551", "1111.555",".0001"); - test_ds(".555", ".555","0"); - test_ds("10000000", "1","9999999"); - test_ds("1000001000", ".1","1000000999.9"); - test_ds("1000000000", ".1","999999999.9"); - test_ds("12345", "123.45","12221.55"); - test_ds("-12345", "-123.45","-12221.55"); - test_da("-12345", "123.45","-12221.55"); - test_da("12345", "-123.45","12221.55"); - test_ds("123.45", "12345","-12221.55"); - test_ds("-123.45", "-12345","12221.55"); - test_da("123.45", "-12345","-12221.55"); - test_da("-123.45", "12345","12221.55"); - test_da("5", "-6.0","-1.0"); + test_ds(".00012345000098765", "123.45","-123.44987654999901235", 0); + test_ds("1234500009876.5", ".00012345000098765","1234500009876.49987654999901235", 0); + test_ds("9999900000000.5", ".555","9999899999999.945", 0); + test_ds("1111.5551", "1111.555","0.0001", 0); + test_ds(".555", ".555","0", 0); + test_ds("10000000", "1","9999999", 0); + test_ds("1000001000", ".1","1000000999.9", 0); + test_ds("1000000000", ".1","999999999.9", 0); + test_ds("12345", "123.45","12221.55", 0); + test_ds("-12345", "-123.45","-12221.55", 0); + test_da("-12345", "123.45","-12221.55", 0); + test_da("12345", "-123.45","12221.55", 0); + test_ds("123.45", "12345","-12221.55", 0); + test_ds("-123.45", "-12345","12221.55", 0); + test_da("123.45", "-12345","-12221.55", 0); + test_da("-123.45", "12345","12221.55", 0); + test_da("5", "-6.0","-1.0", 0); printf("==== decimal_mul ====\n"); - test_dm("12", "10","120"); - test_dm("-123.456", "98765.4321","-12193185.1853376"); - test_dm("-123456000000", "98765432100000","-12193185185337600000000000"); - test_dm("123456", "987654321","121931851853376"); - test_dm("123456", "9876543210","1219318518533760"); - test_dm("123", "0.01","1.23"); - test_dm("123", "0","0"); + test_dm("12", "10","120", 0); + test_dm("-123.456", "98765.4321","-12193185.1853376", 0); + test_dm("-123456000000", "98765432100000","-12193185185337600000000000", 0); + test_dm("123456", "987654321","121931851853376", 0); + test_dm("123456", "9876543210","1219318518533760", 0); + test_dm("123", "0.01","1.23", 0); + test_dm("123", "0","0", 0); printf("==== decimal_div ====\n"); - test_dv("120", "10","12.000000000"); - test_dv("123", "0.01","12300.000000000"); - test_dv("120", "100000000000.00000",".000000001200000000"); - test_dv("123", "0",""); - test_dv("-12193185.1853376", "98765.4321","-123.456000000000000000"); - test_dv("121931851853376", "987654321","123456.000000000"); - test_dv("0", "987","0"); - test_dv("1", "3",".333333333"); - test_dv("1.000000000000", "3",".333333333333333333"); - test_dv("1", "1","1.000000000"); - test_dv("0.0123456789012345678912345", "9999999999",".000000000001234567890246913578148141"); + test_dv("120", "10","12.000000000", 0); + test_dv("123", "0.01","12300.000000000", 0); + test_dv("120", "100000000000.00000","0.000000001200000000", 0); + test_dv("123", "0","", 4); + test_dv("-12193185.1853376", "98765.4321","-123.456000000000000000", 0); + test_dv("121931851853376", "987654321","123456.000000000", 0); + test_dv("0", "987","0", 0); + test_dv("1", "3","0.333333333", 0); + test_dv("1.000000000000", "3","0.333333333333333333", 0); + test_dv("1", "1","1.000000000", 0); + test_dv("0.0123456789012345678912345", "9999999999","0.000000000001234567890246913578148141", 0); printf("==== decimal_mod ====\n"); - test_md("234","10","4"); - test_md("234.567","10.555","2.357"); - test_md("-234.567","10.555","-2.357"); - test_md("234.567","-10.555","2.357"); + test_md("234","10","4", 0); + test_md("234.567","10.555","2.357", 0); + test_md("-234.567","10.555","-2.357", 0); + test_md("234.567","-10.555","2.357", 0); if (full) { c.buf[1]=0x3ABECA; - test_md("99999999999999999999999999999999999999","3","0"); + test_md("99999999999999999999999999999999999999","3","0", 0); printf("%X\n", c.buf[1]); } printf("==== decimal2bin/bin2decimal ====\n"); - test_d2b2d("-10.55", 4, 2,"-10.55"); - test_d2b2d("0.0123456789012345678912345", 30, 25,".0123456789012345678912345"); - test_d2b2d("12345", 5, 0,"12345"); - test_d2b2d("12345", 10, 3,"12345.000"); - test_d2b2d("123.45", 10, 3,"123.450"); - test_d2b2d("-123.45", 20, 10,"-123.4500000000"); - test_d2b2d(".00012345000098765", 15, 14,".00012345000098"); - test_d2b2d(".00012345000098765", 22, 20,".00012345000098765000"); - test_d2b2d(".12345000098765", 30, 20,".12345000098765000000"); - test_d2b2d("-.000000012345000098765", 30, 20,"-.00000001234500009876"); - test_d2b2d("1234500009876.5", 30, 5,"1234500009876.50000"); - test_d2b2d("111111111.11", 10, 2,"11111111.11"); - full=1; - test_d2b2d("123.4", 10, 2, "123.40"); + test_d2b2d("-10.55", 4, 2,"-10.55", 0); + test_d2b2d("0.0123456789012345678912345", 30, 25,"0.0123456789012345678912345", 0); + test_d2b2d("12345", 5, 0,"12345", 0); + test_d2b2d("12345", 10, 3,"12345.000", 0); + test_d2b2d("123.45", 10, 3,"123.450", 0); + test_d2b2d("-123.45", 20, 10,"-123.4500000000", 0); + test_d2b2d(".00012345000098765", 15, 14,"0.00012345000098", 0); + test_d2b2d(".00012345000098765", 22, 20,"0.00012345000098765000", 0); + test_d2b2d(".12345000098765", 30, 20,"0.12345000098765000000", 0); + test_d2b2d("-.000000012345000098765", 30, 20,"-0.00000001234500009876", 0); + test_d2b2d("1234500009876.5", 30, 5,"1234500009876.50000", 0); + test_d2b2d("111111111.11", 10, 2,"11111111.11", 0); + test_d2b2d("000000000.01", 7, 3,"0.010", 0); + test_d2b2d("123.4", 10, 2, "123.40", 0); + printf("==== decimal_cmp ====\n"); test_dc("12","13",-1); @@ -2107,45 +2660,174 @@ main() test_dc("4","4",0); printf("==== decimal_round ====\n"); - test_ro("5678.123451",-4,TRUNCATE,"0"); - test_ro("5678.123451",-3,TRUNCATE,"5000"); - test_ro("5678.123451",-2,TRUNCATE,"5600"); - test_ro("5678.123451",-1,TRUNCATE,"5670"); - test_ro("5678.123451",0,TRUNCATE,"5678"); - test_ro("5678.123451",1,TRUNCATE,"5678.1"); - test_ro("5678.123451",2,TRUNCATE,"5678.12"); - test_ro("5678.123451",3,TRUNCATE,"5678.123"); - test_ro("5678.123451",4,TRUNCATE,"5678.1234"); - test_ro("5678.123451",5,TRUNCATE,"5678.12345"); - test_ro("5678.123451",6,TRUNCATE,"5678.123451"); - test_ro("-5678.123451",-4,TRUNCATE,"0"); + test_ro("5678.123451",-4,TRUNCATE,"0", 0); + test_ro("5678.123451",-3,TRUNCATE,"5000", 0); + test_ro("5678.123451",-2,TRUNCATE,"5600", 0); + test_ro("5678.123451",-1,TRUNCATE,"5670", 0); + test_ro("5678.123451",0,TRUNCATE,"5678", 0); + test_ro("5678.123451",1,TRUNCATE,"5678.1", 0); + test_ro("5678.123451",2,TRUNCATE,"5678.12", 0); + test_ro("5678.123451",3,TRUNCATE,"5678.123", 0); + test_ro("5678.123451",4,TRUNCATE,"5678.1234", 0); + test_ro("5678.123451",5,TRUNCATE,"5678.12345", 0); + test_ro("5678.123451",6,TRUNCATE,"5678.123451", 0); + test_ro("-5678.123451",-4,TRUNCATE,"0", 0); memset(buf2, 33, sizeof(buf2)); - test_ro("99999999999999999999999999999999999999",-31,TRUNCATE,"99999990000000000000000000000000000000"); - test_ro("15.1",0,HALF_UP,"15"); - test_ro("15.5",0,HALF_UP,"16"); - test_ro("15.9",0,HALF_UP,"16"); - test_ro("-15.1",0,HALF_UP,"-15"); - test_ro("-15.5",0,HALF_UP,"-16"); - test_ro("-15.9",0,HALF_UP,"-16"); - test_ro("15.1",1,HALF_UP,"15.1"); - test_ro("-15.1",1,HALF_UP,"-15.1"); - test_ro("15.17",1,HALF_UP,"15.2"); - test_ro("15.4",-1,HALF_UP,"20"); - test_ro("-15.4",-1,HALF_UP,"-20"); - test_ro("5.4",-1,HALF_UP,"10"); - test_ro(".999", 0, HALF_UP, "1"); + test_ro("99999999999999999999999999999999999999",-31,TRUNCATE,"99999990000000000000000000000000000000", 0); + test_ro("15.1",0,HALF_UP,"15", 0); + test_ro("15.5",0,HALF_UP,"16", 0); + test_ro("15.9",0,HALF_UP,"16", 0); + test_ro("-15.1",0,HALF_UP,"-15", 0); + test_ro("-15.5",0,HALF_UP,"-16", 0); + test_ro("-15.9",0,HALF_UP,"-16", 0); + test_ro("15.1",1,HALF_UP,"15.1", 0); + test_ro("-15.1",1,HALF_UP,"-15.1", 0); + test_ro("15.17",1,HALF_UP,"15.2", 0); + test_ro("15.4",-1,HALF_UP,"20", 0); + test_ro("-15.4",-1,HALF_UP,"-20", 0); + test_ro("5.4",-1,HALF_UP,"10", 0); + test_ro(".999", 0, HALF_UP, "1", 0); memset(buf2, 33, sizeof(buf2)); - test_ro("999999999", -9, HALF_UP, "1000000000"); - test_ro("15.1",0,HALF_EVEN,"15"); - test_ro("15.5",0,HALF_EVEN,"16"); - test_ro("14.5",0,HALF_EVEN,"14"); - test_ro("15.9",0,HALF_EVEN,"16"); - test_ro("15.1",0,CEILING,"16"); - test_ro("-15.1",0,CEILING,"-15"); - test_ro("15.1",0,FLOOR,"15"); - test_ro("-15.1",0,FLOOR,"-16"); - test_ro("999999999999999999999.999", 0, CEILING,"1000000000000000000000"); - test_ro("-999999999999999999999.999", 0, FLOOR,"-1000000000000000000000"); + test_ro("999999999", -9, HALF_UP, "1000000000", 0); + test_ro("15.1",0,HALF_EVEN,"15", 0); + test_ro("15.5",0,HALF_EVEN,"16", 0); + test_ro("14.5",0,HALF_EVEN,"14", 0); + test_ro("15.9",0,HALF_EVEN,"16", 0); + test_ro("15.1",0,CEILING,"16", 0); + test_ro("-15.1",0,CEILING,"-15", 0); + test_ro("15.1",0,FLOOR,"15", 0); + test_ro("-15.1",0,FLOOR,"-16", 0); + test_ro("999999999999999999999.999", 0, CEILING,"1000000000000000000000", 0); + test_ro("-999999999999999999999.999", 0, FLOOR,"-1000000000000000000000", 0); + + printf("==== max_decimal ====\n"); + test_mx(1,1,"0.9"); + test_mx(1,0,"9"); + test_mx(2,1,"9.9"); + test_mx(4,2,"99.99"); + test_mx(6,3,"999.999"); + test_mx(8,4,"9999.9999"); + test_mx(10,5,"99999.99999"); + test_mx(12,6,"999999.999999"); + test_mx(14,7,"9999999.9999999"); + test_mx(16,8,"99999999.99999999"); + test_mx(18,9,"999999999.999999999"); + test_mx(20,10,"9999999999.9999999999"); + test_mx(20,20,"0.99999999999999999999"); + test_mx(20,0,"99999999999999999999"); + test_mx(40,20,"99999999999999999999.99999999999999999999"); + + printf("==== decimal2string ====\n"); + test_pr("123.123", 0, 0, 0, "123.123", 0); + test_pr("123.123", 7, 3, '0', "123.123", 0); + test_pr("123.123", 9, 3, '0', "00123.123", 0); + test_pr("123.123", 9, 4, '0', "0123.1230", 0); + test_pr("123.123", 9, 5, '0', "123.12300", 0); + test_pr("123.123", 9, 2, '0', "000123.12", 1); + test_pr("123.123", 9, 6, '0', "23.123000", 2); + + printf("==== decimal_shift ====\n"); + test_sh("123.123", 1, "1231.23", 0); + test_sh("123457189.123123456789000", 1, "1234571891.23123456789", 0); + test_sh("123457189.123123456789000", 4, "1234571891231.23456789", 0); + test_sh("123457189.123123456789000", 8, "12345718912312345.6789", 0); + test_sh("123457189.123123456789000", 9, "123457189123123456.789", 0); + test_sh("123457189.123123456789000", 10, "1234571891231234567.89", 0); + test_sh("123457189.123123456789000", 17, "12345718912312345678900000", 0); + test_sh("123457189.123123456789000", 18, "123457189123123456789000000", 0); + test_sh("123457189.123123456789000", 19, "1234571891231234567890000000", 0); + test_sh("123457189.123123456789000", 26, "12345718912312345678900000000000000", 0); + test_sh("123457189.123123456789000", 27, "123457189123123456789000000000000000", 0); + test_sh("123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0); + test_sh("000000000000000000000000123457189.123123456789000", 26, "12345718912312345678900000000000000", 0); + test_sh("00000000123457189.123123456789000", 27, "123457189123123456789000000000000000", 0); + test_sh("00000000000000000123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0); + test_sh("123", 1, "1230", 0); + test_sh("123", 10, "1230000000000", 0); + test_sh(".123", 1, "1.23", 0); + test_sh(".123", 10, "1230000000", 0); + test_sh(".123", 14, "12300000000000", 0); + test_sh("000.000", 1000, "0", 0); + test_sh("000.", 1000, "0", 0); + test_sh(".000", 1000, "0", 0); + test_sh("1", 1000, "1", 2); + test_sh("123.123", -1, "12.3123", 0); + test_sh("123987654321.123456789000", -1, "12398765432.1123456789", 0); + test_sh("123987654321.123456789000", -2, "1239876543.21123456789", 0); + test_sh("123987654321.123456789000", -3, "123987654.321123456789", 0); + test_sh("123987654321.123456789000", -8, "1239.87654321123456789", 0); + test_sh("123987654321.123456789000", -9, "123.987654321123456789", 0); + test_sh("123987654321.123456789000", -10, "12.3987654321123456789", 0); + test_sh("123987654321.123456789000", -11, "1.23987654321123456789", 0); + test_sh("123987654321.123456789000", -12, "0.123987654321123456789", 0); + test_sh("123987654321.123456789000", -13, "0.0123987654321123456789", 0); + test_sh("123987654321.123456789000", -14, "0.00123987654321123456789", 0); + test_sh("00000087654321.123456789000", -14, "0.00000087654321123456789", 0); + a.len= 2; + test_sh("123.123", -2, "1.23123", 0); + test_sh("123.123", -3, "0.123123", 0); + test_sh("123.123", -6, "0.000123123", 0); + test_sh("123.123", -7, "0.0000123123", 0); + test_sh("123.123", -15, "0.000000000000123123", 0); + test_sh("123.123", -16, "0.000000000000012312", 1); + test_sh("123.123", -17, "0.000000000000001231", 1); + test_sh("123.123", -18, "0.000000000000000123", 1); + test_sh("123.123", -19, "0.000000000000000012", 1); + test_sh("123.123", -20, "0.000000000000000001", 1); + test_sh("123.123", -21, "0", 1); + test_sh(".000000000123", -1, "0.0000000000123", 0); + test_sh(".000000000123", -6, "0.000000000000000123", 0); + test_sh(".000000000123", -7, "0.000000000000000012", 1); + test_sh(".000000000123", -8, "0.000000000000000001", 1); + test_sh(".000000000123", -9, "0", 1); + test_sh(".000000000123", 1, "0.00000000123", 0); + test_sh(".000000000123", 8, "0.0123", 0); + test_sh(".000000000123", 9, "0.123", 0); + test_sh(".000000000123", 10, "1.23", 0); + test_sh(".000000000123", 17, "12300000", 0); + test_sh(".000000000123", 18, "123000000", 0); + test_sh(".000000000123", 19, "1230000000", 0); + test_sh(".000000000123", 20, "12300000000", 0); + test_sh(".000000000123", 21, "123000000000", 0); + test_sh(".000000000123", 22, "1230000000000", 0); + test_sh(".000000000123", 23, "12300000000000", 0); + test_sh(".000000000123", 24, "123000000000000", 0); + test_sh(".000000000123", 25, "1230000000000000", 0); + test_sh(".000000000123", 26, "12300000000000000", 0); + test_sh(".000000000123", 27, "123000000000000000", 0); + test_sh(".000000000123", 28, "0.000000000123", 2); + test_sh("123456789.987654321", -1, "12345678.998765432", 1); + test_sh("123456789.987654321", -2, "1234567.899876543", 1); + test_sh("123456789.987654321", -8, "1.234567900", 1); + test_sh("123456789.987654321", -9, "0.123456789987654321", 0); + test_sh("123456789.987654321", -10, "0.012345678998765432", 1); + test_sh("123456789.987654321", -17, "0.000000001234567900", 1); + test_sh("123456789.987654321", -18, "0.000000000123456790", 1); + test_sh("123456789.987654321", -19, "0.000000000012345679", 1); + test_sh("123456789.987654321", -26, "0.000000000000000001", 1); + test_sh("123456789.987654321", -27, "0", 1); + test_sh("123456789.987654321", 1, "1234567900", 1); + test_sh("123456789.987654321", 2, "12345678999", 1); + test_sh("123456789.987654321", 4, "1234567899877", 1); + test_sh("123456789.987654321", 8, "12345678998765432", 1); + test_sh("123456789.987654321", 9, "123456789987654321", 0); + test_sh("123456789.987654321", 10, "123456789.987654321", 2); + test_sh("123456789.987654321", 0, "123456789.987654321", 0); + a.len= sizeof(buf1)/sizeof(dec1); + + printf("==== decimal_optimize_fraction ====\n"); + test_fr("1.123456789000000000", "1.123456789"); + test_fr("1.12345678000000000", "1.12345678"); + test_fr("1.1234567000000000", "1.1234567"); + test_fr("1.123456000000000", "1.123456"); + test_fr("1.12345000000000", "1.12345"); + test_fr("1.1234000000000", "1.1234"); + test_fr("1.123000000000", "1.123"); + test_fr("1.12000000000", "1.12"); + test_fr("1.1000000000", "1.1"); + test_fr("1.000000000", "1"); + test_fr("1.0", "1"); + test_fr("10000000000000000000.0", "10000000000000000000"); return 0; } diff --git a/support-files/Makefile.am b/support-files/Makefile.am index 7ae1071f9ec..0a6077f0efc 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -27,7 +27,8 @@ EXTRA_DIST = mysql.spec.sh \ mysql.server.sh \ binary-configure.sh \ magic \ - MySQL-shared-compat.spec.sh + MySQL-shared-compat.spec.sh \ + ndb-config-2-node.ini.sh SUBDIRS = MacOSX @@ -38,7 +39,8 @@ pkgdata_DATA = my-small.cnf \ my-innodb-heavy-4G.cnf \ mysql-log-rotate \ mysql-@VERSION@.spec \ - MySQL-shared-compat.spec + MySQL-shared-compat.spec \ + ndb-config-2-node.ini pkgdata_SCRIPTS = mysql.server @@ -52,7 +54,8 @@ CLEANFILES = my-small.cnf \ mysql-log-rotate \ mysql.server \ binary-configure \ - MySQL-shared-compat.spec + MySQL-shared-compat.spec \ + ndb-config-2-node.ini mysql-@VERSION@.spec: mysql.spec rm -f $@ diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index b7330d1e5d7..111efab94f9 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -104,6 +104,53 @@ This package contains the standard MySQL clients and administration tools. %description client -l pt_BR Este pacote contém os clientes padrão para o MySQL. +%package ndb-storage +Release: %{release} +Summary: MySQL - ndbcluster storage engine +Group: Applications/Databases + +%description ndb-storage +This package contains the ndbcluster storage engine. +It is necessary to have this package installed on all +computers that should store ndbcluster table data. +Note that this storage engine can only be used in conjunction +with the MySQL Max server. + +%{see_base} + +%package ndb-management +Release: %{release} +Summary: MySQL - ndbcluster storage engine management +Group: Applications/Databases + +%description ndb-management +This package contains ndbcluster storage engine management. +It is necessary to have this package installed on at least +one computer in the cluster. + +%{see_base} + +%package ndb-tools +Release: %{release} +Summary: MySQL - ndbcluster storage engine basic tools +Group: Applications/Databases + +%description ndb-tools +This package contains ndbcluster storage engine basic tools. + +%{see_base} + +%package ndb-extra +Release: %{release} +Summary: MySQL - ndbcluster storage engine extra tools +Group: Applications/Databases + +%description ndb-extra +This package contains some extra ndbcluster storage engine tools for the advanced user. +They should be used with caution. + +%{see_base} + %package bench Release: %{release} Requires: %{name}-client perl-DBI perl @@ -162,6 +209,7 @@ Requires: MySQL-server >= 4.0 Optional MySQL server binary that supports additional features like: - Berkeley DB Storage Engine + - Ndbcluster Storage Engine interface - Archive Storage Engine - CSV Storage Engine - Example Storage Engine @@ -280,6 +328,7 @@ BuildMySQL "--enable-shared \ --without-openssl \ --with-berkeley-db \ --with-innodb \ + --with-ndbcluster \ --with-raid \ --with-archive \ --with-csv-storage-engine \ @@ -295,6 +344,9 @@ BuildMySQL "--enable-shared \ mv sql/mysqld sql/mysqld-max nm --numeric-sort sql/mysqld-max > sql/mysqld-max.sym +# 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/ @@ -437,6 +489,14 @@ chmod -R og-rw $mysql_datadir/mysql # Allow safe_mysqld to start mysqld and print a message before we exit sleep 2 + +%post ndb-storage +mysql_clusterdir=/var/lib/mysql-cluster + +# Create cluster directory if needed +if test ! -d $mysql_clusterdir; then mkdir -m755 $mysql_clusterdir; fi + + %post Max # Restart mysqld, to use the new binary. echo "Restarting mysqld." @@ -477,6 +537,7 @@ fi %doc Docs/manual.{html,ps,texi,txt} %doc Docs/manual_toc.html %doc support-files/my-*.cnf +%doc support-files/ndb-*.ini %doc %attr(644, root, root) %{_infodir}/mysql.info* @@ -553,6 +614,32 @@ fi %postun shared /sbin/ldconfig +%files ndb-storage +%defattr(-,root,root,0755) +%attr(755, root, root) %{_sbindir}/ndbd + +%files ndb-management +%defattr(-,root,root,0755) +%attr(755, root, root) %{_sbindir}/ndb_mgmd +%attr(755, root, root) %{_bindir}/ndb_mgm + +%files ndb-tools +%defattr(-,root,root,0755) +%attr(755, root, root) %{_bindir}/ndb_mgm +%attr(755, root, root) %{_bindir}/ndb_restore +%attr(755, root, root) %{_bindir}/ndb_waiter +%attr(755, root, root) %{_bindir}/ndb_select_all +%attr(755, root, root) %{_bindir}/ndb_select_count +%attr(755, root, root) %{_bindir}/ndb_desc +%attr(755, root, root) %{_bindir}/ndb_show_tables +%attr(755, root, root) %{_bindir}/ndb_test_platform + +%files ndb-extra +%defattr(-,root,root,0755) +%attr(755, root, root) %{_bindir}/ndb_drop_index +%attr(755, root, root) %{_bindir}/ndb_drop_table +%attr(755, root, root) %{_bindir}/ndb_delete_all + %files devel %defattr(-, root, root, 0755) %doc EXCEPTIONS-CLIENT @@ -602,6 +689,12 @@ fi # itself - note that they must be ordered by date (important when # merging BK trees) %changelog +* Monday Feb 7 2005 Tomas Ulin + +- enabled the "Ndbcluster" storage engine for the max binary +- added extra make install in ndb subdir after Max build to get ndb binaries +- added packages for ndbcluster storage engine + * Fri Jan 14 2005 Lenz Grimmer - replaced obsoleted "BuildPrereq" with "BuildRequires" instead diff --git a/support-files/ndb-config-2-node.ini.sh b/support-files/ndb-config-2-node.ini.sh new file mode 100644 index 00000000000..be80f1dd0b3 --- /dev/null +++ b/support-files/ndb-config-2-node.ini.sh @@ -0,0 +1,43 @@ +# Example Ndbcluster storage engine config file. +# +[ndbd default] +NoOfReplicas= 2 +MaxNoOfConcurrentOperations= 10000 +DataMemory= 80M +IndexMemory= 24M +TimeBetweenWatchDogCheck= 30000 +DataDir= /var/lib/mysql-cluster +MaxNoOfOrderedIndexes= 512 + +[ndb_mgmd default] +DataDir= /var/lib/mysql-cluster + +[ndb_mgmd] +Id=1 +HostName= localhost + +[ndbd] +Id= 2 +HostName= localhost + +[ndbd] +Id= 3 +HostName= localhost + +[mysqld] +Id= 4 + +[mysqld] +Id= 5 + +[mysqld] +Id= 6 + +[mysqld] +Id= 7 + +# choose an unused port number +# in this configuration 63132, 63133, and 63134 +# will be used +[tcp default] +PortNumber= 63132 diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 3cbc9918d6c..36cff4d23aa 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7258,7 +7258,7 @@ static void test_decimal_bug() */ bzero((char*) bind, sizeof(bind)); - bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer_type= MYSQL_TYPE_NEWDECIMAL; bind[0].buffer= (void *)data; bind[0].buffer_length= 25; bind[0].is_null= &is_null; diff --git a/vio/viosocket.c b/vio/viosocket.c index 858faac4f1e..3064a01f0f8 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -276,7 +276,7 @@ void vio_in_addr(Vio *vio, struct in_addr *in) { DBUG_ENTER("vio_in_addr"); if (vio->localhost) - bzero((char*) in, sizeof(*in)); /* This should never be executed */ + bzero((char*) in, sizeof(*in)); else *in=vio->remote.sin_addr; DBUG_VOID_RETURN; diff --git a/vio/viossl.c b/vio/viossl.c index 912365adca0..400d8842fd3 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -259,7 +259,7 @@ void vio_ssl_in_addr(Vio *vio, struct in_addr *in) { DBUG_ENTER("vio_ssl_in_addr"); if (vio->localhost) - bzero((char*) in, sizeof(*in)); /* This should never be executed */ + bzero((char*) in, sizeof(*in)); else *in=vio->remote.sin_addr; DBUG_VOID_RETURN; diff --git a/zlib/Makefile.am b/zlib/Makefile.am index 58d3811cd7c..e94d184a841 100644 --- a/zlib/Makefile.am +++ b/zlib/Makefile.am @@ -16,7 +16,7 @@ # Process this file with automake to create Makefile.in -noinst_LTLIBRARIES=libz.la +pkglib_LTLIBRARIES=libz.la noinst_HEADERS= crc32.h deflate.h inffast.h inffixed.h inflate.h \ inftrees.h trees.h zconf.h zlib.h zutil.h