summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUILD/Makefile.am23
-rwxr-xr-xBitKeeper/triggers/post-commit8
-rw-r--r--VC++Files/sql/mysqld.dsp2
-rw-r--r--bdb/dist/gen_rec.awk2
-rw-r--r--client/mysql.cc4
-rw-r--r--client/mysqladmin.cc2
-rw-r--r--client/mysqlbinlog.cc4
-rw-r--r--client/mysqlcheck.c2
-rw-r--r--client/mysqldump.c13
-rw-r--r--client/mysqlimport.c2
-rw-r--r--client/mysqlshow.c2
-rw-r--r--client/mysqltest.c25
-rw-r--r--config/ac-macros/misc.m421
-rw-r--r--config/ac-macros/yassl.m412
-rw-r--r--configure.in5
-rw-r--r--extra/Makefile.am4
-rw-r--r--extra/innochecksum.c2
-rw-r--r--extra/yassl/include/openssl/ssl.h1
-rw-r--r--extra/yassl/src/Makefile.am4
-rw-r--r--extra/yassl/src/handshake.cpp6
-rw-r--r--extra/yassl/src/ssl.cpp4
-rw-r--r--extra/yassl/taocrypt/src/Makefile.am12
-rw-r--r--include/config-netware.h3
-rw-r--r--include/config-win.h27
-rw-r--r--include/hash.h14
-rw-r--r--include/my_base.h51
-rw-r--r--include/my_global.h14
-rw-r--r--include/my_pthread.h4
-rw-r--r--include/myisam.h13
-rw-r--r--include/mysql.h3
-rw-r--r--innobase/btr/btr0sea.c31
-rw-r--r--innobase/dict/dict0dict.c34
-rw-r--r--innobase/dict/dict0load.c9
-rw-r--r--innobase/include/buf0buf.h12
-rw-r--r--innobase/include/dict0dict.h3
-rw-r--r--innobase/include/dict0load.h3
-rw-r--r--innobase/include/os0file.h2
-rw-r--r--innobase/include/rem0cmp.h3
-rw-r--r--innobase/include/srv0srv.h12
-rw-r--r--innobase/rem/rem0cmp.c11
-rw-r--r--innobase/row/row0ins.c27
-rw-r--r--innobase/row/row0mysql.c64
-rw-r--r--innobase/srv/srv0srv.c12
-rw-r--r--innobase/srv/srv0start.c27
-rw-r--r--libmysql/Makefile.am4
-rw-r--r--libmysqld/Makefile.am3
-rw-r--r--libmysqld/examples/Makefile.am4
-rw-r--r--myisam/ft_parser.c4
-rw-r--r--myisam/mi_check.c3
-rw-r--r--myisam/mi_create.c5
-rw-r--r--myisam/mi_delete.c2
-rw-r--r--mysql-test/include/sp-vars.inc122
-rw-r--r--mysql-test/lib/mtr_process.pl9
-rw-r--r--mysql-test/lib/mtr_stress.pl8
-rwxr-xr-xmysql-test/mysql-test-run.pl32
-rw-r--r--mysql-test/mysql-test-run.sh15
-rw-r--r--mysql-test/r/alter_table.result6
-rw-r--r--mysql-test/r/analyze.result9
-rw-r--r--mysql-test/r/bdb.result33
-rw-r--r--mysql-test/r/create.result34
-rw-r--r--mysql-test/r/ctype_recoding.result9
-rw-r--r--mysql-test/r/ctype_uca.result106
-rw-r--r--mysql-test/r/ctype_ucs.result7
-rw-r--r--mysql-test/r/ctype_ujis.result2
-rw-r--r--mysql-test/r/ctype_utf8.result10
-rw-r--r--mysql-test/r/fulltext.result3
-rw-r--r--mysql-test/r/fulltext2.result21
-rw-r--r--mysql-test/r/func_equal.result9
-rw-r--r--mysql-test/r/func_gconcat.result2
-rw-r--r--mysql-test/r/grant.result21
-rw-r--r--mysql-test/r/grant2.result11
-rw-r--r--mysql-test/r/group_min_max.result41
-rw-r--r--mysql-test/r/information_schema.result42
-rw-r--r--mysql-test/r/innodb.result126
-rw-r--r--mysql-test/r/join.result301
-rw-r--r--mysql-test/r/join_nested.result2
-rw-r--r--mysql-test/r/merge.result49
-rw-r--r--mysql-test/r/mysqldump.result69
-rw-r--r--mysql-test/r/mysqltest.result22
-rw-r--r--mysql-test/r/ndb_alter_table.result2
-rw-r--r--mysql-test/r/ndb_basic.result22
-rw-r--r--mysql-test/r/ndb_multi.result1
-rw-r--r--mysql-test/r/ndb_read_multi_range.result2
-rw-r--r--mysql-test/r/ps.result40
-rw-r--r--mysql-test/r/query_cache.result25
-rw-r--r--mysql-test/r/rpl000001.result2
-rw-r--r--mysql-test/r/rpl_deadlock.result2
-rw-r--r--mysql-test/r/rpl_relayrotate.result6
-rw-r--r--mysql-test/r/rpl_sp.result3
-rw-r--r--mysql-test/r/rpl_trigger.result12
-rw-r--r--mysql-test/r/rpl_until.result6
-rw-r--r--mysql-test/r/schema.result1
-rw-r--r--mysql-test/r/select.result62
-rw-r--r--mysql-test/r/show_check.result1
-rw-r--r--mysql-test/r/skip_name_resolve.result4
-rw-r--r--mysql-test/r/sp-big.result1
-rw-r--r--mysql-test/r/sp-destruct.result77
-rw-r--r--mysql-test/r/sp-dynamic.result2
-rw-r--r--mysql-test/r/sp-error.result77
-rw-r--r--mysql-test/r/sp-vars.result1077
-rw-r--r--mysql-test/r/sp.result473
-rw-r--r--mysql-test/r/sp_trans.result56
-rw-r--r--mysql-test/r/subselect.result143
-rw-r--r--mysql-test/r/sum_distinct-big.result29
-rw-r--r--mysql-test/r/trigger.result6
-rw-r--r--mysql-test/r/type_binary.result23
-rw-r--r--mysql-test/r/type_newdecimal-big.result26
-rw-r--r--mysql-test/r/type_newdecimal.result56
-rw-r--r--mysql-test/r/type_ranges.result2
-rw-r--r--mysql-test/r/type_time.result24
-rw-r--r--mysql-test/r/union.result26
-rw-r--r--mysql-test/r/update.result13
-rw-r--r--mysql-test/r/view.result66
-rw-r--r--mysql-test/r/view_query_cache.result61
-rw-r--r--mysql-test/t/alter_table.test11
-rw-r--r--mysql-test/t/analyze.test14
-rw-r--r--mysql-test/t/backup.test1
-rw-r--r--mysql-test/t/bdb.test39
-rw-r--r--mysql-test/t/count_distinct3.test2
-rw-r--r--mysql-test/t/create.test21
-rw-r--r--mysql-test/t/ctype_recoding.test11
-rw-r--r--mysql-test/t/ctype_uca.test1
-rw-r--r--mysql-test/t/ctype_ucs.test8
-rw-r--r--mysql-test/t/ctype_ujis.test2
-rw-r--r--mysql-test/t/ctype_utf8.test6
-rw-r--r--mysql-test/t/disabled.def5
-rw-r--r--mysql-test/t/flush_read_lock_kill.test2
-rw-r--r--mysql-test/t/fulltext.test1
-rw-r--r--mysql-test/t/fulltext2.test30
-rw-r--r--mysql-test/t/func_equal.test9
-rw-r--r--mysql-test/t/func_gconcat.test2
-rw-r--r--mysql-test/t/grant.test12
-rw-r--r--mysql-test/t/grant2.test32
-rw-r--r--mysql-test/t/group_min_max.test22
-rw-r--r--mysql-test/t/information_schema.test52
-rw-r--r--mysql-test/t/innodb.test141
-rw-r--r--mysql-test/t/join.test207
-rw-r--r--mysql-test/t/join_nested.test2
-rw-r--r--mysql-test/t/merge.test26
-rw-r--r--mysql-test/t/mysqldump.test15
-rw-r--r--mysql-test/t/mysqltest.test50
-rw-r--r--mysql-test/t/ndb_alter_table.test2
-rw-r--r--mysql-test/t/ndb_basic.test20
-rw-r--r--mysql-test/t/ndb_multi.test1
-rw-r--r--mysql-test/t/ndb_read_multi_range.test2
-rw-r--r--mysql-test/t/ps.test40
-rw-r--r--mysql-test/t/query_cache.test13
-rw-r--r--mysql-test/t/rpl000001.test2
-rw-r--r--mysql-test/t/rpl_deadlock.test8
-rw-r--r--mysql-test/t/rpl_error_ignored_table.test2
-rw-r--r--mysql-test/t/rpl_relayrotate.test8
-rw-r--r--mysql-test/t/rpl_sp.test8
-rw-r--r--mysql-test/t/rpl_trigger.test29
-rw-r--r--mysql-test/t/rpl_until.test6
-rw-r--r--mysql-test/t/schema.test6
-rw-r--r--mysql-test/t/select.test66
-rw-r--r--mysql-test/t/show_check.test1
-rw-r--r--mysql-test/t/skip_name_resolve.test2
-rw-r--r--mysql-test/t/sp-big.test3
-rw-r--r--mysql-test/t/sp-destruct.test124
-rw-r--r--mysql-test/t/sp-dynamic.test6
-rw-r--r--mysql-test/t/sp-error.test102
-rw-r--r--mysql-test/t/sp-vars.test1273
-rw-r--r--mysql-test/t/sp.test386
-rw-r--r--mysql-test/t/sp_trans.test64
-rw-r--r--mysql-test/t/subselect.test83
-rw-r--r--mysql-test/t/symlink.test2
-rw-r--r--mysql-test/t/trigger-compat.test2
-rw-r--r--mysql-test/t/trigger-grant.test2
-rw-r--r--mysql-test/t/trigger.test15
-rw-r--r--mysql-test/t/type_binary.test24
-rw-r--r--mysql-test/t/type_newdecimal-big.test50
-rw-r--r--mysql-test/t/type_newdecimal.test64
-rw-r--r--mysql-test/t/type_time.test14
-rw-r--r--mysql-test/t/union.test18
-rw-r--r--mysql-test/t/update.test17
-rw-r--r--mysql-test/t/view.test60
-rw-r--r--mysql-test/t/view_query_cache.test31
-rw-r--r--mysys/charset-def.c4
-rw-r--r--mysys/hash.c60
-rw-r--r--mysys/my_copy.c3
-rw-r--r--mysys/my_open.c6
-rw-r--r--mysys/testhash.c9
-rw-r--r--mysys/thr_alarm.c24
-rw-r--r--ndb/include/kernel/signaldata/DumpStateOrd.hpp2
-rw-r--r--ndb/include/ndb_version.h.in3
-rw-r--r--ndb/src/common/mgmcommon/ConfigRetriever.cpp9
-rw-r--r--ndb/src/kernel/blocks/ERROR_codes.txt9
-rw-r--r--ndb/src/kernel/blocks/backup/Backup.cpp17
-rw-r--r--ndb/src/kernel/blocks/dbdih/DbdihMain.cpp72
-rw-r--r--ndb/src/kernel/blocks/dblqh/Dblqh.hpp1
-rw-r--r--ndb/src/kernel/blocks/dblqh/DblqhMain.cpp48
-rw-r--r--ndb/src/kernel/blocks/dbtc/Dbtc.hpp2
-rw-r--r--ndb/src/kernel/blocks/dbtc/DbtcMain.cpp20
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp2
-rw-r--r--ndb/src/kernel/blocks/qmgr/QmgrMain.cpp17
-rw-r--r--ndb/src/kernel/vm/SimulatedBlock.cpp8
-rw-r--r--ndb/src/mgmapi/mgmapi.cpp8
-rw-r--r--ndb/src/ndbapi/NdbEventOperationImpl.cpp2
-rw-r--r--ndb/src/ndbapi/ndberror.c2
-rw-r--r--ndb/test/ndbapi/Makefile.am5
-rw-r--r--ndb/test/ndbapi/testNodeRestart.cpp149
-rw-r--r--ndb/test/ndbapi/test_event_merge.cpp1286
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt21
-rwxr-xr-xndb/tools/ndb_error_reporter88
-rw-r--r--ndb/tools/ndb_size.pl6
-rwxr-xr-xnetware/BUILD/compile-linux-tools5
-rw-r--r--netware/libmysql.def1
-rw-r--r--netware/my_print_defaults.def2
-rw-r--r--netware/myisamlog.def1
-rw-r--r--netware/myisampack.def1
-rw-r--r--netware/mysql_install_db.def1
-rw-r--r--netware/mysql_test_run.c4
-rw-r--r--netware/mysqladmin.def2
-rw-r--r--netware/mysqlbinlog.def1
-rw-r--r--netware/mysqlcheck.def1
-rw-r--r--netware/mysqld_safe.def1
-rw-r--r--netware/mysqldump.def1
-rw-r--r--netware/mysqlimport.def1
-rw-r--r--netware/perror.def1
-rw-r--r--scripts/make_binary_distribution.sh4
-rw-r--r--scripts/make_win_src_distribution.sh4
-rw-r--r--scripts/mysqlhotcopy.sh1
-rw-r--r--server-tools/instance-manager/instance.cc3
-rw-r--r--sql-common/client.c9
-rw-r--r--sql-common/my_time.c28
-rw-r--r--sql/examples/ha_example.cc2
-rw-r--r--sql/field.cc408
-rw-r--r--sql/field.h18
-rw-r--r--sql/ha_archive.cc2
-rw-r--r--sql/ha_innodb.cc122
-rw-r--r--sql/ha_innodb.h2
-rw-r--r--sql/ha_ndbcluster.cc44
-rw-r--r--sql/handler.cc41
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc301
-rw-r--r--sql/item.h301
-rw-r--r--sql/item_cmpfunc.cc63
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_func.cc55
-rw-r--r--sql/item_func.h8
-rw-r--r--sql/item_row.cc2
-rw-r--r--sql/item_strfunc.cc67
-rw-r--r--sql/item_strfunc.h35
-rw-r--r--sql/item_subselect.cc4
-rw-r--r--sql/item_sum.cc272
-rw-r--r--sql/item_sum.h213
-rw-r--r--sql/lock.cc133
-rw-r--r--sql/mysql_priv.h36
-rw-r--r--sql/mysqld.cc47
-rw-r--r--sql/opt_range.cc22
-rw-r--r--sql/share/charsets/latin5.xml13
-rw-r--r--sql/share/errmsg.txt17
-rw-r--r--sql/sp.cc186
-rw-r--r--sql/sp.h13
-rw-r--r--sql/sp_head.cc985
-rw-r--r--sql/sp_head.h64
-rw-r--r--sql/sp_pcontext.cc77
-rw-r--r--sql/sp_pcontext.h113
-rw-r--r--sql/sp_rcontext.cc306
-rw-r--r--sql/sp_rcontext.h142
-rw-r--r--sql/sql_acl.cc145
-rw-r--r--sql/sql_acl.h4
-rw-r--r--sql/sql_base.cc290
-rw-r--r--sql/sql_cache.cc50
-rw-r--r--sql/sql_class.cc20
-rw-r--r--sql/sql_class.h33
-rw-r--r--sql/sql_db.cc6
-rw-r--r--sql/sql_delete.cc8
-rw-r--r--sql/sql_insert.cc110
-rw-r--r--sql/sql_lex.cc10
-rw-r--r--sql/sql_lex.h22
-rw-r--r--sql/sql_list.h19
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc393
-rw-r--r--sql/sql_prepare.cc3
-rw-r--r--sql/sql_select.cc120
-rw-r--r--sql/sql_select.h7
-rw-r--r--sql/sql_show.cc22
-rw-r--r--sql/sql_string.h2
-rw-r--r--sql/sql_table.cc44
-rw-r--r--sql/sql_trigger.cc47
-rw-r--r--sql/sql_trigger.h4
-rw-r--r--sql/sql_update.cc38
-rw-r--r--sql/sql_view.cc40
-rw-r--r--sql/sql_yacc.yy283
-rw-r--r--sql/table.cc127
-rw-r--r--sql/table.h12
-rw-r--r--sql/tztime.cc5
-rw-r--r--sql/unireg.h8
-rw-r--r--strings/ctype-uca.c73
-rw-r--r--strings/ctype-ucs2.c42
-rw-r--r--strings/decimal.c7
-rw-r--r--support-files/mysql.server.sh10
-rw-r--r--support-files/mysql.spec.sh35
-rw-r--r--tests/mysql_client_test.c37
-rw-r--r--vio/vio.c2
-rw-r--r--vio/vio_priv.h1
-rw-r--r--vio/viossl.c19
-rw-r--r--vio/viosslfactories.c21
-rw-r--r--zlib/Makefile.am2
301 files changed, 12798 insertions, 2796 deletions
diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am
index 45c1aaa1a76..a5f3623c25e 100644
--- a/BUILD/Makefile.am
+++ b/BUILD/Makefile.am
@@ -21,27 +21,46 @@ EXTRA_DIST = FINISH.sh \
SETUP.sh \
autorun.sh \
check-cpu \
+ cleanup \
compile-alpha \
compile-alpha-ccc \
compile-alpha-cxx \
compile-alpha-debug \
+ compile-amd64-debug-max \
+ compile-amd64-max \
+ compile-darwin-mwcc \
+ compile-dist \
+ compile-hpux11-parisc2-aCC \
compile-ia64-debug-max \
+ compile-irix-mips64-mipspro \
compile-pentium \
compile-pentium-debug \
compile-pentium-debug-max \
+ compile-pentium-debug-max-no-embedded \
+ compile-pentium-debug-max-no-ndb \
compile-pentium-debug-no-bdb \
compile-pentium-debug-openssl \
compile-pentium-debug-yassl \
compile-pentium-gcov \
compile-pentium-gprof \
+ compile-pentium-icc \
+ compile-pentium-icc-valgrind-max \
+ compile-pentium-icc-yassl \
compile-pentium-max \
compile-pentium-myodbc \
compile-pentium-mysqlfs-debug \
compile-pentium-pgcc \
+ compile-pentium-valgrind-max \
+ compile-pentium64-debug \
+ compile-pentium64-debug-max \
+ compile-pentium64-valgrind-max \
+ compile-ppc \
+ compile-ppc-debug \
+ compile-ppc-debug-max \
+ compile-ppc-debug-max-no-ndb \
+ compile-ppc-max \
compile-solaris-sparc \
compile-solaris-sparc-debug \
- compile-irix-mips64-mipspro \
- compile-hpux11-parisc2-aCC \
compile-solaris-sparc-forte \
compile-solaris-sparc-purify
diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit
index fe263b79325..22d183eae3a 100755
--- a/BitKeeper/triggers/post-commit
+++ b/BitKeeper/triggers/post-commit
@@ -2,7 +2,7 @@
#shift
FROM=$USER@mysql.com
-INTERNALS=internals@lists.mysql.com
+COMMITS=commits@lists.mysql.com
DOCS=docs-commit@mysql.com
LIMIT=10000
VERSION="5.0"
@@ -61,14 +61,14 @@ EOF
) | /usr/sbin/sendmail -t
#++
-# internals@ mail
+# commits@ mail
#--
- echo "Notifying internals list at $INTERNALS"
+ echo "Notifying commits list at $COMMITS"
(
cat <<EOF
List-ID: <bk.mysql-$VERSION>
From: $FROM
-To: $INTERNALS
+To: $COMMITS
Subject: bk commit into $VERSION tree ($CHANGESET)$BS
X-CSetKey: <$CSETKEY>
$BH
diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp
index 7a9ad3e1c76..817e3224ea4 100644
--- a/VC++Files/sql/mysqld.dsp
+++ b/VC++Files/sql/mysqld.dsp
@@ -456,7 +456,7 @@ SOURCE=.\gstream.cpp
# End Source File
# Begin Source File
-SOURCE=.\examples\ha_archive.cpp
+SOURCE=.\ha_archive.cpp
# End Source File
# Begin Source File
diff --git a/bdb/dist/gen_rec.awk b/bdb/dist/gen_rec.awk
index 75f2e86ca9e..e1b75699027 100644
--- a/bdb/dist/gen_rec.awk
+++ b/bdb/dist/gen_rec.awk
@@ -180,7 +180,7 @@ BEGIN {
t = types[i];
if (modes[i] == "POINTER") {
ndx = index(t, "*");
- t = substr(types[i], 0, ndx - 2);
+ t = substr(types[i], 1, ndx - 2);
}
printf("\t%s\t%s;\n", t, vars[i]) >> HFILE
}
diff --git a/client/mysql.cc b/client/mysql.cc
index c5f0b6cd09a..98af6561966 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -259,7 +259,7 @@ static COMMANDS commands[] = {
{ "quit", 'q', com_quit, 0, "Quit mysql." },
{ "rehash", '#', com_rehash, 0, "Rebuild completion hash." },
{ "source", '.', com_source, 1,
- "Execute a SQL script file. Takes a file name as an argument."},
+ "Execute an SQL script file. Takes a file name as an argument."},
{ "status", 's', com_status, 0, "Get status information from the server."},
#ifdef USE_POPEN
{ "system", '!', com_shell, 1, "Execute a system shell command."},
@@ -728,7 +728,7 @@ static void usage(int version)
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
readline, rl_library_version);
#else
- printf("%s Ver %s Distrib %s, for %s (%s)", my_progname, VER,
+ printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, VER,
MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
#endif
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index 53bf59af67a..8d2e040b21f 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -161,7 +161,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &tcp_port,
- (gptr*) &tcp_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0},
+ (gptr*) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"relative", 'r',
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 7eb26d30cf9..ae482a155d5 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -67,7 +67,7 @@ static const char* database= 0;
static my_bool force_opt= 0, short_form= 0, remote_opt= 0;
static ulonglong offset = 0;
static const char* host = 0;
-static int port = MYSQL_PORT;
+static int port= 0;
static const char* sock= 0;
static const char* user = 0;
static char* pass = 0;
@@ -688,7 +688,7 @@ static struct my_option my_long_options[] =
{"password", 'p', "Password to connect to remote server.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Use port to connect to the remote server.",
- (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0,
+ (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0,
0, 0, 0},
{"position", 'j', "Deprecated. Use --start-position instead.",
(gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL,
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index 1324060eb55..2ad35098c33 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -122,7 +122,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
{"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 47ec9a72108..454fc0df84e 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -330,7 +330,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
{"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -2152,6 +2152,8 @@ static void dump_table(char *table, char *db)
for (i = 0; i < mysql_num_fields(res); i++)
{
int is_blob;
+ ulong length= lengths[i];
+
if (!(field = mysql_fetch_field(res)))
{
my_snprintf(query, QUERY_LENGTH,
@@ -2178,7 +2180,6 @@ static void dump_table(char *table, char *db)
field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
if (extended_insert)
{
- ulong length = lengths[i];
if (i == 0)
dynstr_set(&extended_row,"(");
else
@@ -2268,19 +2269,19 @@ static void dump_table(char *table, char *db)
{
print_xml_tag1(md_result_file, "\t\t", "field name=",
field->name, "");
- print_quoted_xml(md_result_file, row[i], lengths[i]);
+ print_quoted_xml(md_result_file, row[i], length);
fputs("</field>\n", md_result_file);
}
- else if (opt_hex_blob && is_blob)
+ else if (opt_hex_blob && is_blob && length)
{
/* sakaik got the idea to to provide blob's in hex notation. */
- char *ptr= row[i], *end= ptr+ lengths[i];
+ char *ptr= row[i], *end= ptr + length;
fputs("0x", md_result_file);
for (; ptr < end ; ptr++)
fprintf(md_result_file, "%02X", *((uchar *)ptr));
}
else
- unescape(md_result_file, row[i], lengths[i]);
+ unescape(md_result_file, row[i], length);
}
else
{
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
index 958f987d16b..8694093f06b 100644
--- a/client/mysqlimport.c
+++ b/client/mysqlimport.c
@@ -121,7 +121,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
{"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index 8369d918d6f..504f0d9844b 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -188,7 +188,7 @@ static struct my_option my_long_options[] =
"Password to use when connecting to server. If password is not given it's asked from the tty.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
#ifdef __WIN__
{"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
diff --git a/client/mysqltest.c b/client/mysqltest.c
index f6d28101fa0..3a4ce5ce7cf 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -2731,10 +2731,8 @@ end:
static struct my_option my_long_options[] =
{
- {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
- 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
{"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir,
(gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"big-test", 'B', "Define BIG_TEST to 1.", (gptr*) &opt_big_test,
@@ -2742,13 +2740,17 @@ static struct my_option my_long_options[] =
{"compress", 'C', "Use the compressed server/client protocol.",
(gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
- {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
- 0, 0, 0, 0, 0, 0},
+ {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef DBUG_OFF
+ {"debug", '#', "This is a non-debug version. Catch this and exit",
+ 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#else
+ {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.",
- (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0,
- 0, 0, 0, 0, 0},
{"manager-host", OPT_MANAGER_HOST, "Undocumented: Used for debugging.",
(gptr*) &manager_host, (gptr*) &manager_host, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
@@ -2757,13 +2759,16 @@ static struct my_option my_long_options[] =
{"manager-port", OPT_MANAGER_PORT, "Undocumented: Used for debugging.",
(gptr*) &manager_port, (gptr*) &manager_port, 0, GET_INT, REQUIRED_ARG,
MYSQL_MANAGER_PORT, 0, 0, 0, 0, 0},
+ {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.",
+ (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0,
+ 0, 0, 0, 0, 0},
{"manager-wait-timeout", OPT_MANAGER_WAIT_TIMEOUT,
"Undocumented: Used for debugging.", (gptr*) &manager_wait_timeout,
(gptr*) &manager_wait_timeout, 0, GET_INT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0},
{"password", 'p', "Password to use when connecting to server.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number to use for connection.", (gptr*) &port,
- (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0},
+ (gptr*) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication",
(gptr*) &ps_protocol, (gptr*) &ps_protocol, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4
index 6f93f38f119..5346b81fb03 100644
--- a/config/ac-macros/misc.m4
+++ b/config/ac-macros/misc.m4
@@ -693,6 +693,27 @@ dnl ---------------------------------------------------------------------------
dnl END OF MYSQL_CHECK_BIG_TABLES SECTION
dnl ---------------------------------------------------------------------------
+
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_MAX_INDEXES
+dnl Sets MAX_INDEXES
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_MAX_INDEXES], [
+ AC_ARG_WITH([max-indexes],
+ [
+ --with-max-indexes=\# Sets the maximum number of indexes per table, default 64],
+ [max_indexes="$withval"],
+ [max_indexes=64])
+ AC_MSG_CHECKING([max indexes per table])
+ AC_DEFINE_UNQUOTED([MAX_INDEXES], [$max_indexes],
+ [Maximum number of indexes per table])
+ AC_MSG_RESULT([$max_indexes])
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_MAX_INDEXES SECTION
+dnl ---------------------------------------------------------------------------
+
+
dnl MYSQL_NEEDS_MYSYS_NEW
AC_DEFUN([MYSQL_NEEDS_MYSYS_NEW],
[AC_CACHE_CHECK([needs mysys_new helpers], mysql_use_mysys_new,
diff --git a/config/ac-macros/yassl.m4 b/config/ac-macros/yassl.m4
index 9d9a4d55000..77208faee0c 100644
--- a/config/ac-macros/yassl.m4
+++ b/config/ac-macros/yassl.m4
@@ -16,28 +16,28 @@ AC_DEFUN([MYSQL_CHECK_YASSL], [
AC_MSG_RESULT([using bundled yaSSL])
yassl_dir="extra/yassl"
yassl_libs="-L\$(top_srcdir)/extra/yassl/src -lyassl -L\$(top_srcdir)/extra/yassl/taocrypt/src -ltaocrypt"
- yassl_libs_with_path="\$(top_srcdir)/extra/yassl/src/libyassl.a \$(top_srcdir)/extra/yassl/taocrypt/src/libtaocrypt.a"
yassl_includes="-I\$(top_srcdir)/extra/yassl/include"
+ yassl_libs_with_path="\$(top_srcdir)/extra/yassl/src/libyassl.la \$(top_srcdir)/extra/yassl/taocrypt/src/libtaocrypt.la"
AC_DEFINE([HAVE_OPENSSL], [1], [Defined by configure. Using yaSSL for OpenSSL emulation.])
AC_DEFINE([HAVE_YASSL], [1], [Defined by configure. Using yaSSL for OpenSSL emulation.])
# System specific checks
yassl_integer_extra_cxxflags=""
case $host_cpu--$CXX_VERSION in
sparc*--*Sun*C++*5.6*)
- # Disable inlining when compiling taocrypt/src/integer.cpp
- yassl_integer_extra_cxxflags="+d"
- AC_MSG_NOTICE([disabling inlining for yassl/taocrypt/src/integer.cpp])
+ # Disable inlining when compiling taocrypt/src/
+ yassl_taocrypt_extra_cxxflags="+d"
+ AC_MSG_NOTICE([disabling inlining for yassl/taocrypt/src/])
;;
esac
- AC_SUBST([yassl_integer_extra_cxxflags])
+ AC_SUBST([yassl_taocrypt_extra_cxxflags])
else
yassl_dir=""
AC_MSG_RESULT(no)
fi
AC_SUBST(yassl_libs)
+ AC_SUBST(yassl_libs_with_path)
AC_SUBST(yassl_includes)
AC_SUBST(yassl_dir)
- AC_SUBST(yassl_libs_with_path)
AM_CONDITIONAL([HAVE_YASSL], [ test "with_yassl" = "yes" ])
])
diff --git a/configure.in b/configure.in
index 9f0867da68a..b5c31361b26 100644
--- a/configure.in
+++ b/configure.in
@@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
# remember to also change ndb version below and update version.c in ndb
-AM_INIT_AUTOMAKE(mysql, 5.0.17)
+AM_INIT_AUTOMAKE(mysql, 5.0.19)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@@ -18,7 +18,7 @@ SHARED_LIB_VERSION=15:0:0
# ndb version
NDB_VERSION_MAJOR=5
NDB_VERSION_MINOR=0
-NDB_VERSION_BUILD=17
+NDB_VERSION_BUILD=19
NDB_VERSION_STATUS=""
# Set all version vars based on $VERSION. How do we do this more elegant ?
@@ -2413,6 +2413,7 @@ AC_SUBST(readline_link)
AC_SUBST(readline_h_ln_cmd)
MYSQL_CHECK_BIG_TABLES
+MYSQL_CHECK_MAX_INDEXES
MYSQL_CHECK_BDB
MYSQL_CHECK_INNODB
MYSQL_CHECK_EXAMPLEDB
diff --git a/extra/Makefile.am b/extra/Makefile.am
index a60656cb5c6..c0ad75059df 100644
--- a/extra/Makefile.am
+++ b/extra/Makefile.am
@@ -29,8 +29,8 @@ SUBDIRS=
DIST_SUBDIRS= yassl
# This will build mysqld_error.h and sql_state.h
-$(top_builddir)/include/mysqld_error.h: comp_err
- $(top_builddir)/extra/comp_err \
+$(top_builddir)/include/mysqld_error.h: comp_err$(EXEEXT)
+ $(top_builddir)/extra/comp_err$(EXEEXT) \
--charset=$(top_srcdir)/sql/share/charsets \
--out-dir=$(top_builddir)/sql/share/ \
--header_file=$(top_builddir)/include/mysqld_error.h \
diff --git a/extra/innochecksum.c b/extra/innochecksum.c
index 739953298af..eda5cef4647 100644
--- a/extra/innochecksum.c
+++ b/extra/innochecksum.c
@@ -28,6 +28,8 @@
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
+#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */
+
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
diff --git a/extra/yassl/include/openssl/ssl.h b/extra/yassl/include/openssl/ssl.h
index 45e26fb56ee..1c8291c2f13 100644
--- a/extra/yassl/include/openssl/ssl.h
+++ b/extra/yassl/include/openssl/ssl.h
@@ -341,6 +341,7 @@ long SSL_CTX_sess_set_cache_size(SSL_CTX*, long);
long SSL_CTX_set_tmp_dh(SSL_CTX*, DH*);
void OpenSSL_add_all_algorithms(void);
+void SSL_library_init();
void SSLeay_add_ssl_algorithms(void);
diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am
index df96018e1cf..a852ca4019b 100644
--- a/extra/yassl/src/Makefile.am
+++ b/extra/yassl/src/Makefile.am
@@ -1,7 +1,7 @@
INCLUDES = -I../include -I../taocrypt/include -I../mySTL
-noinst_LIBRARIES = libyassl.a
-libyassl_a_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \
+noinst_LTLIBRARIES = libyassl.la
+libyassl_la_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \
handshake.cpp lock.cpp log.cpp socket_wrapper.cpp ssl.cpp \
template_instnt.cpp timer.cpp yassl_imp.cpp yassl_error.cpp yassl_int.cpp
EXTRA_DIST = $(wildcard ../include/*.hpp) $(wildcard ../include/openssl/*.h)
diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp
index 45dfb6fa032..d7df438b8df 100644
--- a/extra/yassl/src/handshake.cpp
+++ b/extra/yassl/src/handshake.cpp
@@ -656,7 +656,11 @@ DoProcessReply(SSL& ssl, mySTL::auto_ptr<input_buffer> buffered)
{
ssl.getSocket().wait(); // wait for input if blocking
uint ready = ssl.getSocket().get_ready();
- if (!ready) return buffered;
+ if (!ready) {
+ // Nothing to receive after blocking wait => error
+ ssl.SetError(receive_error);
+ return buffered= null_buffer;
+ }
// add buffered data if its there
uint buffSz = buffered.get() ? buffered.get()->get_size() : 0;
diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp
index 8cea205377e..94e783167b3 100644
--- a/extra/yassl/src/ssl.cpp
+++ b/extra/yassl/src/ssl.cpp
@@ -648,6 +648,10 @@ void OpenSSL_add_all_algorithms() // compatibility only
{}
+void SSL_library_init() // compatibility only
+{}
+
+
DH* DH_new(void)
{
DH* dh = new (ys) DH;
diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am
index 0319fc6057b..d89fa95a940 100644
--- a/extra/yassl/taocrypt/src/Makefile.am
+++ b/extra/yassl/taocrypt/src/Makefile.am
@@ -1,15 +1,11 @@
INCLUDES = -I../include -I../../mySTL
-noinst_LIBRARIES = libtaoint.a libtaocrypt.a
+noinst_LTLIBRARIES = libtaocrypt.la
-libtaoint_a_SOURCES = integer.cpp
-libtaoint_a_CXXFLAGS = @yassl_integer_extra_cxxflags@
-
-libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \
+libtaocrypt_la_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \
coding.cpp dh.cpp des.cpp dsa.cpp file.cpp hash.cpp \
md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \
- template_instnt.cpp
-libtaocrypt_a_LIBADD = libtaoint_a-integer.o
+ template_instnt.cpp integer.cpp
+libtaocrypt_la_CXXFLAGS = @yassl_taocrypt_extra_cxxflags@ -DYASSL_PURE_C
EXTRA_DIST = $(wildcard ../include/*.hpp)
-AM_CXXFLAGS = -DYASSL_PURE_C
diff --git a/include/config-netware.h b/include/config-netware.h
index 7def0053bf2..f517e3c34d3 100644
--- a/include/config-netware.h
+++ b/include/config-netware.h
@@ -72,9 +72,10 @@ extern "C" {
#undef HAVE_CRYPT
#endif /* HAVE_OPENSSL */
-/* Configure can't detect this because it uses AC_TRY_RUN */
+/* Netware has an ancient zlib */
#undef HAVE_COMPRESS
#define HAVE_COMPRESS
+#undef HAVE_ARCHIVE_DB
/* include the old function apis */
#define USE_OLD_FUNCTIONS 1
diff --git a/include/config-win.h b/include/config-win.h
index 5c2f8e00e86..53483f3f39d 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -22,6 +22,11 @@ functions */
#define _WIN32_WINNT 0x0500
#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+/* Avoid endless warnings about sprintf() etc. being unsafe. */
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
#include <sys/locking.h>
#include <windows.h>
#include <math.h> /* Because of rint() */
@@ -61,6 +66,10 @@ functions */
#define __WIN__ /* To make it easier in VC++ */
#endif
+#ifndef MAX_INDEXES
+#define MAX_INDEXES 64
+#endif
+
/* File and lock constants */
#define O_SHARE 0x1000 /* Open file in sharing mode */
#ifdef __BORLANDC__
@@ -279,10 +288,10 @@ inline double ulonglong2double(ulonglong value)
*((T)+4)=(uchar) (((A) >> 32)); }
#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A)
-#define doubleget(V,M) { *((long *) &V) = *((long*) M); \
- *(((long *) &V)+1) = *(((long*) M)+1); }
-#define doublestore(T,V) { *((long *) T) = *((long*) &V); \
- *(((long *) T)+1) = *(((long*) &V)+1); }
+#define doubleget(V,M) do { *((long *) &V) = *((long*) M); \
+ *(((long *) &V)+1) = *(((long*) M)+1); } while(0)
+#define doublestore(T,V) do { *((long *) T) = *((long*) &V); \
+ *(((long *) T)+1) = *(((long*) &V)+1); } while(0)
#define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); }
#define floatstore(T,V) memcpy((byte*)(T), (byte*)(&V), sizeof(float))
#define floatget(V,M) memcpy((byte*)(&V), (byte*)(M), sizeof(float))
@@ -325,6 +334,16 @@ inline double ulonglong2double(ulonglong value)
#define HAVE_SETFILEPOINTER
#define HAVE_VIO_READ_BUFF
+#if defined(_WIN64) && defined(_M_X64)
+/* Avoid type conflicts with built-in functions. */
+#define HAVE_STRNLEN
+#endif
+
+#ifndef __NT__
+#undef FILE_SHARE_DELETE
+#define FILE_SHARE_DELETE 0 /* Not implemented on Win 98/ME */
+#endif
+
#ifdef NOT_USED
#define HAVE_SNPRINTF /* Gave link error */
#define _snprintf snprintf
diff --git a/include/hash.h b/include/hash.h
index 9a6d91036e1..8f5ff21ae5e 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -33,7 +33,7 @@ typedef void (*hash_free_key)(void *);
typedef struct st_hash {
uint key_offset,key_length; /* Length of key if const length */
- uint records,blength,current_record;
+ uint records, blength;
uint flags;
DYNAMIC_ARRAY array; /* Place for hash_keys */
hash_get_key get_key;
@@ -41,6 +41,9 @@ typedef struct st_hash {
CHARSET_INFO *charset;
} HASH;
+/* A search iterator state */
+typedef uint HASH_SEARCH_STATE;
+
#define hash_init(A,B,C,D,E,F,G,H) _hash_init(A,B,C,D,E,F,G, H CALLER_INFO)
my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
uint default_array_elements, uint key_offset,
@@ -49,12 +52,15 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
void hash_free(HASH *tree);
void my_hash_reset(HASH *hash);
byte *hash_element(HASH *hash,uint idx);
-gptr hash_search(HASH *info,const byte *key,uint length);
-gptr hash_next(HASH *info,const byte *key,uint length);
+gptr hash_search(const HASH *info, const byte *key, uint length);
+gptr hash_first(const HASH *info, const byte *key, uint length,
+ HASH_SEARCH_STATE *state);
+gptr hash_next(const HASH *info, const byte *key, uint length,
+ HASH_SEARCH_STATE *state);
my_bool my_hash_insert(HASH *info,const byte *data);
my_bool hash_delete(HASH *hash,byte *record);
my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
-void hash_replace(HASH *hash, uint idx, byte *new_row);
+void hash_replace(HASH *hash, HASH_SEARCH_STATE *state, byte *new_row);
my_bool hash_check(HASH *hash); /* Only in debug library */
#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
diff --git a/include/my_base.h b/include/my_base.h
index ba3edfad0c8..8eab79a96fd 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -248,7 +248,7 @@ enum ha_base_keytype {
#define HA_OPTION_CHECKSUM 32
#define HA_OPTION_DELAY_KEY_WRITE 64
#define HA_OPTION_NO_PACK_KEYS 128 /* Reserved for MySQL */
-#define HA_OPTION_CREATE_FROM_ENGINE 256
+#define HA_OPTION_CREATE_FROM_ENGINE 256
#define HA_OPTION_TEMP_COMPRESS_RECORD ((uint) 16384) /* set by isamchk */
#define HA_OPTION_READ_ONLY_DATA ((uint) 32768) /* Set by isamchk */
@@ -260,15 +260,48 @@ enum ha_base_keytype {
#define HA_CREATE_CHECKSUM 8
#define HA_CREATE_DELAY_KEY_WRITE 64
- /* Bits in flag to _status */
+/*
+ The following flags (OR-ed) are passed to handler::info() method.
+ The method copies misc handler information out of the storage engine
+ to data structures accessible from MySQL
+
+ Same flags are also passed down to mi_status, myrg_status, etc.
+*/
-#define HA_STATUS_POS 1 /* Return position */
-#define HA_STATUS_NO_LOCK 2 /* Don't use external lock */
-#define HA_STATUS_TIME 4 /* Return update time */
-#define HA_STATUS_CONST 8 /* Return constants values */
-#define HA_STATUS_VARIABLE 16
-#define HA_STATUS_ERRKEY 32
-#define HA_STATUS_AUTO 64
+/* this one is not used */
+#define HA_STATUS_POS 1
+/*
+ assuming the table keeps shared actual copy of the 'info' and
+ local, possibly outdated copy, the following flag means that
+ it should not try to get the actual data (locking the shared structure)
+ slightly outdated version will suffice
+*/
+#define HA_STATUS_NO_LOCK 2
+/* update the time of the last modification (in handler::update_time) */
+#define HA_STATUS_TIME 4
+/*
+ update the 'constant' part of the info:
+ handler::max_data_file_length, max_index_file_length, create_time
+ sortkey, ref_length, block_size, data_file_name, index_file_name.
+ handler::table->s->keys_in_use, keys_for_keyread, rec_per_key
+*/
+#define HA_STATUS_CONST 8
+/*
+ update the 'variable' part of the info:
+ handler::records, deleted, data_file_length, index_file_length,
+ delete_length, check_time, mean_rec_length
+*/
+#define HA_STATUS_VARIABLE 16
+/*
+ get the information about the key that caused last duplicate value error
+ update handler::errkey and handler::dupp_ref
+ see handler::get_dup_key()
+*/
+#define HA_STATUS_ERRKEY 32
+/*
+ update handler::auto_increment_value
+*/
+#define HA_STATUS_AUTO 64
/* Errorcodes given by functions */
diff --git a/include/my_global.h b/include/my_global.h
index 851033cf366..0df9ac78eb2 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -453,6 +453,17 @@ typedef unsigned short ushort;
#define __attribute__(A)
#endif
+/*
+ Wen using the embedded library, users might run into link problems,
+ dupicate declaration of __cxa_pure_virtual, solved by declaring it a
+ weak symbol.
+*/
+#ifdef USE_MYSYS_NEW
+C_MODE_START
+int __cxa_pure_virtual () __attribute__ ((weak));
+C_MODE_END
+#endif
+
/* From old s-system.h */
/*
@@ -851,6 +862,7 @@ typedef off_t os_off_t;
#define SOCKET_EAGAIN WSAEINPROGRESS
#define SOCKET_ETIMEDOUT WSAETIMEDOUT
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
+#define SOCKET_EADDRINUSE WSAEADDRINUSE
#define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE
#elif defined(OS2)
@@ -859,6 +871,7 @@ typedef off_t os_off_t;
#define SOCKET_EAGAIN SOCEINPROGRESS
#define SOCKET_ETIMEDOUT SOCKET_EINTR
#define SOCKET_EWOULDBLOCK SOCEWOULDBLOCK
+#define SOCKET_EADDRINUSE SOCEADDRINUSE
#define SOCKET_ENFILE SOCENFILE
#define SOCKET_EMFILE SOCEMFILE
#define closesocket(A) soclose(A)
@@ -869,6 +882,7 @@ typedef off_t os_off_t;
#define SOCKET_EAGAIN EAGAIN
#define SOCKET_ETIMEDOUT SOCKET_EINTR
#define SOCKET_EWOULDBLOCK EWOULDBLOCK
+#define SOCKET_EADDRINUSE EADDRINUSE
#define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE
#endif
diff --git a/include/my_pthread.h b/include/my_pthread.h
index 6f60a6df2c1..202e047dc4e 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -643,10 +643,10 @@ extern int pthread_dummy(int);
#define THREAD_NAME_SIZE 10
#ifndef DEFAULT_THREAD_STACK
-#if defined(__ia64__)
+#if SIZEOF_CHARP > 4
/*
MySQL can survive with 32K, but some glibc libraries require > 128K stack
- To resolve hostnames
+ To resolve hostnames. Also recursive stored procedures needs stack.
*/
#define DEFAULT_THREAD_STACK (256*1024L)
#else
diff --git a/include/myisam.h b/include/myisam.h
index 56717524bb2..96c1e7e192e 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -33,8 +33,6 @@ extern "C" {
#endif
#include "my_handler.h"
- /* defines used by myisam-funktions */
-
/*
There is a hard limit for the maximum number of keys as there are only
8 bits in the index file header for the number of keys in a table.
@@ -45,14 +43,19 @@ extern "C" {
running myisamchk compiled for 128 keys on a table with 255 keys.
*/
#define MI_MAX_POSSIBLE_KEY 255 /* For myisam_chk */
+#if MAX_INDEXES > MI_MAX_POSSIBLE_KEY
+#define MI_MAX_KEY MI_MAX_POSSIBLE_KEY /* Max allowed keys */
+#else
+#define MI_MAX_KEY MAX_INDEXES /* Max allowed keys */
+#endif
+
#define MI_MAX_POSSIBLE_KEY_BUFF (1024+6+6) /* For myisam_chk */
/*
The following defines can be increased if necessary.
- BUT: MI_MAX_KEY must be <= MI_MAX_POSSIBLE_KEY.
+ But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and MI_MAX_KEY_LENGTH.
*/
-#define MI_MAX_KEY 64 /* Max allowed keys */
+#define MI_MAX_KEY_LENGTH 1000 /* Max length in bytes */
#define MI_MAX_KEY_SEG 16 /* Max segments for key */
-#define MI_MAX_KEY_LENGTH 1000
#define MI_MAX_KEY_BUFF (MI_MAX_KEY_LENGTH+MI_MAX_KEY_SEG*6+8+8)
#define MI_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */
diff --git a/include/mysql.h b/include/mysql.h
index c4b4e026e5b..f3244d4ba36 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -117,6 +117,9 @@ typedef unsigned long long my_ulonglong;
#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0)
+/* backward compatibility define - to be removed eventually */
+#define ER_WARN_DATA_TRUNCATED WARN_DATA_TRUNCATED
+
typedef struct st_mysql_rows {
struct st_mysql_rows *next; /* list of rows */
MYSQL_ROW data;
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c
index 7a4e92a672a..81f23cfa99c 100644
--- a/innobase/btr/btr0sea.c
+++ b/innobase/btr/btr0sea.c
@@ -889,7 +889,8 @@ Drops a page hash index. */
void
btr_search_drop_page_hash_index(
/*============================*/
- page_t* page) /* in: index page, s- or x-latched */
+ page_t* page) /* in: index page, s- or x-latched, or an index page
+ for which we know that block->buf_fix_count == 0 */
{
hash_table_t* table;
buf_block_t* block;
@@ -904,6 +905,7 @@ btr_search_drop_page_hash_index(
ulint* folds;
ulint i;
mem_heap_t* heap;
+ dict_index_t* index;
ulint* offsets;
#ifdef UNIV_SYNC_DEBUG
@@ -932,11 +934,16 @@ btr_search_drop_page_hash_index(
n_fields = block->curr_n_fields;
n_bytes = block->curr_n_bytes;
+ index = block->index;
- ut_a(n_fields + n_bytes > 0);
+ /* NOTE: The fields of block must not be accessed after
+ releasing btr_search_latch, as the index page might only
+ be s-latched! */
rw_lock_s_unlock(&btr_search_latch);
+ ut_a(n_fields + n_bytes > 0);
+
n_recs = page_get_n_recs(page);
/* Calculate and cache fold values into an array for fast deletion
@@ -949,14 +956,6 @@ btr_search_drop_page_hash_index(
rec = page_get_infimum_rec(page);
rec = page_rec_get_next(rec);
- if (!page_rec_is_supremum(rec)) {
- ut_a(n_fields <= rec_get_n_fields(rec, block->index));
-
- if (n_bytes > 0) {
- ut_a(n_fields < rec_get_n_fields(rec, block->index));
- }
- }
-
tree_id = btr_page_get_index_id(page);
prev_fold = 0;
@@ -964,18 +963,12 @@ btr_search_drop_page_hash_index(
heap = NULL;
offsets = NULL;
- if (block->index == NULL) {
-
- mem_analyze_corruption((byte*)block);
-
- ut_a(block->index != NULL);
- }
-
while (!page_rec_is_supremum(rec)) {
/* FIXME: in a mixed tree, not all records may have enough
ordering fields: */
- offsets = rec_get_offsets(rec, block->index,
- offsets, n_fields + (n_bytes > 0), &heap);
+ offsets = rec_get_offsets(rec, index, offsets,
+ n_fields + (n_bytes > 0), &heap);
+ ut_a(rec_offs_n_fields(offsets) == n_fields + (n_bytes > 0));
fold = rec_fold(rec, offsets, n_fields, n_bytes, tree_id);
if (fold == prev_fold && prev_fold != 0) {
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index fb95ffbd80c..8050eebddd8 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -2104,8 +2104,11 @@ dict_foreign_find_index(
dict_table_t* table, /* in: table */
const char** columns,/* in: array of column names */
ulint n_cols, /* in: number of columns */
- dict_index_t* types_idx)/* in: NULL or an index to whose types the
- column types must match */
+ dict_index_t* types_idx, /* in: NULL or an index to whose types the
+ column types must match */
+ ibool check_charsets) /* in: whether to check charsets.
+ only has an effect if types_idx !=
+ NULL. */
{
#ifndef UNIV_HOTBACKUP
dict_index_t* index;
@@ -2135,7 +2138,8 @@ dict_foreign_find_index(
if (types_idx && !cmp_types_are_equal(
dict_index_get_nth_type(index, i),
- dict_index_get_nth_type(types_idx, i))) {
+ dict_index_get_nth_type(types_idx, i),
+ check_charsets)) {
break;
}
@@ -2212,7 +2216,8 @@ dict_foreign_add_to_cache(
/*======================*/
/* out: DB_SUCCESS or error code */
dict_foreign_t* foreign, /* in, own: foreign key constraint */
- ibool check_types) /* in: TRUE=check type compatibility */
+ ibool check_charsets) /* in: TRUE=check charset
+ compatibility */
{
dict_table_t* for_table;
dict_table_t* ref_table;
@@ -2248,16 +2253,10 @@ dict_foreign_add_to_cache(
}
if (for_in_cache->referenced_table == NULL && ref_table) {
- dict_index_t* types_idx;
- if (check_types) {
- types_idx = for_in_cache->foreign_index;
- } else {
- types_idx = NULL;
- }
index = dict_foreign_find_index(ref_table,
(const char**) for_in_cache->referenced_col_names,
for_in_cache->n_fields,
- types_idx);
+ for_in_cache->foreign_index, check_charsets);
if (index == NULL) {
dict_foreign_error_report(ef, for_in_cache,
@@ -2281,16 +2280,10 @@ dict_foreign_add_to_cache(
}
if (for_in_cache->foreign_table == NULL && for_table) {
- dict_index_t* types_idx;
- if (check_types) {
- types_idx = for_in_cache->referenced_index;
- } else {
- types_idx = NULL;
- }
index = dict_foreign_find_index(for_table,
(const char**) for_in_cache->foreign_col_names,
for_in_cache->n_fields,
- types_idx);
+ for_in_cache->referenced_index, check_charsets);
if (index == NULL) {
dict_foreign_error_report(ef, for_in_cache,
@@ -3097,7 +3090,7 @@ col_loop1:
/* Try to find an index which contains the columns
as the first fields and in the right order */
- index = dict_foreign_find_index(table, column_names, i, NULL);
+ index = dict_foreign_find_index(table, column_names, i, NULL, TRUE);
if (!index) {
mutex_enter(&dict_foreign_err_mutex);
@@ -3362,8 +3355,7 @@ try_find_index:
if (referenced_table) {
index = dict_foreign_find_index(referenced_table,
- column_names, i,
- foreign->foreign_index);
+ column_names, i, foreign->foreign_index, TRUE);
if (!index) {
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c
index 9bafcf33553..3281f9926f9 100644
--- a/innobase/dict/dict0load.c
+++ b/innobase/dict/dict0load.c
@@ -1091,7 +1091,7 @@ dict_load_foreign(
/* out: DB_SUCCESS or error code */
const char* id, /* in: foreign constraint id as a
null-terminated string */
- ibool check_types)/* in: TRUE=check type compatibility */
+ ibool check_charsets)/* in: TRUE=check charset compatibility */
{
dict_foreign_t* foreign;
dict_table_t* sys_foreign;
@@ -1204,7 +1204,7 @@ dict_load_foreign(
a new foreign key constraint but loading one from the data
dictionary. */
- return(dict_foreign_add_to_cache(foreign, check_types));
+ return(dict_foreign_add_to_cache(foreign, check_charsets));
}
/***************************************************************************
@@ -1219,7 +1219,8 @@ dict_load_foreigns(
/*===============*/
/* out: DB_SUCCESS or error code */
const char* table_name, /* in: table name */
- ibool check_types) /* in: TRUE=check type compatibility */
+ ibool check_charsets) /* in: TRUE=check charset
+ compatibility */
{
btr_pcur_t pcur;
mem_heap_t* heap;
@@ -1319,7 +1320,7 @@ loop:
/* Load the foreign constraint definition to the dictionary cache */
- err = dict_load_foreign(id, check_types);
+ err = dict_load_foreign(id, check_charsets);
if (err != DB_SUCCESS) {
btr_pcur_close(&pcur);
diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h
index ae8d0411c12..fc1d9a64c7f 100644
--- a/innobase/include/buf0buf.h
+++ b/innobase/include/buf0buf.h
@@ -745,8 +745,6 @@ struct buf_block_struct{
buffer pool which are index pages,
but this flag is not set because
we do not keep track of all pages */
- dict_index_t* index; /* index for which the adaptive
- hash index has been created */
/* 2. Page flushing fields */
UT_LIST_NODE_T(buf_block_t) flush_list;
@@ -833,7 +831,13 @@ struct buf_block_struct{
records with the same prefix should be
indexed in the hash index */
- /* The following 4 fields are protected by btr_search_latch: */
+ /* These 6 fields may only be modified when we have
+ an x-latch on btr_search_latch AND
+ a) we are holding an s-latch or x-latch on block->lock or
+ b) we know that block->buf_fix_count == 0.
+
+ An exception to this is when we init or create a page
+ in the buffer pool in buf0buf.c. */
ibool is_hashed; /* TRUE if hash index has already been
built on this page; note that it does
@@ -850,6 +854,8 @@ struct buf_block_struct{
ulint curr_side; /* BTR_SEARCH_LEFT_SIDE or
BTR_SEARCH_RIGHT_SIDE in hash
indexing */
+ dict_index_t* index; /* Index for which the adaptive
+ hash index has been created. */
/* 6. Debug fields */
#ifdef UNIV_SYNC_DEBUG
rw_lock_t debug_latch; /* in the debug version, each thread
diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h
index 5215d51cabe..4396611e529 100644
--- a/innobase/include/dict0dict.h
+++ b/innobase/include/dict0dict.h
@@ -197,7 +197,8 @@ dict_foreign_add_to_cache(
/*======================*/
/* out: DB_SUCCESS or error code */
dict_foreign_t* foreign, /* in, own: foreign key constraint */
- ibool check_types); /* in: TRUE=check type compatibility */
+ ibool check_charsets);/* in: TRUE=check charset
+ compatibility */
/*************************************************************************
Checks if a table is referenced by foreign keys. */
diff --git a/innobase/include/dict0load.h b/innobase/include/dict0load.h
index f13620bc6e8..741123614ab 100644
--- a/innobase/include/dict0load.h
+++ b/innobase/include/dict0load.h
@@ -82,7 +82,8 @@ dict_load_foreigns(
/*===============*/
/* out: DB_SUCCESS or error code */
const char* table_name, /* in: table name */
- ibool check_types); /* in: TRUE=check type compatibility */
+ ibool check_charsets);/* in: TRUE=check charsets
+ compatibility */
/************************************************************************
Prints to the standard output information on all tables found in the data
dictionary system table. */
diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h
index 224fd59a76b..02a38dd49ef 100644
--- a/innobase/include/os0file.h
+++ b/innobase/include/os0file.h
@@ -187,7 +187,7 @@ Creates a temporary file. */
FILE*
os_file_create_tmpfile(void);
/*========================*/
- /* out: temporary file handle (never NULL) */
+ /* out: temporary file handle, or NULL on error */
/***************************************************************************
The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
diff --git a/innobase/include/rem0cmp.h b/innobase/include/rem0cmp.h
index 1b1ee26b809..f6762078cbc 100644
--- a/innobase/include/rem0cmp.h
+++ b/innobase/include/rem0cmp.h
@@ -24,7 +24,8 @@ cmp_types_are_equal(
/* out: TRUE if the types are considered
equal in comparisons */
dtype_t* type1, /* in: type 1 */
- dtype_t* type2); /* in: type 2 */
+ dtype_t* type2, /* in: type 2 */
+ ibool check_charsets); /* in: whether to check charsets */
/*****************************************************************
This function is used to compare two data fields for which we know the
data type. */
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 11347f430d4..99ea4f2de27 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -34,6 +34,18 @@ extern ibool srv_lower_case_table_names;
extern mutex_t srv_monitor_file_mutex;
/* Temporary file for innodb monitor output */
extern FILE* srv_monitor_file;
+/* Mutex for locking srv_dict_tmpfile.
+This mutex has a very high rank; threads reserving it should not
+be holding any InnoDB latches. */
+extern mutex_t srv_dict_tmpfile_mutex;
+/* Temporary file for output from the data dictionary */
+extern FILE* srv_dict_tmpfile;
+/* Mutex for locking srv_misc_tmpfile.
+This mutex has a very low rank; threads reserving it should not
+acquire any further latches or sleep before releasing this one. */
+extern mutex_t srv_misc_tmpfile_mutex;
+/* Temporary file for miscellanous diagnostic output */
+extern FILE* srv_misc_tmpfile;
/* Server parameters which are read from the initfile */
diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c
index 7c33476fb9e..6a463b7d4cf 100644
--- a/innobase/rem/rem0cmp.c
+++ b/innobase/rem/rem0cmp.c
@@ -99,7 +99,8 @@ cmp_types_are_equal(
/* out: TRUE if the types are considered
equal in comparisons */
dtype_t* type1, /* in: type 1 */
- dtype_t* type2) /* in: type 2 */
+ dtype_t* type2, /* in: type 2 */
+ ibool check_charsets) /* in: whether to check charsets */
{
if (dtype_is_non_binary_string_type(type1->mtype, type1->prtype)
&& dtype_is_non_binary_string_type(type2->mtype, type2->prtype)) {
@@ -107,12 +108,12 @@ cmp_types_are_equal(
/* Both are non-binary string types: they can be compared if
and only if the charset-collation is the same */
- if (dtype_get_charset_coll(type1->prtype)
- == dtype_get_charset_coll(type2->prtype)) {
+ if (check_charsets) {
+ return(dtype_get_charset_coll(type1->prtype)
+ == dtype_get_charset_coll(type2->prtype));
+ } else {
return(TRUE);
}
-
- return(FALSE);
}
if (dtype_is_binary_string_type(type1->mtype, type1->prtype)
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 5e833372299..32aa0385596 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -588,20 +588,21 @@ row_ins_set_detailed(
trx_t* trx, /* in: transaction */
dict_foreign_t* foreign) /* in: foreign key constraint */
{
-
- FILE* tf = os_file_create_tmpfile();
-
- if (tf) {
- ut_print_name(tf, trx, foreign->foreign_table_name);
- dict_print_info_on_foreign_key_in_create_format(tf, trx,
- foreign, FALSE);
-
- trx_set_detailed_error_from_file(trx, tf);
-
- fclose(tf);
+ mutex_enter(&srv_misc_tmpfile_mutex);
+ rewind(srv_misc_tmpfile);
+
+ if (os_file_set_eof(srv_misc_tmpfile)) {
+ ut_print_name(srv_misc_tmpfile, trx,
+ foreign->foreign_table_name);
+ dict_print_info_on_foreign_key_in_create_format(
+ srv_misc_tmpfile,
+ trx, foreign, FALSE);
+ trx_set_detailed_error_from_file(trx, srv_misc_tmpfile);
} else {
- trx_set_detailed_error(trx, "temp file creation failed");
+ trx_set_detailed_error(trx, "temp file operation failed");
}
+
+ mutex_exit(&srv_misc_tmpfile_mutex);
}
/*************************************************************************
@@ -709,7 +710,7 @@ row_ins_foreign_report_add_err(
}
if (rec) {
- rec_print(ef, rec, foreign->foreign_index);
+ rec_print(ef, rec, foreign->referenced_index);
}
putc('\n', ef);
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 82f7daf2ed8..723e305b2ab 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -2132,7 +2132,7 @@ row_table_add_foreign_constraints(
if (err == DB_SUCCESS) {
/* Check that also referencing constraints are ok */
- err = dict_load_foreigns(name, trx->check_foreigns);
+ err = dict_load_foreigns(name, TRUE);
}
if (err != DB_SUCCESS) {
@@ -3590,7 +3590,8 @@ row_rename_table_for_mysql(
mem_heap_t* heap = NULL;
const char** constraints_to_drop = NULL;
ulint n_constraints_to_drop = 0;
- ibool recovering_temp_table = FALSE;
+ ibool recovering_temp_table = FALSE;
+ ibool old_is_tmp, new_is_tmp;
ulint len;
ulint i;
ibool success;
@@ -3630,6 +3631,9 @@ row_rename_table_for_mysql(
trx->op_info = "renaming table";
trx_start_if_not_started(trx);
+ old_is_tmp = row_is_mysql_tmp_table_name(old_name);
+ new_is_tmp = row_is_mysql_tmp_table_name(new_name);
+
if (row_mysql_is_recovered_tmp_table(new_name)) {
recovering_temp_table = TRUE;
@@ -3676,7 +3680,7 @@ row_rename_table_for_mysql(
len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4
+ ut_strlenq(new_name, '\'') + ut_strlenq(old_name, '\'');
- if (row_is_mysql_tmp_table_name(new_name)) {
+ if (new_is_tmp) {
db_name_len = dict_get_db_name_len(old_name) + 1;
/* MySQL is doing an ALTER TABLE command and it renames the
@@ -3829,7 +3833,7 @@ row_rename_table_for_mysql(
the table is stored in a single-table tablespace */
success = dict_table_rename_in_cache(table, new_name,
- !row_is_mysql_tmp_table_name(new_name));
+ !new_is_tmp);
if (!success) {
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL);
@@ -3846,19 +3850,16 @@ row_rename_table_for_mysql(
goto funct_exit;
}
- err = dict_load_foreigns(new_name, trx->check_foreigns);
-
- if (row_is_mysql_tmp_table_name(old_name)) {
+ /* We only want to switch off some of the type checking in
+ an ALTER, not in a RENAME. */
+
+ err = dict_load_foreigns(new_name,
+ old_is_tmp ? trx->check_foreigns : TRUE);
- /* MySQL is doing an ALTER TABLE command and it
- renames the created temporary table to the name
- of the original table. In the ALTER TABLE we maybe
- created some FOREIGN KEY constraints for the temporary
- table. But we want to load also the foreign key
- constraint definitions for the original table name. */
+ if (err != DB_SUCCESS) {
+ ut_print_timestamp(stderr);
- if (err != DB_SUCCESS) {
- ut_print_timestamp(stderr);
+ if (old_is_tmp) {
fputs(" InnoDB: Error: in ALTER TABLE ",
stderr);
ut_print_name(stderr, trx, new_name);
@@ -3866,36 +3867,23 @@ row_rename_table_for_mysql(
"InnoDB: has or is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n",
stderr);
-
- ut_a(dict_table_rename_in_cache(table,
- old_name, FALSE));
- trx->error_state = DB_SUCCESS;
- trx_general_rollback_for_mysql(trx, FALSE,
- NULL);
- trx->error_state = DB_SUCCESS;
- }
- } else {
- if (err != DB_SUCCESS) {
-
- ut_print_timestamp(stderr);
-
+ } else {
fputs(
" InnoDB: Error: in RENAME TABLE table ",
stderr);
ut_print_name(stderr, trx, new_name);
fputs("\n"
- "InnoDB: is referenced in foreign key constraints\n"
- "InnoDB: which are not compatible with the new table definition.\n",
+ "InnoDB: is referenced in foreign key constraints\n"
+ "InnoDB: which are not compatible with the new table definition.\n",
stderr);
-
- ut_a(dict_table_rename_in_cache(table,
- old_name, FALSE));
-
- trx->error_state = DB_SUCCESS;
- trx_general_rollback_for_mysql(trx, FALSE,
- NULL);
- trx->error_state = DB_SUCCESS;
}
+
+ ut_a(dict_table_rename_in_cache(table,
+ old_name, FALSE));
+ trx->error_state = DB_SUCCESS;
+ trx_general_rollback_for_mysql(trx, FALSE,
+ NULL);
+ trx->error_state = DB_SUCCESS;
}
}
funct_exit:
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index c585536baee..6e0b9b23266 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -397,6 +397,18 @@ mutex_t srv_innodb_monitor_mutex;
mutex_t srv_monitor_file_mutex;
/* Temporary file for innodb monitor output */
FILE* srv_monitor_file;
+/* Mutex for locking srv_dict_tmpfile.
+This mutex has a very high rank; threads reserving it should not
+be holding any InnoDB latches. */
+mutex_t srv_dict_tmpfile_mutex;
+/* Temporary file for output from the data dictionary */
+FILE* srv_dict_tmpfile;
+/* Mutex for locking srv_misc_tmpfile.
+This mutex has a very low rank; threads reserving it should not
+acquire any further latches or sleep before releasing this one. */
+mutex_t srv_misc_tmpfile_mutex;
+/* Temporary file for miscellanous diagnostic output */
+FILE* srv_misc_tmpfile;
ulint srv_main_thread_process_no = 0;
ulint srv_main_thread_id = 0;
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index e5151ebf631..4f99f340e1c 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -1180,6 +1180,20 @@ NetWare. */
}
}
+ mutex_create(&srv_dict_tmpfile_mutex);
+ mutex_set_level(&srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION);
+ srv_dict_tmpfile = os_file_create_tmpfile();
+ if (!srv_dict_tmpfile) {
+ return(DB_ERROR);
+ }
+
+ mutex_create(&srv_misc_tmpfile_mutex);
+ mutex_set_level(&srv_misc_tmpfile_mutex, SYNC_ANY_LATCH);
+ srv_misc_tmpfile = os_file_create_tmpfile();
+ if (!srv_misc_tmpfile) {
+ return(DB_ERROR);
+ }
+
/* Restrict the maximum number of file i/o threads */
if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) {
@@ -1822,8 +1836,19 @@ innobase_shutdown_for_mysql(void)
mem_free(srv_monitor_file_name);
}
}
-
+ if (srv_dict_tmpfile) {
+ fclose(srv_dict_tmpfile);
+ srv_dict_tmpfile = 0;
+ }
+
+ if (srv_misc_tmpfile) {
+ fclose(srv_misc_tmpfile);
+ srv_misc_tmpfile = 0;
+ }
+
mutex_free(&srv_monitor_file_mutex);
+ mutex_free(&srv_dict_tmpfile_mutex);
+ mutex_free(&srv_misc_tmpfile_mutex);
/* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside
them */
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
index 319a9913255..a3e16b521a9 100644
--- a/libmysql/Makefile.am
+++ b/libmysql/Makefile.am
@@ -22,14 +22,14 @@
target = libmysqlclient.la
target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
-LIBS = @CLIENT_LIBS@ @yassl_libs@
+LIBS = @CLIENT_LIBS@
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
$(openssl_includes) $(yassl_includes) @ZLIB_INCLUDES@
include $(srcdir)/Makefile.shared
libmysqlclient_la_SOURCES = $(target_sources)
-libmysqlclient_la_LIBADD = $(target_libadd)
+libmysqlclient_la_LIBADD = $(target_libadd) $(yassl_libs_with_path)
libmysqlclient_la_LDFLAGS = $(target_ldflags)
EXTRA_DIST = Makefile.shared libmysql.def
noinst_HEADERS = client_settings.h
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index 8ddc8752f07..f07bbacba02 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -80,8 +80,7 @@ INC_LIB= $(top_builddir)/regex/libregex.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/strings/libmystrings.a \
$(top_builddir)/dbug/libdbug.a \
- $(top_builddir)/vio/libvio.a \
- @yassl_libs_with_path@
+ $(top_builddir)/vio/libvio.a
#
diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am
index 925a6573efe..414cf63b003 100644
--- a/libmysqld/examples/Makefile.am
+++ b/libmysqld/examples/Makefile.am
@@ -34,8 +34,8 @@ link_sources:
DEFS = -DEMBEDDED_LIBRARY
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \
-I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \
- $(openssl_includes)
-LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@
+ $(openssl_includes) $(yassl_includes)
+LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ $(yassl_libs)
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @innodb_system_libs@ @LIBDL@ $(CXXLDFLAGS)
mysqltest_embedded_LINK = $(CXXLINK)
diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c
index 9198f89ee35..6e79696bd6e 100644
--- a/myisam/ft_parser.c
+++ b/myisam/ft_parser.c
@@ -149,8 +149,10 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
for (word->pos=doc; doc<end; length++, mbl=my_mbcharlen(cs, *(uchar *)doc), doc+=(mbl ? mbl : 1))
if (true_word_char(cs,*doc))
mwc=0;
- else if (!misc_word_char(*doc) || mwc++)
+ else if (!misc_word_char(*doc) || mwc)
break;
+ else
+ mwc++;
param->prev='A'; /* be sure *prev is true_word_char */
word->len= (uint)(doc-word->pos) - mwc;
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 6296193d6b0..9ce1dff51af 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -402,7 +402,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
full_text_keys++;
if (share->state.key_root[key] == HA_OFFSET_ERROR &&
(info->state->records == 0 || keyinfo->flag & HA_FULLTEXT))
- continue;
+ goto do_stat;
if (!_mi_fetch_keypage(info,keyinfo,share->state.key_root[key],
DFLT_INIT_HITS,info->buff,0))
{
@@ -498,6 +498,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
param->max_level);
all_keydata+=param->keydata; all_totaldata+=param->totaldata; key_totlength+=length;
+do_stat:
if (param->testflag & T_STATISTICS)
update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
diff --git a/myisam/mi_create.c b/myisam/mi_create.c
index 6d4106afda5..1a17febe94a 100644
--- a/myisam/mi_create.c
+++ b/myisam/mi_create.c
@@ -72,7 +72,6 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
}
LINT_INIT(dfile);
LINT_INIT(file);
- pthread_mutex_lock(&THR_LOCK_myisam);
errpos=0;
options=0;
bzero((byte*) &share,sizeof(share));
@@ -135,7 +134,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
pack_reclength++;
min_pack_length++;
/* We must test for 257 as length includes pack-length */
- if (test(rec->length >= 257))
+ if (test(rec->length >= 257))
{
long_varchar_count++;
pack_reclength+= 2; /* May be packed on 3 bytes */
@@ -542,6 +541,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (! (flags & HA_DONT_TOUCH_DATA))
share.state.create_time= (long) time((time_t*) 0);
+ pthread_mutex_lock(&THR_LOCK_myisam);
+
if (ci->index_file_name)
{
fn_format(filename, ci->index_file_name,"",MI_NAME_IEXT,4);
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
index bf99830b37f..416d951d138 100644
--- a/myisam/mi_delete.c
+++ b/myisam/mi_delete.c
@@ -170,7 +170,7 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo,
goto err;
}
if ((error=d_search(info,keyinfo,
- (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND
+ (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND | SEARCH_UPDATE
: SEARCH_SAME),
key,key_length,old_root,root_buff)) >0)
{
diff --git a/mysql-test/include/sp-vars.inc b/mysql-test/include/sp-vars.inc
new file mode 100644
index 00000000000..3e02c9d1709
--- /dev/null
+++ b/mysql-test/include/sp-vars.inc
@@ -0,0 +1,122 @@
+delimiter |;
+
+---------------------------------------------------------------------------
+
+CREATE PROCEDURE sp_vars_check_dflt()
+BEGIN
+ DECLARE v1 TINYINT DEFAULT 1e200;
+ DECLARE v1u TINYINT UNSIGNED DEFAULT 1e200;
+ DECLARE v2 TINYINT DEFAULT -1e200;
+ DECLARE v2u TINYINT UNSIGNED DEFAULT -1e200;
+ DECLARE v3 TINYINT DEFAULT 300;
+ DECLARE v3u TINYINT UNSIGNED DEFAULT 300;
+ DECLARE v4 TINYINT DEFAULT -300;
+ DECLARE v4u TINYINT UNSIGNED DEFAULT -300;
+
+ DECLARE v5 TINYINT DEFAULT 10 * 10 * 10;
+ DECLARE v5u TINYINT UNSIGNED DEFAULT 10 * 10 * 10;
+ DECLARE v6 TINYINT DEFAULT -10 * 10 * 10;
+ DECLARE v6u TINYINT UNSIGNED DEFAULT -10 * 10 * 10;
+
+ DECLARE v7 TINYINT DEFAULT '10';
+ DECLARE v8 TINYINT DEFAULT '10 ';
+ DECLARE v9 TINYINT DEFAULT ' 10 ';
+ DECLARE v10 TINYINT DEFAULT 'String 10 ';
+ DECLARE v11 TINYINT DEFAULT 'String10';
+ DECLARE v12 TINYINT DEFAULT '10 String';
+ DECLARE v13 TINYINT DEFAULT '10String';
+ DECLARE v14 TINYINT DEFAULT concat('10', ' ');
+ DECLARE v15 TINYINT DEFAULT concat(' ', '10');
+ DECLARE v16 TINYINT DEFAULT concat('Hello, ', 'world');
+
+ DECLARE v17 DECIMAL(64, 2) DEFAULT 12;
+ DECLARE v18 DECIMAL(64, 2) DEFAULT 12.123;
+ DECLARE v19 DECIMAL(64, 2) DEFAULT 11 + 1;
+ DECLARE v20 DECIMAL(64, 2) DEFAULT 12 + 0.123;
+
+ SELECT v1, v1u, v2, v2u, v3, v3u, v4, v4u;
+ SELECT v5, v5u, v6, v6u;
+ SELECT v7, v8, v9, v10, v11, v12, v13, v14, v15, v16;
+ SELECT v17, v18, v19, v20;
+END|
+
+---------------------------------------------------------------------------
+
+CREATE PROCEDURE sp_vars_check_assignment()
+BEGIN
+ DECLARE i1, i2, i3, i4 TINYINT;
+ DECLARE u1, u2, u3, u4 TINYINT UNSIGNED;
+ DECLARE d1, d2, d3 DECIMAL(64, 2);
+
+ SET i1 = 1e200;
+ SET i2 = -1e200;
+ SET i3 = 300;
+ SET i4 = -300;
+
+ SELECT i1, i2, i3, i4;
+
+ SET i1 = 10 * 10 * 10;
+ SET i2 = -10 * 10 * 10;
+ SET i3 = sign(10 * 10) * 10 * 20;
+ SET i4 = sign(-10 * 10) * -10 * 20;
+
+ SELECT i1, i2, i3, i4;
+
+ SET u1 = 1e200;
+ SET u2 = -1e200;
+ SET u3 = 300;
+ SET u4 = -300;
+
+ SELECT u1, u2, u3, u4;
+
+ SET u1 = 10 * 10 * 10;
+ SET u2 = -10 * 10 * 10;
+ SET u3 = sign(10 * 10) * 10 * 20;
+ SET u4 = sign(-10 * 10) * -10 * 20;
+
+ SELECT u1, u2, u3, u4;
+
+ SET d1 = 1234;
+ SET d2 = 1234.12;
+ SET d3 = 1234.1234;
+
+ SELECT d1, d2, d3;
+
+ SET d1 = 12 * 100 + 34;
+ SET d2 = 12 * 100 + 34 + 0.12;
+ SET d3 = 12 * 100 + 34 + 0.1234;
+
+ SELECT d1, d2, d3;
+END|
+
+---------------------------------------------------------------------------
+
+CREATE FUNCTION sp_vars_check_ret1() RETURNS TINYINT
+BEGIN
+ RETURN 1e200;
+END|
+
+---------------------------------------------------------------------------
+
+CREATE FUNCTION sp_vars_check_ret2() RETURNS TINYINT
+BEGIN
+ RETURN 10 * 10 * 10;
+END|
+
+---------------------------------------------------------------------------
+
+CREATE FUNCTION sp_vars_check_ret3() RETURNS TINYINT
+BEGIN
+ RETURN 'Hello, world';
+END|
+
+---------------------------------------------------------------------------
+
+CREATE FUNCTION sp_vars_check_ret4() RETURNS DECIMAL(64, 2)
+BEGIN
+ RETURN 12 * 10 + 34 + 0.1234;
+END|
+
+---------------------------------------------------------------------------
+
+delimiter ;|
diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl
index b3a243444c1..4d88c9b3322 100644
--- a/mysql-test/lib/mtr_process.pl
+++ b/mysql-test/lib/mtr_process.pl
@@ -890,7 +890,14 @@ sub mtr_exit ($) {
# cluck("Called mtr_exit()");
mtr_timer_stop_all($::glob_timers);
local $SIG{HUP} = 'IGNORE';
- kill('HUP', -$$);
+ # ToDo: Signalling -$$ will only work if we are the process group
+ # leader (in fact on QNX it will signal our session group leader,
+ # which might be Do-compile or Pushbuild, causing tests to be
+ # aborted). So we only do it if we are the group leader. We might
+ # set ourselves as the group leader at startup (with
+ # POSIX::setpgrp(0,0)), but then care must be needed to always do
+ # proper child process cleanup.
+ kill('HUP', -$$) if $$ == getpgrp();
sleep 2;
exit($code);
}
diff --git a/mysql-test/lib/mtr_stress.pl b/mysql-test/lib/mtr_stress.pl
index a57d94e8043..d3ed24db545 100644
--- a/mysql-test/lib/mtr_stress.pl
+++ b/mysql-test/lib/mtr_stress.pl
@@ -145,6 +145,14 @@ sub run_stress_test ()
mtr_add_arg($args, "--stress-init-file=%", $::opt_stress_init_file);
}
+ if ( !$::opt_stress_loop_count && !$::opt_stress_test_count &&
+ !$::opt_stress_test_duration )
+ {
+ #Limit stress testing with 20 loops in case when any limit parameter
+ #was specified
+ $::opt_stress_test_count=20;
+ }
+
if ( $::opt_stress_loop_count )
{
mtr_add_arg($args, "--loop-count=%s", $::opt_stress_loop_count);
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 8ccd87fc7a8..2c53b94a248 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -276,9 +276,9 @@ our $opt_stress= "";
our $opt_stress_suite= "main";
our $opt_stress_mode= "random";
our $opt_stress_threads= 5;
-our $opt_stress_test_count= 20;
-our $opt_stress_loop_count= "";
-our $opt_stress_test_duration= "";
+our $opt_stress_test_count= 0;
+our $opt_stress_loop_count= 0;
+our $opt_stress_test_duration= 0;
our $opt_stress_init_file= "";
our $opt_stress_test_file= "";
@@ -804,6 +804,12 @@ sub command_line_setup () {
}
}
+ # On QNX, /tmp/dir/master.sock and /tmp/dir//master.sock seem to be
+ # considered different, so avoid the extra slash (/) in the socket
+ # paths.
+ my $sockdir = $opt_tmpdir;
+ $sockdir =~ s|/+$||;
+
# Put this into a hash, will be a C struct
$master->[0]=
@@ -812,7 +818,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/master.err",
path_mylog => "$opt_vardir/log/master.log",
path_mypid => "$opt_vardir/run/master.pid",
- path_mysock => "$opt_tmpdir/master.sock",
+ path_mysock => "$sockdir/master.sock",
path_myport => $opt_master_myport,
start_timeout => 400, # enough time create innodb tables
@@ -825,7 +831,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/master1.err",
path_mylog => "$opt_vardir/log/master1.log",
path_mypid => "$opt_vardir/run/master1.pid",
- path_mysock => "$opt_tmpdir/master1.sock",
+ path_mysock => "$sockdir/master1.sock",
path_myport => $opt_master_myport + 1,
start_timeout => 400, # enough time create innodb tables
};
@@ -836,7 +842,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/slave.err",
path_mylog => "$opt_vardir/log/slave.log",
path_mypid => "$opt_vardir/run/slave.pid",
- path_mysock => "$opt_tmpdir/slave.sock",
+ path_mysock => "$sockdir/slave.sock",
path_myport => $opt_slave_myport,
start_timeout => 400,
};
@@ -847,7 +853,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/slave1.err",
path_mylog => "$opt_vardir/log/slave1.log",
path_mypid => "$opt_vardir/run/slave1.pid",
- path_mysock => "$opt_tmpdir/slave1.sock",
+ path_mysock => "$sockdir/slave1.sock",
path_myport => $opt_slave_myport + 1,
start_timeout => 300,
};
@@ -858,7 +864,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/slave2.err",
path_mylog => "$opt_vardir/log/slave2.log",
path_mypid => "$opt_vardir/run/slave2.pid",
- path_mysock => "$opt_tmpdir/slave2.sock",
+ path_mysock => "$sockdir/slave2.sock",
path_myport => $opt_slave_myport + 2,
start_timeout => 300,
};
@@ -868,7 +874,7 @@ sub command_line_setup () {
path_err => "$opt_vardir/log/im.err",
path_log => "$opt_vardir/log/im.log",
path_pid => "$opt_vardir/run/im.pid",
- path_sock => "$opt_tmpdir/im.sock",
+ path_sock => "$sockdir/im.sock",
port => $im_port,
start_timeout => $master->[0]->{'start_timeout'},
admin_login => 'im_admin',
@@ -883,7 +889,7 @@ sub command_line_setup () {
server_id => 1,
port => $im_mysqld1_port,
path_datadir => "$opt_vardir/im_mysqld_1.data",
- path_sock => "$opt_tmpdir/mysqld_1.sock",
+ path_sock => "$sockdir/mysqld_1.sock",
path_pid => "$opt_vardir/run/mysqld_1.pid",
};
@@ -892,7 +898,7 @@ sub command_line_setup () {
server_id => 2,
port => $im_mysqld2_port,
path_datadir => "$opt_vardir/im_mysqld_2.data",
- path_sock => "$opt_tmpdir/mysqld_2.sock",
+ path_sock => "$sockdir/mysqld_2.sock",
path_pid => "$opt_vardir/run/mysqld_2.pid",
nonguarded => 1,
};
@@ -964,7 +970,7 @@ sub executable_setup () {
$exe_mysql_fix_system_tables=
mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables");
$exe_my_print_defaults=
- mtr_script_exists("$glob_basedir/extra/my_print_defaults");
+ mtr_exe_exists("$glob_basedir/extra/my_print_defaults");
$path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools");
$exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm";
}
@@ -982,7 +988,7 @@ sub executable_setup () {
mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables",
"$glob_basedir/scripts/mysql_fix_privilege_tables");
$exe_my_print_defaults=
- mtr_script_exists("$path_client_bindir/my_print_defaults");
+ mtr_exe_exists("$path_client_bindir/my_print_defaults");
$path_language= mtr_path_exists("$glob_basedir/share/mysql/english/",
"$glob_basedir/share/english/");
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index c84763713e1..982aed9c633 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -279,7 +279,7 @@ DO_STRESS=""
STRESS_SUITE="main"
STRESS_MODE="random"
STRESS_THREADS=5
-STRESS_TEST_COUNT=20
+STRESS_TEST_COUNT=""
STRESS_LOOP_COUNT=""
STRESS_TEST_DURATION=""
STRESS_INIT_FILE=""
@@ -1261,6 +1261,7 @@ start_master()
--server-id=$id \
--basedir=$MY_BASEDIR \
--port=$this_master_myport \
+ --port-open-timeout=380 \
--local-infile \
--exit-info=256 \
--core \
@@ -1285,6 +1286,7 @@ start_master()
--server-id=$id --rpl-recovery-rank=1 \
--basedir=$MY_BASEDIR --init-rpl-role=master \
--port=$this_master_myport \
+ --port-open-timeout=380 \
--local-infile \
--datadir=$MASTER_MYDDIR$1 \
--pid-file=$MASTER_MYPID$1 \
@@ -1417,6 +1419,7 @@ start_slave()
--datadir=$slave_datadir \
--pid-file=$slave_pid \
--port=$slave_port \
+ --port-open-timeout=380 \
--socket=$slave_sock \
--character-sets-dir=$CHARSETSDIR \
--default-character-set=$CHARACTER_SET \
@@ -1906,7 +1909,7 @@ run_stress_test()
--stress-basedir=$STRESS_BASEDIR \
--server-logs-dir=$STRESS_BASEDIR \
--stress-mode=$STRESS_MODE \
- --mysqltest=$BASEDIR/client/mysqltest \
+ --mysqltest=$CLIENT_BINDIR/mysqltest \
--threads=$STRESS_THREADS \
--verbose \
--cleanup \
@@ -1917,6 +1920,14 @@ run_stress_test()
STRESS_TEST_ARGS="$STRESS_TEST_ARGS --stress-init-file=$STRESS_INIT_FILE"
fi
+ if [ -z "$STRESS_LOOP_COUNT" -a -z "$STRESS_TEST_COUNT" -a
+ -z "$STRESS_TEST_DURATION" ] ; then
+
+ #Limit stress testing with 20 loops in case when any limit parameter
+ #was specified
+ STRESS_TEST_COUNT=20
+ fi
+
if [ -n "$STRESS_LOOP_COUNT" ] ; then
STRESS_TEST_ARGS="$STRESS_TEST_ARGS --loop-count=$STRESS_LOOP_COUNT"
fi
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 9b60a187d0b..f224a10c9bd 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -556,3 +556,9 @@ ERROR 3D000: No database selected
alter table test.t1 rename test.t1;
use test;
drop table t1;
+create table t1 (mycol int(10) not null);
+alter table t1 alter column mycol set default 0;
+desc t1;
+Field Type Null Key Default Extra
+mycol int(10) NO 0
+drop table t1;
diff --git a/mysql-test/r/analyze.result b/mysql-test/r/analyze.result
index 796b382f5d6..17686d597a4 100644
--- a/mysql-test/r/analyze.result
+++ b/mysql-test/r/analyze.result
@@ -30,6 +30,15 @@ check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
+create table t1 (a mediumtext, fulltext key key1(a)) charset utf8 collate utf8_general_ci engine myisam;
+insert into t1 values ('hello');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Table is already up to date
+drop table t1;
CREATE TABLE t1 (a int);
prepare stmt1 from "SELECT * FROM t1 PROCEDURE ANALYSE()";
execute stmt1;
diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result
index 5cdf9612300..a564fd1045c 100644
--- a/mysql-test/r/bdb.result
+++ b/mysql-test/r/bdb.result
@@ -1289,6 +1289,25 @@ SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd");
id
4
DROP TABLE t1;
+create table t1 (a int, key(a)) engine=bdb;
+create table t2 (b int, key(b)) engine=bdb;
+insert into t1 values (1),(1),(2),(3),(4);
+insert into t2 values (1),(5),(6),(7);
+delete from t1 where (a in (select b from t2));
+select count(*) from t1;
+count(*)
+3
+insert into t1 set a=(select b from t2);
+ERROR 21000: Subquery returns more than 1 row
+select count(*) from t1;
+count(*)
+3
+update t1 set a = a + 1 where (a in (select b from t2));
+select count(*) from t1;
+count(*)
+3
+drop table t1, t2;
+End of 4.1 tests
create temporary table t1 (a int, primary key(a)) engine=bdb;
select * from t1;
a
@@ -1891,3 +1910,17 @@ t1 CREATE TABLE `t1` (
) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
drop table t1;
set storage_engine=MyISAM;
+create table t1 (a varchar(255) character set utf8,
+b varchar(255) character set utf8,
+c varchar(255) character set utf8,
+d varchar(255) character set utf8,
+key (a,b,c,d)) engine=bdb;
+drop table t1;
+create table t1 (a varchar(255) character set utf8,
+b varchar(255) character set utf8,
+c varchar(255) character set utf8,
+d varchar(255) character set utf8,
+e varchar(255) character set utf8,
+key (a,b,c,d,e)) engine=bdb;
+ERROR 42000: Specified key was too long; max key length is 3072 bytes
+End of 5.0 tests
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 199fdd1eb5d..bbd4a60c5b1 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -259,21 +259,6 @@ select * from t1;
0 1 2
0 0 1
drop table t1;
-create table t1 select 1,2,3;
-create table if not exists t1 select 1,2;
-Warnings:
-Note 1050 Table 't1' already exists
-create table if not exists t1 select 1,2,3,4;
-ERROR 21S01: Column count doesn't match value count at row 1
-create table if not exists t1 select 1;
-Warnings:
-Note 1050 Table 't1' already exists
-select * from t1;
-1 2 3
-1 2 3
-0 1 2
-0 0 1
-drop table t1;
create table t1 (a int not null, b int, primary key (a));
insert into t1 values (1,1);
create table if not exists t1 select 2;
@@ -756,3 +741,22 @@ t2 CREATE TABLE `t2` (
`a2` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1, t2;
+create table t1 (i int) engine=myisam max_rows=100000000000;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=4294967295
+alter table t1 max_rows=100;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=100
+alter table t1 max_rows=100000000000;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=4294967295
+drop table t1;
diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result
index da0007fdfbe..1b92da2a7a3 100644
--- a/mysql-test/r/ctype_recoding.result
+++ b/mysql-test/r/ctype_recoding.result
@@ -181,11 +181,18 @@ select * from t1 where a=_koi8r'×ÁÓÑ';
a
×ÁÓÑ
select * from t1 where a=concat(_koi8r'×ÁÓÑ');
-ERROR HY000: Illegal mix of collations (cp1251_general_ci,IMPLICIT) and (koi8r_general_ci,COERCIBLE) for operation '='
+a
+×ÁÓÑ
select * from t1 where a=_latin1'×ÁÓÑ';
ERROR HY000: Illegal mix of collations (cp1251_general_ci,IMPLICIT) and (latin1_swedish_ci,COERCIBLE) for operation '='
drop table t1;
set names latin1;
+create table t1 (a char(10) character set utf8 collate utf8_bin);
+insert into t1 values (' xxx');
+select * from t1 where a=lpad('xxx',10,' ');
+a
+ xxx
+drop table t1;
set names koi8r;
create table t1 (c1 char(10) character set cp1251);
insert into t1 values ('ß');
diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result
index 4b245c69d2a..3e286c77c00 100644
--- a/mysql-test/r/ctype_uca.result
+++ b/mysql-test/r/ctype_uca.result
@@ -2015,6 +2015,112 @@ Z,z,Ź,ź,Ż,ż,Ž,ž
Ç
Ç‚
ǃ
+select group_concat(c1 order by c1) from t1 group by c1 collate utf8_hungarian_ci;
+group_concat(c1 order by c1)
+÷
+×
+A,a,À,Ã,Â,Ã,Ä,Ã…,à,á,â,ã,ä,Ã¥,Ä€,Ä,Ä‚,ă,Ä„,Ä…,Ç,ÇŽ,Çž,ÇŸ,Ç ,Ç¡,Ǻ,Ç»
+AA,Aa,aA,aa
+Æ,æ,Ǣ,ǣ,Ǽ,ǽ
+B,b
+Æ€
+Ƃ,ƃ
+C,c,Ç,ç,Ć,ć,Ĉ,ĉ,ÄŠ,Ä‹,ÄŒ,Ä
+CH,Ch,cH,ch
+Ƈ,ƈ
+D,d,ÄŽ,Ä
+DZ,Dz,dZ,dz,DŽ,Dž,dž,DZ,Dz,dz
+Ä,Ä‘
+Ɖ
+ÆŠ
+Ƌ,ƌ
+Ã,ð
+E,e,È,É,Ê,Ë,è,é,ê,ë,Ē,ē,Ĕ,ĕ,Ė,ė,Ę,ę,Ě,ě
+ÆŽ,Ç
+F,f
+Æ‘,Æ’
+G,g,Äœ,Ä,Äž,ÄŸ,Ä ,Ä¡,Ä¢,Ä£,Ǧ,ǧ,Ç´,ǵ
+Ǥ,ǥ
+Æ“
+Æ”
+Æ¢,Æ£
+H,h,Ĥ,ĥ
+ƕ,Ƕ
+Ħ,ħ
+I,i,ÃŒ,Ã,ÃŽ,Ã,ì,í,î,ï,Ĩ,Ä©,Ī,Ä«,Ĭ,Ä­,Ä®,į,Ä°,Ç,Ç
+IJ,Ij,iJ,ij,IJ,ij
+ı
+Æ—
+Æ–
+J,j,Ĵ,ĵ,ǰ
+K,k,Ķ,ķ,Ǩ,ǩ
+Ƙ,ƙ
+L,l,Ĺ,ĺ,Ļ,ļ,Ľ,ľ
+Ä¿,Å€
+LJ,Lj,lJ,lj,LJ,Lj,lj
+LL,Ll,lL,ll
+Å,Å‚
+Æš
+Æ›
+M,m
+N,n,Ñ,ñ,Ń,ń,Ņ,ņ,Ň,ň,Ǹ,ǹ
+NJ,Nj,nJ,nj,NJ,Nj,nj
+Æž
+ÅŠ,Å‹
+O,o,Ã’,Ó,Ô,Õ,ò,ó,ô,õ,ÅŒ,Å,ÅŽ,Å,Æ ,Æ¡,Ç‘,Ç’,Ǫ,Ç«,Ǭ,Ç­
+OE,Oe,oE,oe,Å’,Å“
+Ö,ö,Å,Å‘
+Ø,ø,Ǿ,ǿ
+Ɔ
+ÆŸ
+P,p
+Ƥ,ƥ
+Q,q
+ĸ
+R,r,Ŕ,ŕ,Ŗ,ŗ,Ř,ř
+RR,Rr,rR,rr
+Ʀ
+S,s,Åš,Å›,Åœ,Å,Åž,ÅŸ,Å ,Å¡,Å¿
+SS,Ss,sS,ss,ß
+Æ©
+ƪ
+T,t,Ţ,ţ,Ť,ť
+ƾ
+Ŧ,ŧ
+Æ«
+Ƭ,ƭ
+Æ®
+U,u,Ù,Ú,Û,ù,ú,û,Ũ,ũ,Ū,ū,Ŭ,ŭ,Ů,ů,Ų,ų,Ư,ư,Ǔ,ǔ,Ǖ,ǖ,Ǘ,ǘ,Ǚ,ǚ,Ǜ,ǜ
+Ü,ü,Ű,ű
+Ɯ
+Ʊ
+V,v
+Ʋ
+W,w,Ŵ,ŵ
+X,x
+Y,y,Ã,ý,ÿ,Ŷ,Å·,Ÿ
+Ƴ,ƴ
+Z,z,Ź,ź,Ż,ż,Ž,ž
+Ƶ,ƶ
+Ʒ,Ǯ,ǯ
+Ƹ,ƹ
+ƺ
+Þ,þ
+Æ¿,Ç·
+Æ»
+Ƨ,ƨ
+Ƽ,ƽ
+Æ„,Æ…
+ʼn
+Ç€
+Ç‚
+ǃ
drop table t1;
SET NAMES utf8;
CREATE TABLE t1 (c varchar(255) NOT NULL COLLATE utf8_general_ci, INDEX (c));
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 65b5a1cbba8..d11d25f9b35 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -685,6 +685,13 @@ hex(a)
005B
803D
drop table t1;
+create table t1(f1 varchar(5) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL) engine=InnoDB;
+insert into t1 values('a');
+create index t1f1 on t1(f1);
+select f1 from t1 where f1 like 'a%';
+f1
+a
+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;
diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result
index 15de93440fc..2e14fe34430 100644
--- a/mysql-test/r/ctype_ujis.result
+++ b/mysql-test/r/ctype_ujis.result
@@ -2317,7 +2317,7 @@ CREATE TABLE t2(c2 char(2)) default charset = ujis;
INSERT INTO t1 VALUES(_ujis 0xA4A2);
CREATE PROCEDURE sp1()
BEGIN
-DECLARE a CHAR(1);
+DECLARE a CHAR(2) CHARSET ujis;
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
OPEN cur1;
FETCH cur1 INTO a;
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 874983daff2..c57b06f4895 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -1095,6 +1095,11 @@ char(0xff,0x8f using utf8)
ÿ
Warnings:
Warning 1300 Invalid utf8 character string: 'FF8F'
+select convert(char(0xff,0x8f) using utf8);
+convert(char(0xff,0x8f) using utf8)
+ÿ
+Warnings:
+Warning 1300 Invalid utf8 character string: 'FF8F'
set sql_mode=traditional;
select char(0xff,0x8f using utf8);
char(0xff,0x8f using utf8)
@@ -1116,6 +1121,11 @@ char(2557 using utf8)
NULL
Warnings:
Error 1300 Invalid utf8 character string: 'FD'
+select convert(char(0xff,0x8f) using utf8);
+convert(char(0xff,0x8f) using utf8)
+NULL
+Warnings:
+Error 1300 Invalid utf8 character string: 'FF8F'
select hex(convert(char(2557 using latin1) using utf8));
hex(convert(char(2557 using latin1) using utf8))
09C3BD
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index f0d323670e0..7e2e0a56212 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -433,4 +433,7 @@ INSERT INTO t1 VALUES('testword\'\'');
SELECT a FROM t1 WHERE MATCH a AGAINST('testword' IN BOOLEAN MODE);
a
testword''
+SELECT a FROM t1 WHERE MATCH a AGAINST('testword\'\'' IN BOOLEAN MODE);
+a
+testword''
DROP TABLE t1;
diff --git a/mysql-test/r/fulltext2.result b/mysql-test/r/fulltext2.result
index 0b1d8eb9a15..72c6b2d22ed 100644
--- a/mysql-test/r/fulltext2.result
+++ b/mysql-test/r/fulltext2.result
@@ -215,3 +215,24 @@ select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
262
drop table t1;
+set names utf8;
+create table t1(a text,fulltext(a)) collate=utf8_swedish_ci;
+insert into t1 values('test test '),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test');
+delete from t1 limit 1;
+drop table t1;
+set names latin1;
diff --git a/mysql-test/r/func_equal.result b/mysql-test/r/func_equal.result
index fe5e5b1b371..4750af6e8d8 100644
--- a/mysql-test/r/func_equal.result
+++ b/mysql-test/r/func_equal.result
@@ -33,3 +33,12 @@ id value
select * from t1 where id <=> value or value<=>id;
id value
drop table t1,t2;
+create table t1 (a bigint unsigned);
+insert into t1 values (4828532208463511553);
+select * from t1 where a = '4828532208463511553';
+a
+4828532208463511553
+select * from t1 where a in ('4828532208463511553');
+a
+4828532208463511553
+drop table t1;
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result
index 7987ceca712..2a36e6fe17b 100644
--- a/mysql-test/r/func_gconcat.result
+++ b/mysql-test/r/func_gconcat.result
@@ -163,7 +163,7 @@ show warnings;
Level Code Message
Warning 1260 1 line(s) were cut by GROUP_CONCAT()
set group_concat_max_len = 1024;
-select group_concat(sum(a)) from t1 group by grp;
+select group_concat(sum(c)) from t1 group by grp;
ERROR HY000: Invalid use of group function
select grp,group_concat(c order by 2) from t1 group by grp;
ERROR 42S22: Unknown column '2' in 'order clause'
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index a9f90e24556..448847bc919 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -594,3 +594,24 @@ flush privileges;
set @user123="non-existent";
select * from mysql.db where user=@user123;
Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv
+set names koi8r;
+create database ÂÄ;
+grant select on ÂÄ.* to root@localhost;
+select hex(Db) from mysql.db where Db='ÂÄ';
+hex(Db)
+D0B1D0B4
+show grants for root@localhost;
+Grants for root@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
+GRANT SELECT ON `ÂÄ`.* TO 'root'@'localhost'
+flush privileges;
+show grants for root@localhost;
+Grants for root@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
+GRANT SELECT ON `ÂÄ`.* TO 'root'@'localhost'
+drop database ÂÄ;
+revoke all privileges on ÂÄ.* from root@localhost;
+show grants for root@localhost;
+Grants for root@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
+set names latin1;
diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result
index 9c744396403..246aaa3a93e 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -107,6 +107,17 @@ delete from mysql.columns_priv where user like 'mysqltest\_%';
flush privileges;
drop database mysqltest;
use test;
+create user mysqltest_1@host1;
+create user mysqltest_2@host2;
+create user mysqltest_3@host3;
+create user mysqltest_4@host4;
+create user mysqltest_5@host5;
+create user mysqltest_6@host6;
+create user mysqltest_7@host7;
+flush privileges;
+drop user mysqltest_3@host3;
+drop user mysqltest_1@host1, mysqltest_2@host2, mysqltest_4@host4,
+mysqltest_5@host5, mysqltest_6@host6, mysqltest_7@host7;
set sql_mode='maxdb';
drop table if exists t1, t2;
create table t1(c1 int);
diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result
index 038d0c75f74..91579a7ea42 100644
--- a/mysql-test/r/group_min_max.result
+++ b/mysql-test/r/group_min_max.result
@@ -2002,3 +2002,44 @@ a count(a)
1 1
NULL 1
drop table t1;
+create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb;
+insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d");
+alter table t1 drop primary key, add primary key (f2, f1);
+explain select distinct f1 a, f1 b from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 5 NULL 4 Using index; Using temporary
+explain select distinct f1, f2 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL PRIMARY 5 NULL 3 Using index for group-by; Using temporary
+drop table t1;
+create table t1 (c1 int not null,c2 int not null, primary key(c1,c2));
+insert into t1 (c1,c2) values
+(10,1),(10,2),(10,3),(20,4),(20,5),(20,6),(30,7),(30,8),(30,9);
+select distinct c1, c2 from t1 order by c2;
+c1 c2
+10 1
+10 2
+10 3
+20 4
+20 5
+20 6
+30 7
+30 8
+30 9
+select c1,min(c2) as c2 from t1 group by c1 order by c2;
+c1 c2
+10 1
+20 4
+30 7
+select c1,c2 from t1 group by c1,c2 order by c2;
+c1 c2
+10 1
+10 2
+10 3
+20 4
+20 5
+20 6
+30 7
+30 8
+30 9
+drop table t1;
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 079a1af1184..05f2118a8c7 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -1048,3 +1048,45 @@ blob 65535 65535
text 65535 65535
text 65535 32767
drop table t1;
+create table t1 (f1 int(11));
+create view v1 as select * from t1;
+drop table t1;
+select table_type from information_schema.tables
+where table_name="v1";
+table_type
+VIEW
+drop view v1;
+create temporary table t1(f1 int, index(f1));
+show columns from t1;
+Field Type Null Key Default Extra
+f1 int(11) YES MUL NULL
+describe t1;
+Field Type Null Key Default Extra
+f1 int(11) YES MUL NULL
+show indexes from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 f1 1 f1 A NULL NULL NULL YES BTREE
+drop table t1;
+create table t1(f1 binary(32), f2 varbinary(64));
+select character_maximum_length, character_octet_length
+from information_schema.columns where table_name='t1';
+character_maximum_length character_octet_length
+32 32
+64 64
+drop table t1;
+CREATE TABLE t1 (f1 BIGINT, f2 VARCHAR(20), f3 BIGINT);
+INSERT INTO t1 SET f1 = 1, f2 = 'Schoenenbourg', f3 = 1;
+CREATE FUNCTION func2() RETURNS BIGINT RETURN 1;
+CREATE FUNCTION func1() RETURNS BIGINT
+BEGIN
+RETURN ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.VIEWS);
+END//
+CREATE VIEW v1 AS SELECT 1 FROM t1
+WHERE f3 = (SELECT func2 ());
+SELECT func1();
+func1()
+1
+DROP TABLE t1;
+DROP VIEW v1;
+DROP FUNCTION func1;
+DROP FUNCTION func2;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index dc4893c3bfa..dcff72ba7c0 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -2437,7 +2437,9 @@ a b
20 NULL
drop table t1;
create table t1 (v varchar(65530), key(v));
-ERROR HY000: Can't create table './test/t1' (errno: 139)
+Warnings:
+Warning 1071 Specified key was too long; max key length is 767 bytes
+drop table t1;
create table t1 (v varchar(65536));
Warnings:
Note 1246 Converting column 'v' from VARCHAR to TEXT
@@ -2577,22 +2579,49 @@ create table t8 (col1 blob, index(col1(767)))
character set = latin1 engine = innodb;
create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2))
character set = latin1 engine = innodb;
+show create table t9;
+Table Create Table
+t9 CREATE TABLE `t9` (
+ `col1` varchar(512) default NULL,
+ `col2` varchar(512) default NULL,
+ KEY `col1` (`col1`,`col2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1, t2, t3, t4, t5, t6, t7, t8, t9;
-create table t1 (col1 varchar(768), index (col1))
+create table t1 (col1 varchar(768), index(col1))
character set = latin1 engine = innodb;
-ERROR HY000: Can't create table './test/t1.frm' (errno: 139)
-create table t2 (col1 varchar(768) primary key)
+Warnings:
+Warning 1071 Specified key was too long; max key length is 767 bytes
+create table t2 (col1 varbinary(768), index(col1))
character set = latin1 engine = innodb;
-ERROR HY000: Can't create table './test/t2.frm' (errno: 139)
-create table t3 (col1 varbinary(768) primary key)
+Warnings:
+Warning 1071 Specified key was too long; max key length is 767 bytes
+create table t3 (col1 text, index(col1(768)))
character set = latin1 engine = innodb;
-ERROR HY000: Can't create table './test/t3.frm' (errno: 139)
-create table t4 (col1 text, index(col1(768)))
+Warnings:
+Warning 1071 Specified key was too long; max key length is 767 bytes
+create table t4 (col1 blob, index(col1(768)))
character set = latin1 engine = innodb;
-ERROR HY000: Can't create table './test/t4.frm' (errno: 139)
-create table t5 (col1 blob, index(col1(768)))
+Warnings:
+Warning 1071 Specified key was too long; max key length is 767 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `col1` varchar(768) default NULL,
+ KEY `col1` (`col1`(767))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1, t2, t3, t4;
+create table t1 (col1 varchar(768) primary key)
+character set = latin1 engine = innodb;
+ERROR 42000: Specified key was too long; max key length is 767 bytes
+create table t2 (col1 varbinary(768) primary key)
+character set = latin1 engine = innodb;
+ERROR 42000: Specified key was too long; max key length is 767 bytes
+create table t3 (col1 text, primary key(col1(768)))
character set = latin1 engine = innodb;
-ERROR HY000: Can't create table './test/t5.frm' (errno: 139)
+ERROR 42000: Specified key was too long; max key length is 767 bytes
+create table t4 (col1 blob, primary key(col1(768)))
+character set = latin1 engine = innodb;
+ERROR 42000: Specified key was too long; max key length is 767 bytes
CREATE TABLE t1
(
id INT PRIMARY KEY
@@ -2772,3 +2801,78 @@ insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
drop table t1;
drop table t2;
commit;
+set foreign_key_checks=0;
+create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb;
+create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
+ERROR HY000: Can't create table './test/t1.frm' (errno: 150)
+set foreign_key_checks=1;
+drop table t2;
+set foreign_key_checks=0;
+create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1;
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8;
+ERROR HY000: Can't create table './test/t2.frm' (errno: 150)
+set foreign_key_checks=1;
+drop table t1;
+set foreign_key_checks=0;
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb;
+create table t1(a varchar(10) primary key) engine = innodb;
+alter table t1 modify column a int;
+Got one of the listed errors
+set foreign_key_checks=1;
+drop table t2,t1;
+set foreign_key_checks=0;
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1;
+create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1;
+alter table t1 convert to character set utf8;
+set foreign_key_checks=1;
+drop table t2,t1;
+set foreign_key_checks=0;
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1;
+create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8;
+rename table t3 to t1;
+ERROR HY000: Error on rename of './test/t3' to './test/t1' (errno: 150)
+set foreign_key_checks=1;
+drop table t2,t3;
+create table t1 (a varchar(255) character set utf8,
+b varchar(255) character set utf8,
+c varchar(255) character set utf8,
+d varchar(255) character set utf8,
+key (a,b,c,d)) engine=innodb;
+drop table t1;
+create table t1 (a varchar(255) character set utf8,
+b varchar(255) character set utf8,
+c varchar(255) character set utf8,
+d varchar(255) character set utf8,
+e varchar(255) character set utf8,
+key (a,b,c,d,e)) engine=innodb;
+ERROR 42000: Specified key was too long; max key length is 3072 bytes
+create table t1(a int primary key) row_format=redundant engine=innodb;
+create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb;
+create table t3(a int primary key) row_format=compact engine=innodb;
+create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb;
+insert into t1 values(1);
+insert into t3 values(1);
+insert into t2 values(2);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+insert into t4 values(2);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+insert into t2 values(1);
+insert into t4 values(1);
+update t1 set a=2;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+update t2 set a=2;
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+update t3 set a=2;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+update t4 set a=2;
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+truncate t1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+truncate t3;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+truncate t2;
+truncate t4;
+truncate t1;
+truncate t3;
+drop table t4,t3,t2,t1;
+End of 5.0 tests
diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result
index c887dc9d6a7..724d1b1e39f 100644
--- a/mysql-test/r/join.result
+++ b/mysql-test/r/join.result
@@ -391,3 +391,304 @@ i i i
2 NULL 4
2 2 2
drop table t1,t2,t3;
+create table t1 (c int, b int);
+create table t2 (a int, b int);
+create table t3 (b int, c int);
+create table t4 (y int, c int);
+create table t5 (y int, z int);
+create table t6 (a int, c int);
+insert into t1 values (10,1);
+insert into t1 values (3 ,1);
+insert into t1 values (3 ,2);
+insert into t2 values (2, 1);
+insert into t3 values (1, 3);
+insert into t3 values (1,10);
+insert into t4 values (11,3);
+insert into t4 values (2, 3);
+insert into t5 values (11,4);
+insert into t6 values (2, 3);
+create algorithm=merge view v1a as
+select * from t1 natural join t2;
+create algorithm=merge view v1b(a,b,c) as
+select * from t1 natural join t2;
+create algorithm=merge view v1c as
+select b as a, c as b, a as c from t1 natural join t2;
+create algorithm=merge view v1d(b, a, c) as
+select a as c, c as b, b as a from t1 natural join t2;
+create algorithm=merge view v2a as
+select t1.c, t1.b, t2.a from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c;
+create algorithm=merge view v2b as
+select t1.c as b, t1.b as a, t2.a as c
+from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c;
+create algorithm=merge view v3a as
+select * from t1 natural join t2 natural join t3;
+create algorithm=merge view v3b as
+select * from t1 natural join (t2 natural join t3);
+create algorithm=merge view v4 as
+select * from v2a natural join v3a;
+select * from (t1 natural join t2) natural join (t3 natural join t4);
+b c a y
+1 3 2 11
+1 3 2 2
+select * from (t1 natural join t2) natural left join (t3 natural join t4);
+b c a y
+1 10 2 NULL
+1 3 2 11
+1 3 2 2
+select * from (t3 natural join t4) natural right join (t1 natural join t2);
+b c a y
+1 10 2 NULL
+1 3 2 11
+1 3 2 2
+select * from (t1 natural left join t2) natural left join (t3 natural left join t4);
+b c a y
+1 10 2 NULL
+1 3 2 11
+1 3 2 2
+2 3 NULL NULL
+select * from (t4 natural right join t3) natural right join (t2 natural right join t1);
+b c a y
+1 10 2 NULL
+1 3 2 11
+1 3 2 2
+2 3 NULL NULL
+select * from t1 natural join t2 natural join t3 natural join t4;
+c b a y
+3 1 2 11
+3 1 2 2
+select * from ((t1 natural join t2) natural join t3) natural join t4;
+c b a y
+3 1 2 11
+3 1 2 2
+select * from t1 natural join (t2 natural join (t3 natural join t4));
+c b a y
+3 1 2 11
+3 1 2 2
+select * from t5 natural right join (t4 natural right join ((t2 natural right join t1) natural right join t3));
+y c b a z
+11 3 1 2 4
+2 3 1 2 NULL
+NULL 10 1 2 NULL
+select * from (t1 natural join t2), (t3 natural join t4);
+b c a c b y
+1 10 2 3 1 11
+1 10 2 3 1 2
+1 3 2 3 1 11
+1 3 2 3 1 2
+select * from (t1 join t2 using (b)) join (t3 join t4 using (c)) using (c);
+c b a b y
+3 1 2 1 11
+3 1 2 1 2
+select * from (t1 join t2 using (b)) natural join (t3 join t4 using (c));
+b c a y
+1 3 2 11
+1 3 2 2
+select a,b,c from (t1 natural join t2) natural join (t3 natural join t4)
+where b + 1 = y or b + 10 = y group by b,c,a having min(b) < max(y) order by a;
+a b c
+2 1 3
+select * from (t1 natural join t2) natural left join (t3 natural join t4)
+where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y;
+b c a y
+1 3 2 2
+1 3 2 11
+select * from (t3 natural join t4) natural right join (t1 natural join t2)
+where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y;
+b c a y
+1 3 2 2
+1 3 2 11
+select * from t1 natural join t2 where t1.c > t2.a;
+b c a
+1 10 2
+1 3 2
+select * from t1 natural join t2 where t1.b > t2.b;
+b c a
+select * from t1 natural left join (t4 natural join t5) where t5.z is not NULL;
+c b y z
+3 1 11 4
+3 2 11 4
+select * from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c;
+c b a b y c
+3 1 2 1 2 3
+3 2 2 1 2 3
+select * from (t2 join t4 on b + 1 = y) join t1 on t1.c = t4.c;
+a b y c c b
+2 1 2 3 3 1
+2 1 2 3 3 2
+select * from t1 natural join (t2 join t4 on b + 1 = y);
+c b a y
+3 1 2 2
+select * from (t1 cross join t2) join (t3 cross join t4) on (a < y and t2.b < t3.c);
+c b a b b c y c
+10 1 2 1 1 3 11 3
+10 1 2 1 1 10 11 3
+3 1 2 1 1 3 11 3
+3 1 2 1 1 10 11 3
+3 2 2 1 1 3 11 3
+3 2 2 1 1 10 11 3
+select * from (t1, t2) join (t3, t4) on (a < y and t2.b < t3.c);
+c b a b b c y c
+10 1 2 1 1 3 11 3
+10 1 2 1 1 10 11 3
+3 1 2 1 1 3 11 3
+3 1 2 1 1 10 11 3
+3 2 2 1 1 3 11 3
+3 2 2 1 1 10 11 3
+select * from (t1 natural join t2) join (t3 natural join t4) on a = y;
+b c a c b y
+1 10 2 3 1 2
+1 3 2 3 1 2
+select * from ((t3 join (t1 join t2 on c > a) on t3.b < t2.a) join t4 on y > t1.c) join t5 on z = t1.b + 3;
+b c c b a b y c y z
+1 3 10 1 2 1 11 3 11 4
+1 10 10 1 2 1 11 3 11 4
+1 3 3 1 2 1 11 3 11 4
+1 10 3 1 2 1 11 3 11 4
+select * from t1 natural join t2 where t1.b > 0;
+b c a
+1 10 2
+1 3 2
+select * from t1 natural join (t4 natural join t5) where t4.y > 7;
+c b y z
+3 1 11 4
+3 2 11 4
+select * from (t4 natural join t5) natural join t1 where t4.y > 7;
+c y z b
+3 11 4 1
+3 11 4 2
+select * from t1 natural left join (t4 natural join t5) where t4.y > 7;
+c b y z
+3 1 11 4
+3 2 11 4
+select * from (t4 natural join t5) natural right join t1 where t4.y > 7;
+c b y z
+3 1 11 4
+3 2 11 4
+select * from (t1 natural join t2) join (t3 natural join t4) on t1.b = t3.b;
+b c a c b y
+1 10 2 3 1 11
+1 10 2 3 1 2
+1 3 2 3 1 11
+1 3 2 3 1 2
+select t1.*, t2.* from t1 natural join t2;
+c b a b
+10 1 2 1
+3 1 2 1
+select t1.*, t2.*, t3.*, t4.* from (t1 natural join t2) natural join (t3 natural join t4);
+c b a b b c y c
+3 1 2 1 1 3 11 3
+3 1 2 1 1 3 2 3
+select * from (select * from t1 natural join t2) as t12
+natural join
+(select * from t3 natural join t4) as t34;
+b c a y
+1 3 2 11
+1 3 2 2
+select * from (select * from t1 natural join t2) as t12
+natural left join
+(select * from t3 natural join t4) as t34;
+b c a y
+1 10 2 NULL
+1 3 2 11
+1 3 2 2
+select * from (select * from t3 natural join t4) as t34
+natural right join
+(select * from t1 natural join t2) as t12;
+b c a y
+1 10 2 NULL
+1 3 2 11
+1 3 2 2
+select * from v1a;
+b c a
+1 10 2
+1 3 2
+select * from v1b;
+a b c
+1 10 2
+1 3 2
+select * from v1c;
+a b c
+1 10 2
+1 3 2
+select * from v1d;
+b a c
+2 10 1
+2 3 1
+select * from v2a;
+c b a
+3 1 2
+3 2 2
+select * from v2b;
+b a c
+3 1 2
+3 2 2
+select * from v3a;
+b c a
+1 10 2
+1 3 2
+select * from v3b;
+c b a
+10 1 2
+3 1 2
+select * from v4;
+c b a
+3 1 2
+select * from v1a natural join v2a;
+b c a
+1 3 2
+select v2a.* from v1a natural join v2a;
+c b a
+3 1 2
+select * from v1b join v2a on v1b.b = v2a.c;
+a b c c b a
+1 3 2 3 1 2
+1 3 2 3 2 2
+select * from v1c join v2a on v1c.b = v2a.c;
+a b c c b a
+1 3 2 3 1 2
+1 3 2 3 2 2
+select * from v1d join v2a on v1d.a = v2a.c;
+b a c c b a
+2 3 1 3 1 2
+2 3 1 3 2 2
+select * from v1a join (t3 natural join t4) on a = y;
+b c a c b y
+1 10 2 3 1 2
+1 3 2 3 1 2
+select * from t1 natural join (t3 cross join t4);
+ERROR 23000: Column 'c' in from clause is ambiguous
+select * from (t3 cross join t4) natural join t1;
+ERROR 23000: Column 'c' in from clause is ambiguous
+select * from t1 join (t2, t3) using (b);
+ERROR 23000: Column 'b' in from clause is ambiguous
+select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6;
+ERROR 23000: Column 'c' in from clause is ambiguous
+select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6;
+ERROR 23000: Column 'c' in from clause is ambiguous
+select * from (t1 join t2 on t1.b=t2.b) natural join (t3 natural join t4);
+ERROR 23000: Column 'b' in from clause is ambiguous
+select * from (t3 natural join t4) natural join (t1 join t2 on t1.b=t2.b);
+ERROR 23000: Column 'b' in from clause is ambiguous
+select * from (t3 join (t4 natural join t5) on (b < z))
+natural join
+(t1 natural join t2);
+ERROR 23000: Column 'c' in from clause is ambiguous
+select t1.b from v1a;
+ERROR 42S22: Unknown column 't1.b' in 'field list'
+select * from v1a join v1b on t1.b = t2.b;
+ERROR 42S22: Unknown column 't1.b' in 'on clause'
+drop table t1;
+drop table t2;
+drop table t3;
+drop table t4;
+drop table t5;
+drop table t6;
+drop view v1a;
+drop view v1b;
+drop view v1c;
+drop view v1d;
+drop view v2a;
+drop view v2b;
+drop view v3a;
+drop view v3b;
+drop view v4;
diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result
index c4dd6cf9a86..6b7293d46bc 100644
--- a/mysql-test/r/join_nested.result
+++ b/mysql-test/r/join_nested.result
@@ -1466,4 +1466,4 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ref a a 5 test.t3.b X
1 SIMPLE t6 ref a a 5 test.t4.b X
1 SIMPLE t5 ref a a 5 test.t3.b X
-drop table t0, t1, t2, t4, t5, t6;
+drop table t0, t1, t2, t3, t4, t5, t6, t7;
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index e028e58acf5..7e3ccc83d73 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -719,3 +719,52 @@ SELECT b FROM t2;
b
3
DROP TABLE t1, t2;
+create table t1(a int);
+create table t2(a int);
+insert into t1 values (1);
+insert into t2 values (2);
+create table t3 (a int) engine=merge union=(t1, t2) insert_method=first;
+select * from t3;
+a
+1
+2
+insert t2 select * from t2;
+select * from t2;
+a
+2
+2
+insert t3 select * from t1;
+select * from t3;
+a
+1
+1
+2
+2
+insert t1 select * from t3;
+select * from t1;
+a
+1
+1
+1
+1
+2
+2
+select * from t2;
+a
+2
+2
+select * from t3;
+a
+1
+1
+1
+1
+2
+2
+2
+2
+check table t1, t2;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+test.t2 check status OK
+drop table t1, t2, t3;
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index bb89ff29b8a..62d2b46e617 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -2550,3 +2550,72 @@ DELIMITER ;
DROP TRIGGER tr1;
DROP TABLE t1;
+create table t1 (a binary(1), b blob);
+insert into t1 values ('','');
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+DROP TABLE IF EXISTS `t1`;
+CREATE TABLE `t1` (
+ `a` binary(1) default NULL,
+ `b` blob
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+
+/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
+LOCK TABLES `t1` WRITE;
+INSERT INTO `t1` VALUES (0x00,'');
+UNLOCK TABLES;
+/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+DROP TABLE IF EXISTS `t1`;
+CREATE TABLE `t1` (
+ `a` binary(1) default NULL,
+ `b` blob
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+
+/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
+LOCK TABLES `t1` WRITE;
+INSERT INTO `t1` VALUES (0x00,'');
+UNLOCK TABLES;
+/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+drop table t1;
diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result
index 54bdb1b45d8..5ff931dafb5 100644
--- a/mysql-test/r/mysqltest.result
+++ b/mysql-test/r/mysqltest.result
@@ -391,3 +391,25 @@ root@localhost
--------------------------------------------------------------------------------
this will be executed
this will be executed
+mysqltest: At line 3: query 'create table t1 (a int primary key);
+insert into t1 values (1);
+select 'select-me';
+insertz 'error query'' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz 'error query'' at line 1
+drop table t1;
+drop table t1;
+create table t1 (a int primary key);
+insert into t1 values (1);
+select 'select-me';
+insertz error query||||
+select-me
+select-me
+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 'insertz error query' at line 1
+drop table t1;
+create table t1 (a int primary key);
+insert into t1 values (1);
+select 'select-me';
+insertz error query||||
+select-me
+select-me
+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 'insertz error query' at line 1
+drop table t1;
diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result
index ae64a5f9d3f..acb67250c26 100644
--- a/mysql-test/r/ndb_alter_table.result
+++ b/mysql-test/r/ndb_alter_table.result
@@ -179,7 +179,7 @@ a b c
2 two two
alter table t1 drop index c;
select * from t1 where b = 'two';
-ERROR HY000: Table definition has changed, please retry transaction
+ERROR HY000: Can't lock file (errno: 241)
select * from t1 where b = 'two';
a b c
2 two two
diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result
index e288592c390..9dd75f1390c 100644
--- a/mysql-test/r/ndb_basic.result
+++ b/mysql-test/r/ndb_basic.result
@@ -667,13 +667,29 @@ counter datavalue
57 newval
58 newval
drop table t1;
+CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb;
+select * from t1;
+b
+drop table t1;
create table atablewithareallylongandirritatingname (a int);
insert into atablewithareallylongandirritatingname values (2);
select * from atablewithareallylongandirritatingname;
a
2
drop table atablewithareallylongandirritatingname;
-CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb;
-select * from t1;
-b
+create table t1 (f1 varchar(50), f2 text,f3 int, primary key(f1)) engine=NDB;
+insert into t1 (f1,f2,f3)VALUES("111111","aaaaaa",1);
+insert into t1 (f1,f2,f3)VALUES("222222","bbbbbb",2);
+select * from t1 order by f1;
+f1 f2 f3
+111111 aaaaaa 1
+222222 bbbbbb 2
+select * from t1 order by f2;
+f1 f2 f3
+111111 aaaaaa 1
+222222 bbbbbb 2
+select * from t1 order by f3;
+f1 f2 f3
+111111 aaaaaa 1
+222222 bbbbbb 2
drop table t1;
diff --git a/mysql-test/r/ndb_multi.result b/mysql-test/r/ndb_multi.result
index 2080be241e8..bd3af223a65 100644
--- a/mysql-test/r/ndb_multi.result
+++ b/mysql-test/r/ndb_multi.result
@@ -30,6 +30,7 @@ create table t1 (a int) engine=ndbcluster;
insert into t1 value (2);
select * from t1;
ERROR HY000: Got error 241 'Invalid schema object version' from ndbcluster
+flush table t1;
select * from t1;
a
2
diff --git a/mysql-test/r/ndb_read_multi_range.result b/mysql-test/r/ndb_read_multi_range.result
index f42ac394b6c..bb9398054ff 100644
--- a/mysql-test/r/ndb_read_multi_range.result
+++ b/mysql-test/r/ndb_read_multi_range.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1, r1;
+DROP TABLE IF EXISTS t1, t2, r1;
create table t1 (
a int primary key,
b int not null,
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index f1c3672083d..bc3d2a6108c 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -337,7 +337,7 @@ set @precision=10000000000;
select rand(),
cast(rand(10)*@precision as unsigned integer) from t1;
rand() cast(rand(10)*@precision as unsigned integer)
-- 6570515219
+- 6570515220
- 1282061302
- 6698761160
- 9647622201
@@ -348,23 +348,23 @@ prepare stmt from
set @var=1;
execute stmt using @var;
rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
-- 6570515219 -
+- 6570515220 -
- 1282061302 -
- 6698761160 -
- 9647622201 -
set @var=2;
execute stmt using @var;
rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
-- 6570515219 6555866465
-- 1282061302 1223466192
-- 6698761160 6449731873
+- 6570515220 6555866465
+- 1282061302 1223466193
+- 6698761160 6449731874
- 9647622201 8578261098
set @var=3;
execute stmt using @var;
rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer)
-- 6570515219 9057697559
+- 6570515220 9057697560
- 1282061302 3730790581
-- 6698761160 1480860534
+- 6698761160 1480860535
- 9647622201 6211931236
drop table t1;
deallocate prepare stmt;
@@ -806,3 +806,29 @@ execute stmt;
@@tx_isolation
REPEATABLE-READ
deallocate prepare stmt;
+prepare stmt from "create temporary table t1 (letter enum('','a','b','c')
+not null)";
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+set names latin1;
+prepare stmt from "create table t1 (a enum('test') default 'test')
+ character set utf8";
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+set names default;
+deallocate prepare stmt;
+create table t1 (id int);
+prepare ins_call from "insert into t1 (id) values (1)";
+execute ins_call;
+select row_count();
+row_count()
+1
+drop table t1;
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 97d14b2be3a..405669e95f8 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -1022,6 +1022,31 @@ Variable_name Value
Qcache_hits 1
drop table t1;
create table t1 (a int);
+flush status;
+(select a from t1) union (select a from t1);
+a
+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 a from t1) union (select a from t1);
+a
+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 1
+drop table t1;
+create table t1 (a int);
insert into t1 values (1),(2);
CREATE PROCEDURE `p1`()
begin
diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result
index 450e728090e..de9f6f16b2a 100644
--- a/mysql-test/r/rpl000001.result
+++ b/mysql-test/r/rpl000001.result
@@ -50,7 +50,7 @@ select (@id := id) - id from t2;
0
kill @id;
drop table t2;
-ERROR 08S01: Server shutdown in progress
+Got one of the listed errors
set global sql_slave_skip_counter=1;
start slave;
select count(*) from t1;
diff --git a/mysql-test/r/rpl_deadlock.result b/mysql-test/r/rpl_deadlock.result
index b112a51a145..c25cb1e6a53 100644
--- a/mysql-test/r/rpl_deadlock.result
+++ b/mysql-test/r/rpl_deadlock.result
@@ -83,5 +83,5 @@ a
22
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 18911 # # master-bin.000001 Yes Yes 0 0 18911 # None 0 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 18911 # # master-bin.000001 # Yes 0 0 18911 # None 0 No #
drop table t1,t2,t3,t4;
diff --git a/mysql-test/r/rpl_relayrotate.result b/mysql-test/r/rpl_relayrotate.result
index c79187e12d0..20f19973d83 100644
--- a/mysql-test/r/rpl_relayrotate.result
+++ b/mysql-test/r/rpl_relayrotate.result
@@ -10,13 +10,7 @@ reset slave;
start slave;
stop slave;
start slave;
-select master_pos_wait('master-bin.001',3000)>=0;
-master_pos_wait('master-bin.001',3000)>=0
-1
select max(a) from t1;
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 735186 # # master-bin.000001 Yes Yes 0 0 735186 # None 0 No #
drop table t1;
diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result
index 41bcfc7d72c..c9a9e162fa6 100644
--- a/mysql-test/r/rpl_sp.result
+++ b/mysql-test/r/rpl_sp.result
@@ -57,6 +57,9 @@ insert into t1 values (15);
grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1;
grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1;
grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1;
+SELECT 1;
+1
+1
create procedure foo4()
deterministic
begin
diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result
index 999af131b8b..7613f2547f0 100644
--- a/mysql-test/r/rpl_trigger.result
+++ b/mysql-test/r/rpl_trigger.result
@@ -122,3 +122,15 @@ a=b && a=c
1
drop function bug12480;
drop table t1;
+create table t1 (i int);
+create table t2 (i int);
+create trigger tr1 before insert on t1 for each row
+begin
+insert into t2 values (1);
+end|
+create database other;
+use other;
+insert into test.t1 values (1);
+use test;
+drop table t1,t2;
+drop database other;
diff --git a/mysql-test/r/rpl_until.result b/mysql-test/r/rpl_until.result
index 64efeab0145..b584e04ed57 100644
--- a/mysql-test/r/rpl_until.result
+++ b/mysql-test/r/rpl_until.result
@@ -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 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 319 # Master master-bin.000001 319 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-bin.000001 319 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 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 319 # Master master-no-such-bin.000001 291 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-no-such-bin.000001 291 No #
start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746;
select * from t2;
n
@@ -49,7 +49,7 @@ 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 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 608 # Relay slave-relay-bin.000004 746 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 608 # Relay slave-relay-bin.000004 746 No #
start slave;
stop slave;
start slave until master_log_file='master-bin.000001', master_log_pos=776;
diff --git a/mysql-test/r/schema.result b/mysql-test/r/schema.result
index 48e6ebcfad2..538abd8d039 100644
--- a/mysql-test/r/schema.result
+++ b/mysql-test/r/schema.result
@@ -1,3 +1,4 @@
+drop database if exists mysqltest1;
create schema foo;
show create schema foo;
Database Create Database
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index 8a126b7ddfb..e2c4609d902 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -2708,6 +2708,14 @@ select distinct count(f2) >0 from t1 left join t2 on f1=f3 group by f1;
count(f2) >0
1
drop table t1,t2;
+create table t1 (f1 int,f2 int);
+insert into t1 values(1,1);
+create table t2 (f3 int, f4 int, primary key(f3,f4));
+insert into t2 values(1,1);
+select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 from t2));
+f1 f2
+1 1
+drop table t1,t2;
CREATE TABLE t1 ( city char(30) );
INSERT INTO t1 VALUES ('London');
INSERT INTO t1 VALUES ('Paris');
@@ -3283,3 +3291,57 @@ f1 f2 x1
30 1 30
drop table t1;
drop view v1, v2, v3;
+CREATE TABLE t1(key_a int4 NOT NULL, optimus varchar(32), PRIMARY KEY(key_a));
+CREATE TABLE t2(key_a int4 NOT NULL, prime varchar(32), PRIMARY KEY(key_a));
+CREATE table t3(key_a int4 NOT NULL, key_b int4 NOT NULL, foo varchar(32),
+PRIMARY KEY(key_a,key_b));
+INSERT INTO t1 VALUES (0,'');
+INSERT INTO t1 VALUES (1,'i');
+INSERT INTO t1 VALUES (2,'j');
+INSERT INTO t1 VALUES (3,'k');
+INSERT INTO t2 VALUES (1,'r');
+INSERT INTO t2 VALUES (2,'s');
+INSERT INTO t2 VALUES (3,'t');
+INSERT INTO t3 VALUES (1,5,'x');
+INSERT INTO t3 VALUES (1,6,'y');
+INSERT INTO t3 VALUES (2,5,'xx');
+INSERT INTO t3 VALUES (2,6,'yy');
+INSERT INTO t3 VALUES (2,7,'zz');
+INSERT INTO t3 VALUES (3,5,'xxx');
+SELECT t2.key_a,foo
+FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a
+INNER JOIN t3 ON t1.key_a = t3.key_a
+WHERE t2.key_a=2 and key_b=5;
+key_a foo
+2 xx
+EXPLAIN SELECT t2.key_a,foo
+FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a
+INNER JOIN t3 ON t1.key_a = t3.key_a
+WHERE t2.key_a=2 and key_b=5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
+1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index
+1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1
+SELECT t2.key_a,foo
+FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a
+INNER JOIN t3 ON t1.key_a = t3.key_a
+WHERE t2.key_a=2 and key_b=5;
+key_a foo
+2 xx
+EXPLAIN SELECT t2.key_a,foo
+FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a
+INNER JOIN t3 ON t1.key_a = t3.key_a
+WHERE t2.key_a=2 and key_b=5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
+1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index
+1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1
+DROP TABLE t1,t2,t3;
+create table t1(f1 char, f2 char not null);
+insert into t1 values(null,'a');
+create table t2 (f2 char not null);
+insert into t2 values('b');
+select * from t1 left join t2 on f1=t2.f2 where t1.f2='a';
+f1 f2 f2
+NULL a NULL
+drop table t1,t2;
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index fdb0db602ff..61a820b4469 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -1,6 +1,7 @@
drop table if exists t1,t2;
drop table if exists t1aa,t2aa;
drop database if exists mysqltest;
+drop database if exists mysqltest1;
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
flush privileges;
diff --git a/mysql-test/r/skip_name_resolve.result b/mysql-test/r/skip_name_resolve.result
index a969c5c9ae0..8ef52e75238 100644
--- a/mysql-test/r/skip_name_resolve.result
+++ b/mysql-test/r/skip_name_resolve.result
@@ -10,5 +10,5 @@ user()
#
show processlist;
Id User Host db Command Time State Info
-# root # test Sleep # NULL
-# root # test Query # NULL show processlist
+<id> root <host> test <command> <time> <state> <info>
+<id> root <host> test <command> <time> <state> <info>
diff --git a/mysql-test/r/sp-big.result b/mysql-test/r/sp-big.result
index 1f0b6b34651..9765508859c 100644
--- a/mysql-test/r/sp-big.result
+++ b/mysql-test/r/sp-big.result
@@ -25,6 +25,7 @@ count(*)
select count(*) from t2;
count(*)
0
+drop procedure if exists p1;
create procedure p1()
begin
declare done integer default 0;
diff --git a/mysql-test/r/sp-destruct.result b/mysql-test/r/sp-destruct.result
new file mode 100644
index 00000000000..1b720be9403
--- /dev/null
+++ b/mysql-test/r/sp-destruct.result
@@ -0,0 +1,77 @@
+use test;
+drop procedure if exists bug14233;
+drop function if exists bug14233;
+drop table if exists t1;
+drop view if exists v1;
+create procedure bug14233()
+set @x = 42;
+create function bug14233_f() returns int
+return 42;
+create table t1 (id int);
+create trigger t1_ai after insert on t1 for each row call bug14233();
+alter table mysql.proc drop type;
+call bug14233();
+ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5)
+create view v1 as select bug14233_f();
+ERROR HY000: Failed to load routine test.bug14233_f. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5)
+insert into t1 values (0);
+ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5)
+flush table mysql.proc;
+call bug14233();
+ERROR HY000: Incorrect information in file: './mysql/proc.frm'
+create view v1 as select bug14233_f();
+ERROR HY000: Incorrect information in file: './mysql/proc.frm'
+insert into t1 values (0);
+ERROR HY000: Incorrect information in file: './mysql/proc.frm'
+flush table mysql.proc;
+call bug14233();
+ERROR 42S02: Table 'mysql.proc' doesn't exist
+create view v1 as select bug14233_f();
+ERROR 42S02: Table 'mysql.proc' doesn't exist
+insert into t1 values (0);
+ERROR 42S02: Table 'mysql.proc' doesn't exist
+flush table mysql.proc;
+flush privileges;
+delete from mysql.proc where name like 'bug14233%';
+insert into mysql.proc
+(
+db, name, type, specific_name, language, sql_data_access, is_deterministic,
+security_type, param_list, returns, body, definer, created, modified,
+sql_mode, comment
+)
+values
+(
+'test', 'bug14233_1', 'FUNCTION', 'bug14233_1', 'SQL', 'READS_SQL_DATA', 'NO',
+'DEFINER', '', 'int(10)',
+'select count(*) from mysql.user',
+'root@localhost', NOW() , '0000-00-00 00:00:00', '', ''
+),
+(
+'test', 'bug14233_2', 'FUNCTION', 'bug14233_2', 'SQL', 'READS_SQL_DATA', 'NO',
+'DEFINER', '', 'int(10)',
+'begin declare x int; select count(*) into x from mysql.user; end',
+'root@localhost', NOW() , '0000-00-00 00:00:00', '', ''
+),
+(
+'test', 'bug14233_3', 'PROCEDURE', 'bug14233_3', 'SQL', 'READS_SQL_DATA','NO',
+'DEFINER', '', '',
+'alksj wpsj sa ^#!@ ',
+'root@localhost', NOW() , '0000-00-00 00:00:00', '', ''
+);
+select bug14233_1();
+ERROR HY000: Failed to load routine test.bug14233_1. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6)
+create view v1 as select bug14233_1();
+ERROR HY000: Failed to load routine test.bug14233_1. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6)
+select bug14233_2();
+ERROR HY000: Failed to load routine test.bug14233_2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6)
+create view v1 as select bug14233_2();
+ERROR HY000: Failed to load routine test.bug14233_2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6)
+call bug14233_3();
+ERROR HY000: Failed to load routine test.bug14233_3. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6)
+drop trigger t1_ai;
+create trigger t1_ai after insert on t1 for each row call bug14233_3();
+insert into t1 values (0);
+ERROR HY000: Failed to load routine test.bug14233_3. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6)
+delete from mysql.proc where name like 'bug14233%';
+drop trigger t1_ai;
+drop table t1;
diff --git a/mysql-test/r/sp-dynamic.result b/mysql-test/r/sp-dynamic.result
index cf07f540608..c00b09f90e1 100644
--- a/mysql-test/r/sp-dynamic.result
+++ b/mysql-test/r/sp-dynamic.result
@@ -1,3 +1,5 @@
+drop procedure if exists p1|
+drop procedure if exists p2|
create procedure p1()
begin
prepare stmt from "select 1";
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 963f14820be..d7bed7e88a7 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -124,7 +124,7 @@ begin
declare x int;
set x = val+3;
end|
-ERROR 42000: No RETURN found in FUNCTION f
+ERROR 42000: No RETURN found in FUNCTION test.f
create function f(val int) returns int
begin
declare x int;
@@ -768,7 +768,7 @@ BEGIN
OPTIMIZE TABLE t1;
RETURN 1;
END|
-ERROR 0A000: OPTIMIZE TABLE is not allowed in stored procedures
+ERROR 0A000: Not allowed to return a result set from a function
DROP FUNCTION IF EXISTS bug12995|
CREATE FUNCTION bug12995() RETURNS INT
BEGIN
@@ -981,6 +981,8 @@ END |
drop table t1|
drop function bug_13627_f|
drop function if exists bug12329;
+Warnings:
+Note 1305 FUNCTION bug12329 does not exist
create table t1 as select 1 a;
create table t2 as select 1 a;
create function bug12329() returns int return (select a from t1);
@@ -1055,3 +1057,74 @@ Db Name Type Definer Modified Created Security_type Comment
mysqltest2 p1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
drop database mysqltest2;
use test;
+DROP FUNCTION IF EXISTS bug13012|
+CREATE FUNCTION bug13012() RETURNS INT
+BEGIN
+REPAIR TABLE t1;
+RETURN 1;
+END|
+ERROR 0A000: Not allowed to return a result set from a function
+CREATE FUNCTION bug13012() RETURNS INT
+BEGIN
+BACKUP TABLE t1 TO '/tmp';
+RETURN 1;
+END|
+ERROR 0A000: Not allowed to return a result set from a function
+CREATE FUNCTION bug13012() RETURNS INT
+BEGIN
+RESTORE TABLE t1 FROM '/tmp';
+RETURN 1;
+END|
+ERROR 0A000: Not allowed to return a result set from a function
+create table t1 (a int)|
+CREATE PROCEDURE bug13012_1() REPAIR TABLE t1|
+CREATE FUNCTION bug13012_2() RETURNS INT
+BEGIN
+CALL bug13012_1();
+RETURN 1;
+END|
+SELECT bug13012_2()|
+ERROR 0A000: Not allowed to return a result set from a function
+drop table t1|
+drop procedure bug13012_1|
+drop function bug13012_2|
+drop function if exists bug11555_1;
+drop function if exists bug11555_2;
+drop view if exists v1, v2, v3, v4;
+create function bug11555_1() returns int return (select max(i) from t1);
+create function bug11555_2() returns int return bug11555_1();
+create view v1 as select bug11555_1();
+ERROR 42S02: Table 'test.t1' doesn't exist
+create view v2 as select bug11555_2();
+ERROR 42S02: Table 'test.t1' doesn't exist
+create table t1 (i int);
+create view v1 as select bug11555_1();
+create view v2 as select bug11555_2();
+create view v3 as select * from v1;
+drop table t1;
+select * from v1;
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+select * from v2;
+ERROR HY000: View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+select * from v3;
+ERROR HY000: View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+create view v4 as select * from v1;
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+drop view v1, v2, v3;
+drop function bug11555_1;
+drop function bug11555_2;
+create table t1 (i int);
+create table t2 (i int);
+create trigger t1_ai after insert on t1 for each row insert into t2 values (new.i);
+create view v1 as select * from t1;
+drop table t2;
+insert into v1 values (1);
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+drop trigger t1_ai;
+create function bug11555_1() returns int return (select max(i) from t2);
+create trigger t1_ai after insert on t1 for each row set @a:=bug11555_1();
+insert into v1 values (2);
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+drop function bug11555_1;
+drop table t1;
+drop view v1;
diff --git a/mysql-test/r/sp-vars.result b/mysql-test/r/sp-vars.result
new file mode 100644
index 00000000000..6b4d7b1a6d3
--- /dev/null
+++ b/mysql-test/r/sp-vars.result
@@ -0,0 +1,1077 @@
+DROP PROCEDURE IF EXISTS sp_vars_check_dflt;
+DROP PROCEDURE IF EXISTS sp_vars_check_assignment;
+DROP FUNCTION IF EXISTS sp_vars_check_ret1;
+DROP FUNCTION IF EXISTS sp_vars_check_ret2;
+DROP FUNCTION IF EXISTS sp_vars_check_ret3;
+DROP FUNCTION IF EXISTS sp_vars_check_ret4;
+SET @@sql_mode = 'ansi';
+CREATE PROCEDURE sp_vars_check_dflt()
+BEGIN
+DECLARE v1 TINYINT DEFAULT 1e200;
+DECLARE v1u TINYINT UNSIGNED DEFAULT 1e200;
+DECLARE v2 TINYINT DEFAULT -1e200;
+DECLARE v2u TINYINT UNSIGNED DEFAULT -1e200;
+DECLARE v3 TINYINT DEFAULT 300;
+DECLARE v3u TINYINT UNSIGNED DEFAULT 300;
+DECLARE v4 TINYINT DEFAULT -300;
+DECLARE v4u TINYINT UNSIGNED DEFAULT -300;
+DECLARE v5 TINYINT DEFAULT 10 * 10 * 10;
+DECLARE v5u TINYINT UNSIGNED DEFAULT 10 * 10 * 10;
+DECLARE v6 TINYINT DEFAULT -10 * 10 * 10;
+DECLARE v6u TINYINT UNSIGNED DEFAULT -10 * 10 * 10;
+DECLARE v7 TINYINT DEFAULT '10';
+DECLARE v8 TINYINT DEFAULT '10 ';
+DECLARE v9 TINYINT DEFAULT ' 10 ';
+DECLARE v10 TINYINT DEFAULT 'String 10 ';
+DECLARE v11 TINYINT DEFAULT 'String10';
+DECLARE v12 TINYINT DEFAULT '10 String';
+DECLARE v13 TINYINT DEFAULT '10String';
+DECLARE v14 TINYINT DEFAULT concat('10', ' ');
+DECLARE v15 TINYINT DEFAULT concat(' ', '10');
+DECLARE v16 TINYINT DEFAULT concat('Hello, ', 'world');
+DECLARE v17 DECIMAL(64, 2) DEFAULT 12;
+DECLARE v18 DECIMAL(64, 2) DEFAULT 12.123;
+DECLARE v19 DECIMAL(64, 2) DEFAULT 11 + 1;
+DECLARE v20 DECIMAL(64, 2) DEFAULT 12 + 0.123;
+SELECT v1, v1u, v2, v2u, v3, v3u, v4, v4u;
+SELECT v5, v5u, v6, v6u;
+SELECT v7, v8, v9, v10, v11, v12, v13, v14, v15, v16;
+SELECT v17, v18, v19, v20;
+END|
+CREATE PROCEDURE sp_vars_check_assignment()
+BEGIN
+DECLARE i1, i2, i3, i4 TINYINT;
+DECLARE u1, u2, u3, u4 TINYINT UNSIGNED;
+DECLARE d1, d2, d3 DECIMAL(64, 2);
+SET i1 = 1e200;
+SET i2 = -1e200;
+SET i3 = 300;
+SET i4 = -300;
+SELECT i1, i2, i3, i4;
+SET i1 = 10 * 10 * 10;
+SET i2 = -10 * 10 * 10;
+SET i3 = sign(10 * 10) * 10 * 20;
+SET i4 = sign(-10 * 10) * -10 * 20;
+SELECT i1, i2, i3, i4;
+SET u1 = 1e200;
+SET u2 = -1e200;
+SET u3 = 300;
+SET u4 = -300;
+SELECT u1, u2, u3, u4;
+SET u1 = 10 * 10 * 10;
+SET u2 = -10 * 10 * 10;
+SET u3 = sign(10 * 10) * 10 * 20;
+SET u4 = sign(-10 * 10) * -10 * 20;
+SELECT u1, u2, u3, u4;
+SET d1 = 1234;
+SET d2 = 1234.12;
+SET d3 = 1234.1234;
+SELECT d1, d2, d3;
+SET d1 = 12 * 100 + 34;
+SET d2 = 12 * 100 + 34 + 0.12;
+SET d3 = 12 * 100 + 34 + 0.1234;
+SELECT d1, d2, d3;
+END|
+CREATE FUNCTION sp_vars_check_ret1() RETURNS TINYINT
+BEGIN
+RETURN 1e200;
+END|
+CREATE FUNCTION sp_vars_check_ret2() RETURNS TINYINT
+BEGIN
+RETURN 10 * 10 * 10;
+END|
+CREATE FUNCTION sp_vars_check_ret3() RETURNS TINYINT
+BEGIN
+RETURN 'Hello, world';
+END|
+CREATE FUNCTION sp_vars_check_ret4() RETURNS DECIMAL(64, 2)
+BEGIN
+RETURN 12 * 10 + 34 + 0.1234;
+END|
+
+---------------------------------------------------------------
+Calling the routines, created in ANSI mode.
+---------------------------------------------------------------
+
+CALL sp_vars_check_dflt();
+v1 v1u v2 v2u v3 v3u v4 v4u
+127 255 -128 0 127 255 -128 0
+v5 v5u v6 v6u
+127 255 -128 0
+v7 v8 v9 v10 v11 v12 v13 v14 v15 v16
+10 10 10 0 0 10 10 10 10 0
+v17 v18 v19 v20
+12.00 12.12 12.00 12.12
+Warnings:
+Warning 1264 Out of range value adjusted for column 'v1' at row 1
+Warning 1264 Out of range value adjusted for column 'v1u' at row 1
+Warning 1264 Out of range value adjusted for column 'v2' at row 1
+Warning 1264 Out of range value adjusted for column 'v2u' at row 1
+Warning 1264 Out of range value adjusted for column 'v3' at row 1
+Warning 1264 Out of range value adjusted for column 'v3u' at row 1
+Warning 1264 Out of range value adjusted for column 'v4' at row 1
+Warning 1264 Out of range value adjusted for column 'v4u' at row 1
+Warning 1264 Out of range value adjusted for column 'v5' at row 1
+Warning 1264 Out of range value adjusted for column 'v5u' at row 1
+Warning 1264 Out of range value adjusted for column 'v6' at row 1
+Warning 1264 Out of range value adjusted for column 'v6u' at row 1
+Warning 1366 Incorrect integer value: 'String 10 ' for column 'v10' at row 1
+Warning 1366 Incorrect integer value: 'String10' for column 'v11' at row 1
+Warning 1265 Data truncated for column 'v12' at row 1
+Warning 1265 Data truncated for column 'v13' at row 1
+Warning 1366 Incorrect integer value: 'Hello, world' for column 'v16' at row 1
+Note 1265 Data truncated for column 'v18' at row 1
+Note 1265 Data truncated for column 'v20' at row 1
+CALL sp_vars_check_assignment();
+i1 i2 i3 i4
+127 -128 127 -128
+i1 i2 i3 i4
+127 -128 127 127
+u1 u2 u3 u4
+255 0 255 0
+u1 u2 u3 u4
+255 0 200 200
+d1 d2 d3
+1234.00 1234.12 1234.12
+d1 d2 d3
+1234.00 1234.12 1234.12
+Warnings:
+Warning 1264 Out of range value adjusted for column 'i1' at row 1
+Warning 1264 Out of range value adjusted for column 'i2' at row 1
+Warning 1264 Out of range value adjusted for column 'i3' at row 1
+Warning 1264 Out of range value adjusted for column 'i4' at row 1
+Warning 1264 Out of range value adjusted for column 'i1' at row 1
+Warning 1264 Out of range value adjusted for column 'i2' at row 1
+Warning 1264 Out of range value adjusted for column 'i3' at row 1
+Warning 1264 Out of range value adjusted for column 'i4' at row 1
+Warning 1264 Out of range value adjusted for column 'u1' at row 1
+Warning 1264 Out of range value adjusted for column 'u2' at row 1
+Warning 1264 Out of range value adjusted for column 'u3' at row 1
+Warning 1264 Out of range value adjusted for column 'u4' at row 1
+Warning 1264 Out of range value adjusted for column 'u1' at row 1
+Warning 1264 Out of range value adjusted for column 'u2' at row 1
+Note 1265 Data truncated for column 'd3' at row 1
+Note 1265 Data truncated for column 'd3' at row 1
+SELECT sp_vars_check_ret1();
+sp_vars_check_ret1()
+127
+Warnings:
+Warning 1264 Out of range value adjusted for column 'sp_vars_check_ret1()' at row 1
+SELECT sp_vars_check_ret2();
+sp_vars_check_ret2()
+127
+Warnings:
+Warning 1264 Out of range value adjusted for column 'sp_vars_check_ret2()' at row 1
+SELECT sp_vars_check_ret3();
+sp_vars_check_ret3()
+0
+Warnings:
+Warning 1366 Incorrect integer value: 'Hello, world' for column 'sp_vars_check_ret3()' at row 1
+SELECT sp_vars_check_ret4();
+sp_vars_check_ret4()
+154.12
+Warnings:
+Note 1265 Data truncated for column 'sp_vars_check_ret4()' at row 1
+SET @@sql_mode = 'traditional';
+
+---------------------------------------------------------------
+Calling in TRADITIONAL mode the routines, created in ANSI mode.
+---------------------------------------------------------------
+
+CALL sp_vars_check_dflt();
+v1 v1u v2 v2u v3 v3u v4 v4u
+127 255 -128 0 127 255 -128 0
+v5 v5u v6 v6u
+127 255 -128 0
+v7 v8 v9 v10 v11 v12 v13 v14 v15 v16
+10 10 10 0 0 10 10 10 10 0
+v17 v18 v19 v20
+12.00 12.12 12.00 12.12
+Warnings:
+Warning 1264 Out of range value adjusted for column 'v1' at row 1
+Warning 1264 Out of range value adjusted for column 'v1u' at row 1
+Warning 1264 Out of range value adjusted for column 'v2' at row 1
+Warning 1264 Out of range value adjusted for column 'v2u' at row 1
+Warning 1264 Out of range value adjusted for column 'v3' at row 1
+Warning 1264 Out of range value adjusted for column 'v3u' at row 1
+Warning 1264 Out of range value adjusted for column 'v4' at row 1
+Warning 1264 Out of range value adjusted for column 'v4u' at row 1
+Warning 1264 Out of range value adjusted for column 'v5' at row 1
+Warning 1264 Out of range value adjusted for column 'v5u' at row 1
+Warning 1264 Out of range value adjusted for column 'v6' at row 1
+Warning 1264 Out of range value adjusted for column 'v6u' at row 1
+Warning 1366 Incorrect integer value: 'String 10 ' for column 'v10' at row 1
+Warning 1366 Incorrect integer value: 'String10' for column 'v11' at row 1
+Warning 1265 Data truncated for column 'v12' at row 1
+Warning 1265 Data truncated for column 'v13' at row 1
+Warning 1366 Incorrect integer value: 'Hello, world' for column 'v16' at row 1
+Note 1265 Data truncated for column 'v18' at row 1
+Note 1265 Data truncated for column 'v20' at row 1
+CALL sp_vars_check_assignment();
+i1 i2 i3 i4
+127 -128 127 -128
+i1 i2 i3 i4
+127 -128 127 127
+u1 u2 u3 u4
+255 0 255 0
+u1 u2 u3 u4
+255 0 200 200
+d1 d2 d3
+1234.00 1234.12 1234.12
+d1 d2 d3
+1234.00 1234.12 1234.12
+Warnings:
+Warning 1264 Out of range value adjusted for column 'i1' at row 1
+Warning 1264 Out of range value adjusted for column 'i2' at row 1
+Warning 1264 Out of range value adjusted for column 'i3' at row 1
+Warning 1264 Out of range value adjusted for column 'i4' at row 1
+Warning 1264 Out of range value adjusted for column 'i1' at row 1
+Warning 1264 Out of range value adjusted for column 'i2' at row 1
+Warning 1264 Out of range value adjusted for column 'i3' at row 1
+Warning 1264 Out of range value adjusted for column 'i4' at row 1
+Warning 1264 Out of range value adjusted for column 'u1' at row 1
+Warning 1264 Out of range value adjusted for column 'u2' at row 1
+Warning 1264 Out of range value adjusted for column 'u3' at row 1
+Warning 1264 Out of range value adjusted for column 'u4' at row 1
+Warning 1264 Out of range value adjusted for column 'u1' at row 1
+Warning 1264 Out of range value adjusted for column 'u2' at row 1
+Note 1265 Data truncated for column 'd3' at row 1
+Note 1265 Data truncated for column 'd3' at row 1
+SELECT sp_vars_check_ret1();
+sp_vars_check_ret1()
+127
+Warnings:
+Warning 1264 Out of range value adjusted for column 'sp_vars_check_ret1()' at row 1
+SELECT sp_vars_check_ret2();
+sp_vars_check_ret2()
+127
+Warnings:
+Warning 1264 Out of range value adjusted for column 'sp_vars_check_ret2()' at row 1
+SELECT sp_vars_check_ret3();
+sp_vars_check_ret3()
+0
+Warnings:
+Warning 1366 Incorrect integer value: 'Hello, world' for column 'sp_vars_check_ret3()' at row 1
+SELECT sp_vars_check_ret4();
+sp_vars_check_ret4()
+154.12
+Warnings:
+Note 1265 Data truncated for column 'sp_vars_check_ret4()' at row 1
+DROP PROCEDURE sp_vars_check_dflt;
+DROP PROCEDURE sp_vars_check_assignment;
+DROP FUNCTION sp_vars_check_ret1;
+DROP FUNCTION sp_vars_check_ret2;
+DROP FUNCTION sp_vars_check_ret3;
+DROP FUNCTION sp_vars_check_ret4;
+CREATE PROCEDURE sp_vars_check_dflt()
+BEGIN
+DECLARE v1 TINYINT DEFAULT 1e200;
+DECLARE v1u TINYINT UNSIGNED DEFAULT 1e200;
+DECLARE v2 TINYINT DEFAULT -1e200;
+DECLARE v2u TINYINT UNSIGNED DEFAULT -1e200;
+DECLARE v3 TINYINT DEFAULT 300;
+DECLARE v3u TINYINT UNSIGNED DEFAULT 300;
+DECLARE v4 TINYINT DEFAULT -300;
+DECLARE v4u TINYINT UNSIGNED DEFAULT -300;
+DECLARE v5 TINYINT DEFAULT 10 * 10 * 10;
+DECLARE v5u TINYINT UNSIGNED DEFAULT 10 * 10 * 10;
+DECLARE v6 TINYINT DEFAULT -10 * 10 * 10;
+DECLARE v6u TINYINT UNSIGNED DEFAULT -10 * 10 * 10;
+DECLARE v7 TINYINT DEFAULT '10';
+DECLARE v8 TINYINT DEFAULT '10 ';
+DECLARE v9 TINYINT DEFAULT ' 10 ';
+DECLARE v10 TINYINT DEFAULT 'String 10 ';
+DECLARE v11 TINYINT DEFAULT 'String10';
+DECLARE v12 TINYINT DEFAULT '10 String';
+DECLARE v13 TINYINT DEFAULT '10String';
+DECLARE v14 TINYINT DEFAULT concat('10', ' ');
+DECLARE v15 TINYINT DEFAULT concat(' ', '10');
+DECLARE v16 TINYINT DEFAULT concat('Hello, ', 'world');
+DECLARE v17 DECIMAL(64, 2) DEFAULT 12;
+DECLARE v18 DECIMAL(64, 2) DEFAULT 12.123;
+DECLARE v19 DECIMAL(64, 2) DEFAULT 11 + 1;
+DECLARE v20 DECIMAL(64, 2) DEFAULT 12 + 0.123;
+SELECT v1, v1u, v2, v2u, v3, v3u, v4, v4u;
+SELECT v5, v5u, v6, v6u;
+SELECT v7, v8, v9, v10, v11, v12, v13, v14, v15, v16;
+SELECT v17, v18, v19, v20;
+END|
+CREATE PROCEDURE sp_vars_check_assignment()
+BEGIN
+DECLARE i1, i2, i3, i4 TINYINT;
+DECLARE u1, u2, u3, u4 TINYINT UNSIGNED;
+DECLARE d1, d2, d3 DECIMAL(64, 2);
+SET i1 = 1e200;
+SET i2 = -1e200;
+SET i3 = 300;
+SET i4 = -300;
+SELECT i1, i2, i3, i4;
+SET i1 = 10 * 10 * 10;
+SET i2 = -10 * 10 * 10;
+SET i3 = sign(10 * 10) * 10 * 20;
+SET i4 = sign(-10 * 10) * -10 * 20;
+SELECT i1, i2, i3, i4;
+SET u1 = 1e200;
+SET u2 = -1e200;
+SET u3 = 300;
+SET u4 = -300;
+SELECT u1, u2, u3, u4;
+SET u1 = 10 * 10 * 10;
+SET u2 = -10 * 10 * 10;
+SET u3 = sign(10 * 10) * 10 * 20;
+SET u4 = sign(-10 * 10) * -10 * 20;
+SELECT u1, u2, u3, u4;
+SET d1 = 1234;
+SET d2 = 1234.12;
+SET d3 = 1234.1234;
+SELECT d1, d2, d3;
+SET d1 = 12 * 100 + 34;
+SET d2 = 12 * 100 + 34 + 0.12;
+SET d3 = 12 * 100 + 34 + 0.1234;
+SELECT d1, d2, d3;
+END|
+CREATE FUNCTION sp_vars_check_ret1() RETURNS TINYINT
+BEGIN
+RETURN 1e200;
+END|
+CREATE FUNCTION sp_vars_check_ret2() RETURNS TINYINT
+BEGIN
+RETURN 10 * 10 * 10;
+END|
+CREATE FUNCTION sp_vars_check_ret3() RETURNS TINYINT
+BEGIN
+RETURN 'Hello, world';
+END|
+CREATE FUNCTION sp_vars_check_ret4() RETURNS DECIMAL(64, 2)
+BEGIN
+RETURN 12 * 10 + 34 + 0.1234;
+END|
+
+---------------------------------------------------------------
+Calling the routines, created in TRADITIONAL mode.
+---------------------------------------------------------------
+
+CALL sp_vars_check_dflt();
+ERROR 22003: Out of range value adjusted for column 'v1' at row 1
+CALL sp_vars_check_assignment();
+ERROR 22003: Out of range value adjusted for column 'i1' at row 1
+SELECT sp_vars_check_ret1();
+ERROR 22003: Out of range value adjusted for column 'sp_vars_check_ret1()' at row 1
+SELECT sp_vars_check_ret2();
+ERROR 22003: Out of range value adjusted for column 'sp_vars_check_ret2()' at row 1
+SELECT sp_vars_check_ret3();
+ERROR HY000: Incorrect integer value: 'Hello, world' for column 'sp_vars_check_ret3()' at row 1
+SELECT sp_vars_check_ret4();
+sp_vars_check_ret4()
+154.12
+Warnings:
+Note 1265 Data truncated for column 'sp_vars_check_ret4()' at row 1
+SET @@sql_mode = 'ansi';
+DROP PROCEDURE sp_vars_check_dflt;
+DROP PROCEDURE sp_vars_check_assignment;
+DROP FUNCTION sp_vars_check_ret1;
+DROP FUNCTION sp_vars_check_ret2;
+DROP FUNCTION sp_vars_check_ret3;
+DROP FUNCTION sp_vars_check_ret4;
+
+---------------------------------------------------------------
+BIT data type tests
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE v1 BIT;
+DECLARE v2 BIT(1);
+DECLARE v3 BIT(3) DEFAULT b'101';
+DECLARE v4 BIT(64) DEFAULT 0x5555555555555555;
+DECLARE v5 BIT(3);
+DECLARE v6 BIT(64);
+DECLARE v7 BIT(8) DEFAULT 128;
+DECLARE v8 BIT(8) DEFAULT '128';
+DECLARE v9 BIT(8) DEFAULT ' 128';
+DECLARE v10 BIT(8) DEFAULT 'x 128';
+SET v1 = v4;
+SET v2 = 0;
+SET v5 = v4; # check overflow
+SET v6 = v3; # check padding
+SELECT HEX(v1);
+SELECT HEX(v2);
+SELECT HEX(v3);
+SELECT HEX(v4);
+SELECT HEX(v5);
+SELECT HEX(v6);
+SELECT HEX(v7);
+SELECT HEX(v8);
+SELECT HEX(v9);
+SELECT HEX(v10);
+END|
+CALL p1();
+HEX(v1)
+01
+HEX(v2)
+00
+HEX(v3)
+05
+HEX(v4)
+5555555555555555
+HEX(v5)
+07
+HEX(v6)
+0000000000000005
+HEX(v7)
+80
+HEX(v8)
+FF
+HEX(v9)
+FF
+HEX(v10)
+FF
+Warnings:
+Warning 1264 Out of range value adjusted for column 'v8' at row 1
+Warning 1264 Out of range value adjusted for column 'v9' at row 1
+Warning 1264 Out of range value adjusted for column 'v10' at row 1
+Warning 1264 Out of range value adjusted for column 'v1' at row 1
+Warning 1264 Out of range value adjusted for column 'v5' at row 1
+DROP PROCEDURE p1;
+
+---------------------------------------------------------------
+CASE expression tests.
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+Warnings:
+Note 1305 PROCEDURE p1 does not exist
+DROP PROCEDURE IF EXISTS p2;
+Warnings:
+Note 1305 PROCEDURE p2 does not exist
+DROP TABLE IF EXISTS t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE t1(log_msg VARCHAR(1024));
+CREATE PROCEDURE p1(arg VARCHAR(255))
+BEGIN
+INSERT INTO t1 VALUES('p1: step1');
+CASE arg * 10
+WHEN 10 * 10 THEN
+INSERT INTO t1 VALUES('p1: case1: on 10');
+WHEN 10 * 10 + 10 * 10 THEN
+BEGIN
+CASE arg / 10
+WHEN 1 THEN
+INSERT INTO t1 VALUES('p1: case1: case2: on 1');
+WHEN 2 THEN
+BEGIN
+DECLARE i TINYINT DEFAULT 10;
+WHILE i > 0 DO
+INSERT INTO t1 VALUES(CONCAT('p1: case1: case2: loop: i: ', i));
+CASE MOD(i, 2)
+WHEN 0 THEN
+INSERT INTO t1 VALUES('p1: case1: case2: loop: i is even');
+WHEN 1 THEN
+INSERT INTO t1 VALUES('p1: case1: case2: loop: i is odd');
+ELSE
+INSERT INTO t1 VALUES('p1: case1: case2: loop: ERROR');
+END CASE;
+SET i = i - 1;
+END WHILE;
+END;
+ELSE
+INSERT INTO t1 VALUES('p1: case1: case2: ERROR');
+END CASE;
+CASE arg
+WHEN 10 THEN
+INSERT INTO t1 VALUES('p1: case1: case3: on 10');
+WHEN 20 THEN
+INSERT INTO t1 VALUES('p1: case1: case3: on 20');
+ELSE
+INSERT INTO t1 VALUES('p1: case1: case3: ERROR');
+END CASE;
+END;
+ELSE
+INSERT INTO t1 VALUES('p1: case1: ERROR');
+END CASE;
+CASE arg * 10
+WHEN 10 * 10 THEN
+INSERT INTO t1 VALUES('p1: case4: on 10');
+WHEN 10 * 10 + 10 * 10 THEN
+BEGIN
+CASE arg / 10
+WHEN 1 THEN
+INSERT INTO t1 VALUES('p1: case4: case5: on 1');
+WHEN 2 THEN
+BEGIN
+DECLARE i TINYINT DEFAULT 10;
+WHILE i > 0 DO
+INSERT INTO t1 VALUES(CONCAT('p1: case4: case5: loop: i: ', i));
+CASE MOD(i, 2)
+WHEN 0 THEN
+INSERT INTO t1 VALUES('p1: case4: case5: loop: i is even');
+WHEN 1 THEN
+INSERT INTO t1 VALUES('p1: case4: case5: loop: i is odd');
+ELSE
+INSERT INTO t1 VALUES('p1: case4: case5: loop: ERROR');
+END CASE;
+SET i = i - 1;
+END WHILE;
+END;
+ELSE
+INSERT INTO t1 VALUES('p1: case4: case5: ERROR');
+END CASE;
+CASE arg
+WHEN 10 THEN
+INSERT INTO t1 VALUES('p1: case4: case6: on 10');
+WHEN 20 THEN
+INSERT INTO t1 VALUES('p1: case4: case6: on 20');
+ELSE
+INSERT INTO t1 VALUES('p1: case4: case6: ERROR');
+END CASE;
+END;
+ELSE
+INSERT INTO t1 VALUES('p1: case4: ERROR');
+END CASE;
+END|
+CREATE PROCEDURE p2()
+BEGIN
+DECLARE i TINYINT DEFAULT 3;
+WHILE i > 0 DO
+IF MOD(i, 2) = 0 THEN
+SET @_test_session_var = 10;
+ELSE
+SET @_test_session_var = 'test';
+END IF;
+CASE @_test_session_var
+WHEN 10 THEN
+INSERT INTO t1 VALUES('p2: case: numerical type');
+WHEN 'test' THEN
+INSERT INTO t1 VALUES('p2: case: string type');
+ELSE
+INSERT INTO t1 VALUES('p2: case: ERROR');
+END CASE;
+SET i = i - 1;
+END WHILE;
+END|
+CALL p1(10);
+CALL p1(20);
+CALL p2();
+SELECT * FROM t1;
+log_msg
+p1: step1
+p1: case1: on 10
+p1: case4: on 10
+p1: step1
+p1: case1: case2: loop: i: 10
+p1: case1: case2: loop: i is even
+p1: case1: case2: loop: i: 9
+p1: case1: case2: loop: i is odd
+p1: case1: case2: loop: i: 8
+p1: case1: case2: loop: i is even
+p1: case1: case2: loop: i: 7
+p1: case1: case2: loop: i is odd
+p1: case1: case2: loop: i: 6
+p1: case1: case2: loop: i is even
+p1: case1: case2: loop: i: 5
+p1: case1: case2: loop: i is odd
+p1: case1: case2: loop: i: 4
+p1: case1: case2: loop: i is even
+p1: case1: case2: loop: i: 3
+p1: case1: case2: loop: i is odd
+p1: case1: case2: loop: i: 2
+p1: case1: case2: loop: i is even
+p1: case1: case2: loop: i: 1
+p1: case1: case2: loop: i is odd
+p1: case1: case3: on 20
+p1: case4: case5: loop: i: 10
+p1: case4: case5: loop: i is even
+p1: case4: case5: loop: i: 9
+p1: case4: case5: loop: i is odd
+p1: case4: case5: loop: i: 8
+p1: case4: case5: loop: i is even
+p1: case4: case5: loop: i: 7
+p1: case4: case5: loop: i is odd
+p1: case4: case5: loop: i: 6
+p1: case4: case5: loop: i is even
+p1: case4: case5: loop: i: 5
+p1: case4: case5: loop: i is odd
+p1: case4: case5: loop: i: 4
+p1: case4: case5: loop: i is even
+p1: case4: case5: loop: i: 3
+p1: case4: case5: loop: i is odd
+p1: case4: case5: loop: i: 2
+p1: case4: case5: loop: i is even
+p1: case4: case5: loop: i: 1
+p1: case4: case5: loop: i is odd
+p1: case4: case6: on 20
+p2: case: string type
+p2: case: numerical type
+p2: case: string type
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP TABLE t1;
+
+---------------------------------------------------------------
+BUG#14161
+---------------------------------------------------------------
+
+DROP TABLE IF EXISTS t1;
+DROP PROCEDURE IF EXISTS p1;
+CREATE TABLE t1(col BIGINT UNSIGNED);
+INSERT INTO t1 VALUE(18446744073709551614);
+CREATE PROCEDURE p1(IN arg BIGINT UNSIGNED)
+BEGIN
+SELECT arg;
+SELECT * FROM t1;
+SELECT * FROM t1 WHERE col = arg;
+END|
+CALL p1(18446744073709551614);
+arg
+18446744073709551614
+col
+18446744073709551614
+col
+18446744073709551614
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+---------------------------------------------------------------
+BUG#13705
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+CREATE PROCEDURE p1(x VARCHAR(10), y CHAR(3)) READS SQL DATA
+BEGIN
+SELECT x, y;
+END|
+CALL p1('alpha', 'abc');
+x y
+alpha abc
+CALL p1('alpha', 'abcdef');
+x y
+alpha abc
+Warnings:
+Warning 1265 Data truncated for column 'y' at row 1
+DROP PROCEDURE p1;
+
+---------------------------------------------------------------
+BUG#13675
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+DROP TABLE IF EXISTS t1;
+CREATE PROCEDURE p1(x DATETIME)
+BEGIN
+CREATE TABLE t1 SELECT x;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+END|
+CALL p1(NOW());
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "x" varbinary(19) default NULL
+)
+CALL p1('test');
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "x" varbinary(19) default NULL
+)
+Warnings:
+Warning 1264 Out of range value adjusted for column 'x' at row 1
+DROP PROCEDURE p1;
+
+---------------------------------------------------------------
+BUG#12976
+---------------------------------------------------------------
+
+DROP TABLE IF EXISTS t1;
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+CREATE TABLE t1(b BIT(1));
+INSERT INTO t1(b) VALUES(b'0'), (b'1');
+CREATE PROCEDURE p1()
+BEGIN
+SELECT HEX(b),
+b = 0,
+b = FALSE,
+b IS FALSE,
+b = 1,
+b = TRUE,
+b IS TRUE
+FROM t1;
+END|
+CREATE PROCEDURE p2()
+BEGIN
+DECLARE vb BIT(1);
+SELECT b INTO vb FROM t1 WHERE b = 0;
+SELECT HEX(vb),
+vb = 0,
+vb = FALSE,
+vb IS FALSE,
+vb = 1,
+vb = TRUE,
+vb IS TRUE;
+SELECT b INTO vb FROM t1 WHERE b = 1;
+SELECT HEX(vb),
+vb = 0,
+vb = FALSE,
+vb IS FALSE,
+vb = 1,
+vb = TRUE,
+vb IS TRUE;
+END|
+call p1();
+HEX(b) b = 0 b = FALSE b IS FALSE b = 1 b = TRUE b IS TRUE
+
+0 1 1 1 0 0 0
+1 0 0 0 1 1 1
+call p2();
+HEX(vb) vb = 0 vb = FALSE vb IS FALSE vb = 1 vb = TRUE vb IS TRUE
+00 1 1 1 0 0 0
+HEX(vb) vb = 0 vb = FALSE vb IS FALSE vb = 1 vb = TRUE vb IS TRUE
+01 0 0 1 1 1 0
+DROP TABLE t1;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+---------------------------------------------------------------
+BUG#9572
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+DROP PROCEDURE IF EXISTS p3;
+DROP PROCEDURE IF EXISTS p4;
+DROP PROCEDURE IF EXISTS p5;
+DROP PROCEDURE IF EXISTS p6;
+SET @@sql_mode = 'traditional';
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE v TINYINT DEFAULT 1e200;
+SELECT v;
+END|
+CREATE PROCEDURE p2()
+BEGIN
+DECLARE v DECIMAL(5) DEFAULT 1e200;
+SELECT v;
+END|
+CREATE PROCEDURE p3()
+BEGIN
+DECLARE v CHAR(5) DEFAULT 'abcdef';
+SELECT v LIKE 'abc___';
+END|
+CREATE PROCEDURE p4(arg VARCHAR(2))
+BEGIN
+DECLARE var VARCHAR(1);
+SET var := arg;
+SELECT arg, var;
+END|
+CREATE PROCEDURE p5(arg CHAR(2))
+BEGIN
+DECLARE var CHAR(1);
+SET var := arg;
+SELECT arg, var;
+END|
+CREATE PROCEDURE p6(arg DECIMAL(2))
+BEGIN
+DECLARE var DECIMAL(1);
+SET var := arg;
+SELECT arg, var;
+END|
+CALL p1();
+ERROR 22003: Out of range value adjusted for column 'v' at row 1
+CALL p2();
+ERROR 22003: Out of range value adjusted for column 'v' at row 1
+CALL p3();
+ERROR 22001: Data too long for column 'v' at row 1
+CALL p4('aaa');
+ERROR 22001: Data too long for column 'arg' at row 1
+CALL p5('aa');
+ERROR 22001: Data too long for column 'var' at row 1
+CALL p6(10);
+ERROR 22003: Out of range value adjusted for column 'var' at row 1
+SET @@sql_mode = 'ansi';
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP PROCEDURE p6;
+
+---------------------------------------------------------------
+BUG#9078
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+CREATE PROCEDURE p1 (arg DECIMAL(64,2))
+BEGIN
+DECLARE var DECIMAL(64,2);
+SET var = arg;
+SELECT var;
+END|
+CALL p1(1929);
+var
+1929.00
+CALL p1(1929.00);
+var
+1929.00
+CALL p1(1929.003);
+var
+1929.00
+Warnings:
+Note 1265 Data truncated for column 'arg' at row 1
+DROP PROCEDURE p1;
+
+---------------------------------------------------------------
+BUG#8768
+---------------------------------------------------------------
+
+DROP FUNCTION IF EXISTS f1;
+CREATE FUNCTION f1(arg TINYINT UNSIGNED) RETURNS TINYINT
+BEGIN
+RETURN arg;
+END|
+SELECT f1(-2500);
+f1(-2500)
+0
+Warnings:
+Warning 1264 Out of range value adjusted for column 'arg' at row 1
+SET @@sql_mode = 'traditional';
+SELECT f1(-2500);
+ERROR 22003: Out of range value adjusted for column 'arg' at row 1
+DROP FUNCTION f1;
+CREATE FUNCTION f1(arg TINYINT UNSIGNED) RETURNS TINYINT
+BEGIN
+RETURN arg;
+END|
+SELECT f1(-2500);
+ERROR 22003: Out of range value adjusted for column 'arg' at row 1
+SET @@sql_mode = 'ansi';
+DROP FUNCTION f1;
+
+---------------------------------------------------------------
+BUG#8769
+---------------------------------------------------------------
+
+DROP FUNCTION IF EXISTS f1;
+CREATE FUNCTION f1(arg MEDIUMINT) RETURNS MEDIUMINT
+BEGIN
+RETURN arg;
+END|
+SELECT f1(8388699);
+f1(8388699)
+8388607
+Warnings:
+Warning 1264 Out of range value adjusted for column 'arg' at row 1
+SET @@sql_mode = 'traditional';
+SELECT f1(8388699);
+ERROR 22003: Out of range value adjusted for column 'arg' at row 1
+DROP FUNCTION f1;
+CREATE FUNCTION f1(arg MEDIUMINT) RETURNS MEDIUMINT
+BEGIN
+RETURN arg;
+END|
+SELECT f1(8388699);
+ERROR 22003: Out of range value adjusted for column 'arg' at row 1
+SET @@sql_mode = 'ansi';
+DROP FUNCTION f1;
+
+---------------------------------------------------------------
+BUG#8702
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(col VARCHAR(255));
+INSERT INTO t1(col) VALUES('Hello, world!');
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE sp_var INTEGER;
+SELECT col INTO sp_var FROM t1 LIMIT 1;
+SET @user_var = sp_var;
+SELECT sp_var;
+SELECT @user_var;
+END|
+CALL p1();
+sp_var
+0
+@user_var
+0
+Warnings:
+Warning 1264 Out of range value adjusted for column 'sp_var' at row 1
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+---------------------------------------------------------------
+BUG#12903
+---------------------------------------------------------------
+
+DROP FUNCTION IF EXISTS f1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(txt VARCHAR(255));
+CREATE FUNCTION f1(arg VARCHAR(255)) RETURNS VARCHAR(255)
+BEGIN
+DECLARE v1 VARCHAR(255);
+DECLARE v2 VARCHAR(255);
+SET v1 = CONCAT(LOWER(arg), UPPER(arg));
+SET v2 = CONCAT(LOWER(v1), UPPER(v1));
+INSERT INTO t1 VALUES(v1), (v2);
+RETURN CONCAT(LOWER(arg), UPPER(arg));
+END|
+SELECT f1('_aBcDe_');
+f1('_aBcDe_')
+_abcde__ABCDE_
+SELECT * FROM t1;
+txt
+_abcde__ABCDE_
+_abcde__abcde__ABCDE__ABCDE_
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+---------------------------------------------------------------
+BUG#13808
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+DROP FUNCTION IF EXISTS f1;
+CREATE PROCEDURE p1(arg ENUM('a', 'b'))
+BEGIN
+SELECT arg;
+END|
+CREATE PROCEDURE p2(arg ENUM('a', 'b'))
+BEGIN
+DECLARE var ENUM('c', 'd') DEFAULT arg;
+SELECT arg, var;
+END|
+CREATE FUNCTION f1(arg ENUM('a', 'b')) RETURNS ENUM('c', 'd')
+BEGIN
+RETURN arg;
+END|
+CALL p1('c');
+arg
+
+Warnings:
+Warning 1265 Data truncated for column 'arg' at row 1
+CALL p2('a');
+arg var
+a
+Warnings:
+Warning 1265 Data truncated for column 'var' at row 1
+SELECT f1('a');
+f1('a')
+
+Warnings:
+Warning 1265 Data truncated for column 'f1('a')' at row 1
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP FUNCTION f1;
+
+---------------------------------------------------------------
+BUG#13909
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+CREATE PROCEDURE p1(arg VARCHAR(255))
+BEGIN
+SELECT CHARSET(arg);
+END|
+CREATE PROCEDURE p2(arg VARCHAR(255) CHARACTER SET UTF8)
+BEGIN
+SELECT CHARSET(arg);
+END|
+CALL p1('t');
+CHARSET(arg)
+latin1
+CALL p1(_UTF8 't');
+CHARSET(arg)
+latin1
+CALL p2('t');
+CHARSET(arg)
+utf8
+CALL p2(_LATIN1 't');
+CHARSET(arg)
+utf8
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+---------------------------------------------------------------
+BUG#14188
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+CREATE PROCEDURE p1(arg1 BINARY(2), arg2 VARBINARY(2))
+BEGIN
+DECLARE var1 BINARY(2) DEFAULT 0x41;
+DECLARE var2 VARBINARY(2) DEFAULT 0x42;
+SELECT HEX(arg1), HEX(arg2);
+SELECT HEX(var1), HEX(var2);
+END|
+CALL p1(0x41, 0x42);
+HEX(arg1) HEX(arg2)
+4100 42
+HEX(var1) HEX(var2)
+4100 42
+DROP PROCEDURE p1;
+
+---------------------------------------------------------------
+BUG#15148
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(col1 TINYINT, col2 TINYINT);
+INSERT INTO t1 VALUES(1, 2), (11, 12);
+CREATE PROCEDURE p1(arg TINYINT)
+BEGIN
+SELECT arg;
+END|
+CALL p1((1, 2));
+ERROR 21000: Operand should contain 1 column(s)
+CALL p1((SELECT * FROM t1 LIMIT 1));
+ERROR 21000: Operand should contain 1 column(s)
+CALL p1((SELECT col1, col2 FROM t1 LIMIT 1));
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+---------------------------------------------------------------
+BUG#13613
+---------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS p1;
+DROP FUNCTION IF EXISTS f1;
+CREATE PROCEDURE p1(x VARCHAR(50))
+BEGIN
+SET x = SUBSTRING(x, 1, 3);
+SELECT x;
+END|
+CREATE FUNCTION f1(x VARCHAR(50)) RETURNS VARCHAR(50)
+BEGIN
+RETURN SUBSTRING(x, 1, 3);
+END|
+CALL p1('abcdef');
+x
+abc
+SELECT f1('ABCDEF');
+f1('ABCDEF')
+ABC
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+
+---------------------------------------------------------------
+BUG#13665
+---------------------------------------------------------------
+
+DROP FUNCTION IF EXISTS f1;
+CREATE FUNCTION f1() RETURNS VARCHAR(20000)
+BEGIN
+DECLARE var VARCHAR(2000);
+SET var = '';
+SET var = CONCAT(var, 'abc');
+SET var = CONCAT(var, '');
+RETURN var;
+END|
+SELECT f1();
+f1()
+abc
+DROP FUNCTION f1;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index c3b4039d12d..ded9754f172 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -248,13 +248,13 @@ return i+1|
call sub1("sub1a", (select 7))|
call sub1("sub1b", (select max(i) from t2))|
call sub1("sub1c", (select i,d from t2 limit 1))|
+ERROR 21000: Operand should contain 1 column(s)
call sub1("sub1d", (select 1 from (select 1) a))|
call sub2("sub2")|
select * from t1|
id data
sub1a 7
sub1b 3
-sub1c 1
sub1d 1
sub2 6
select sub3((select max(i) from t2))|
@@ -988,6 +988,10 @@ end|
select f5(1)|
f5(1)
1
+select f5(2)|
+ERROR HY000: Recursive stored functions and triggers are not allowed.
+select f5(3)|
+ERROR HY000: Recursive stored functions and triggers are not allowed.
create function f6() returns int
begin
declare n int;
@@ -1035,6 +1039,12 @@ select * from v1|
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
create function f1() returns int
return (select sum(data) from t1) + (select sum(data) from v1)|
+select f1()|
+ERROR HY000: Recursive stored functions and triggers are not allowed.
+select * from v1|
+ERROR HY000: Recursive stored functions and triggers are not allowed.
+select * from v2|
+ERROR HY000: Recursive stored functions and triggers are not allowed.
drop function f1|
create function f1() returns int
return (select sum(data) from t1)|
@@ -1053,7 +1063,7 @@ f0()
select *, f0() from v0|
f0() f0()
100 100
-lock tables t1 read, t1 as t11 read, mysql.proc read|
+lock tables t1 read, t1 as t11 read|
select f3()|
f3()
1
@@ -1251,6 +1261,62 @@ drop procedure opp|
drop procedure ip|
show procedure status like '%p%'|
Db Name Type Definer Modified Created Security_type Comment
+drop table if exists fib|
+create table fib ( f bigint unsigned not null )|
+drop procedure if exists fib|
+create procedure fib(n int unsigned)
+begin
+if n > 1 then
+begin
+declare x, y bigint unsigned;
+declare c cursor for select f from fib order by f desc limit 2;
+open c;
+fetch c into y;
+fetch c into x;
+close c;
+insert into fib values (x+y);
+call fib(n-1);
+end;
+end if;
+end|
+set @@max_sp_recursion_depth= 20|
+insert into fib values (0), (1)|
+call fib(3)|
+select * from fib order by f asc|
+f
+0
+1
+1
+2
+delete from fib|
+insert into fib values (0), (1)|
+call fib(20)|
+select * from fib order by f asc|
+f
+0
+1
+1
+2
+3
+5
+8
+13
+21
+34
+55
+89
+144
+233
+377
+610
+987
+1597
+2584
+4181
+6765
+drop table fib|
+drop procedure fib|
+set @@max_sp_recursion_depth= 0|
drop procedure if exists bar|
create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker
@@ -1479,6 +1545,52 @@ select @x2|
@x2
2
drop procedure bug2260|
+drop procedure if exists bug2267_1|
+create procedure bug2267_1()
+begin
+show procedure status;
+end|
+drop procedure if exists bug2267_2|
+create procedure bug2267_2()
+begin
+show function status;
+end|
+drop procedure if exists bug2267_3|
+create procedure bug2267_3()
+begin
+show create procedure bug2267_1;
+end|
+drop procedure if exists bug2267_4|
+drop function if exists bug2267_4|
+create procedure bug2267_4()
+begin
+show create function bug2267_4;
+end|
+create function bug2267_4() returns int return 100|
+call bug2267_1()|
+Db Name Type Definer Modified Created Security_type Comment
+test bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+test bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+test bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+test bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+call bug2267_2()|
+Db Name Type Definer Modified Created Security_type Comment
+test bug2267_4 FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+call bug2267_3()|
+Procedure sql_mode Create Procedure
+bug2267_1 CREATE PROCEDURE `bug2267_1`()
+begin
+show procedure status;
+end
+call bug2267_4()|
+Function sql_mode Create Function
+bug2267_4 CREATE FUNCTION `bug2267_4`() RETURNS int(11)
+return 100
+drop procedure bug2267_1|
+drop procedure bug2267_2|
+drop procedure bug2267_3|
+drop procedure bug2267_4|
+drop function bug2267_4|
drop procedure if exists bug2227|
create procedure bug2227(x int)
begin
@@ -1490,6 +1602,18 @@ 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|
@@ -2562,7 +2686,7 @@ call bug8937()|
s x y z
16 3 1 6
a
-3.2000
+3.2
drop procedure bug8937|
delete from t1|
drop procedure if exists bug6900|
@@ -2766,21 +2890,30 @@ create function bug9775(v1 char(1)) returns enum('a','b') return v1|
select bug9775('a'),bug9775('b'),bug9775('c')|
bug9775('a') bug9775('b') bug9775('c')
a b
+Warnings:
+Warning 1265 Data truncated for column 'bug9775('c')' at row 1
drop function bug9775|
create function bug9775(v1 int) returns enum('a','b') return v1|
select bug9775(1),bug9775(2),bug9775(3)|
bug9775(1) bug9775(2) bug9775(3)
a b
+Warnings:
+Warning 1265 Data truncated for column 'bug9775(3)' at row 1
drop function bug9775|
create function bug9775(v1 char(1)) returns set('a','b') return v1|
select bug9775('a'),bug9775('b'),bug9775('a,b'),bug9775('c')|
bug9775('a') bug9775('b') bug9775('a,b') bug9775('c')
-a b a,b
+a b a
+Warnings:
+Warning 1265 Data truncated for column 'v1' at row 1
+Warning 1265 Data truncated for column 'bug9775('c')' at row 1
drop function bug9775|
create function bug9775(v1 int) returns set('a','b') return v1|
select bug9775(1),bug9775(2),bug9775(3),bug9775(4)|
bug9775(1) bug9775(2) bug9775(3) bug9775(4)
a b a,b
+Warnings:
+Warning 1265 Data truncated for column 'bug9775(4)' at row 1
drop function bug9775|
drop function if exists bug8861|
create function bug8861(v1 int) returns year return v1|
@@ -2803,12 +2936,10 @@ create procedure bug9004_2(x char(16))
call bug9004_1(x)|
call bug9004_1('12345678901234567')|
Warnings:
-Warning 1265 Data truncated for column 'id' at row 1
-Warning 1265 Data truncated for column 'id' at row 2
+Warning 1265 Data truncated for column 'x' at row 1
call bug9004_2('12345678901234567890')|
Warnings:
-Warning 1265 Data truncated for column 'id' at row 1
-Warning 1265 Data truncated for column 'id' at row 2
+Warning 1265 Data truncated for column 'x' at row 1
delete from t1|
drop procedure bug9004_1|
drop procedure bug9004_2|
@@ -3403,14 +3534,15 @@ end|
call bug12589_1()|
Table Create Table
tm1 CREATE TEMPORARY TABLE `tm1` (
- `spv1` decimal(1,0) unsigned default NULL
+ `spv1` decimal(3,3) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Warnings:
-Warning 1292 Truncated incorrect DECIMAL value: 'test'
+Warning 1264 Out of range value adjusted for column 'spv1' at row 1
+Warning 1366 Incorrect decimal value: 'test' for column 'spv1' at row 1
call bug12589_2()|
Table Create Table
tm1 CREATE TEMPORARY TABLE `tm1` (
- `spv1` decimal(6,3) unsigned default NULL
+ `spv1` decimal(6,3) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
call bug12589_3()|
Table Create Table
@@ -3868,5 +4000,324 @@ drop procedure bug10100pv|
drop procedure bug10100pd|
drop procedure bug10100pc|
drop view v1|
+drop procedure if exists bug13729|
+drop table if exists t3|
+create table t3 (s1 int, primary key (s1))|
+insert into t3 values (1),(2)|
+create procedure bug13729()
+begin
+declare continue handler for sqlexception select 55;
+update t3 set s1 = 1;
+end|
+call bug13729()|
+55
+55
+select * from t3|
+s1
+1
+2
+drop procedure bug13729|
+drop table t3|
+drop procedure if exists bug14643_1|
+drop procedure if exists bug14643_2|
+create procedure bug14643_1()
+begin
+declare continue handler for sqlexception select 'boo' as 'Handler';
+begin
+declare v int default undefined_var;
+if v = 1 then
+select 1;
+else
+select v, isnull(v);
+end if;
+end;
+end|
+create procedure bug14643_2()
+begin
+declare continue handler for sqlexception select 'boo' as 'Handler';
+case undefined_var
+when 1 then
+select 1;
+else
+select 2;
+end case;
+select undefined_var;
+end|
+call bug14643_1()|
+Handler
+boo
+v isnull(v)
+NULL 1
+call bug14643_2()|
+Handler
+boo
+2
+2
+Handler
+boo
+drop procedure bug14643_1|
+drop procedure bug14643_2|
+drop procedure if exists bug14304|
+drop table if exists t3, t4|
+create table t3(a int primary key auto_increment)|
+create table t4(a int primary key auto_increment)|
+create procedure bug14304()
+begin
+insert into t3 set a=null;
+insert into t4 set a=null;
+insert into t4 set a=null;
+insert into t4 set a=null;
+insert into t4 set a=null;
+insert into t4 set a=null;
+insert into t4 select null as a;
+insert into t3 set a=null;
+insert into t3 set a=null;
+select * from t3;
+end|
+call bug14304()|
+a
+1
+2
+3
+drop procedure bug14304|
+drop table t3, t4|
+drop procedure if exists bug14376|
+create procedure bug14376()
+begin
+declare x int default x;
+end|
+call bug14376()|
+ERROR 42S22: Unknown column 'x' in 'field list'
+drop procedure bug14376|
+create procedure bug14376()
+begin
+declare x int default 42;
+begin
+declare x int default x;
+select x;
+end;
+end|
+call bug14376()|
+x
+42
+drop procedure bug14376|
+create procedure bug14376(x int)
+begin
+declare x int default x;
+select x;
+end|
+call bug14376(4711)|
+x
+4711
+drop procedure bug14376|
+drop procedure if exists bug5967|
+drop table if exists t3|
+create table t3 (a varchar(255))|
+insert into t3 (a) values ("a - table column")|
+create procedure bug5967(a varchar(255))
+begin
+declare i varchar(255);
+declare c cursor for select a from t3;
+select a;
+select a from t3 into i;
+select i as 'Parameter takes precedence over table column'; open c;
+fetch c into i;
+close c;
+select i as 'Parameter takes precedence over table column in cursors';
+begin
+declare a varchar(255) default 'a - local variable';
+declare c1 cursor for select a from t3;
+select a as 'A local variable takes precedence over parameter';
+open c1;
+fetch c1 into i;
+close c1;
+select i as 'A local variable takes precedence over parameter in cursors';
+begin
+declare a varchar(255) default 'a - local variable in a nested compound statement';
+declare c2 cursor for select a from t3;
+select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement';
+select a from t3 into i;
+select i as 'A local variable in a nested compound statement takes precedence over table column';
+open c2;
+fetch c2 into i;
+close c2;
+select i as 'A local variable in a nested compound statement takes precedence over table column in cursors';
+end;
+end;
+end|
+call bug5967("a - stored procedure parameter")|
+a
+a - stored procedure parameter
+Parameter takes precedence over table column
+a - stored procedure parameter
+Parameter takes precedence over table column in cursors
+a - stored procedure parameter
+A local variable takes precedence over parameter
+a - local variable
+A local variable takes precedence over parameter in cursors
+a - local variable
+A local variable in a nested compound statement takes precedence over a local variable in the outer statement
+a - local variable in a nested compound statement
+A local variable in a nested compound statement takes precedence over table column
+a - local variable in a nested compound statement
+A local variable in a nested compound statement takes precedence over table column in cursors
+a - local variable in a nested compound statement
+drop procedure bug5967|
+drop procedure if exists bug13012|
+create procedure bug13012()
+BEGIN
+REPAIR TABLE t1;
+BACKUP TABLE t1 to '../tmp';
+DROP TABLE t1;
+RESTORE TABLE t1 FROM '../tmp';
+END|
+call bug13012()|
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+Table Op Msg_type Msg_text
+test.t1 backup status OK
+Table Op Msg_type Msg_text
+test.t1 restore status OK
+drop procedure bug13012|
+create view v1 as select * from t1|
+create procedure bug13012()
+BEGIN
+REPAIR TABLE t1,t2,t3,v1;
+OPTIMIZE TABLE t1,t2,t3,v1;
+ANALYZE TABLE t1,t2,t3,v1;
+END|
+call bug13012()|
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+test.t2 repair status OK
+test.t3 repair status OK
+test.v1 repair error 'test.v1' is not BASE TABLE
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+test.t2 optimize status OK
+test.t3 optimize status OK
+test.v1 optimize error 'test.v1' is not BASE TABLE
+Table Op Msg_type Msg_text
+test.t1 analyze status Table is already up to date
+test.t2 analyze status Table is already up to date
+test.t3 analyze status Table is already up to date
+test.v1 analyze error 'test.v1' is not BASE TABLE
+Warnings:
+Error 1347 'test.v1' is not BASE TABLE
+call bug13012()|
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+test.t2 repair status OK
+test.t3 repair status OK
+test.v1 repair error 'test.v1' is not BASE TABLE
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+test.t2 optimize status OK
+test.t3 optimize status OK
+test.v1 optimize error 'test.v1' is not BASE TABLE
+Table Op Msg_type Msg_text
+test.t1 analyze status Table is already up to date
+test.t2 analyze status Table is already up to date
+test.t3 analyze status Table is already up to date
+test.v1 analyze error 'test.v1' is not BASE TABLE
+Warnings:
+Error 1347 'test.v1' is not BASE TABLE
+call bug13012()|
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+test.t2 repair status OK
+test.t3 repair status OK
+test.v1 repair error 'test.v1' is not BASE TABLE
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+test.t2 optimize status OK
+test.t3 optimize status OK
+test.v1 optimize error 'test.v1' is not BASE TABLE
+Table Op Msg_type Msg_text
+test.t1 analyze status Table is already up to date
+test.t2 analyze status Table is already up to date
+test.t3 analyze status Table is already up to date
+test.v1 analyze error 'test.v1' is not BASE TABLE
+Warnings:
+Error 1347 'test.v1' is not BASE TABLE
+drop procedure bug13012|
+drop view v1;
+select * from t1|
+id data
+aa 0
+aa 1
+aa 2
+aa 3
+aa 4
+aa 5
+aa 6
+aa 7
+aa 8
+aa 9
+drop schema if exists mysqltest1|
+Warnings:
+Note 1008 Can't drop database 'mysqltest1'; database doesn't exist
+drop schema if exists mysqltest2|
+Warnings:
+Note 1008 Can't drop database 'mysqltest2'; database doesn't exist
+drop schema if exists mysqltest3|
+Warnings:
+Note 1008 Can't drop database 'mysqltest3'; database doesn't exist
+create schema mysqltest1|
+create schema mysqltest2|
+create schema mysqltest3|
+use mysqltest3|
+create procedure mysqltest1.p1 (out prequestid varchar(100))
+begin
+call mysqltest2.p2('call mysqltest3.p3(1, 2)');
+end|
+create procedure mysqltest2.p2(in psql text)
+begin
+declare lsql text;
+set @lsql= psql;
+prepare lstatement from @lsql;
+execute lstatement;
+deallocate prepare lstatement;
+end|
+create procedure mysqltest3.p3(in p1 int)
+begin
+select p1;
+end|
+call mysqltest1.p1(@rs)|
+ERROR 42000: Incorrect number of arguments for PROCEDURE mysqltest3.p3; expected 1, got 2
+call mysqltest1.p1(@rs)|
+ERROR 42000: Incorrect number of arguments for PROCEDURE mysqltest3.p3; expected 1, got 2
+call mysqltest1.p1(@rs)|
+ERROR 42000: Incorrect number of arguments for PROCEDURE mysqltest3.p3; expected 1, got 2
+drop schema if exists mysqltest1|
+drop schema if exists mysqltest2|
+drop schema if exists mysqltest3|
+use test|
+drop table if exists t3|
+drop procedure if exists bug15441|
+create table t3 (id int not null primary key, county varchar(25))|
+insert into t3 (id, county) values (1, 'York')|
+create procedure bug15441(c varchar(25))
+begin
+update t3 set id=2, county=values(c);
+end|
+call bug15441('county')|
+ERROR 42S22: Unknown column 'c' in 'field list'
+drop procedure bug15441|
+create procedure bug15441(county varchar(25))
+begin
+declare c varchar(25) default "hello";
+insert into t3 (id, county) values (1, county)
+on duplicate key update county= values(county);
+select * from t3;
+update t3 set id=2, county=values(id);
+select * from t3;
+end|
+call bug15441('Yale')|
+id county
+1 Yale
+id county
+2 NULL
drop table t3|
+drop procedure bug15441|
drop table t1,t2;
diff --git a/mysql-test/r/sp_trans.result b/mysql-test/r/sp_trans.result
index bb742d0d3d7..8f2bd9985fc 100644
--- a/mysql-test/r/sp_trans.result
+++ b/mysql-test/r/sp_trans.result
@@ -369,3 +369,59 @@ drop procedure bug13825_0|
drop procedure bug13825_1|
drop procedure bug13825_2|
drop table t1, t2|
+drop table if exists t3|
+drop procedure if exists bug14840_1|
+drop procedure if exists bug14840_2|
+create table t3
+(
+x int,
+y int,
+primary key (x)
+) engine=InnoDB|
+create procedure bug14840_1()
+begin
+declare err int default 0;
+declare continue handler for sqlexception
+set err = err + 1;
+start transaction;
+update t3 set x = 1, y = 42 where x = 2;
+insert into t3 values (3, 4711);
+if err > 0 then
+rollback;
+else
+commit;
+end if;
+select * from t3;
+end|
+create procedure bug14840_2()
+begin
+declare err int default 0;
+declare continue handler for sqlexception
+begin
+set err = err + 1;
+select err as 'Ping';
+end;
+update t3 set x = 1, y = 42 where x = 2;
+update t3 set x = 1, y = 42 where x = 2;
+insert into t3 values (3, 4711);
+select * from t3;
+end|
+insert into t3 values (1, 3), (2, 5)|
+call bug14840_1()|
+x y
+1 3
+2 5
+delete from t3|
+insert into t3 values (1, 3), (2, 5)|
+call bug14840_2()|
+Ping
+1
+Ping
+2
+x y
+1 3
+2 5
+3 4711
+drop procedure bug14840_1|
+drop procedure bug14840_2|
+drop table t3|
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index d42e439f4de..6094d23b0d0 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -2988,3 +2988,146 @@ max(fld)
1
drop table t1;
purge master logs before (select adddate(current_timestamp(), interval -4 day));
+CREATE TABLE t1 (a int, b int);
+CREATE TABLE t2 (c int, d int);
+CREATE TABLE t3 (e int);
+INSERT INTO t1 VALUES
+(1,10), (2,10), (1,20), (2,20), (3,20), (2,30), (4,40);
+INSERT INTO t2 VALUES
+(2,10), (2,20), (4,10), (5,10), (3,20), (2,40);
+INSERT INTO t3 VALUES (10), (30), (10), (20) ;
+SELECT a, MAX(b), MIN(b) FROM t1 GROUP BY a;
+a MAX(b) MIN(b)
+1 20 10
+2 30 10
+3 20 20
+4 40 40
+SELECT * FROM t2;
+c d
+2 10
+2 20
+4 10
+5 10
+3 20
+2 40
+SELECT * FROM t3;
+e
+10
+30
+10
+20
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>20);
+a
+2
+4
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2 WHERE MAX(b)<d);
+a
+2
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>d);
+a
+2
+4
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2
+WHERE d >= SOME(SELECT e FROM t3 WHERE MAX(b)=e));
+a
+2
+3
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2
+WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d));
+a
+2
+3
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2
+WHERE d > SOME(SELECT e FROM t3 WHERE MAX(b)=e));
+a
+2
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2
+WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e < d));
+a
+2
+SELECT a FROM t1 GROUP BY a
+HAVING a IN (SELECT c FROM t2
+WHERE MIN(b) < d AND
+EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d));
+a
+2
+SELECT a, SUM(a) FROM t1 GROUP BY a;
+a SUM(a)
+1 2
+2 6
+3 3
+4 4
+SELECT a FROM t1
+WHERE EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c) GROUP BY a;
+a
+3
+4
+SELECT a FROM t1 GROUP BY a
+HAVING EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c);
+a
+1
+3
+4
+SELECT a FROM t1
+WHERE a < 3 AND
+EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c) GROUP BY a;
+a
+1
+2
+SELECT a FROM t1
+WHERE a < 3 AND
+EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c);
+a
+1
+2
+1
+2
+2
+SELECT t1.a FROM t1 GROUP BY t1.a
+HAVING t1.a < ALL(SELECT t2.c FROM t2 GROUP BY t2.c
+HAVING EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e
+HAVING SUM(t1.a+t2.c) < t3.e/4));
+a
+1
+2
+SELECT t1.a FROM t1 GROUP BY t1.a
+HAVING t1.a > ALL(SELECT t2.c FROM t2
+WHERE EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e
+HAVING SUM(t1.a+t2.c) < t3.e/4));
+a
+4
+SELECT t1.a FROM t1 GROUP BY t1.a
+HAVING t1.a > ALL(SELECT t2.c FROM t2
+WHERE EXISTS(SELECT t3.e FROM t3
+WHERE SUM(t1.a+t2.c) < t3.e/4));
+ERROR HY000: Invalid use of group function
+SELECT t1.a from t1 GROUP BY t1.a HAVING AVG(SUM(t1.b)) > 20;
+ERROR HY000: Invalid use of group function
+SELECT t1.a FROM t1 GROUP BY t1.a
+HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+HAVING AVG(t2.c+SUM(t1.b)) > 20);
+a
+2
+3
+4
+SELECT t1.a FROM t1 GROUP BY t1.a
+HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+HAVING AVG(SUM(t1.b)) > 20);
+a
+2
+4
+SELECT t1.a, SUM(b) AS sum FROM t1 GROUP BY t1.a
+HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+HAVING t2.c+sum > 20);
+a sum
+2 60
+3 20
+4 40
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/r/sum_distinct-big.result b/mysql-test/r/sum_distinct-big.result
index 06bfc6b1f78..9b55d59ab91 100644
--- a/mysql-test/r/sum_distinct-big.result
+++ b/mysql-test/r/sum_distinct-big.result
@@ -1,5 +1,4 @@
-using_big_test
-0
+DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (id INTEGER);
CREATE TABLE t2 (id INTEGER);
INSERT INTO t1 (id) VALUES (1), (1), (1),(1);
@@ -40,19 +39,19 @@ AVG(DISTINCT id)
512.5000
SELECT SUM(DISTINCT id)/COUNT(DISTINCT id) FROM t1 GROUP BY id % 13;
SUM(DISTINCT id)/COUNT(DISTINCT id)
-513.50000
-508.00000
-509.00000
-510.00000
-511.00000
-512.00000
-513.00000
-514.00000
-515.00000
-516.00000
-517.00000
-511.50000
-512.50000
+513.5000
+508.0000
+509.0000
+510.0000
+511.0000
+512.0000
+513.0000
+514.0000
+515.0000
+516.0000
+517.0000
+511.5000
+512.5000
INSERT INTO t1 SELECT id+1024 FROM t1;
INSERT INTO t1 SELECT id+2048 FROM t1;
INSERT INTO t1 SELECT id+4096 FROM t1;
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 0ad5c485b28..38dff6f8ca5 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -779,3 +779,9 @@ end//
CALL p1();
drop procedure p1;
drop table t1;
+create trigger t1_bi before insert on test.t1 for each row set @a:=0;
+ERROR 3D000: No database selected
+create trigger test.t1_bi before insert on t1 for each row set @a:=0;
+ERROR 3D000: No database selected
+drop trigger t1_bi;
+ERROR 3D000: No database selected
diff --git a/mysql-test/r/type_binary.result b/mysql-test/r/type_binary.result
index 1c60bf46608..597defb7a9b 100644
--- a/mysql-test/r/type_binary.result
+++ b/mysql-test/r/type_binary.result
@@ -114,3 +114,26 @@ drop table t1;
select hex(cast(0x10 as binary(2)));
hex(cast(0x10 as binary(2)))
1000
+create table t1 (b binary(2), vb varbinary(2));
+insert into t1 values(0x4120, 0x4120);
+insert into t1 values(0x412020, 0x412020);
+Warnings:
+Warning 1265 Data truncated for column 'b' at row 1
+Warning 1265 Data truncated for column 'vb' at row 1
+drop table t1;
+create table t1 (c char(2), vc varchar(2));
+insert into t1 values(0x4120, 0x4120);
+insert into t1 values(0x412020, 0x412020);
+Warnings:
+Note 1265 Data truncated for column 'vc' at row 1
+drop table t1;
+set @old_sql_mode= @@sql_mode, sql_mode= 'traditional';
+create table t1 (b binary(2), vb varbinary(2));
+insert into t1 values(0x4120, 0x4120);
+insert into t1 values(0x412020, NULL);
+ERROR 22001: Data too long for column 'b' at row 1
+insert into t1 values(NULL, 0x412020);
+ERROR 22001: Data too long for column 'vb' at row 1
+drop table t1;
+set @@sql_mode= @old_sql_mode;
+End of 5.0 tests
diff --git a/mysql-test/r/type_newdecimal-big.result b/mysql-test/r/type_newdecimal-big.result
new file mode 100644
index 00000000000..4e694702d14
--- /dev/null
+++ b/mysql-test/r/type_newdecimal-big.result
@@ -0,0 +1,26 @@
+drop procedure if exists sp1;
+CREATE PROCEDURE sp1()
+BEGIN
+DECLARE v1, v2, v3, v4 DECIMAL(28,12);
+DECLARE v3_2, v4_2 DECIMAL(28, 12);
+DECLARE counter INT;
+SET v1 = 1;
+SET v2 = 2;
+SET v3 = 1000000000000;
+SET v4 = 2000000000000;
+SET counter = 0;
+WHILE counter < 100000 DO
+SET v1 = v1 + 0.000000000001;
+SET v2 = v2 - 0.000000000001;
+SET v3 = v3 + 1;
+SET v4 = v4 - 1;
+SET counter = counter + 1;
+END WHILE;
+SET v3_2 = v3 * 0.000000000001;
+SET v4_2 = v4 * 0.000000000001;
+SELECT v1, v2, v3, v3_2, v4, v4_2;
+END//
+call sp1()//
+v1 v2 v3 v3_2 v4 v4_2
+1.000000100000 1.999999900000 1000000100000.000000000000 1.000000100000 1999999900000.000000000000 1.999999900000
+drop procedure sp1;
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index 7d7fe7efa35..938dccc864c 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -678,16 +678,6 @@ select -18.3=18.3;
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.000000100000 1.999999900000
-drop procedure p1;
drop table if exists t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -1267,34 +1257,6 @@ CAST(my_varchar AS DECIMAL(65,30)) my_varchar
0.011754943450000000000000000000 1.175494345e-2
0.117549434500000000000000000000 1.175494345e-1
UPDATE t1 SET my_decimal = my_float;
-Warnings:
-Note 1265 Data truncated for column 'my_decimal' at row 1
-Note 1265 Data truncated for column 'my_decimal' at row 2
-Note 1265 Data truncated for column 'my_decimal' at row 3
-Note 1265 Data truncated for column 'my_decimal' at row 4
-Note 1265 Data truncated for column 'my_decimal' at row 5
-Note 1265 Data truncated for column 'my_decimal' at row 6
-Note 1265 Data truncated for column 'my_decimal' at row 7
-Note 1265 Data truncated for column 'my_decimal' at row 8
-Note 1265 Data truncated for column 'my_decimal' at row 9
-Note 1265 Data truncated for column 'my_decimal' at row 10
-Note 1265 Data truncated for column 'my_decimal' at row 11
-Note 1265 Data truncated for column 'my_decimal' at row 12
-Note 1265 Data truncated for column 'my_decimal' at row 13
-Note 1265 Data truncated for column 'my_decimal' at row 14
-Note 1265 Data truncated for column 'my_decimal' at row 15
-Note 1265 Data truncated for column 'my_decimal' at row 16
-Note 1265 Data truncated for column 'my_decimal' at row 17
-Note 1265 Data truncated for column 'my_decimal' at row 19
-Note 1265 Data truncated for column 'my_decimal' at row 20
-Note 1265 Data truncated for column 'my_decimal' at row 21
-Note 1265 Data truncated for column 'my_decimal' at row 22
-Note 1265 Data truncated for column 'my_decimal' at row 23
-Note 1265 Data truncated for column 'my_decimal' at row 26
-Note 1265 Data truncated for column 'my_decimal' at row 27
-Note 1265 Data truncated for column 'my_decimal' at row 30
-Note 1265 Data truncated for column 'my_decimal' at row 31
-Note 1265 Data truncated for column 'my_decimal' at row 32
SELECT my_decimal, my_float FROM t1;
my_decimal my_float
0.000000000000000000000000000000 1.17549e-32
@@ -1330,24 +1292,6 @@ my_decimal my_float
0.011754943057894710000000000000 0.0117549
0.117549434304237400000000000000 0.117549
UPDATE t1 SET my_decimal = my_double;
-Warnings:
-Note 1265 Data truncated for column 'my_decimal' at row 1
-Note 1265 Data truncated for column 'my_decimal' at row 2
-Note 1265 Data truncated for column 'my_decimal' at row 3
-Note 1265 Data truncated for column 'my_decimal' at row 4
-Note 1265 Data truncated for column 'my_decimal' at row 5
-Note 1265 Data truncated for column 'my_decimal' at row 6
-Note 1265 Data truncated for column 'my_decimal' at row 7
-Note 1265 Data truncated for column 'my_decimal' at row 8
-Note 1265 Data truncated for column 'my_decimal' at row 9
-Note 1265 Data truncated for column 'my_decimal' at row 10
-Note 1265 Data truncated for column 'my_decimal' at row 11
-Note 1265 Data truncated for column 'my_decimal' at row 13
-Note 1265 Data truncated for column 'my_decimal' at row 14
-Note 1265 Data truncated for column 'my_decimal' at row 16
-Note 1265 Data truncated for column 'my_decimal' at row 18
-Note 1265 Data truncated for column 'my_decimal' at row 20
-Note 1265 Data truncated for column 'my_decimal' at row 31
SELECT my_decimal, my_double FROM t1;
my_decimal my_double
0.000000000000000000000000000000 1.175494345e-32
diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result
index ff07dcca106..bcdba3dca76 100644
--- a/mysql-test/r/type_ranges.result
+++ b/mysql-test/r/type_ranges.result
@@ -215,7 +215,7 @@ Field Type Collation Null Key Default Extra Privileges Comment
auto int(5) unsigned NULL NO MUL NULL auto_increment #
string char(10) latin1_swedish_ci YES newdefault #
tiny tinyint(4) NULL NO MUL 0 #
-short smallint(6) NULL NO MUL 0 #
+short smallint(6) NULL NO MUL #
medium mediumint(8) NULL NO MUL 0 #
long_int int(11) NULL NO 0 #
longlong bigint(13) NULL NO MUL 0 #
diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index 442435b0459..deb60a95f21 100644
--- a/mysql-test/r/type_time.result
+++ b/mysql-test/r/type_time.result
@@ -85,3 +85,27 @@ sec_to_time(time_to_sec(t))
13:00:00
09:00:00
drop table t1;
+SELECT CAST(235959.123456 AS TIME);
+CAST(235959.123456 AS TIME)
+23:59:59.123456
+SELECT CAST(0.235959123456e+6 AS TIME);
+CAST(0.235959123456e+6 AS TIME)
+23:59:59.123456
+SELECT CAST(235959123456e-6 AS TIME);
+CAST(235959123456e-6 AS TIME)
+23:59:59.123456
+SELECT CAST(235959.1234567 AS TIME);
+CAST(235959.1234567 AS TIME)
+23:59:59.123456
+Warnings:
+Warning 1292 Truncated incorrect time value: '235959.1234567'
+SELECT CAST(0.2359591234567e6 AS TIME);
+CAST(0.2359591234567e6 AS TIME)
+23:59:59.123456
+Warnings:
+Warning 1292 Truncated incorrect time value: '235959.1234567'
+SELECT CAST(0.2359591234567e+30 AS TIME);
+CAST(0.2359591234567e+30 AS TIME)
+NULL
+Warnings:
+Warning 1292 Truncated incorrect time value: '2.359591234567e+29'
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index 042dfb5ad8d..f2708a50c77 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -1220,6 +1220,32 @@ show columns from t2;
Field Type Null Key Default Extra
a varchar(3) YES NULL
drop table t2, t1;
+create table t1 (f1 decimal(60,25), f2 decimal(60,25));
+insert into t1 values (0.0,0.0);
+select f1 from t1 union all select f2 from t1;
+f1
+0.0000000000000000000000000
+0.0000000000000000000000000
+select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1
+union all
+select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1;
+description f1
+XXXXXXXXXXXXXXXXXXXX 0.0000000000000000000000000
+YYYYYYYYYYYYYYYYYYYY 0.0000000000000000000000000
+drop table t1;
+create table t1 (f1 decimal(60,24), f2 decimal(60,24));
+insert into t1 values (0.0,0.0);
+select f1 from t1 union all select f2 from t1;
+f1
+0.000000000000000000000000
+0.000000000000000000000000
+select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1
+union all
+select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1;
+description f1
+XXXXXXXXXXXXXXXXXXXX 0.000000000000000000000000
+YYYYYYYYYYYYYYYYYYYY 0.000000000000000000000000
+drop table t1;
create table t1 (a varchar(5));
create table t2 select * from t1 union select 'abcdefghijkl';
show create table t2;
diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result
index aeb44fa4e6c..abeade5df0c 100644
--- a/mysql-test/r/update.result
+++ b/mysql-test/r/update.result
@@ -345,3 +345,16 @@ f1
2000-01-01
2002-02-02
drop table t1;
+create table t1 (f1 int);
+create table t2 (f2 int);
+insert into t1 values(1),(2);
+insert into t2 values(1),(1);
+update t1,t2 set f1=3,f2=3 where f1=f2 and f1=1;
+affected rows: 3
+info: Rows matched: 3 Changed: 3 Warnings: 0
+update t2 set f2=1;
+update t1 set f1=1 where f1=3;
+update t2,t1 set f1=3,f2=3 where f1=f2 and f1=1;
+affected rows: 3
+info: Rows matched: 3 Changed: 3 Warnings: 0
+drop table t1,t2;
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index c26671ac937..b9380dcf033 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -1933,11 +1933,11 @@ create function f1 () returns int return (select max(col1) from t1);
DROP TABLE t1;
CHECK TABLE v1, v2, v3, v4, v5, v6;
Table Op Msg_type Msg_text
-test.v1 check error Table 'test.t1' doesn't exist
+test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
test.v2 check status OK
-test.v3 check error Table 'test.t1' doesn't exist
+test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
test.v4 check status OK
-test.v5 check error Table 'test.t1' doesn't exist
+test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
test.v6 check status OK
drop function f1;
drop function f2;
@@ -2383,20 +2383,25 @@ CREATE TABLE t1(id INT);
CREATE VIEW v1 AS SELECT id FROM t1;
OPTIMIZE TABLE v1;
Table Op Msg_type Msg_text
-test.v1 optimize note Unknown table 'test.v1'
+test.v1 optimize error 'test.v1' is not BASE TABLE
+Warnings:
+Error 1347 'test.v1' is not BASE TABLE
ANALYZE TABLE v1;
Table Op Msg_type Msg_text
-test.v1 analyze note Unknown table 'test.v1'
+test.v1 analyze error 'test.v1' is not BASE TABLE
+Warnings:
+Error 1347 'test.v1' is not BASE TABLE
REPAIR TABLE v1;
Table Op Msg_type Msg_text
-test.v1 repair note Unknown table 'test.v1'
+test.v1 repair error 'test.v1' is not BASE TABLE
+Warnings:
+Error 1347 'test.v1' is not BASE TABLE
DROP TABLE t1;
OPTIMIZE TABLE v1;
Table Op Msg_type Msg_text
-test.v1 optimize note Unknown table 'test.v1'
+test.v1 optimize error 'test.v1' is not BASE TABLE
Warnings:
-Error 1146 Table 'test.t1' doesn't exist
-Error 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+Error 1347 'test.v1' is not BASE TABLE
DROP VIEW v1;
create definer = current_user() sql security invoker view v1 as select 1;
show create view v1;
@@ -2427,3 +2432,46 @@ f1 sum(f2)
NULL 12
drop view v1;
drop table t1;
+drop procedure if exists p1;
+create procedure p1 () deterministic
+begin
+create view v1 as select 1;
+end;
+//
+call p1();
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`
+drop view v1;
+drop procedure p1;
+CREATE VIEW v1 AS SELECT 42 AS Meaning;
+DROP FUNCTION IF EXISTS f1;
+CREATE FUNCTION f1() RETURNS INTEGER
+BEGIN
+DECLARE retn INTEGER;
+SELECT Meaning FROM v1 INTO retn;
+RETURN retn;
+END
+//
+CREATE VIEW v2 AS SELECT f1();
+select * from v2;
+f1()
+42
+drop view v2,v1;
+drop function f1;
+create table t1 (id numeric, warehouse_id numeric);
+create view v1 as select id from t1;
+create view v2 as
+select t1.warehouse_id, v1.id as receipt_id
+from t1, v1 where t1.id = v1.id;
+insert into t1 (id, warehouse_id) values(3, 2);
+insert into t1 (id, warehouse_id) values(4, 2);
+insert into t1 (id, warehouse_id) values(5, 1);
+select v2.receipt_id as alias1, v2.receipt_id as alias2 from v2
+order by v2.receipt_id;
+alias1 alias2
+3 3
+4 4
+5 5
+drop view v2, v1;
+drop table t1;
diff --git a/mysql-test/r/view_query_cache.result b/mysql-test/r/view_query_cache.result
index 944e1db34c9..03430bd504b 100644
--- a/mysql-test/r/view_query_cache.result
+++ b/mysql-test/r/view_query_cache.result
@@ -132,4 +132,65 @@ unlock tables;
set query_cache_wlock_invalidate=default;
drop view v1;
drop table t1;
+flush status;
+create table t1 (a int, b int);
+create algorithm=temptable view v1 as select * from t1;
+select * from v1;
+a b
+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 v1;
+a b
+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 1
+insert into t1 values (1,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 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+select * from v1;
+a b
+1 1
+select * from v1;
+a b
+1 1
+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 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+drop view v1;
+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 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+drop table t1;
set GLOBAL query_cache_size=default;
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index bae94656125..f4245abfe86 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -340,7 +340,9 @@ drop table t1;
#
# BUG 12207 alter table ... discard table space on MyISAM table causes ERROR 2013 (HY000)
#
+# Some platforms (Mac OS X, Windows) will send the error message using small letters.
CREATE TABLE T12207(a int) ENGINE=MYISAM;
+--replace_result t12207 T12207
--error 1031
ALTER TABLE T12207 DISCARD TABLESPACE;
DROP TABLE T12207;
@@ -401,3 +403,12 @@ use test;
drop table t1;
# End of 4.1 tests
+
+#
+# Bug #14693 (ALTER SET DEFAULT doesn't work)
+#
+
+create table t1 (mycol int(10) not null);
+alter table t1 alter column mycol set default 0;
+desc t1;
+drop table t1;
diff --git a/mysql-test/t/analyze.test b/mysql-test/t/analyze.test
index 5d653b65579..656ff752c9b 100644
--- a/mysql-test/t/analyze.test
+++ b/mysql-test/t/analyze.test
@@ -39,6 +39,20 @@ check table t1;
drop table t1;
+# Bug #14902 ANALYZE TABLE fails to recognize up-to-date tables
+# minimal test case to get an error.
+# The problem is happening when analysing table with FT index that
+# contains stopwords only. The first execution of analyze table should
+# mark index statistics as up to date so that next execution of this
+# statement will end up with Table is up to date status.
+create table t1 (a mediumtext, fulltext key key1(a)) charset utf8 collate utf8_general_ci engine myisam;
+insert into t1 values ('hello');
+
+analyze table t1;
+analyze table t1;
+
+drop table t1;
+
#
# procedure in PS BUG#13673
#
diff --git a/mysql-test/t/backup.test b/mysql-test/t/backup.test
index 3034129ad4b..40a9fa73b60 100644
--- a/mysql-test/t/backup.test
+++ b/mysql-test/t/backup.test
@@ -52,5 +52,6 @@ unlock tables;
connection con1;
reap;
drop table t5;
+--system rm $MYSQL_TEST_DIR/var/tmp/t?.*
# End of 4.1 tests
diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test
index 97d8f28cd3f..d3068b29e28 100644
--- a/mysql-test/t/bdb.test
+++ b/mysql-test/t/bdb.test
@@ -938,7 +938,25 @@ SELECT id FROM t1 WHERE (list_id = 1) AND (term = "lettera");
SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd");
DROP TABLE t1;
-# End of 4.1 tests
+#
+# Bug #15536: Crash when DELETE with subquery using BDB tables
+#
+create table t1 (a int, key(a)) engine=bdb;
+create table t2 (b int, key(b)) engine=bdb;
+insert into t1 values (1),(1),(2),(3),(4);
+insert into t2 values (1),(5),(6),(7);
+delete from t1 where (a in (select b from t2));
+select count(*) from t1;
+# INSERT also blows up
+--error 1242
+insert into t1 set a=(select b from t2);
+select count(*) from t1;
+# UPDATE also blows up
+update t1 set a = a + 1 where (a in (select b from t2));
+select count(*) from t1;
+drop table t1, t2;
+
+--echo End of 4.1 tests
#
# alter temp table
@@ -974,3 +992,22 @@ drop table t1;
# End varchar test
eval set storage_engine=$default;
+
+#
+# Test that we can create a large key
+#
+create table t1 (a varchar(255) character set utf8,
+ b varchar(255) character set utf8,
+ c varchar(255) character set utf8,
+ d varchar(255) character set utf8,
+ key (a,b,c,d)) engine=bdb;
+drop table t1;
+--error ER_TOO_LONG_KEY
+create table t1 (a varchar(255) character set utf8,
+ b varchar(255) character set utf8,
+ c varchar(255) character set utf8,
+ d varchar(255) character set utf8,
+ e varchar(255) character set utf8,
+ key (a,b,c,d,e)) engine=bdb;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/count_distinct3.test b/mysql-test/t/count_distinct3.test
index 52a4f271dac..f817b2c635d 100644
--- a/mysql-test/t/count_distinct3.test
+++ b/mysql-test/t/count_distinct3.test
@@ -17,7 +17,7 @@ while ($1)
SET @rnd= RAND();
SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
SET @id_rev= @rnd_max - @id;
- SET @grp= CAST(128.0 * @rnd AS UNSIGNED);
+ SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
dec $1;
}
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index fcbdff7ec5b..162db3d0c0a 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -218,13 +218,6 @@ create table if not exists t1 select 1,2,3,4;
create table if not exists t1 select 1;
select * from t1;
drop table t1;
-create table t1 select 1,2,3;
-create table if not exists t1 select 1,2;
---error 1136
-create table if not exists t1 select 1,2,3,4;
-create table if not exists t1 select 1;
-select * from t1;
-drop table t1;
#
# Test create table if not exists with duplicate key error
@@ -647,3 +640,17 @@ show create table t2;
drop table t1, t2;
# End of 4.1 tests
+
+#
+# Bug #14155: Maximum value of MAX_ROWS handled incorrectly on 64-bit
+# platforms
+#
+create table t1 (i int) engine=myisam max_rows=100000000000;
+show create table t1;
+alter table t1 max_rows=100;
+show create table t1;
+alter table t1 max_rows=100000000000;
+show create table t1;
+drop table t1;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/ctype_recoding.test b/mysql-test/t/ctype_recoding.test
index 9949ef88da4..5648cea7fd3 100644
--- a/mysql-test/t/ctype_recoding.test
+++ b/mysql-test/t/ctype_recoding.test
@@ -144,8 +144,7 @@ create table t1 (a char(10) character set cp1251);
insert into t1 values (_koi8r'×ÁÓÑ');
# this is possible:
select * from t1 where a=_koi8r'×ÁÓÑ';
-# this is not possible, because we have a function, not just a constant:
---error 1267
+# this is possible, because we have a function with constant arguments:
select * from t1 where a=concat(_koi8r'×ÁÓÑ');
# this is not posible, cannot convert _latin1'×ÁÓÑ' into cp1251:
--error 1267
@@ -154,6 +153,14 @@ drop table t1;
set names latin1;
#
+# Bug#10446 Illegal mix of collations
+#
+create table t1 (a char(10) character set utf8 collate utf8_bin);
+insert into t1 values (' xxx');
+select * from t1 where a=lpad('xxx',10,' ');
+drop table t1;
+
+#
# Check more automatic conversion
#
set names koi8r;
diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test
index 6d8713f4910..3e49b9de883 100644
--- a/mysql-test/t/ctype_uca.test
+++ b/mysql-test/t/ctype_uca.test
@@ -212,6 +212,7 @@ select group_concat(c1 order by c1) from t1 group by c1 collate utf8_slovak_ci;
select group_concat(c1 order by c1) from t1 group by c1 collate utf8_spanish2_ci;
select group_concat(c1 order by c1) from t1 group by c1 collate utf8_roman_ci;
select group_concat(c1 order by c1) from t1 group by c1 collate utf8_esperanto_ci;
+select group_concat(c1 order by c1) from t1 group by c1 collate utf8_hungarian_ci;
drop table t1;
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 626c7e0e1b6..04de13f8228 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -421,6 +421,14 @@ insert into t1 values (0x005b);
select hex(a) from t1;
drop table t1;
+#
+# Bug #14583 Bug on query using a LIKE on indexed field with ucs2_bin collation
+#
+create table t1(f1 varchar(5) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL) engine=InnoDB;
+insert into t1 values('a');
+create index t1f1 on t1(f1);
+select f1 from t1 where f1 like 'a%';
+drop table t1;
# End of 4.1 tests
#
diff --git a/mysql-test/t/ctype_ujis.test b/mysql-test/t/ctype_ujis.test
index c1d6c67387b..77d250b5c45 100644
--- a/mysql-test/t/ctype_ujis.test
+++ b/mysql-test/t/ctype_ujis.test
@@ -1170,7 +1170,7 @@ INSERT INTO t1 VALUES(_ujis 0xA4A2);
DELIMITER |;
CREATE PROCEDURE sp1()
BEGIN
- DECLARE a CHAR(1);
+ DECLARE a CHAR(2) CHARSET ujis;
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
OPEN cur1;
FETCH cur1 INTO a;
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 5670e9efbf9..a96564f4e76 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -884,7 +884,9 @@ SELECT DISTINCT id FROM t1 ORDER BY id;
DROP TABLE t1;
#
-# Bugs#10504: Character set does not support traditional mode
+# Bug#10504: Character set does not support traditional mode
+# Bug#14146: CHAR(...USING ...) and CONVERT(CHAR(...) USING...)
+# produce different results
#
set names utf8;
# correct value
@@ -894,12 +896,14 @@ select char(0xd18f using utf8);
select char(53647 using utf8);
# incorrect value: return with warning
select char(0xff,0x8f using utf8);
+select convert(char(0xff,0x8f) using utf8);
# incorrect value in strict mode: return NULL with "Error" level warning
set sql_mode=traditional;
select char(0xff,0x8f using utf8);
select char(195 using utf8);
select char(196 using utf8);
select char(2557 using utf8);
+select convert(char(0xff,0x8f) using utf8);
#
# Check convert + char + using
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index b96aa7befd9..a209088f202 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -11,6 +11,5 @@
##############################################################################
sp-goto : GOTO is currently is disabled - will be fixed in the future
-rpl_relayrotate : Unstable test case, bug#12429
-rpl_until : Unstable test case, bug#12429
-rpl_deadlock : Unstable test case, bug#12429
+subselect : Bug#15706
+type_time : Bug#15805
diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test
index de2576300dc..19a47b2893a 100644
--- a/mysql-test/t/flush_read_lock_kill.test
+++ b/mysql-test/t/flush_read_lock_kill.test
@@ -42,7 +42,7 @@ connection con1;
# debug build running without our --debug=make_global..., will be
# error 0 (no error). The only important thing to test is that on
# debug builds with our --debug=make_global... we don't hang forever.
---error 0,1053
+--error 0,1053,2013
reap;
connection con2;
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index b52c5d0ec08..ea92ec944ed 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -354,6 +354,7 @@ SET myisam_repair_threads=@@global.myisam_repair_threads;
#
INSERT INTO t1 VALUES('testword\'\'');
SELECT a FROM t1 WHERE MATCH a AGAINST('testword' IN BOOLEAN MODE);
+SELECT a FROM t1 WHERE MATCH a AGAINST('testword\'\'' IN BOOLEAN MODE);
DROP TABLE t1;
# End of 4.1 tests
diff --git a/mysql-test/t/fulltext2.test b/mysql-test/t/fulltext2.test
index bcd39b9ea04..7a7b572d58f 100644
--- a/mysql-test/t/fulltext2.test
+++ b/mysql-test/t/fulltext2.test
@@ -179,7 +179,37 @@ update t1 set a='aaaxxx' where a = 'aaayyy';
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+drop table t1;
+
+#
+# BUG#11336
+#
+# for uca collation isalnum and strnncollsp don't agree on whether
+# 0xC2A0 is a space (strnncollsp is right, isalnum is wrong).
+#
+# they still don't, the bug was fixed by avoiding strnncollsp
+#
+set names utf8;
+create table t1(a text,fulltext(a)) collate=utf8_swedish_ci;
+insert into t1 values('test test '),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test');
+delete from t1 limit 1;
drop table t1;
+set names latin1;
# End of 4.1 tests
diff --git a/mysql-test/t/func_equal.test b/mysql-test/t/func_equal.test
index 4c88ed170a1..1c219af0254 100644
--- a/mysql-test/t/func_equal.test
+++ b/mysql-test/t/func_equal.test
@@ -34,4 +34,13 @@ select * from t1 where value <=> value;
select * from t1 where id <=> value or value<=>id;
drop table t1,t2;
+#
+# Bug #12612: quoted bigint unsigned value and the use of "in" in where clause
+#
+create table t1 (a bigint unsigned);
+insert into t1 values (4828532208463511553);
+select * from t1 where a = '4828532208463511553';
+select * from t1 where a in ('4828532208463511553');
+drop table t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test
index cd686585dd8..058df9af56b 100644
--- a/mysql-test/t/func_gconcat.test
+++ b/mysql-test/t/func_gconcat.test
@@ -69,7 +69,7 @@ set group_concat_max_len = 1024;
# Test errors
--error 1111
-select group_concat(sum(a)) from t1 group by grp;
+select group_concat(sum(c)) from t1 group by grp;
--error 1054
select grp,group_concat(c order by 2) from t1 group by grp;
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 635c7a3f4e7..e806df5e91c 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -487,4 +487,16 @@ flush privileges;
set @user123="non-existent";
select * from mysql.db where user=@user123;
+set names koi8r;
+create database ÂÄ;
+grant select on ÂÄ.* to root@localhost;
+select hex(Db) from mysql.db where Db='ÂÄ';
+show grants for root@localhost;
+flush privileges;
+show grants for root@localhost;
+drop database ÂÄ;
+revoke all privileges on ÂÄ.* from root@localhost;
+show grants for root@localhost;
+set names latin1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test
index 2fa82ce5dce..c19bb1482d6 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -155,6 +155,38 @@ flush privileges;
drop database mysqltest;
use test;
+
+#
+# Bug #15775: "drop user" command does not refresh acl_check_hosts
+#
+
+# Create some test users
+create user mysqltest_1@host1;
+create user mysqltest_2@host2;
+create user mysqltest_3@host3;
+create user mysqltest_4@host4;
+create user mysqltest_5@host5;
+create user mysqltest_6@host6;
+create user mysqltest_7@host7;
+flush privileges;
+
+# Drop one user
+drop user mysqltest_3@host3;
+
+# This connect failed before fix since the acl_check_hosts list was corrupted by the "drop user"
+connect (con8,127.0.0.1,root,,test,$MASTER_MYPORT,);
+disconnect con8;
+connection default;
+
+# Clean up - Drop all of the remaining users at once
+drop user mysqltest_1@host1, mysqltest_2@host2, mysqltest_4@host4,
+ mysqltest_5@host5, mysqltest_6@host6, mysqltest_7@host7;
+
+# Check that it's still possible to connect
+connect (con9,127.0.0.1,root,,test,$MASTER_MYPORT,);
+disconnect con9;
+connection default;
+
#
# Create and drop user
#
diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test
index 3d751f4a571..e15ef92116c 100644
--- a/mysql-test/t/group_min_max.test
+++ b/mysql-test/t/group_min_max.test
@@ -693,3 +693,25 @@ create table t1(a int, key(a)) engine=innodb;
insert into t1 values(1);
select a, count(a) from t1 group by a with rollup;
drop table t1;
+
+#
+# Bug #13293 Wrongly used index results in endless loop.
+#
+create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb;
+insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d");
+alter table t1 drop primary key, add primary key (f2, f1);
+explain select distinct f1 a, f1 b from t1;
+explain select distinct f1, f2 from t1;
+drop table t1;
+
+#
+# Bug #14920 Ordering aggregated result sets with composite primary keys
+# corrupts resultset
+#
+create table t1 (c1 int not null,c2 int not null, primary key(c1,c2));
+insert into t1 (c1,c2) values
+(10,1),(10,2),(10,3),(20,4),(20,5),(20,6),(30,7),(30,8),(30,9);
+select distinct c1, c2 from t1 order by c2;
+select c1,min(c2) as c2 from t1 group by c1 order by c2;
+select c1,c2 from t1 group by c1,c2 order by c2;
+drop table t1;
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index 1cd55926e80..f835a7148a2 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -738,3 +738,55 @@ create table t1(a blob, b text charset utf8, c text charset ucs2);
select data_type, character_octet_length, character_maximum_length
from information_schema.columns where table_name='t1';
drop table t1;
+
+#
+# Bug#14476 `information_schema`.`TABLES`.`TABLE_TYPE` with empty value
+#
+create table t1 (f1 int(11));
+create view v1 as select * from t1;
+drop table t1;
+select table_type from information_schema.tables
+where table_name="v1";
+drop view v1;
+
+#
+# Bug #14387 SHOW COLUMNS doesn't work on temporary tables
+# Bug #15224 SHOW INDEX from temporary table doesn't work
+# Bug #12770 DESC cannot display the info. about temporary table
+#
+create temporary table t1(f1 int, index(f1));
+show columns from t1;
+describe t1;
+show indexes from t1;
+drop table t1;
+
+#
+# Bug#14271 I_S: columns has no size for (var)binary columns
+#
+create table t1(f1 binary(32), f2 varbinary(64));
+select character_maximum_length, character_octet_length
+from information_schema.columns where table_name='t1';
+drop table t1;
+
+#
+# Bug#15533 crash, information_schema, function, view
+#
+CREATE TABLE t1 (f1 BIGINT, f2 VARCHAR(20), f3 BIGINT);
+INSERT INTO t1 SET f1 = 1, f2 = 'Schoenenbourg', f3 = 1;
+
+CREATE FUNCTION func2() RETURNS BIGINT RETURN 1;
+
+delimiter //;
+CREATE FUNCTION func1() RETURNS BIGINT
+BEGIN
+ RETURN ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.VIEWS);
+END//
+delimiter ;//
+
+CREATE VIEW v1 AS SELECT 1 FROM t1
+ WHERE f3 = (SELECT func2 ());
+SELECT func1();
+DROP TABLE t1;
+DROP VIEW v1;
+DROP FUNCTION func1;
+DROP FUNCTION func2;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index cf0e08e2e66..887d8193157 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1356,8 +1356,8 @@ source include/varchar.inc;
# Clean up filename -- embedded server reports whole path without .frm,
# regular server reports relative path with .frm (argh!)
--replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ / t1.frm t1
---error 1005
create table t1 (v varchar(65530), key(v));
+drop table t1;
create table t1 (v varchar(65536));
show create table t1;
drop table t1;
@@ -1485,7 +1485,7 @@ CREATE TEMPORARY TABLE t2
DROP TABLE t1;
#
-# Test that index column max sizes are checked (bug #13315)
+# Test that index column max sizes are honored (bug #13315)
#
# prefix index
@@ -1512,22 +1512,36 @@ create table t8 (col1 blob, index(col1(767)))
create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2))
character set = latin1 engine = innodb;
+show create table t9;
+
drop table t1, t2, t3, t4, t5, t6, t7, t8, t9;
---error 1005
-create table t1 (col1 varchar(768), index (col1))
+# these should have their index length trimmed
+create table t1 (col1 varchar(768), index(col1))
character set = latin1 engine = innodb;
---error 1005
-create table t2 (col1 varchar(768) primary key)
+create table t2 (col1 varbinary(768), index(col1))
character set = latin1 engine = innodb;
---error 1005
-create table t3 (col1 varbinary(768) primary key)
+create table t3 (col1 text, index(col1(768)))
character set = latin1 engine = innodb;
---error 1005
-create table t4 (col1 text, index(col1(768)))
+create table t4 (col1 blob, index(col1(768)))
character set = latin1 engine = innodb;
---error 1005
-create table t5 (col1 blob, index(col1(768)))
+
+show create table t1;
+
+drop table t1, t2, t3, t4;
+
+# these should be refused
+--error 1071
+create table t1 (col1 varchar(768) primary key)
+ character set = latin1 engine = innodb;
+--error 1071
+create table t2 (col1 varbinary(768) primary key)
+ character set = latin1 engine = innodb;
+--error 1071
+create table t3 (col1 text, primary key(col1(768)))
+ character set = latin1 engine = innodb;
+--error 1071
+create table t4 (col1 blob, primary key(col1(768)))
character set = latin1 engine = innodb;
#
@@ -1751,3 +1765,106 @@ insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
drop table t1;
drop table t2;
commit;
+
+# tests for bugs #9802 and #13778
+
+# test that FKs between invalid types are not accepted
+
+set foreign_key_checks=0;
+create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb;
+-- error 1005
+create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
+set foreign_key_checks=1;
+drop table t2;
+
+# test that FKs between different charsets are not accepted in CREATE even
+# when f_k_c is 0
+
+set foreign_key_checks=0;
+create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1;
+-- error 1005
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8;
+set foreign_key_checks=1;
+drop table t1;
+
+# test that invalid datatype conversions with ALTER are not allowed
+
+set foreign_key_checks=0;
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb;
+create table t1(a varchar(10) primary key) engine = innodb;
+-- error 1025,1025
+alter table t1 modify column a int;
+set foreign_key_checks=1;
+drop table t2,t1;
+
+# test that charset conversions with ALTER are allowed when f_k_c is 0
+
+set foreign_key_checks=0;
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1;
+create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1;
+alter table t1 convert to character set utf8;
+set foreign_key_checks=1;
+drop table t2,t1;
+
+# test that RENAME does not allow invalid charsets when f_k_c is 0
+
+set foreign_key_checks=0;
+create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1;
+create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8;
+-- error 1025
+rename table t3 to t1;
+set foreign_key_checks=1;
+drop table t2,t3;
+
+#
+# Test that we can create a large (>1K) key
+#
+create table t1 (a varchar(255) character set utf8,
+ b varchar(255) character set utf8,
+ c varchar(255) character set utf8,
+ d varchar(255) character set utf8,
+ key (a,b,c,d)) engine=innodb;
+drop table t1;
+--error ER_TOO_LONG_KEY
+create table t1 (a varchar(255) character set utf8,
+ b varchar(255) character set utf8,
+ c varchar(255) character set utf8,
+ d varchar(255) character set utf8,
+ e varchar(255) character set utf8,
+ key (a,b,c,d,e)) engine=innodb;
+
+# test that foreign key errors are reported correctly (Bug #15550)
+
+create table t1(a int primary key) row_format=redundant engine=innodb;
+create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb;
+create table t3(a int primary key) row_format=compact engine=innodb;
+create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb;
+
+insert into t1 values(1);
+insert into t3 values(1);
+-- error 1452
+insert into t2 values(2);
+-- error 1452
+insert into t4 values(2);
+insert into t2 values(1);
+insert into t4 values(1);
+-- error 1451
+update t1 set a=2;
+-- error 1452
+update t2 set a=2;
+-- error 1451
+update t3 set a=2;
+-- error 1452
+update t4 set a=2;
+-- error 1451
+truncate t1;
+-- error 1451
+truncate t3;
+truncate t2;
+truncate t4;
+truncate t1;
+truncate t3;
+
+drop table t4,t3,t2,t1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test
index bb82a93c6c4..553aaf987bb 100644
--- a/mysql-test/t/join.test
+++ b/mysql-test/t/join.test
@@ -334,3 +334,210 @@ select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i
drop table t1,t2,t3;
# End of 4.1 tests
+
+#
+# Tests for WL#2486 Natural/using join according to SQL:2003.
+#
+# NOTICE:
+# - The tests are designed so that all statements, except MySQL
+# extensions run on any SQL server. Please do no change.
+# - Tests marked with TODO will be submitted as bugs.
+#
+
+create table t1 (c int, b int);
+create table t2 (a int, b int);
+create table t3 (b int, c int);
+create table t4 (y int, c int);
+create table t5 (y int, z int);
+create table t6 (a int, c int);
+
+insert into t1 values (10,1);
+insert into t1 values (3 ,1);
+insert into t1 values (3 ,2);
+insert into t2 values (2, 1);
+insert into t3 values (1, 3);
+insert into t3 values (1,10);
+insert into t4 values (11,3);
+insert into t4 values (2, 3);
+insert into t5 values (11,4);
+insert into t6 values (2, 3);
+
+-- Views with simple natural join.
+create algorithm=merge view v1a as
+select * from t1 natural join t2;
+-- as above, but column names are cross-renamed: a->c, c->b, b->a
+create algorithm=merge view v1b(a,b,c) as
+select * from t1 natural join t2;
+-- as above, but column names are aliased: a->c, c->b, b->a
+create algorithm=merge view v1c as
+select b as a, c as b, a as c from t1 natural join t2;
+-- as above, but column names are cross-renamed, and aliased
+-- a->c->b, c->b->a, b->a->c
+create algorithm=merge view v1d(b, a, c) as
+select a as c, c as b, b as a from t1 natural join t2;
+
+-- Views with JOIN ... ON
+create algorithm=merge view v2a as
+select t1.c, t1.b, t2.a from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c;
+create algorithm=merge view v2b as
+select t1.c as b, t1.b as a, t2.a as c
+from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c;
+
+-- Views with bigger natural join
+create algorithm=merge view v3a as
+select * from t1 natural join t2 natural join t3;
+create algorithm=merge view v3b as
+select * from t1 natural join (t2 natural join t3);
+
+-- View over views with mixed natural join and join ... on
+create algorithm=merge view v4 as
+select * from v2a natural join v3a;
+
+-- Nested natural/using joins.
+select * from (t1 natural join t2) natural join (t3 natural join t4);
+select * from (t1 natural join t2) natural left join (t3 natural join t4);
+select * from (t3 natural join t4) natural right join (t1 natural join t2);
+select * from (t1 natural left join t2) natural left join (t3 natural left join t4);
+select * from (t4 natural right join t3) natural right join (t2 natural right join t1);
+select * from t1 natural join t2 natural join t3 natural join t4;
+select * from ((t1 natural join t2) natural join t3) natural join t4;
+select * from t1 natural join (t2 natural join (t3 natural join t4));
+-- BUG#15355: this query fails in 'prepared statements' mode
+-- select * from ((t3 natural join (t1 natural join t2)) natural join t4) natural join t5;
+-- select * from ((t3 natural left join (t1 natural left join t2)) natural left join t4) natural left join t5;
+select * from t5 natural right join (t4 natural right join ((t2 natural right join t1) natural right join t3));
+select * from (t1 natural join t2), (t3 natural join t4);
+-- MySQL extension - nested comma ',' operator instead of cross join.
+-- BUG#15357 - natural join with nested cross-join results in incorrect columns
+-- select * from t5 natural join ((t1 natural join t2), (t3 natural join t4));
+-- select * from ((t1 natural join t2), (t3 natural join t4)) natural join t5;
+-- select * from t5 natural join ((t1 natural join t2) cross join (t3 natural join t4));
+-- select * from ((t1 natural join t2) cross join (t3 natural join t4)) natural join t5;
+
+select * from (t1 join t2 using (b)) join (t3 join t4 using (c)) using (c);
+select * from (t1 join t2 using (b)) natural join (t3 join t4 using (c));
+
+
+-- Other clauses refer to NJ columns.
+select a,b,c from (t1 natural join t2) natural join (t3 natural join t4)
+where b + 1 = y or b + 10 = y group by b,c,a having min(b) < max(y) order by a;
+select * from (t1 natural join t2) natural left join (t3 natural join t4)
+where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y;
+select * from (t3 natural join t4) natural right join (t1 natural join t2)
+where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y;
+
+-- Qualified column references to NJ columns.
+select * from t1 natural join t2 where t1.c > t2.a;
+select * from t1 natural join t2 where t1.b > t2.b;
+select * from t1 natural left join (t4 natural join t5) where t5.z is not NULL;
+
+-- Nested 'join ... on' - name resolution of ON conditions
+select * from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c;
+select * from (t2 join t4 on b + 1 = y) join t1 on t1.c = t4.c;
+select * from t1 natural join (t2 join t4 on b + 1 = y);
+select * from (t1 cross join t2) join (t3 cross join t4) on (a < y and t2.b < t3.c);
+
+-- MySQL extension - 'join ... on' over nested comma operator
+select * from (t1, t2) join (t3, t4) on (a < y and t2.b < t3.c);
+select * from (t1 natural join t2) join (t3 natural join t4) on a = y;
+select * from ((t3 join (t1 join t2 on c > a) on t3.b < t2.a) join t4 on y > t1.c) join t5 on z = t1.b + 3;
+
+-- MySQL extension - refererence qualified coalesced columns
+select * from t1 natural join t2 where t1.b > 0;
+select * from t1 natural join (t4 natural join t5) where t4.y > 7;
+select * from (t4 natural join t5) natural join t1 where t4.y > 7;
+select * from t1 natural left join (t4 natural join t5) where t4.y > 7;
+select * from (t4 natural join t5) natural right join t1 where t4.y > 7;
+select * from (t1 natural join t2) join (t3 natural join t4) on t1.b = t3.b;
+
+-- MySQL extension - select qualified columns of NJ columns
+select t1.*, t2.* from t1 natural join t2;
+select t1.*, t2.*, t3.*, t4.* from (t1 natural join t2) natural join (t3 natural join t4);
+
+-- Queries over subselects in the FROM clause
+select * from (select * from t1 natural join t2) as t12
+ natural join
+ (select * from t3 natural join t4) as t34;
+select * from (select * from t1 natural join t2) as t12
+ natural left join
+ (select * from t3 natural join t4) as t34;
+select * from (select * from t3 natural join t4) as t34
+ natural right join
+ (select * from t1 natural join t2) as t12;
+
+-- Queries over views
+select * from v1a;
+select * from v1b;
+select * from v1c;
+select * from v1d;
+select * from v2a;
+select * from v2b;
+select * from v3a;
+select * from v3b;
+select * from v4;
+select * from v1a natural join v2a;
+select v2a.* from v1a natural join v2a;
+select * from v1b join v2a on v1b.b = v2a.c;
+select * from v1c join v2a on v1c.b = v2a.c;
+select * from v1d join v2a on v1d.a = v2a.c;
+select * from v1a join (t3 natural join t4) on a = y;
+
+-- TODO: add tests with correlated subqueries for natural join/join on.
+-- related to BUG#15269
+
+
+----------------------------------------------------------------------
+-- Negative tests (tests for errors)
+----------------------------------------------------------------------
+-- error 1052
+select * from t1 natural join (t3 cross join t4); -- works in Oracle - bug
+-- error 1052
+select * from (t3 cross join t4) natural join t1; -- works in Oracle - bug
+-- error 1052
+select * from t1 join (t2, t3) using (b);
+-- error 1052
+select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6;
+-- error 1052
+select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6;
+-- error 1052
+-- BUG#15357: doesn't detect non-unique column 'c', as in the above query.
+-- select * from t6 natural join ((t1 natural join t2), (t3 natural join t4));
+-- error 1052
+select * from (t1 join t2 on t1.b=t2.b) natural join (t3 natural join t4);
+-- error 1052
+select * from (t3 natural join t4) natural join (t1 join t2 on t1.b=t2.b);
+-- this one is OK, the next equivalent one is incorrect (bug in Oracle)
+-- error 1052
+select * from (t3 join (t4 natural join t5) on (b < z))
+ natural join
+ (t1 natural join t2);
+-- error 1052
+-- BUG#15357: this query should return an ambiguous column error
+-- Expected result: the query must return error with duplicate column 'c'
+--select * from (t1 natural join t2)
+-- natural join
+-- (t3 join (t4 natural join t5) on (b < z));
+
+-- error 1054
+select t1.b from v1a;
+-- error 1054
+select * from v1a join v1b on t1.b = t2.b;
+
+drop table t1;
+drop table t2;
+drop table t3;
+drop table t4;
+drop table t5;
+drop table t6;
+
+drop view v1a;
+drop view v1b;
+drop view v1c;
+drop view v1d;
+drop view v2a;
+drop view v2b;
+drop view v3a;
+drop view v3b;
+drop view v4;
+
+# End of tests for WL#2486 - natural/using join
diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test
index 9dbf153ec55..9f23e2d0e2f 100644
--- a/mysql-test/t/join_nested.test
+++ b/mysql-test/t/join_nested.test
@@ -899,4 +899,4 @@ explain select * from t2 left join
(t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b
join t5 on t5.a=t3.b) on t3.a=t2.b;
-drop table t0, t1, t2, t4, t5, t6;
+drop table t0, t1, t2, t3, t4, t5, t6, t7;
diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test
index ff05867b7c1..060f1ea167b 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -352,4 +352,30 @@ INSERT INTO t2 (b) VALUES (1) ON DUPLICATE KEY UPDATE b=3;
SELECT b FROM t2;
DROP TABLE t1, t2;
+
+#
+# BUG#5390 - problems with merge tables
+# Problem #1: INSERT...SELECT
+#
+#drop table if exists t1, t2, t3;
+create table t1(a int);
+create table t2(a int);
+insert into t1 values (1);
+insert into t2 values (2);
+create table t3 (a int) engine=merge union=(t1, t2) insert_method=first;
+select * from t3;
+#
+insert t2 select * from t2;
+select * from t2;
+#
+insert t3 select * from t1;
+select * from t3;
+#
+insert t1 select * from t3;
+select * from t1;
+select * from t2;
+select * from t3;
+check table t1, t2;
+drop table t1, t2, t3;
+
# End of 4.1 tests
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index 5666f23f5aa..e54bf6386c5 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -605,6 +605,7 @@ select * from t2 order by a;
drop table t1, t2;
drop database db1;
+
#
# Bug #9558 mysqldump --no-data db t1 t2 format still dumps data
#
@@ -644,7 +645,7 @@ select '------ Testing with illegal table names ------' as test_sequence ;
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\t1" 2>&1
-
+
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\\\t1" 2>&1
@@ -685,6 +686,7 @@ drop table t1, t2, t3;
drop database mysqldump_test_db;
use test;
+
#
# Bug #9657 mysqldump xml ( -x ) does not format NULL fields correctly
#
@@ -1023,3 +1025,14 @@ SET SQL_MODE = @old_sql_mode;
DROP TRIGGER tr1;
DROP TABLE t1;
+
+#
+# Bug #13318: Bad result with empty field and --hex-blob
+#
+create table t1 (a binary(1), b blob);
+insert into t1 values ('','');
+--exec $MYSQL_DUMP --skip-comments --skip-extended-insert --hex-blob test t1
+--exec $MYSQL_DUMP --skip-comments --hex-blob test t1
+drop table t1;
+
+# End of 4.1 tests
diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test
index 3d9dff4d373..440a7787985 100644
--- a/mysql-test/t/mysqltest.test
+++ b/mysql-test/t/mysqltest.test
@@ -945,3 +945,53 @@ select "this will not be executed";
--enable_parsing
select "this will be executed";
--enable_query_log
+
+
+#
+# Bug #11731 mysqltest in multi-statement queries ignores errors in
+# non-1st queries
+#
+
+# Failing multi statement query
+# PS does not support multi statement
+--exec echo "--disable_ps_protocol" > var/tmp/bug11731.sql
+--exec echo "delimiter ||||;" >> var/tmp/bug11731.sql
+--exec echo "create table t1 (a int primary key);" >> var/tmp/bug11731.sql
+--exec echo "insert into t1 values (1);" >> var/tmp/bug11731.sql
+--exec echo "select 'select-me';" >> var/tmp/bug11731.sql
+--exec echo "insertz 'error query'||||" >> var/tmp/bug11731.sql
+--exec echo "delimiter ;||||" >> var/tmp/bug11731.sql
+
+--error 1
+--exec $MYSQL_TEST -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql 2>&1
+drop table t1;
+
+--error 1
+--exec $MYSQL_TEST --record -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql -R $MYSQL_TEST_DIR/var/tmp/bug11731.out
+# The .out file should be empty
+--error 1
+--exec test -s $MYSQL_TEST_DIR/var/tmp/bug11731.out
+drop table t1;
+
+
+# Using expected error
+# PS does not support multi statement
+--exec echo "--disable_ps_protocol" > var/tmp/bug11731.sql
+--exec echo "delimiter ||||;" >> var/tmp/bug11731.sql
+--exec echo "--error 1064" >> var/tmp/bug11731.sql
+--exec echo "create table t1 (a int primary key);" >> var/tmp/bug11731.sql
+--exec echo "insert into t1 values (1);" >> var/tmp/bug11731.sql
+--exec echo "select 'select-me';" >> var/tmp/bug11731.sql
+--exec echo "insertz "error query"||||" >> var/tmp/bug11731.sql
+--exec echo "delimiter ;||||" >> var/tmp/bug11731.sql
+
+# These two should work since the error is expected
+--exec $MYSQL_TEST -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql 2>&1
+drop table t1;
+
+--exec $MYSQL_TEST --record -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql -R $MYSQL_TEST_DIR/var/tmp/bug11731.out
+--exec cat $MYSQL_TEST_DIR/var/tmp/bug11731.out
+drop table t1;
+
+
+
diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test
index 70c48bba112..0a0211c8c83 100644
--- a/mysql-test/t/ndb_alter_table.test
+++ b/mysql-test/t/ndb_alter_table.test
@@ -153,7 +153,7 @@ connection server1;
alter table t1 drop index c;
connection server2;
# This should fail since index information is not automatically refreshed
---error 1412
+--error 1015
select * from t1 where b = 'two';
select * from t1 where b = 'two';
connection server1;
diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test
index 1a351018b8d..12aca73d82b 100644
--- a/mysql-test/t/ndb_basic.test
+++ b/mysql-test/t/ndb_basic.test
@@ -606,6 +606,14 @@ select * from t1 order by counter;
drop table t1;
+#
+# BUG#14514 Creating table with packed key fails silently
+#
+
+CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb;
+select * from t1;
+drop table t1;
+
# End of 4.1 tests
#
@@ -616,11 +624,13 @@ insert into atablewithareallylongandirritatingname values (2);
select * from atablewithareallylongandirritatingname;
drop table atablewithareallylongandirritatingname;
-
#
-# BUG#14514
+# Bug#15682
#
-
-CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb;
-select * from t1;
+create table t1 (f1 varchar(50), f2 text,f3 int, primary key(f1)) engine=NDB;
+insert into t1 (f1,f2,f3)VALUES("111111","aaaaaa",1);
+insert into t1 (f1,f2,f3)VALUES("222222","bbbbbb",2);
+select * from t1 order by f1;
+select * from t1 order by f2;
+select * from t1 order by f3;
drop table t1;
diff --git a/mysql-test/t/ndb_multi.test b/mysql-test/t/ndb_multi.test
index 760150c6f6a..1183f2b283f 100644
--- a/mysql-test/t/ndb_multi.test
+++ b/mysql-test/t/ndb_multi.test
@@ -40,6 +40,7 @@ connection server1;
# Currently a retry is required remotely
--error 1296
select * from t1;
+flush table t1;
select * from t1;
# Connect to server2 and use the tables from there
diff --git a/mysql-test/t/ndb_read_multi_range.test b/mysql-test/t/ndb_read_multi_range.test
index 9d1f918fef0..b1bf7fe4258 100644
--- a/mysql-test/t/ndb_read_multi_range.test
+++ b/mysql-test/t/ndb_read_multi_range.test
@@ -2,7 +2,7 @@
-- source include/not_embedded.inc
--disable_warnings
-DROP TABLE IF EXISTS t1, r1;
+DROP TABLE IF EXISTS t1, t2, r1;
--enable_warnings
#
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 94ee2b1ca39..22d0abf645e 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -842,4 +842,44 @@ set @@tx_isolation=default;
execute stmt;
deallocate prepare stmt;
+#
+# Bug#14410 "Crash in Enum or Set type in CREATE TABLE and PS/SP"
+#
+# Part I. Make sure the typelib for ENUM is created in the statement memory
+# root.
+prepare stmt from "create temporary table t1 (letter enum('','a','b','c')
+not null)";
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+# Part II. Make sure that when the default value is converted to UTF-8,
+# the new item is # created in the statement memory root.
+set names latin1;
+prepare stmt from "create table t1 (a enum('test') default 'test')
+ character set utf8";
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+execute stmt;
+drop table t1;
+# Cleanup
+set names default;
+deallocate prepare stmt;
+
# End of 4.1 tests
+
+#
+# Bug #14956: ROW_COUNT() returns incorrect result after EXECUTE of prepared
+# statement
+#
+create table t1 (id int);
+prepare ins_call from "insert into t1 (id) values (1)";
+execute ins_call;
+select row_count();
+drop table t1;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index 646151a5aae..a9f171ff5b5 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -743,6 +743,19 @@ show status like "Qcache_hits";
drop table t1;
#
+# BUG#14652: Queries with leading '(' characters.
+#
+create table t1 (a int);
+flush status;
+(select a from t1) union (select a from t1);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+(select a from t1) union (select a from t1);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+drop table t1;
# SP cursors and selects with query cache (BUG#9715)
#
create table t1 (a int);
diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test
index 3d03823d474..45d621b730f 100644
--- a/mysql-test/t/rpl000001.test
+++ b/mysql-test/t/rpl000001.test
@@ -92,7 +92,7 @@ kill @id;
# We don't drop t3 as this is a temporary table
drop table t2;
connection master;
---error 1053
+--error 1053,2013
reap;
connection slave;
# The SQL slave thread should now have stopped because the query was killed on
diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test
index d2a8fc0c844..c74ed989ece 100644
--- a/mysql-test/t/rpl_deadlock.test
+++ b/mysql-test/t/rpl_deadlock.test
@@ -58,7 +58,7 @@ while ($1)
enable_query_log;
select * from t1 for update;
start slave;
---sleep 3 # hope that slave is blocked now
+--real_sleep 3 # hope that slave is blocked now
insert into t2 values(22); # provoke deadlock, slave should be victim
commit;
sync_with_master;
@@ -76,7 +76,7 @@ change master to master_log_pos=532; # the BEGIN log event
begin;
select * from t2 for update; # hold lock
start slave;
---sleep 10 # slave should have blocked, and be retrying
+--real_sleep 10 # slave should have blocked, and be retrying
commit;
sync_with_master;
select * from t1; # check that slave succeeded finally
@@ -97,12 +97,12 @@ change master to master_log_pos=532;
begin;
select * from t2 for update;
start slave;
---sleep 10
+--real_sleep 10
commit;
sync_with_master;
select * from t1;
select * from t2;
---replace_column 1 # 8 # 9 # 23 # 33 #
+--replace_column 1 # 8 # 9 # 11 # 23 # 33 #
--replace_result $MASTER_MYPORT MASTER_MYPORT
show slave status;
diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test
index cb4137c49e0..339d966dbb3 100644
--- a/mysql-test/t/rpl_error_ignored_table.test
+++ b/mysql-test/t/rpl_error_ignored_table.test
@@ -45,7 +45,7 @@ select (@id := id) - id from t3;
kill @id;
drop table t2,t3;
connection master;
---error 0,1053
+--error 0,1053,2013
reap;
connection master1;
--replace_column 2 # 5 #
diff --git a/mysql-test/t/rpl_relayrotate.test b/mysql-test/t/rpl_relayrotate.test
index b66cf7a6e0d..04f03367e20 100644
--- a/mysql-test/t/rpl_relayrotate.test
+++ b/mysql-test/t/rpl_relayrotate.test
@@ -52,13 +52,9 @@ start slave;
# which proves that the transaction restarted at
# the right place.
# We must wait for the transaction to commit before
-# reading, MASTER_POS_WAIT() will do it for sure
-# (the only statement with position>=3000 is COMMIT).
-select master_pos_wait('master-bin.001',3000)>=0;
+# reading:
+sync_with_master;
select max(a) from t1;
---replace_column 1 # 8 # 9 # 23 # 33 #
---replace_result $MASTER_MYPORT MASTER_MYPORT
-show slave status;
connection master;
# The following DROP is a very important cleaning task:
diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test
index 386582f8f1b..8fa330584e2 100644
--- a/mysql-test/t/rpl_sp.test
+++ b/mysql-test/t/rpl_sp.test
@@ -87,6 +87,14 @@ grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1;
grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1;
grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1;
+# ToDo: BUG#14931: There is a race between the last grant binlogging, and
+# the binlogging in the new connection made below, causing sporadic test
+# failures due to switched statement order in binlog. To fix this we do
+# SELECT 1 in the first connection before starting the second, ensuring
+# that binlogging is done in the expected order.
+# Please remove this SELECT 1 when BUG#14931 is fixed.
+SELECT 1;
+
connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,);
connection con1;
diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test
index bf2836b6049..fa6054372c7 100644
--- a/mysql-test/t/rpl_trigger.test
+++ b/mysql-test/t/rpl_trigger.test
@@ -134,6 +134,35 @@ drop function bug12480;
drop table t1;
#
+# #14614: Replication of tables with trigger generates error message if databases is changed
+# Note. The error message is emitted by _myfree() using fprintf() to the stderr
+# and because of that does not fall into the .result file.
+#
+
+create table t1 (i int);
+create table t2 (i int);
+
+delimiter |;
+create trigger tr1 before insert on t1 for each row
+begin
+ insert into t2 values (1);
+end|
+delimiter ;|
+
+create database other;
+use other;
+insert into test.t1 values (1);
+
+save_master_pos;
+connection slave;
+sync_with_master;
+
+connection master;
+use test;
+drop table t1,t2;
+drop database other;
+
+#
# End of test
#
save_master_pos;
diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test
index 5bc7a040b1b..e0ecf981fea 100644
--- a/mysql-test/t/rpl_until.test
+++ b/mysql-test/t/rpl_until.test
@@ -30,7 +30,7 @@ wait_for_slave_to_stop;
# here table should be still not deleted
select * from t1;
--replace_result $MASTER_MYPORT MASTER_MYPORT
---replace_column 1 # 9 # 23 # 33 #
+--replace_column 1 # 9 # 11 # 23 # 33 #
show slave status;
# this should fail right after start
@@ -40,7 +40,7 @@ select * from t1;
sleep 2;
wait_for_slave_to_stop;
--replace_result $MASTER_MYPORT MASTER_MYPORT
---replace_column 1 # 9 # 23 # 33 #
+--replace_column 1 # 9 # 11 # 23 # 33 #
show slave status;
# try replicate all until second insert to t2;
@@ -49,7 +49,7 @@ sleep 2;
wait_for_slave_to_stop;
select * from t2;
--replace_result $MASTER_MYPORT MASTER_MYPORT
---replace_column 1 # 9 # 23 # 33 #
+--replace_column 1 # 9 # 11 # 23 # 33 #
show slave status;
# clean up
diff --git a/mysql-test/t/schema.test b/mysql-test/t/schema.test
index d9bd607b2db..a08d9b38935 100644
--- a/mysql-test/t/schema.test
+++ b/mysql-test/t/schema.test
@@ -1,6 +1,12 @@
#
# Just a couple of tests to make sure that schema works.
#
+# Drop mysqltest1 database, as it can left from the previous tests.
+#
+
+--disable_warnings
+drop database if exists mysqltest1;
+--enable_warnings
create schema foo;
show create schema foo;
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index 33a3ff578f8..a85b82a7767 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -2253,6 +2253,17 @@ insert into t1 values (1,1);
insert into t2 values (1,1),(1,2);
select distinct count(f2) >0 from t1 left join t2 on f1=f3 group by f1;
drop table t1,t2;
+
+#
+# Bug #14482 Server crash when subselecting from the same table
+#
+create table t1 (f1 int,f2 int);
+insert into t1 values(1,1);
+create table t2 (f3 int, f4 int, primary key(f3,f4));
+insert into t2 values(1,1);
+select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 from t2));
+drop table t1,t2;
+
# End of 4.1 tests
#
@@ -2749,3 +2760,58 @@ select f1, f2, v2.f1 as x1 from v2 order by v2.f1;
select f1, f2, v3.f1 as x1 from v3 order by v3.f1;
drop table t1;
drop view v1, v2, v3;
+
+#
+# Bug #15106: lost equality predicate of the form field=const in a join query
+#
+
+CREATE TABLE t1(key_a int4 NOT NULL, optimus varchar(32), PRIMARY KEY(key_a));
+CREATE TABLE t2(key_a int4 NOT NULL, prime varchar(32), PRIMARY KEY(key_a));
+CREATE table t3(key_a int4 NOT NULL, key_b int4 NOT NULL, foo varchar(32),
+ PRIMARY KEY(key_a,key_b));
+
+INSERT INTO t1 VALUES (0,'');
+INSERT INTO t1 VALUES (1,'i');
+INSERT INTO t1 VALUES (2,'j');
+INSERT INTO t1 VALUES (3,'k');
+
+INSERT INTO t2 VALUES (1,'r');
+INSERT INTO t2 VALUES (2,'s');
+INSERT INTO t2 VALUES (3,'t');
+
+INSERT INTO t3 VALUES (1,5,'x');
+INSERT INTO t3 VALUES (1,6,'y');
+INSERT INTO t3 VALUES (2,5,'xx');
+INSERT INTO t3 VALUES (2,6,'yy');
+INSERT INTO t3 VALUES (2,7,'zz');
+INSERT INTO t3 VALUES (3,5,'xxx');
+
+SELECT t2.key_a,foo
+ FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a
+ INNER JOIN t3 ON t1.key_a = t3.key_a
+ WHERE t2.key_a=2 and key_b=5;
+EXPLAIN SELECT t2.key_a,foo
+ FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a
+ INNER JOIN t3 ON t1.key_a = t3.key_a
+ WHERE t2.key_a=2 and key_b=5;
+
+SELECT t2.key_a,foo
+ FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a
+ INNER JOIN t3 ON t1.key_a = t3.key_a
+ WHERE t2.key_a=2 and key_b=5;
+EXPLAIN SELECT t2.key_a,foo
+ FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a
+ INNER JOIN t3 ON t1.key_a = t3.key_a
+ WHERE t2.key_a=2 and key_b=5;
+
+DROP TABLE t1,t2,t3;
+
+#
+# Bug#15268 Unchecked null value caused server crash
+#
+create table t1(f1 char, f2 char not null);
+insert into t1 values(null,'a');
+create table t2 (f2 char not null);
+insert into t2 values('b');
+select * from t1 left join t2 on f1=t2.f2 where t1.f2='a';
+drop table t1,t2;
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index 89d281a2c58..4d418303e6d 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -10,6 +10,7 @@
drop table if exists t1,t2;
drop table if exists t1aa,t2aa;
drop database if exists mysqltest;
+drop database if exists mysqltest1;
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
diff --git a/mysql-test/t/skip_name_resolve.test b/mysql-test/t/skip_name_resolve.test
index b67869692d2..3f732c8912b 100644
--- a/mysql-test/t/skip_name_resolve.test
+++ b/mysql-test/t/skip_name_resolve.test
@@ -15,6 +15,6 @@ DROP USER mysqltest_1@'127.0.0.1/255.255.255.255';
connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, );
--replace_column 1 #
select user();
---replace_column 1 # 6 # 3 #
+--replace_column 1 <id> 3 <host> 5 <command> 6 <time> 7 <state> 8 <info>
show processlist;
connection default;
diff --git a/mysql-test/t/sp-big.test b/mysql-test/t/sp-big.test
index 389a6f04504..90a3a79dd53 100644
--- a/mysql-test/t/sp-big.test
+++ b/mysql-test/t/sp-big.test
@@ -52,6 +52,9 @@ while ($1)
--enable_query_log
select count(*) from t1;
select count(*) from t2;
+--disable_warnings
+drop procedure if exists p1;
+--enable_warnings
delimiter |;
create procedure p1()
begin
diff --git a/mysql-test/t/sp-destruct.test b/mysql-test/t/sp-destruct.test
new file mode 100644
index 00000000000..a2a66090866
--- /dev/null
+++ b/mysql-test/t/sp-destruct.test
@@ -0,0 +1,124 @@
+#
+# Destructive stored procedure tests
+#
+# We do horrible things to the mysql.proc table here, so any unexpected
+# failures here might leave it in an undetermined state.
+#
+# In the case of trouble you might want to skip this.
+#
+
+# We're using --system things that probably doesn't work on Windows.
+--source include/not_windows.inc
+
+# Backup proc table
+--system rm -rf var/master-data/mysql/backup
+--system mkdir var/master-data/mysql/backup
+--system cp var/master-data/mysql/proc.* var/master-data/mysql/backup/
+
+use test;
+
+--disable_warnings
+drop procedure if exists bug14233;
+drop function if exists bug14233;
+drop table if exists t1;
+drop view if exists v1;
+--enable_warnings
+
+create procedure bug14233()
+ set @x = 42;
+
+create function bug14233_f() returns int
+ return 42;
+
+create table t1 (id int);
+create trigger t1_ai after insert on t1 for each row call bug14233();
+
+# Unsupported tampering with the mysql.proc definition
+alter table mysql.proc drop type;
+--error ER_SP_PROC_TABLE_CORRUPT
+call bug14233();
+--error ER_SP_PROC_TABLE_CORRUPT
+create view v1 as select bug14233_f();
+--error ER_SP_PROC_TABLE_CORRUPT
+insert into t1 values (0);
+
+flush table mysql.proc;
+
+# Thrashing the .frm file
+--system echo 'saljdlfa' > var/master-data/mysql/proc.frm
+--error ER_NOT_FORM_FILE
+call bug14233();
+--error ER_NOT_FORM_FILE
+create view v1 as select bug14233_f();
+--error ER_NOT_FORM_FILE
+insert into t1 values (0);
+
+
+flush table mysql.proc;
+
+# Drop the mysql.proc table
+--system rm var/master-data/mysql/proc.*
+--error ER_NO_SUCH_TABLE
+call bug14233();
+--error ER_NO_SUCH_TABLE
+create view v1 as select bug14233_f();
+--error ER_NO_SUCH_TABLE
+insert into t1 values (0);
+
+# Restore mysql.proc
+--system mv var/master-data/mysql/backup/* var/master-data/mysql/
+--system rmdir var/master-data/mysql/backup
+
+flush table mysql.proc;
+flush privileges;
+
+delete from mysql.proc where name like 'bug14233%';
+
+# Unsupported editing of mysql.proc, circumventing checks in "create ..."
+insert into mysql.proc
+(
+ db, name, type, specific_name, language, sql_data_access, is_deterministic,
+ security_type, param_list, returns, body, definer, created, modified,
+ sql_mode, comment
+)
+values
+(
+ 'test', 'bug14233_1', 'FUNCTION', 'bug14233_1', 'SQL', 'READS_SQL_DATA', 'NO',
+ 'DEFINER', '', 'int(10)',
+ 'select count(*) from mysql.user',
+ 'root@localhost', NOW() , '0000-00-00 00:00:00', '', ''
+),
+(
+ 'test', 'bug14233_2', 'FUNCTION', 'bug14233_2', 'SQL', 'READS_SQL_DATA', 'NO',
+ 'DEFINER', '', 'int(10)',
+ 'begin declare x int; select count(*) into x from mysql.user; end',
+ 'root@localhost', NOW() , '0000-00-00 00:00:00', '', ''
+),
+(
+ 'test', 'bug14233_3', 'PROCEDURE', 'bug14233_3', 'SQL', 'READS_SQL_DATA','NO',
+ 'DEFINER', '', '',
+ 'alksj wpsj sa ^#!@ ',
+ 'root@localhost', NOW() , '0000-00-00 00:00:00', '', ''
+);
+
+--error ER_SP_PROC_TABLE_CORRUPT
+select bug14233_1();
+--error ER_SP_PROC_TABLE_CORRUPT
+create view v1 as select bug14233_1();
+
+--error ER_SP_PROC_TABLE_CORRUPT
+select bug14233_2();
+--error ER_SP_PROC_TABLE_CORRUPT
+create view v1 as select bug14233_2();
+
+--error ER_SP_PROC_TABLE_CORRUPT
+call bug14233_3();
+drop trigger t1_ai;
+create trigger t1_ai after insert on t1 for each row call bug14233_3();
+--error ER_SP_PROC_TABLE_CORRUPT
+insert into t1 values (0);
+
+# Clean-up
+delete from mysql.proc where name like 'bug14233%';
+drop trigger t1_ai;
+drop table t1;
diff --git a/mysql-test/t/sp-dynamic.test b/mysql-test/t/sp-dynamic.test
index 5416f5931ff..6546a5ab548 100644
--- a/mysql-test/t/sp-dynamic.test
+++ b/mysql-test/t/sp-dynamic.test
@@ -1,4 +1,10 @@
delimiter |;
+
+--disable_warnings
+drop procedure if exists p1|
+drop procedure if exists p2|
+--enable_warnings
+
######################################################################
# Test Dynamic SQL in stored procedures. #############################
######################################################################
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 69e5f73817b..cf8f8dfc79c 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -1095,7 +1095,7 @@ delimiter |;
--disable_warnings
DROP FUNCTION IF EXISTS bug12953|
--enable_warnings
---error ER_SP_BADSTATEMENT
+--error ER_SP_NO_RETSET
CREATE FUNCTION bug12953() RETURNS INT
BEGIN
OPTIMIZE TABLE t1;
@@ -1410,7 +1410,6 @@ delimiter ;|
# BUG#12329: "Bogus error msg when executing PS with stored procedure after
# SP was re-created". See also test for related bug#13399 in trigger.test
---disable_warnings
drop function if exists bug12329;
--enable_warnings
create table t1 as select 1 a;
@@ -1518,6 +1517,105 @@ show procedure status;
drop database mysqltest2;
use test;
+#
+# Bug#13012 "SP: REPAIR/BACKUP/RESTORE TABLE crashes the server"
+#
+delimiter |;
+--disable_warnings
+DROP FUNCTION IF EXISTS bug13012|
+--enable_warnings
+--error ER_SP_NO_RETSET
+CREATE FUNCTION bug13012() RETURNS INT
+BEGIN
+ REPAIR TABLE t1;
+ RETURN 1;
+END|
+--error ER_SP_NO_RETSET
+CREATE FUNCTION bug13012() RETURNS INT
+BEGIN
+ BACKUP TABLE t1 TO '/tmp';
+ RETURN 1;
+END|
+--error ER_SP_NO_RETSET
+CREATE FUNCTION bug13012() RETURNS INT
+BEGIN
+ RESTORE TABLE t1 FROM '/tmp';
+ RETURN 1;
+END|
+create table t1 (a int)|
+CREATE PROCEDURE bug13012_1() REPAIR TABLE t1|
+CREATE FUNCTION bug13012_2() RETURNS INT
+BEGIN
+ CALL bug13012_1();
+ RETURN 1;
+END|
+--error ER_SP_NO_RETSET
+SELECT bug13012_2()|
+drop table t1|
+drop procedure bug13012_1|
+drop function bug13012_2|
+delimiter ;|
+
+# BUG#11555 "Stored procedures: current SP tables locking make
+# impossible view security". We should not expose names of tables
+# which are implicitly used by view (via stored routines/triggers).
+#
+# Note that SQL standard assumes that you simply won't be able drop table
+# and leave some objects (routines/views/triggers) which were depending on
+# it. Such objects should be dropped in advance (by default) or will be
+# dropped simultaneously with table (DROP TABLE with CASCADE clause).
+# So these tests probably should go away once we will implement standard
+# behavior.
+--disable_warnings
+drop function if exists bug11555_1;
+drop function if exists bug11555_2;
+drop view if exists v1, v2, v3, v4;
+--enable_warnings
+create function bug11555_1() returns int return (select max(i) from t1);
+create function bug11555_2() returns int return bug11555_1();
+# It is OK to report name of implicitly used table which is missing
+# when we create view.
+--error ER_NO_SUCH_TABLE
+create view v1 as select bug11555_1();
+--error ER_NO_SUCH_TABLE
+create view v2 as select bug11555_2();
+# But we should hide name of missing implicitly used table when we use view
+create table t1 (i int);
+create view v1 as select bug11555_1();
+create view v2 as select bug11555_2();
+create view v3 as select * from v1;
+drop table t1;
+--error ER_VIEW_INVALID
+select * from v1;
+--error ER_VIEW_INVALID
+select * from v2;
+--error ER_VIEW_INVALID
+select * from v3;
+# Note that creation of view which depends on broken view is yet
+# another form of view usage.
+--error ER_VIEW_INVALID
+create view v4 as select * from v1;
+drop view v1, v2, v3;
+# We also should hide details about broken triggers which are
+# invoked for view.
+drop function bug11555_1;
+drop function bug11555_2;
+create table t1 (i int);
+create table t2 (i int);
+create trigger t1_ai after insert on t1 for each row insert into t2 values (new.i);
+create view v1 as select * from t1;
+drop table t2;
+--error ER_VIEW_INVALID
+insert into v1 values (1);
+drop trigger t1_ai;
+create function bug11555_1() returns int return (select max(i) from t2);
+create trigger t1_ai after insert on t1 for each row set @a:=bug11555_1();
+--error ER_VIEW_INVALID
+insert into v1 values (2);
+drop function bug11555_1;
+drop table t1;
+drop view v1;
+
# BUG#NNNN: New bug synopsis
#
diff --git a/mysql-test/t/sp-vars.test b/mysql-test/t/sp-vars.test
new file mode 100644
index 00000000000..81504904797
--- /dev/null
+++ b/mysql-test/t/sp-vars.test
@@ -0,0 +1,1273 @@
+###########################################################################
+#
+# Cleanup.
+#
+###########################################################################
+
+--disable_warnings
+
+# Drop stored routines (if any) for general SP-vars test cases. These routines
+# are created in include/sp-vars.inc file.
+
+DROP PROCEDURE IF EXISTS sp_vars_check_dflt;
+DROP PROCEDURE IF EXISTS sp_vars_check_assignment;
+DROP FUNCTION IF EXISTS sp_vars_check_ret1;
+DROP FUNCTION IF EXISTS sp_vars_check_ret2;
+DROP FUNCTION IF EXISTS sp_vars_check_ret3;
+DROP FUNCTION IF EXISTS sp_vars_check_ret4;
+
+--enable_warnings
+
+###########################################################################
+#
+# Some general tests for SP-vars functionality.
+#
+###########################################################################
+
+# Create the procedure in ANSI mode. Check that all necessary warnings are
+# emitted properly.
+
+SET @@sql_mode = 'ansi';
+
+--source include/sp-vars.inc
+
+--echo
+--echo ---------------------------------------------------------------
+--echo Calling the routines, created in ANSI mode.
+--echo ---------------------------------------------------------------
+--echo
+
+CALL sp_vars_check_dflt();
+
+CALL sp_vars_check_assignment();
+
+SELECT sp_vars_check_ret1();
+
+SELECT sp_vars_check_ret2();
+
+SELECT sp_vars_check_ret3();
+
+SELECT sp_vars_check_ret4();
+
+# Check that changing sql_mode after creating a store procedure does not
+# matter.
+
+SET @@sql_mode = 'traditional';
+
+--echo
+--echo ---------------------------------------------------------------
+--echo Calling in TRADITIONAL mode the routines, created in ANSI mode.
+--echo ---------------------------------------------------------------
+--echo
+
+CALL sp_vars_check_dflt();
+
+CALL sp_vars_check_assignment();
+
+SELECT sp_vars_check_ret1();
+
+SELECT sp_vars_check_ret2();
+
+SELECT sp_vars_check_ret3();
+
+SELECT sp_vars_check_ret4();
+
+# Create the procedure in TRADITIONAL mode. Check that error will be thrown on
+# execution.
+
+DROP PROCEDURE sp_vars_check_dflt;
+DROP PROCEDURE sp_vars_check_assignment;
+DROP FUNCTION sp_vars_check_ret1;
+DROP FUNCTION sp_vars_check_ret2;
+DROP FUNCTION sp_vars_check_ret3;
+DROP FUNCTION sp_vars_check_ret4;
+
+--source include/sp-vars.inc
+
+--echo
+--echo ---------------------------------------------------------------
+--echo Calling the routines, created in TRADITIONAL mode.
+--echo ---------------------------------------------------------------
+--echo
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+CALL sp_vars_check_dflt();
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+CALL sp_vars_check_assignment();
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+SELECT sp_vars_check_ret1();
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+SELECT sp_vars_check_ret2();
+
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+SELECT sp_vars_check_ret3();
+
+# TODO: Is it an error, that only a warning is emitted here? Check the same
+# behaviour with tables.
+
+SELECT sp_vars_check_ret4();
+
+SET @@sql_mode = 'ansi';
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE sp_vars_check_dflt;
+DROP PROCEDURE sp_vars_check_assignment;
+DROP FUNCTION sp_vars_check_ret1;
+DROP FUNCTION sp_vars_check_ret2;
+DROP FUNCTION sp_vars_check_ret3;
+DROP FUNCTION sp_vars_check_ret4;
+
+###########################################################################
+#
+# Tests for BIT data type.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BIT data type tests
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+CREATE PROCEDURE p1()
+BEGIN
+ DECLARE v1 BIT;
+ DECLARE v2 BIT(1);
+ DECLARE v3 BIT(3) DEFAULT b'101';
+ DECLARE v4 BIT(64) DEFAULT 0x5555555555555555;
+ DECLARE v5 BIT(3);
+ DECLARE v6 BIT(64);
+ DECLARE v7 BIT(8) DEFAULT 128;
+ DECLARE v8 BIT(8) DEFAULT '128';
+ DECLARE v9 BIT(8) DEFAULT ' 128';
+ DECLARE v10 BIT(8) DEFAULT 'x 128';
+
+ SET v1 = v4;
+ SET v2 = 0;
+ SET v5 = v4; # check overflow
+ SET v6 = v3; # check padding
+
+ SELECT HEX(v1);
+ SELECT HEX(v2);
+ SELECT HEX(v3);
+ SELECT HEX(v4);
+ SELECT HEX(v5);
+ SELECT HEX(v6);
+ SELECT HEX(v7);
+ SELECT HEX(v8);
+ SELECT HEX(v9);
+ SELECT HEX(v10);
+END|
+delimiter ;|
+
+CALL p1();
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+
+###########################################################################
+#
+# Tests for CASE statements functionality:
+# - test for general functionality (scopes, nested cases, CASE in loops);
+# - test that if type of the CASE expression is changed on each iteration,
+# the execution will be correct.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo CASE expression tests.
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+DROP TABLE IF EXISTS t1;
+
+#
+# Test case.
+#
+
+CREATE TABLE t1(log_msg VARCHAR(1024));
+
+delimiter |;
+
+CREATE PROCEDURE p1(arg VARCHAR(255))
+BEGIN
+ INSERT INTO t1 VALUES('p1: step1');
+
+ CASE arg * 10
+ WHEN 10 * 10 THEN
+ INSERT INTO t1 VALUES('p1: case1: on 10');
+ WHEN 10 * 10 + 10 * 10 THEN
+ BEGIN
+ CASE arg / 10
+ WHEN 1 THEN
+ INSERT INTO t1 VALUES('p1: case1: case2: on 1');
+ WHEN 2 THEN
+ BEGIN
+ DECLARE i TINYINT DEFAULT 10;
+
+ WHILE i > 0 DO
+ INSERT INTO t1 VALUES(CONCAT('p1: case1: case2: loop: i: ', i));
+
+ CASE MOD(i, 2)
+ WHEN 0 THEN
+ INSERT INTO t1 VALUES('p1: case1: case2: loop: i is even');
+ WHEN 1 THEN
+ INSERT INTO t1 VALUES('p1: case1: case2: loop: i is odd');
+ ELSE
+ INSERT INTO t1 VALUES('p1: case1: case2: loop: ERROR');
+ END CASE;
+
+ SET i = i - 1;
+ END WHILE;
+ END;
+ ELSE
+ INSERT INTO t1 VALUES('p1: case1: case2: ERROR');
+ END CASE;
+
+ CASE arg
+ WHEN 10 THEN
+ INSERT INTO t1 VALUES('p1: case1: case3: on 10');
+ WHEN 20 THEN
+ INSERT INTO t1 VALUES('p1: case1: case3: on 20');
+ ELSE
+ INSERT INTO t1 VALUES('p1: case1: case3: ERROR');
+ END CASE;
+ END;
+ ELSE
+ INSERT INTO t1 VALUES('p1: case1: ERROR');
+ END CASE;
+
+ CASE arg * 10
+ WHEN 10 * 10 THEN
+ INSERT INTO t1 VALUES('p1: case4: on 10');
+ WHEN 10 * 10 + 10 * 10 THEN
+ BEGIN
+ CASE arg / 10
+ WHEN 1 THEN
+ INSERT INTO t1 VALUES('p1: case4: case5: on 1');
+ WHEN 2 THEN
+ BEGIN
+ DECLARE i TINYINT DEFAULT 10;
+
+ WHILE i > 0 DO
+ INSERT INTO t1 VALUES(CONCAT('p1: case4: case5: loop: i: ', i));
+
+ CASE MOD(i, 2)
+ WHEN 0 THEN
+ INSERT INTO t1 VALUES('p1: case4: case5: loop: i is even');
+ WHEN 1 THEN
+ INSERT INTO t1 VALUES('p1: case4: case5: loop: i is odd');
+ ELSE
+ INSERT INTO t1 VALUES('p1: case4: case5: loop: ERROR');
+ END CASE;
+
+ SET i = i - 1;
+ END WHILE;
+ END;
+ ELSE
+ INSERT INTO t1 VALUES('p1: case4: case5: ERROR');
+ END CASE;
+
+ CASE arg
+ WHEN 10 THEN
+ INSERT INTO t1 VALUES('p1: case4: case6: on 10');
+ WHEN 20 THEN
+ INSERT INTO t1 VALUES('p1: case4: case6: on 20');
+ ELSE
+ INSERT INTO t1 VALUES('p1: case4: case6: ERROR');
+ END CASE;
+ END;
+ ELSE
+ INSERT INTO t1 VALUES('p1: case4: ERROR');
+ END CASE;
+END|
+
+CREATE PROCEDURE p2()
+BEGIN
+ DECLARE i TINYINT DEFAULT 3;
+
+ WHILE i > 0 DO
+ IF MOD(i, 2) = 0 THEN
+ SET @_test_session_var = 10;
+ ELSE
+ SET @_test_session_var = 'test';
+ END IF;
+
+ CASE @_test_session_var
+ WHEN 10 THEN
+ INSERT INTO t1 VALUES('p2: case: numerical type');
+ WHEN 'test' THEN
+ INSERT INTO t1 VALUES('p2: case: string type');
+ ELSE
+ INSERT INTO t1 VALUES('p2: case: ERROR');
+ END CASE;
+
+ SET i = i - 1;
+ END WHILE;
+END|
+
+delimiter ;|
+
+CALL p1(10);
+CALL p1(20);
+
+CALL p2();
+
+SELECT * FROM t1;
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP TABLE t1;
+
+###########################################################################
+#
+# Test case for BUG#14161: Stored procedure cannot retrieve bigint unsigned.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#14161
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+CREATE TABLE t1(col BIGINT UNSIGNED);
+
+INSERT INTO t1 VALUE(18446744073709551614);
+
+delimiter |;
+CREATE PROCEDURE p1(IN arg BIGINT UNSIGNED)
+BEGIN
+ SELECT arg;
+ SELECT * FROM t1;
+ SELECT * FROM t1 WHERE col = arg;
+END|
+delimiter ;|
+
+CALL p1(18446744073709551614);
+
+#
+# Cleanup.
+#
+
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+###########################################################################
+#
+# Test case for BUG#13705: parameters to stored procedures are not verified.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#13705
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+CREATE PROCEDURE p1(x VARCHAR(10), y CHAR(3)) READS SQL DATA
+BEGIN
+ SELECT x, y;
+END|
+delimiter ;|
+
+CALL p1('alpha', 'abc');
+CALL p1('alpha', 'abcdef');
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+
+###########################################################################
+#
+# Test case for BUG#13675: DATETIME/DATE type in store proc param seems to be
+# converted as varbinary.
+#
+# TODO: test case failed.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#13675
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+CREATE PROCEDURE p1(x DATETIME)
+BEGIN
+ CREATE TABLE t1 SELECT x;
+ SHOW CREATE TABLE t1;
+ DROP TABLE t1;
+END|
+delimiter ;|
+
+CALL p1(NOW());
+
+CALL p1('test');
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+
+###########################################################################
+#
+# Test case for BUG#12976: Boolean values reversed in stored procedures?
+#
+# TODO: test case failed.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#12976
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+--enable_warnings
+
+#
+# Test case.
+#
+
+CREATE TABLE t1(b BIT(1));
+
+INSERT INTO t1(b) VALUES(b'0'), (b'1');
+
+delimiter |;
+CREATE PROCEDURE p1()
+BEGIN
+ SELECT HEX(b),
+ b = 0,
+ b = FALSE,
+ b IS FALSE,
+ b = 1,
+ b = TRUE,
+ b IS TRUE
+ FROM t1;
+END|
+
+CREATE PROCEDURE p2()
+BEGIN
+ DECLARE vb BIT(1);
+ SELECT b INTO vb FROM t1 WHERE b = 0;
+
+ SELECT HEX(vb),
+ vb = 0,
+ vb = FALSE,
+ vb IS FALSE,
+ vb = 1,
+ vb = TRUE,
+ vb IS TRUE;
+
+ SELECT b INTO vb FROM t1 WHERE b = 1;
+
+ SELECT HEX(vb),
+ vb = 0,
+ vb = FALSE,
+ vb IS FALSE,
+ vb = 1,
+ vb = TRUE,
+ vb IS TRUE;
+END|
+delimiter ;|
+
+# The expected and correct result.
+
+call p1();
+
+# The wrong result. Note that only hex(vb) works, but is printed with two
+# digits for some reason in this case.
+
+call p2();
+
+#
+# Cleanup.
+#
+
+DROP TABLE t1;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+###########################################################################
+#
+# Test case for BUG#9572: Stored procedures: variable type declarations
+# ignored.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#9572
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+DROP PROCEDURE IF EXISTS p3;
+
+DROP PROCEDURE IF EXISTS p4;
+DROP PROCEDURE IF EXISTS p5;
+DROP PROCEDURE IF EXISTS p6;
+--enable_warnings
+
+#
+# Test case.
+#
+
+SET @@sql_mode = 'traditional';
+
+delimiter |;
+
+CREATE PROCEDURE p1()
+BEGIN
+ DECLARE v TINYINT DEFAULT 1e200;
+ SELECT v;
+END|
+
+CREATE PROCEDURE p2()
+BEGIN
+ DECLARE v DECIMAL(5) DEFAULT 1e200;
+ SELECT v;
+END|
+
+CREATE PROCEDURE p3()
+BEGIN
+ DECLARE v CHAR(5) DEFAULT 'abcdef';
+ SELECT v LIKE 'abc___';
+END|
+
+CREATE PROCEDURE p4(arg VARCHAR(2))
+BEGIN
+ DECLARE var VARCHAR(1);
+ SET var := arg;
+ SELECT arg, var;
+END|
+
+CREATE PROCEDURE p5(arg CHAR(2))
+BEGIN
+ DECLARE var CHAR(1);
+ SET var := arg;
+ SELECT arg, var;
+END|
+
+CREATE PROCEDURE p6(arg DECIMAL(2))
+BEGIN
+ DECLARE var DECIMAL(1);
+ SET var := arg;
+ SELECT arg, var;
+END|
+
+delimiter ;|
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+CALL p1();
+--error ER_WARN_DATA_OUT_OF_RANGE
+CALL p2();
+--error ER_DATA_TOO_LONG
+CALL p3();
+
+--error ER_DATA_TOO_LONG
+CALL p4('aaa');
+--error ER_DATA_TOO_LONG
+CALL p5('aa');
+--error ER_WARN_DATA_OUT_OF_RANGE
+CALL p6(10);
+
+#
+# Cleanup.
+#
+
+SET @@sql_mode = 'ansi';
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP PROCEDURE p6;
+
+###########################################################################
+#
+# Test case for BUG#9078: STORED PROCDURE: Decimal digits are not displayed
+# when we use DECIMAL datatype.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#9078
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+CREATE PROCEDURE p1 (arg DECIMAL(64,2))
+BEGIN
+ DECLARE var DECIMAL(64,2);
+
+ SET var = arg;
+ SELECT var;
+END|
+delimiter ;|
+
+CALL p1(1929);
+CALL p1(1929.00);
+CALL p1(1929.003);
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+
+###########################################################################
+#
+# Test case for BUG#8768: Functions: For any unsigned data type, -ve values can
+# be passed and returned.
+#
+# TODO: there is a bug here -- the function created in ANSI mode should not
+# throw errors instead of warnings if called in TRADITIONAL mode.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#8768
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+# Create a function in ANSI mode.
+
+delimiter |;
+CREATE FUNCTION f1(arg TINYINT UNSIGNED) RETURNS TINYINT
+BEGIN
+ RETURN arg;
+END|
+delimiter ;|
+
+SELECT f1(-2500);
+
+# Call in TRADITIONAL mode the function created in ANSI mode.
+
+SET @@sql_mode = 'traditional';
+
+# TODO: a warning should be emitted here.
+--error ER_WARN_DATA_OUT_OF_RANGE
+SELECT f1(-2500);
+
+# Recreate the function in TRADITIONAL mode.
+
+DROP FUNCTION f1;
+
+delimiter |;
+CREATE FUNCTION f1(arg TINYINT UNSIGNED) RETURNS TINYINT
+BEGIN
+ RETURN arg;
+END|
+delimiter ;|
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+SELECT f1(-2500);
+
+#
+# Cleanup.
+#
+
+SET @@sql_mode = 'ansi';
+
+DROP FUNCTION f1;
+
+###########################################################################
+#
+# Test case for BUG#8769: Functions: For Int datatypes, out of range values can
+# be passed and returned.
+#
+# TODO: there is a bug here -- the function created in ANSI mode should not
+# throw errors instead of warnings if called in TRADITIONAL mode.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#8769
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+# Create a function in ANSI mode.
+
+delimiter |;
+CREATE FUNCTION f1(arg MEDIUMINT) RETURNS MEDIUMINT
+BEGIN
+ RETURN arg;
+END|
+delimiter ;|
+
+SELECT f1(8388699);
+
+# Call in TRADITIONAL mode the function created in ANSI mode.
+
+SET @@sql_mode = 'traditional';
+
+# TODO: a warning should be emitted here.
+--error ER_WARN_DATA_OUT_OF_RANGE
+SELECT f1(8388699);
+
+# Recreate the function in TRADITIONAL mode.
+
+DROP FUNCTION f1;
+
+delimiter |;
+CREATE FUNCTION f1(arg MEDIUMINT) RETURNS MEDIUMINT
+BEGIN
+ RETURN arg;
+END|
+delimiter ;|
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+SELECT f1(8388699);
+
+#
+# Cleanup.
+#
+
+SET @@sql_mode = 'ansi';
+
+DROP FUNCTION f1;
+
+###########################################################################
+#
+# Test case for BUG#8702: Stored Procedures: No Error/Warning shown for
+# inappropriate data type matching.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#8702
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+CREATE TABLE t1(col VARCHAR(255));
+
+INSERT INTO t1(col) VALUES('Hello, world!');
+
+delimiter |;
+CREATE PROCEDURE p1()
+BEGIN
+ DECLARE sp_var INTEGER;
+
+ SELECT col INTO sp_var FROM t1 LIMIT 1;
+ SET @user_var = sp_var;
+
+ SELECT sp_var;
+ SELECT @user_var;
+END|
+delimiter ;|
+
+CALL p1();
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+###########################################################################
+#
+# Test case for BUG#12903: upper function does not work inside a function.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#12903
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+CREATE TABLE t1(txt VARCHAR(255));
+
+delimiter |;
+CREATE FUNCTION f1(arg VARCHAR(255)) RETURNS VARCHAR(255)
+BEGIN
+ DECLARE v1 VARCHAR(255);
+ DECLARE v2 VARCHAR(255);
+
+ SET v1 = CONCAT(LOWER(arg), UPPER(arg));
+ SET v2 = CONCAT(LOWER(v1), UPPER(v1));
+
+ INSERT INTO t1 VALUES(v1), (v2);
+
+ RETURN CONCAT(LOWER(arg), UPPER(arg));
+END|
+delimiter ;|
+
+SELECT f1('_aBcDe_');
+
+SELECT * FROM t1;
+
+#
+# Cleanup.
+#
+
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+###########################################################################
+#
+# Test case for BUG#13808: ENUM type stored procedure parameter accepts
+# non-enumerated data.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#13808
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+
+CREATE PROCEDURE p1(arg ENUM('a', 'b'))
+BEGIN
+ SELECT arg;
+END|
+
+CREATE PROCEDURE p2(arg ENUM('a', 'b'))
+BEGIN
+ DECLARE var ENUM('c', 'd') DEFAULT arg;
+
+ SELECT arg, var;
+END|
+
+CREATE FUNCTION f1(arg ENUM('a', 'b')) RETURNS ENUM('c', 'd')
+BEGIN
+ RETURN arg;
+END|
+
+delimiter ;|
+
+CALL p1('c');
+
+CALL p2('a');
+
+SELECT f1('a');
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP FUNCTION f1;
+
+###########################################################################
+#
+# Test case for BUG#13909: Varchar Stored Procedure Parameter always BINARY
+# string (ignores CHARACTER SET).
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#13909
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+
+CREATE PROCEDURE p1(arg VARCHAR(255))
+BEGIN
+ SELECT CHARSET(arg);
+END|
+
+CREATE PROCEDURE p2(arg VARCHAR(255) CHARACTER SET UTF8)
+BEGIN
+ SELECT CHARSET(arg);
+END|
+
+delimiter ;|
+
+CALL p1('t');
+CALL p1(_UTF8 't');
+
+
+CALL p2('t');
+CALL p2(_LATIN1 't');
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+###########################################################################
+#
+# Test case for BUG#14188: BINARY variables have no 0x00 padding.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#14188
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+CREATE PROCEDURE p1(arg1 BINARY(2), arg2 VARBINARY(2))
+BEGIN
+ DECLARE var1 BINARY(2) DEFAULT 0x41;
+ DECLARE var2 VARBINARY(2) DEFAULT 0x42;
+
+ SELECT HEX(arg1), HEX(arg2);
+ SELECT HEX(var1), HEX(var2);
+END|
+delimiter ;|
+
+CALL p1(0x41, 0x42);
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+
+###########################################################################
+#
+# Test case for BUG#15148: Stored procedure variables accept non-scalar values.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#15148
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+CREATE TABLE t1(col1 TINYINT, col2 TINYINT);
+
+INSERT INTO t1 VALUES(1, 2), (11, 12);
+
+delimiter |;
+CREATE PROCEDURE p1(arg TINYINT)
+BEGIN
+ SELECT arg;
+END|
+delimiter ;|
+
+--error ER_OPERAND_COLUMNS
+CALL p1((1, 2));
+
+--error ER_OPERAND_COLUMNS
+CALL p1((SELECT * FROM t1 LIMIT 1));
+
+--error ER_OPERAND_COLUMNS
+CALL p1((SELECT col1, col2 FROM t1 LIMIT 1));
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+###########################################################################
+#
+# Test case for BUG#13613: substring function in stored procedure.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#13613
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+
+CREATE PROCEDURE p1(x VARCHAR(50))
+BEGIN
+ SET x = SUBSTRING(x, 1, 3);
+ SELECT x;
+END|
+
+CREATE FUNCTION f1(x VARCHAR(50)) RETURNS VARCHAR(50)
+BEGIN
+ RETURN SUBSTRING(x, 1, 3);
+END|
+
+delimiter ;|
+
+CALL p1('abcdef');
+
+SELECT f1('ABCDEF');
+
+#
+# Cleanup.
+#
+
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+
+###########################################################################
+#
+# Test case for BUG#13665: concat with '' produce incorrect results in SP.
+#
+###########################################################################
+
+--echo
+--echo ---------------------------------------------------------------
+--echo BUG#13665
+--echo ---------------------------------------------------------------
+--echo
+
+#
+# Prepare.
+#
+
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+#
+# Test case.
+#
+
+delimiter |;
+CREATE FUNCTION f1() RETURNS VARCHAR(20000)
+BEGIN
+ DECLARE var VARCHAR(2000);
+
+ SET var = '';
+ SET var = CONCAT(var, 'abc');
+ SET var = CONCAT(var, '');
+
+ RETURN var;
+END|
+delimiter ;|
+
+SELECT f1();
+
+#
+# Cleanup.
+#
+
+DROP FUNCTION f1;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index def6afc000e..f73288f04ba 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -13,6 +13,8 @@
# Tests that require multiple connections, except security/privilege tests,
# go to sp-thread.
# Tests that uses 'goto' to into sp-goto.test (currently disabled)
+# Tests that destroys system tables (e.g. mysql.proc) for error testing
+# go to sp-destruct.
use test;
@@ -365,6 +367,7 @@ create function sub3(i int) returns int
call sub1("sub1a", (select 7))|
call sub1("sub1b", (select max(i) from t2))|
+--error ER_OPERAND_COLUMNS
call sub1("sub1c", (select i,d from t2 limit 1))|
call sub1("sub1d", (select 1 from (select 1) a))|
call sub2("sub2")|
@@ -1211,15 +1214,13 @@ begin
end if;
end|
select f5(1)|
-# This should generate an error about insuficient number of tables locked
-# Now this crash server
---disable_parsing # until bug#11394 fix
---error 1100
+# Since currently recursive functions are disallowed ER_SP_NO_RECURSION
+# error will be returned, once we will allow them error about
+# insufficient number of locked tables will be returned instead.
+--error ER_SP_NO_RECURSION
select f5(2)|
-# But now it simply miserably fails because we are trying to use the same
-# lex on the next iteration :/ It should generate some error too...
+--error ER_SP_NO_RECURSION
select f5(3)|
---enable_parsing
# OTOH this should work
create function f6() returns int
@@ -1265,13 +1266,12 @@ select * from v1|
# views and functions ?
create function f1() returns int
return (select sum(data) from t1) + (select sum(data) from v1)|
-# This queries will crash server because we can't use LEX in
-# reenterable fashion yet. Patch disabling recursion will heal this.
---disable_parsing
+--error ER_SP_NO_RECURSION
select f1()|
+--error ER_SP_NO_RECURSION
select * from v1|
+--error ER_SP_NO_RECURSION
select * from v2|
---enable_parsing
# Back to the normal cases
drop function f1|
create function f1() returns int
@@ -1289,9 +1289,7 @@ select *, f0() from v0|
#
# Let us test how well prelocking works with explicit LOCK TABLES.
#
-# Nowdays we have to lock mysql.proc to be able to read SP definitions.
-# But Monty was going to fix this.
-lock tables t1 read, t1 as t11 read, mysql.proc read|
+lock tables t1 read, t1 as t11 read|
# These should work well
select f3()|
select id, f3() from t1 as t11|
@@ -1481,9 +1479,6 @@ show procedure status like '%p%'|
# Fibonacci, for recursion test. (Yet Another Numerical series :)
#
-# This part of test is disabled until we implement support for
-# recursive stored procedures.
---disable_parsing
--disable_warnings
drop table if exists fib|
--enable_warnings
@@ -1512,6 +1507,9 @@ begin
end if;
end|
+# Enable recursion
+set @@max_sp_recursion_depth= 20|
+
# Minimum test: recursion of 3 levels
insert into fib values (0), (1)|
@@ -1531,7 +1529,7 @@ call fib(20)|
select * from fib order by f asc|
drop table fib|
drop procedure fib|
---enable_parsing
+set @@max_sp_recursion_depth= 0|
#
# Comment & suid
@@ -1800,16 +1798,8 @@ select @x2|
drop procedure bug2260|
#
-# BUG#2267
+# BUG#2267 "Lost connect if stored procedure has SHOW FUNCTION STATUS"
#
-# NOTE: This test case will be fixed as soon as Monty
-# will allow to open mysql.proc table under LOCK TABLES
-# without mentioning in lock list.
-#
-# FIXME: Other solution would be to use preopened proc table
-# instead of opening it anew.
-#
---disable_parsing
--disable_warnings
drop procedure if exists bug2267_1|
--enable_warnings
@@ -1836,11 +1826,13 @@ end|
--disable_warnings
drop procedure if exists bug2267_4|
+drop function if exists bug2267_4|
--enable_warnings
create procedure bug2267_4()
begin
- show create function fac;
+ show create function bug2267_4;
end|
+create function bug2267_4() returns int return 100|
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
call bug2267_1()|
@@ -1853,7 +1845,7 @@ drop procedure bug2267_1|
drop procedure bug2267_2|
drop procedure bug2267_3|
drop procedure bug2267_4|
---enable_parsing
+drop function bug2267_4|
#
# BUG#2227
@@ -1873,23 +1865,16 @@ call bug2227(9)|
drop procedure bug2227|
#
-# BUG#2614
+# BUG#2614 "Stored procedure with INSERT ... SELECT that does not
+# contain any tables crashes server"
#
-# 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_parsing
--disable_warnings
drop procedure if exists bug2614|
--enable_warnings
create procedure bug2614()
begin
- drop temporary table if exists t3;
- create temporary table t3 (id int default '0' not null);
+ 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|
@@ -1898,9 +1883,8 @@ end|
call bug2614()|
--enable_warnings
call bug2614()|
-drop temporary table t3|
+drop table t3|
drop procedure bug2614|
---enable_parsing
#
# BUG#2674
@@ -4773,8 +4757,326 @@ drop procedure bug10100pv|
drop procedure bug10100pd|
drop procedure bug10100pc|
drop view v1|
+
+#
+# BUG#13729: Stored procedures: packet error after exception handled
+#
+--disable_warnings
+drop procedure if exists bug13729|
+drop table if exists t3|
+--enable_warnings
+
+create table t3 (s1 int, primary key (s1))|
+
+insert into t3 values (1),(2)|
+
+create procedure bug13729()
+begin
+ declare continue handler for sqlexception select 55;
+
+ update t3 set s1 = 1;
+end|
+
+call bug13729()|
+# Used to cause Packets out of order
+select * from t3|
+
+drop procedure bug13729|
drop table t3|
+#
+# BUG#14643: Stored Procedure: Continuing after failed var. initialization
+# crashes server.
+#
+--disable_warnings
+drop procedure if exists bug14643_1|
+drop procedure if exists bug14643_2|
+--enable_warnings
+
+create procedure bug14643_1()
+begin
+ declare continue handler for sqlexception select 'boo' as 'Handler';
+
+ begin
+ declare v int default undefined_var;
+
+ if v = 1 then
+ select 1;
+ else
+ select v, isnull(v);
+ end if;
+ end;
+end|
+
+create procedure bug14643_2()
+begin
+ declare continue handler for sqlexception select 'boo' as 'Handler';
+
+ case undefined_var
+ when 1 then
+ select 1;
+ else
+ select 2;
+ end case;
+
+ select undefined_var;
+end|
+
+call bug14643_1()|
+call bug14643_2()|
+
+drop procedure bug14643_1|
+drop procedure bug14643_2|
+
+#
+# BUG#14304: auto_increment field incorrect set in SP
+#
+--disable_warnings
+drop procedure if exists bug14304|
+drop table if exists t3, t4|
+--enable_warnings
+
+create table t3(a int primary key auto_increment)|
+create table t4(a int primary key auto_increment)|
+
+create procedure bug14304()
+begin
+ insert into t3 set a=null;
+ insert into t4 set a=null;
+ insert into t4 set a=null;
+ insert into t4 set a=null;
+ insert into t4 set a=null;
+ insert into t4 set a=null;
+ insert into t4 select null as a;
+
+ insert into t3 set a=null;
+ insert into t3 set a=null;
+
+ select * from t3;
+end|
+
+call bug14304()|
+
+drop procedure bug14304|
+drop table t3, t4|
+
+#
+# BUG#14376: MySQL crash on scoped variable (re)initialization
+#
+--disable_warnings
+drop procedure if exists bug14376|
+--enable_warnings
+
+create procedure bug14376()
+begin
+ declare x int default x;
+end|
+
+# Not the error we want, but that's what we got for now...
+--error ER_BAD_FIELD_ERROR
+call bug14376()|
+drop procedure bug14376|
+
+create procedure bug14376()
+begin
+ declare x int default 42;
+
+ begin
+ declare x int default x;
+
+ select x;
+ end;
+end|
+
+call bug14376()|
+
+drop procedure bug14376|
+
+create procedure bug14376(x int)
+begin
+ declare x int default x;
+
+ select x;
+end|
+
+call bug14376(4711)|
+
+drop procedure bug14376|
+
+#
+# Bug#5967 "Stored procedure declared variable used instead of column"
+# The bug should be fixed later.
+# Test precedence of names of parameters, variable declarations,
+# variable declarations in nested compound statements, table columns,
+# table columns in cursor declarations.
+# According to the standard, table columns take precedence over
+# variable declarations. In MySQL 5.0 it's vice versa.
+#
+
+--disable_warnings
+drop procedure if exists bug5967|
+drop table if exists t3|
+--enable_warnings
+create table t3 (a varchar(255))|
+insert into t3 (a) values ("a - table column")|
+create procedure bug5967(a varchar(255))
+begin
+ declare i varchar(255);
+ declare c cursor for select a from t3;
+ select a;
+ select a from t3 into i;
+ select i as 'Parameter takes precedence over table column'; open c;
+ fetch c into i;
+ close c;
+ select i as 'Parameter takes precedence over table column in cursors';
+ begin
+ declare a varchar(255) default 'a - local variable';
+ declare c1 cursor for select a from t3;
+ select a as 'A local variable takes precedence over parameter';
+ open c1;
+ fetch c1 into i;
+ close c1;
+ select i as 'A local variable takes precedence over parameter in cursors';
+ begin
+ declare a varchar(255) default 'a - local variable in a nested compound statement';
+ declare c2 cursor for select a from t3;
+ select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement';
+ select a from t3 into i;
+ select i as 'A local variable in a nested compound statement takes precedence over table column';
+ open c2;
+ fetch c2 into i;
+ close c2;
+ select i as 'A local variable in a nested compound statement takes precedence over table column in cursors';
+ end;
+ end;
+end|
+call bug5967("a - stored procedure parameter")|
+drop procedure bug5967|
+
+#
+# Bug#13012 "SP: REPAIR/BACKUP/RESTORE TABLE crashes the server"
+#
+--disable_warnings
+drop procedure if exists bug13012|
+--enable_warnings
+create procedure bug13012()
+BEGIN
+ REPAIR TABLE t1;
+ BACKUP TABLE t1 to '../tmp';
+ DROP TABLE t1;
+ RESTORE TABLE t1 FROM '../tmp';
+END|
+call bug13012()|
+drop procedure bug13012|
+create view v1 as select * from t1|
+create procedure bug13012()
+BEGIN
+ REPAIR TABLE t1,t2,t3,v1;
+ OPTIMIZE TABLE t1,t2,t3,v1;
+ ANALYZE TABLE t1,t2,t3,v1;
+END|
+call bug13012()|
+call bug13012()|
+call bug13012()|
+drop procedure bug13012|
+drop view v1;
+select * from t1|
+
+#
+# A test case for Bug#15392 "Server crashes during prepared statement
+# execute": make sure that stored procedure check for error conditions
+# properly and do not continue execution if an error has been set.
+#
+# It's necessary to use several DBs because in the original code
+# the successful return of mysql_change_db overrode the error from
+# execution.
+drop schema if exists mysqltest1|
+drop schema if exists mysqltest2|
+drop schema if exists mysqltest3|
+create schema mysqltest1|
+create schema mysqltest2|
+create schema mysqltest3|
+use mysqltest3|
+
+create procedure mysqltest1.p1 (out prequestid varchar(100))
+begin
+ call mysqltest2.p2('call mysqltest3.p3(1, 2)');
+end|
+
+create procedure mysqltest2.p2(in psql text)
+begin
+ declare lsql text;
+ set @lsql= psql;
+ prepare lstatement from @lsql;
+ execute lstatement;
+ deallocate prepare lstatement;
+end|
+
+create procedure mysqltest3.p3(in p1 int)
+begin
+ select p1;
+end|
+
+--error ER_SP_WRONG_NO_OF_ARGS
+call mysqltest1.p1(@rs)|
+--error ER_SP_WRONG_NO_OF_ARGS
+call mysqltest1.p1(@rs)|
+--error ER_SP_WRONG_NO_OF_ARGS
+call mysqltest1.p1(@rs)|
+drop schema if exists mysqltest1|
+drop schema if exists mysqltest2|
+drop schema if exists mysqltest3|
+use test|
+
+#
+# Bug#15441 "Running SP causes Server to Crash": check that an SP variable
+# can not be used in VALUES() function.
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug15441|
+--enable_warnings
+create table t3 (id int not null primary key, county varchar(25))|
+insert into t3 (id, county) values (1, 'York')|
+
+# First check that a stored procedure that refers to a parameter in VALUES()
+# function won't parse.
+
+create procedure bug15441(c varchar(25))
+begin
+ update t3 set id=2, county=values(c);
+end|
+--error ER_BAD_FIELD_ERROR
+call bug15441('county')|
+drop procedure bug15441|
+
+# Now check the case when there is an ambiguity between column names
+# and stored procedure parameters: the parser shall resolve the argument
+# of VALUES() function to the column name.
+
+# It's hard to deduce what county refers to in every case (INSERT statement):
+# 1st county refers to the column
+# 2nd county refers to the procedure parameter
+# 3d and 4th county refers to the column, again, but
+# for 4th county it has the value of SP parameter
+
+# In UPDATE statement, just check that values() function returns NULL for
+# non- INSERT...UPDATE statements, as stated in the manual.
+
+create procedure bug15441(county varchar(25))
+begin
+ declare c varchar(25) default "hello";
+
+ insert into t3 (id, county) values (1, county)
+ on duplicate key update county= values(county);
+ select * from t3;
+
+ update t3 set id=2, county=values(id);
+ select * from t3;
+end|
+call bug15441('Yale')|
+drop table t3|
+drop procedure bug15441|
#
# BUG#NNNN: New bug synopsis
diff --git a/mysql-test/t/sp_trans.test b/mysql-test/t/sp_trans.test
index d72eaf5dca0..308d4ad5c33 100644
--- a/mysql-test/t/sp_trans.test
+++ b/mysql-test/t/sp_trans.test
@@ -356,6 +356,70 @@ drop table t1, t2|
#
+# BUG#14840: CONTINUE handler problem
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug14840_1|
+drop procedure if exists bug14840_2|
+--enable_warnings
+
+create table t3
+(
+ x int,
+ y int,
+ primary key (x)
+) engine=InnoDB|
+
+# This used to hang the client since the insert returned with an
+# error status (left over from the update) even though it succeeded,
+# which caused the execution to end at that point.
+create procedure bug14840_1()
+begin
+ declare err int default 0;
+ declare continue handler for sqlexception
+ set err = err + 1;
+
+ start transaction;
+ update t3 set x = 1, y = 42 where x = 2;
+ insert into t3 values (3, 4711);
+ if err > 0 then
+ rollback;
+ else
+ commit;
+ end if;
+ select * from t3;
+end|
+
+# A simpler (non-transactional) case: insert at select should be done
+create procedure bug14840_2()
+begin
+ declare err int default 0;
+ declare continue handler for sqlexception
+ begin
+ set err = err + 1;
+ select err as 'Ping';
+ end;
+
+ update t3 set x = 1, y = 42 where x = 2;
+ update t3 set x = 1, y = 42 where x = 2;
+ insert into t3 values (3, 4711);
+ select * from t3;
+end|
+
+insert into t3 values (1, 3), (2, 5)|
+call bug14840_1()|
+
+delete from t3|
+insert into t3 values (1, 3), (2, 5)|
+call bug14840_2()|
+
+drop procedure bug14840_1|
+drop procedure bug14840_2|
+drop table t3|
+
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index cc621fb5835..762ff36ba63 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -1968,3 +1968,86 @@ drop table t1;
purge master logs before (select adddate(current_timestamp(), interval -4 day));
+#
+# Test for bug #11762: subquery with an aggregate function in HAVING
+#
+
+CREATE TABLE t1 (a int, b int);
+CREATE TABLE t2 (c int, d int);
+CREATE TABLE t3 (e int);
+
+INSERT INTO t1 VALUES
+ (1,10), (2,10), (1,20), (2,20), (3,20), (2,30), (4,40);
+INSERT INTO t2 VALUES
+ (2,10), (2,20), (4,10), (5,10), (3,20), (2,40);
+INSERT INTO t3 VALUES (10), (30), (10), (20) ;
+
+SELECT a, MAX(b), MIN(b) FROM t1 GROUP BY a;
+SELECT * FROM t2;
+SELECT * FROM t3;
+
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>20);
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2 WHERE MAX(b)<d);
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>d);
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2
+ WHERE d >= SOME(SELECT e FROM t3 WHERE MAX(b)=e));
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2
+ WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d));
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2
+ WHERE d > SOME(SELECT e FROM t3 WHERE MAX(b)=e));
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2
+ WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e < d));
+SELECT a FROM t1 GROUP BY a
+ HAVING a IN (SELECT c FROM t2
+ WHERE MIN(b) < d AND
+ EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d));
+
+SELECT a, SUM(a) FROM t1 GROUP BY a;
+
+SELECT a FROM t1
+ WHERE EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c) GROUP BY a;
+SELECT a FROM t1 GROUP BY a
+ HAVING EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c);
+
+SELECT a FROM t1
+ WHERE a < 3 AND
+ EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c) GROUP BY a;
+SELECT a FROM t1
+ WHERE a < 3 AND
+ EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c);
+
+SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a < ALL(SELECT t2.c FROM t2 GROUP BY t2.c
+ HAVING EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e
+ HAVING SUM(t1.a+t2.c) < t3.e/4));
+SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL(SELECT t2.c FROM t2
+ WHERE EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e
+ HAVING SUM(t1.a+t2.c) < t3.e/4));
+-- error 1111
+SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL(SELECT t2.c FROM t2
+ WHERE EXISTS(SELECT t3.e FROM t3
+ WHERE SUM(t1.a+t2.c) < t3.e/4));
+-- error 1111
+SELECT t1.a from t1 GROUP BY t1.a HAVING AVG(SUM(t1.b)) > 20;
+
+SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+ HAVING AVG(t2.c+SUM(t1.b)) > 20);
+SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+ HAVING AVG(SUM(t1.b)) > 20);
+
+SELECT t1.a, SUM(b) AS sum FROM t1 GROUP BY t1.a
+ HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+ HAVING t2.c+sum > 20);
+
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test
index b7a7e83d569..6a6dd305006 100644
--- a/mysql-test/t/symlink.test
+++ b/mysql-test/t/symlink.test
@@ -3,6 +3,8 @@ disable_query_log;
show variables like "have_symlink";
enable_query_log;
+--source include/not_windows.inc
+
--disable_warnings
drop table if exists t1,t2,t7,t8,t9;
drop database if exists mysqltest;
diff --git a/mysql-test/t/trigger-compat.test b/mysql-test/t/trigger-compat.test
index ace18639172..c2acc235135 100644
--- a/mysql-test/t/trigger-compat.test
+++ b/mysql-test/t/trigger-compat.test
@@ -61,7 +61,7 @@ CREATE TRIGGER wl2818_trg1 BEFORE INSERT ON t1
--echo
--echo ---> patching t1.TRG...
---exec grep --text -v 'definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG
+--exec grep -v 'definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG
--exec mv $MYSQL_TEST_DIR/var/tmp/t1.TRG $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG
#
diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test
index c058816ee75..deeaeacbccc 100644
--- a/mysql-test/t/trigger-grant.test
+++ b/mysql-test/t/trigger-grant.test
@@ -449,7 +449,7 @@ CREATE TRIGGER trg5 BEFORE DELETE ON t1
FOR EACH ROW
SET @a = 5;
---exec egrep --text -v '^definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG
+--exec egrep -v '^definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG
--exec echo "definers='' '@' '@abc@def@@' '@hostname' '@abcdef@@@hostname'" >> $MYSQL_TEST_DIR/var/tmp/t1.TRG
--exec mv $MYSQL_TEST_DIR/var/tmp/t1.TRG $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index acd3297e12a..f2d9bb6c856 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -13,6 +13,8 @@ drop procedure if exists p1;
# Create additional connections used through test
connect (addconroot1, localhost, root,,);
connect (addconroot2, localhost, root,,);
+# Connection without current database set
+connect (addconwithoutdb, localhost, root,,*NO-ONE*);
connection default;
create table t1 (i int);
@@ -943,3 +945,16 @@ CALL p1();
drop procedure p1;
drop table t1;
+#
+# Test for bug #14863 "Triggers: crash if create and there is no current
+# database". We should not crash and give proper error when database for
+# trigger or its table is not specified and there is no current database.
+#
+connection addconwithoutdb;
+--error ER_NO_DB_ERROR
+create trigger t1_bi before insert on test.t1 for each row set @a:=0;
+--error ER_NO_DB_ERROR
+create trigger test.t1_bi before insert on t1 for each row set @a:=0;
+--error ER_NO_DB_ERROR
+drop trigger t1_bi;
+connection default;
diff --git a/mysql-test/t/type_binary.test b/mysql-test/t/type_binary.test
index 451363c1ae4..1639aff4711 100644
--- a/mysql-test/t/type_binary.test
+++ b/mysql-test/t/type_binary.test
@@ -68,3 +68,27 @@ drop table t1;
# check that cast appends trailing zeros
select hex(cast(0x10 as binary(2)));
+
+#
+# Bug #14299: BINARY space truncation should cause warning or error
+#
+create table t1 (b binary(2), vb varbinary(2));
+insert into t1 values(0x4120, 0x4120);
+insert into t1 values(0x412020, 0x412020);
+drop table t1;
+create table t1 (c char(2), vc varchar(2));
+insert into t1 values(0x4120, 0x4120);
+insert into t1 values(0x412020, 0x412020);
+drop table t1;
+
+set @old_sql_mode= @@sql_mode, sql_mode= 'traditional';
+create table t1 (b binary(2), vb varbinary(2));
+insert into t1 values(0x4120, 0x4120);
+--error ER_DATA_TOO_LONG
+insert into t1 values(0x412020, NULL);
+--error ER_DATA_TOO_LONG
+insert into t1 values(NULL, 0x412020);
+drop table t1;
+set @@sql_mode= @old_sql_mode;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/type_newdecimal-big.test b/mysql-test/t/type_newdecimal-big.test
new file mode 100644
index 00000000000..9a1104e4fe6
--- /dev/null
+++ b/mysql-test/t/type_newdecimal-big.test
@@ -0,0 +1,50 @@
+--source include/big_test.inc
+
+--disable_warnings
+drop procedure if exists sp1;
+--enable_warnings
+
+#
+#-- 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.
+#
+
+delimiter //;
+#
+CREATE PROCEDURE sp1()
+BEGIN
+ DECLARE v1, v2, v3, v4 DECIMAL(28,12);
+ DECLARE v3_2, v4_2 DECIMAL(28, 12);
+ DECLARE counter INT;
+
+ SET v1 = 1;
+ SET v2 = 2;
+ SET v3 = 1000000000000;
+ SET v4 = 2000000000000;
+ SET counter = 0;
+
+ WHILE counter < 100000 DO
+ SET v1 = v1 + 0.000000000001;
+ SET v2 = v2 - 0.000000000001;
+ SET v3 = v3 + 1;
+ SET v4 = v4 - 1;
+ SET counter = counter + 1;
+ END WHILE;
+
+ SET v3_2 = v3 * 0.000000000001;
+ SET v4_2 = v4 * 0.000000000001;
+
+ SELECT v1, v2, v3, v3_2, v4, v4_2;
+END//
+#
+call sp1()//
+#-- should return
+# -- v1=1.0000001
+# -- v2=1.999999900000
+# -- v3=1.0000001
+# -- v4=1.999999900000
+#
+delimiter ;//
+#
+drop procedure sp1;
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index ad71ffa02e5..e2fe9767432 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -473,7 +473,7 @@ drop table wl1612_4;
#
#-- Additional tests for WL#1612 Precision math
#
-#-- 1. Comparisons should show that a number is
+#-- Comparisons should show that a number is
#-- exactly equal to its value as displayed.
#
set sql_mode='';
@@ -487,34 +487,9 @@ 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
+#-- 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
@@ -565,7 +540,7 @@ select * from t1;
#
drop table t1;
#
-#-- 4. The usual arithmetic operators / * + - should work.
+#-- The usual arithmetic operators / * + - should work.
#
#select 77777777777777777777777777777777777777 / 7777777777777777777777777777777777777 = 10;
#-- should return 0 (false).
@@ -668,7 +643,7 @@ select truncate(99999999999999999999999999999999999999,-31);
#drop procedure p1;
#drop table t1;
#
-#-- 7. When I say DECIMAL(x) I should be able to store x digits.
+#-- 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;
@@ -676,7 +651,8 @@ select truncate(99999999999999999999999999999999999999,-31);
#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.
+#-- When I say DECIMAL(x,y) there should be no silent change of precision or
+#-- scale.
#
#drop table if exists t1;
#
@@ -694,7 +670,7 @@ select truncate(99999999999999999999999999999999999999,-31);
#
#drop table t1;
#
-#-- 9. From WL#1612 "The future" point 2.:
+#-- 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.
#
@@ -715,7 +691,7 @@ show create table t1;
#
drop table t1;
#
-#-- 10. From WL#1612, "The future", point 3.: We have to start rounding correctly.
+#-- From WL#1612, "The future", point 3.: We have to start rounding correctly.
#
select round(1.5),round(2.5);
#-- should return:
@@ -725,13 +701,13 @@ select 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.
+#-- 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.
+#-- From WL#1612, "The future", point 5.: Division by zero is an error.
#
set sql_mode='traditional';
#
@@ -752,7 +728,7 @@ select 1 / 0;
#+-------+
#1 row in set, 1 warning (0.00 sec)
#
-#-- 13. From WL#1612 "The future" point 6.: Overflow is an error.
+#-- From WL#1612 "The future" point 6.: Overflow is an error.
#
#set sql_mode='';
#
@@ -793,7 +769,8 @@ select 1 / 0;
#drop table t2;
#drop table t1;
#
-#-- 15. From WL#1612 "The future" point 8.: Stop storing leading "+" signs and leading "0"s.
+#-- From WL#1612 "The future" point 8.: Stop storing leading "+" signs and
+# leading "0"s.
#
#drop table if exists t1;
#
@@ -805,7 +782,7 @@ select 1 / 0;
#
#drop table t1;
#
-#-- 16. From WL#1612, The future" point 9.:
+#-- 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.
#
@@ -817,7 +794,7 @@ select 1 / 0;
#
#drop table t1;
#
-#-- 17. The scripts in the following bugs should work:
+#-- The scripts in the following bugs should work:
#
#BUG#559 Maximum precision for DECIMAL column ...
@@ -833,7 +810,7 @@ select 1 / 0;
#BUG#6048 Stored procedure causes operating system reboot
#BUG#6053 DOUBLE PRECISION literal
--- 18. Tests from 'traditional' mode tests
+-- Tests from 'traditional' mode tests
#
set sql_mode='ansi,traditional';
#
@@ -1077,10 +1054,17 @@ SELECT CAST(my_float AS DECIMAL(65,30)), my_float FROM t1;
SELECT CAST(my_double AS DECIMAL(65,30)), my_double FROM t1;
SELECT CAST(my_varchar AS DECIMAL(65,30)), my_varchar FROM t1;
+# We have to disable warnings here as the test in
+# Field_new_decimal::store(double):
+# if (nr2 != nr)
+# fails randomly depending on compiler options
+
+--disable_warnings
UPDATE t1 SET my_decimal = my_float;
SELECT my_decimal, my_float FROM t1;
UPDATE t1 SET my_decimal = my_double;
SELECT my_decimal, my_double FROM t1;
+--enable_warnings
UPDATE t1 SET my_decimal = my_varchar;
SELECT my_decimal, my_varchar FROM t1;
diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test
index 7ae3f65f7cc..9abfe914335 100644
--- a/mysql-test/t/type_time.test
+++ b/mysql-test/t/type_time.test
@@ -21,4 +21,18 @@ select t, time_to_sec(t),sec_to_time(time_to_sec(t)) from t1;
select sec_to_time(time_to_sec(t)) from t1;
drop table t1;
+#
+# BUG #12440: Incorrect processing of time values containing
+# long fraction part and/or large exponent part.
+#
+# These must return normal result:
+SELECT CAST(235959.123456 AS TIME);
+SELECT CAST(0.235959123456e+6 AS TIME);
+SELECT CAST(235959123456e-6 AS TIME);
+# These must cut fraction part and produce warning:
+SELECT CAST(235959.1234567 AS TIME);
+SELECT CAST(0.2359591234567e6 AS TIME);
+# This must return NULL and produce warning:
+SELECT CAST(0.2359591234567e+30 AS TIME);
+
# End of 4.1 tests
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index daa83ef0fa4..6de90dd446d 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -753,6 +753,24 @@ create table t2 select a from t1 union select b from t1;
show columns from t2;
drop table t2, t1;
+#
+# Bug #14216: UNION + DECIMAL wrong values in result
+#
+create table t1 (f1 decimal(60,25), f2 decimal(60,25));
+insert into t1 values (0.0,0.0);
+select f1 from t1 union all select f2 from t1;
+select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1
+union all
+select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1;
+drop table t1;
+create table t1 (f1 decimal(60,24), f2 decimal(60,24));
+insert into t1 values (0.0,0.0);
+select f1 from t1 union all select f2 from t1;
+select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1
+union all
+select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1;
+drop table t1;
+
#
# Test that union with VARCHAR produces dynamic row tables
#
diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test
index 2a151f0dd38..d0496b48c7a 100644
--- a/mysql-test/t/update.test
+++ b/mysql-test/t/update.test
@@ -270,4 +270,21 @@ insert into t1 values('2000-01-01'),('0000-00-00');
update t1 set f1='2002-02-02' where f1 is null;
select * from t1;
drop table t1;
+
+#
+# Bug#15028 Multitable update returns different numbers of matched rows
+# depending on table order
+create table t1 (f1 int);
+create table t2 (f2 int);
+insert into t1 values(1),(2);
+insert into t2 values(1),(1);
+--enable_info
+update t1,t2 set f1=3,f2=3 where f1=f2 and f1=1;
+--disable_info
+update t2 set f2=1;
+update t1 set f1=1 where f1=3;
+--enable_info
+update t2,t1 set f1=3,f2=3 where f1=f2 and f1=1;
+--disable_info
+drop table t1,t2;
# End of 4.1 tests
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index bc54287afb2..db6c12fdacb 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -1744,7 +1744,6 @@ drop function f1;
CHECK TABLE v1, v2, v3, v4, v5, v6;
create function f1 () returns int return (select max(col1) from t1);
DROP TABLE t1;
-# following will show underlying table until BUG#11555 fix
CHECK TABLE v1, v2, v3, v4, v5, v6;
drop function f1;
drop function f2;
@@ -2281,3 +2280,62 @@ create view v1 as select * from t1;
select f1, sum(f2) from v1 group by f1;
drop view v1;
drop table t1;
+
+#
+# BUG#14885: incorrect SOURCE in view created in a procedure
+# TODO: here SOURCE string must be shown when it will be possible
+#
+--disable_warnings
+drop procedure if exists p1;
+--enable_warnings
+delimiter //;
+create procedure p1 () deterministic
+begin
+create view v1 as select 1;
+end;
+//
+delimiter ;//
+call p1();
+show create view v1;
+drop view v1;
+drop procedure p1;
+
+#
+# BUG#15096: using function with view for view creation
+#
+CREATE VIEW v1 AS SELECT 42 AS Meaning;
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+DELIMITER //;
+CREATE FUNCTION f1() RETURNS INTEGER
+BEGIN
+ DECLARE retn INTEGER;
+ SELECT Meaning FROM v1 INTO retn;
+ RETURN retn;
+END
+//
+DELIMITER ;//
+CREATE VIEW v2 AS SELECT f1();
+select * from v2;
+drop view v2,v1;
+drop function f1;
+
+#
+# Bug#14861: aliased column names are not preserved.
+#
+create table t1 (id numeric, warehouse_id numeric);
+create view v1 as select id from t1;
+create view v2 as
+select t1.warehouse_id, v1.id as receipt_id
+from t1, v1 where t1.id = v1.id;
+
+insert into t1 (id, warehouse_id) values(3, 2);
+insert into t1 (id, warehouse_id) values(4, 2);
+insert into t1 (id, warehouse_id) values(5, 1);
+
+select v2.receipt_id as alias1, v2.receipt_id as alias2 from v2
+order by v2.receipt_id;
+
+drop view v2, v1;
+drop table t1;
diff --git a/mysql-test/t/view_query_cache.test b/mysql-test/t/view_query_cache.test
index 81994407641..d4ebe45b7ac 100644
--- a/mysql-test/t/view_query_cache.test
+++ b/mysql-test/t/view_query_cache.test
@@ -96,4 +96,35 @@ unlock tables;
set query_cache_wlock_invalidate=default;
drop view v1;
drop table t1;
+
+#
+# BUG#15119: returning temptable view from the query cache.
+#
+flush status;
+create table t1 (a int, b int);
+create algorithm=temptable view v1 as select * from t1;
+select * from v1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from v1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+insert into t1 values (1,1);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from v1;
+select * from v1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+drop view v1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+drop table t1;
+
+# Reset default environment.
set GLOBAL query_cache_size=default;
diff --git a/mysys/charset-def.c b/mysys/charset-def.c
index 5b30d1ee135..0559fe59d06 100644
--- a/mysys/charset-def.c
+++ b/mysys/charset-def.c
@@ -43,6 +43,7 @@ extern CHARSET_INFO my_charset_ucs2_spanish2_uca_ci;
extern CHARSET_INFO my_charset_ucs2_roman_uca_ci;
extern CHARSET_INFO my_charset_ucs2_persian_uca_ci;
extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci;
+extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci;
#endif
#ifdef HAVE_CHARSET_utf8
@@ -64,6 +65,7 @@ extern CHARSET_INFO my_charset_utf8_spanish2_uca_ci;
extern CHARSET_INFO my_charset_utf8_roman_uca_ci;
extern CHARSET_INFO my_charset_utf8_persian_uca_ci;
extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci;
+extern CHARSET_INFO my_charset_utf8_hungarian_uca_ci;
#ifdef HAVE_UTF8_GENERAL_CS
extern CHARSET_INFO my_charset_utf8_general_cs;
#endif
@@ -151,6 +153,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_ucs2_roman_uca_ci);
add_compiled_collation(&my_charset_ucs2_persian_uca_ci);
add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci);
+ add_compiled_collation(&my_charset_ucs2_hungarian_uca_ci);
#endif
#endif
@@ -184,6 +187,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_utf8_roman_uca_ci);
add_compiled_collation(&my_charset_utf8_persian_uca_ci);
add_compiled_collation(&my_charset_utf8_esperanto_uca_ci);
+ add_compiled_collation(&my_charset_utf8_hungarian_uca_ci);
#endif
#endif
diff --git a/mysys/hash.c b/mysys/hash.c
index 45cf7d5ff1d..99479ef6769 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -36,9 +36,10 @@ typedef struct st_hash_info {
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
-static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length);
+static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key,
+ uint length);
-static uint calc_hash(HASH *hash,const byte *key,uint length)
+static uint calc_hash(const HASH *hash, const byte *key, uint length)
{
ulong nr1=1, nr2=4;
hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2);
@@ -63,7 +64,6 @@ _hash_init(HASH *hash,CHARSET_INFO *charset,
hash->key_offset=key_offset;
hash->key_length=key_length;
hash->blength=1;
- hash->current_record= NO_RECORD; /* For the future */
hash->get_key=get_key;
hash->free=free_element;
hash->flags=flags;
@@ -135,7 +135,6 @@ void my_hash_reset(HASH *hash)
reset_dynamic(&hash->array);
/* Set row pointers so that the hash can be reused at once */
hash->blength= 1;
- hash->current_record= NO_RECORD;
DBUG_VOID_RETURN;
}
@@ -147,7 +146,8 @@ void my_hash_reset(HASH *hash)
*/
static inline char*
-hash_key(HASH *hash,const byte *record,uint *length,my_bool first)
+hash_key(const HASH *hash, const byte *record, uint *length,
+ my_bool first)
{
if (hash->get_key)
return (*hash->get_key)(record,length,first);
@@ -163,8 +163,8 @@ static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
return (hashnr & ((buffmax >> 1) -1));
}
-static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax,
- uint maxlength)
+static uint hash_rec_mask(const HASH *hash, HASH_LINK *pos,
+ uint buffmax, uint maxlength)
{
uint length;
byte *key= (byte*) hash_key(hash,pos->data,&length,0);
@@ -186,14 +186,25 @@ unsigned int rec_hashnr(HASH *hash,const byte *record)
}
- /* Search after a record based on a key */
- /* Sets info->current_ptr to found record */
+gptr hash_search(const HASH *hash, const byte *key, uint length)
+{
+ HASH_SEARCH_STATE state;
+ return hash_first(hash, key, length, &state);
+}
+
+/*
+ Search after a record based on a key
+
+ NOTE
+ Assigns the number of the found record to HASH_SEARCH_STATE state
+*/
-gptr hash_search(HASH *hash,const byte *key,uint length)
+gptr hash_first(const HASH *hash, const byte *key, uint length,
+ HASH_SEARCH_STATE *current_record)
{
HASH_LINK *pos;
uint flag,idx;
- DBUG_ENTER("hash_search");
+ DBUG_ENTER("hash_first");
flag=1;
if (hash->records)
@@ -206,7 +217,7 @@ gptr hash_search(HASH *hash,const byte *key,uint length)
if (!hashcmp(hash,pos,key,length))
{
DBUG_PRINT("exit",("found key at %d",idx));
- hash->current_record= idx;
+ *current_record= idx;
DBUG_RETURN (pos->data);
}
if (flag)
@@ -218,31 +229,32 @@ gptr hash_search(HASH *hash,const byte *key,uint length)
}
while ((idx=pos->next) != NO_RECORD);
}
- hash->current_record= NO_RECORD;
+ *current_record= NO_RECORD;
DBUG_RETURN(0);
}
/* Get next record with identical key */
/* Can only be called if previous calls was hash_search */
-gptr hash_next(HASH *hash,const byte *key,uint length)
+gptr hash_next(const HASH *hash, const byte *key, uint length,
+ HASH_SEARCH_STATE *current_record)
{
HASH_LINK *pos;
uint idx;
- if (hash->current_record != NO_RECORD)
+ if (*current_record != NO_RECORD)
{
HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
- for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next)
+ for (idx=data[*current_record].next; idx != NO_RECORD ; idx=pos->next)
{
pos=data+idx;
if (!hashcmp(hash,pos,key,length))
{
- hash->current_record= idx;
+ *current_record= idx;
return pos->data;
}
}
- hash->current_record=NO_RECORD;
+ *current_record= NO_RECORD;
}
return 0;
}
@@ -281,7 +293,8 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
!= 0 key of record != key
*/
-static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length)
+static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key,
+ uint length)
{
uint rec_keylength;
byte *rec_key= (byte*) hash_key(hash,pos->data,&rec_keylength,1);
@@ -307,7 +320,6 @@ my_bool my_hash_insert(HASH *info,const byte *record)
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
return(TRUE); /* No more memory */
- info->current_record= NO_RECORD;
data=dynamic_element(&info->array,0,HASH_LINK*);
halfbuff= info->blength >> 1;
@@ -450,7 +462,6 @@ my_bool hash_delete(HASH *hash,byte *record)
}
if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
- hash->current_record= NO_RECORD;
lastpos=data+hash->records;
/* Remove link to record */
@@ -543,7 +554,6 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
if ((idx=pos->next) == NO_RECORD)
DBUG_RETURN(1); /* Not found in links */
}
- hash->current_record= NO_RECORD;
org_link= *pos;
empty=idx;
@@ -593,10 +603,10 @@ byte *hash_element(HASH *hash,uint idx)
isn't changed
*/
-void hash_replace(HASH *hash, uint idx, byte *new_row)
+void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, byte *new_row)
{
- if (idx != NO_RECORD) /* Safety */
- dynamic_element(&hash->array,idx,HASH_LINK*)->data=new_row;
+ if (*current_record != NO_RECORD) /* Safety */
+ dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row;
}
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
index 072492172e3..2fb022a25f2 100644
--- a/mysys/my_copy.c
+++ b/mysys/my_copy.c
@@ -53,7 +53,7 @@ struct utimbuf {
int my_copy(const char *from, const char *to, myf MyFlags)
{
uint Count;
- my_bool new_file_stat; /* 1 if we could stat "to" */
+ my_bool new_file_stat= 0; /* 1 if we could stat "to" */
int create_flag;
File from_file,to_file;
char buff[IO_SIZE];
@@ -62,7 +62,6 @@ int my_copy(const char *from, const char *to, myf MyFlags)
DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
from_file=to_file= -1;
- LINT_INIT(new_file_stat);
DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */
if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */
new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0)));
diff --git a/mysys/my_open.c b/mysys/my_open.c
index baca97450b7..6ed3cb5becf 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -267,7 +267,7 @@ File my_sopen(const char *path, int oflag, int shflag, int pmode)
*/
switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
case 0:
- case _O_EXCL: // ignore EXCL w/o CREAT
+ case _O_EXCL: /* ignore EXCL w/o CREAT */
filecreate= OPEN_EXISTING;
break;
@@ -281,7 +281,7 @@ File my_sopen(const char *path, int oflag, int shflag, int pmode)
break;
case _O_TRUNC:
- case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT
+ case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
filecreate= TRUNCATE_EXISTING;
break;
@@ -290,7 +290,7 @@ File my_sopen(const char *path, int oflag, int shflag, int pmode)
break;
default:
- // this can't happen ... all cases are covered
+ /* this can't happen ... all cases are covered */
errno= EINVAL;
_doserrno= 0L;
return -1;
diff --git a/mysys/testhash.c b/mysys/testhash.c
index 72badffdbcd..d15016113cd 100644
--- a/mysys/testhash.c
+++ b/mysys/testhash.c
@@ -74,7 +74,7 @@ static int do_test()
bzero((char*) key1,sizeof(key1[0])*1000);
printf("- Creating hash\n");
- if (hash_init(&hash,recant/2,0,6,0,free_record,0))
+ if (hash_init(&hash, default_charset_info, recant/2, 0, 6, 0, free_record, 0))
goto err;
printf("- Writing records:\n");
@@ -172,15 +172,16 @@ static int do_test()
break;
if (key1[j] > 1)
{
+ HASH_SEARCH_STATE state;
printf("- Testing identical read\n");
sprintf(key,"%6d",j);
pos=1;
- if (!(recpos=hash_search(&hash,key,0)))
+ if (!(recpos= hash_first(&hash, key, 0, &state)))
{
printf("can't find key1: \"%s\"\n",key);
goto err;
}
- while (hash_next(&hash,key,0) && pos < (ulong) (key1[j]+10))
+ while (hash_next(&hash, key, 0, &state) && pos < (ulong) (key1[j]+10))
pos++;
if (pos != (ulong) key1[j])
{
@@ -189,7 +190,7 @@ static int do_test()
}
}
printf("- Creating output heap-file 2\n");
- if (hash_init(&hash2,hash.records,0,0,hash2_key,free_record,0))
+ if (hash_init(&hash2, default_charset_info, hash.records, 0, 0, hash2_key, free_record,0))
goto err;
printf("- Copying and removing records\n");
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
index e5b77de5e38..41914080a9d 100644
--- a/mysys/thr_alarm.c
+++ b/mysys/thr_alarm.c
@@ -401,7 +401,7 @@ void end_thr_alarm(my_bool free_structures)
{
DBUG_ENTER("end_thr_alarm");
if (alarm_aborted != 1) /* If memory not freed */
- {
+ {
pthread_mutex_lock(&LOCK_alarm);
DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
alarm_aborted= -1; /* mark aborted */
@@ -415,13 +415,10 @@ void end_thr_alarm(my_bool free_structures)
if (free_structures)
{
struct timespec abstime;
- /*
- The following test is just for safety, the caller should not
- depend on this
- */
+
DBUG_ASSERT(!alarm_queue.elements);
- /* Wait until alarm thread dies */
+ /* Wait until alarm thread dies */
set_timespec(abstime, 10); /* Wait up to 10 seconds */
while (alarm_thread_running)
{
@@ -429,16 +426,13 @@ void end_thr_alarm(my_bool free_structures)
if (error == ETIME || error == ETIMEDOUT)
break; /* Don't wait forever */
}
- if (!alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ alarm_aborted= 1;
+ pthread_mutex_unlock(&LOCK_alarm);
+ if (!alarm_thread_running) /* Safety */
{
- delete_queue(&alarm_queue);
- alarm_aborted= 1;
- pthread_mutex_unlock(&LOCK_alarm);
- if (!alarm_thread_running) /* Safety */
- {
- pthread_mutex_destroy(&LOCK_alarm);
- pthread_cond_destroy(&COND_alarm);
- }
+ pthread_mutex_destroy(&LOCK_alarm);
+ pthread_cond_destroy(&COND_alarm);
}
}
else
diff --git a/ndb/include/kernel/signaldata/DumpStateOrd.hpp b/ndb/include/kernel/signaldata/DumpStateOrd.hpp
index bde690e056d..4dd22cf5092 100644
--- a/ndb/include/kernel/signaldata/DumpStateOrd.hpp
+++ b/ndb/include/kernel/signaldata/DumpStateOrd.hpp
@@ -78,6 +78,8 @@ public:
LqhDumpAllScanRec = 2301,
LqhDumpAllActiveScanRec = 2302,
LqhDumpLcpState = 2303,
+ LqhErrorInsert5042 = 2315,
+
AccDumpOneScanRec = 2400,
AccDumpAllScanRec = 2401,
AccDumpAllActiveScanRec = 2402,
diff --git a/ndb/include/ndb_version.h.in b/ndb/include/ndb_version.h.in
index 826f5124407..38b72306d03 100644
--- a/ndb/include/ndb_version.h.in
+++ b/ndb/include/ndb_version.h.in
@@ -57,5 +57,8 @@ char ndb_version_string_buf[NDB_VERSION_STRING_BUF_SZ];
*/
/*#define NDB_VERSION_ID 0*/
+#define NDBD_INCL_NODECONF_VERSION_4 MAKE_VERSION(4,1,17)
+#define NDBD_INCL_NODECONF_VERSION_5 MAKE_VERSION(5,0,18)
+
#endif
diff --git a/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/ndb/src/common/mgmcommon/ConfigRetriever.cpp
index b3d0221fedb..a44550da48b 100644
--- a/ndb/src/common/mgmcommon/ConfigRetriever.cpp
+++ b/ndb/src/common/mgmcommon/ConfigRetriever.cpp
@@ -336,14 +336,21 @@ ConfigRetriever::setNodeId(Uint32 nodeid)
Uint32
ConfigRetriever::allocNodeId(int no_retries, int retry_delay_in_seconds)
{
+ int res;
_ownNodeId= 0;
if(m_handle != 0)
{
while (1)
{
- int res= ndb_mgm_alloc_nodeid(m_handle, m_version, m_node_type);
+ if(!ndb_mgm_is_connected(m_handle))
+ if(!ndb_mgm_connect(m_handle, 0, 0, 0))
+ goto next;
+
+ res= ndb_mgm_alloc_nodeid(m_handle, m_version, m_node_type);
if(res >= 0)
return _ownNodeId= (Uint32)res;
+
+ next:
if (no_retries == 0)
break;
no_retries--;
diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt
index 1a72537a77e..0be5e91cd71 100644
--- a/ndb/src/kernel/blocks/ERROR_codes.txt
+++ b/ndb/src/kernel/blocks/ERROR_codes.txt
@@ -61,6 +61,8 @@ Insert system error in GCP participant when receiving GCP_SAVEREQ.
5007:
Delay GCP_SAVEREQ by 10 secs
+7165: Delay INCL_NODE_REQ in starting node yeilding error in GCP_PREPARE
+
ERROR CODES FOR TESTING NODE FAILURE, LOCAL CHECKPOINT HANDLING:
-----------------------------------------------------------------
@@ -155,11 +157,15 @@ Insert node failure handling when receiving COMPLETEREQ.
5006:
Insert node failure handling when receiving ABORTREQ.
+5042:
+As 5002, but with specified table (see DumpStateOrd)
+
These error code can be combined with error codes for testing time-out
handling in DBTC to ensure that node failures are also well handled in
time-out handling. They can also be used to test multiple node failure
handling.
+
ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBLQH
-------------------------------------------------
5011:
@@ -198,6 +204,9 @@ Delay execution of ABORTREQ signal 2 seconds to generate time-out.
8050: Send TCKEYREF is operation is non local
+5100,5101: Drop ABORT req in primary replica
+ Crash on "next" ABORT
+
ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBTC
-------------------------------------------------
8040:
diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp
index 2379bd6cf21..2d50890e962 100644
--- a/ndb/src/kernel/blocks/backup/Backup.cpp
+++ b/ndb/src/kernel/blocks/backup/Backup.cpp
@@ -886,13 +886,17 @@ Backup::checkNodeFail(Signal* signal,
pos= &ref->nodeId - signal->getDataPtr();
break;
}
+ case GSN_WAIT_GCP_REQ:
+ case GSN_DROP_TRIG_REQ:
case GSN_CREATE_TRIG_REQ:
case GSN_ALTER_TRIG_REQ:
- case GSN_WAIT_GCP_REQ:
+ ptr.p->setErrorCode(AbortBackupOrd::BackupFailureDueToNodeFail);
+ return;
case GSN_UTIL_SEQUENCE_REQ:
case GSN_UTIL_LOCK_REQ:
- case GSN_DROP_TRIG_REQ:
return;
+ default:
+ ndbrequire(false);
}
for(Uint32 i = 0; (i = mask.find(i+1)) != NdbNodeBitmask::NotFound; )
@@ -1903,7 +1907,7 @@ Backup::execBACKUP_FRAGMENT_CONF(Signal* signal)
const Uint32 nodeId = refToNode(signal->senderBlockRef());
const Uint32 noOfBytes = conf->noOfBytes;
const Uint32 noOfRecords = conf->noOfRecords;
-
+
BackupRecordPtr ptr;
c_backupPool.getPtr(ptr, ptrI);
@@ -1980,7 +1984,7 @@ Backup::execBACKUP_FRAGMENT_REF(Signal* signal)
}
}
}
- ndbrequire(false);
+ goto err;
done:
ptr.p->masterData.sendCounter--;
@@ -1992,7 +1996,8 @@ done:
masterAbort(signal, ptr);
return;
}//if
-
+
+err:
AbortBackupOrd *ord = (AbortBackupOrd*)signal->getDataPtrSend();
ord->backupId = ptr.p->backupId;
ord->backupPtr = ptr.i;
@@ -3866,7 +3871,7 @@ Backup::checkFile(Signal* signal, BackupFilePtr filePtr)
req->userReference = reference();
req->varIndex = 0;
req->offset = tmp - c_startOfPages;
- req->size = sz; // Avrunda uppot
+ req->size = sz; // Round up
sendSignal(NDBFS_REF, GSN_FSAPPENDREQ, signal,
FsAppendReq::SignalLength, JBA);
diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
index 29de0368212..2a28c4db770 100644
--- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
+++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
@@ -215,7 +215,7 @@ void Dbdih::sendINCL_NODEREQ(Signal* signal, Uint32 nodeId)
signal->theData[2] = c_nodeStartMaster.failNr;
signal->theData[3] = 0;
signal->theData[4] = currentgcp;
- sendSignal(nodeDihRef, GSN_INCL_NODEREQ, signal, 5, JBB);
+ sendSignal(nodeDihRef, GSN_INCL_NODEREQ, signal, 5, JBA);
}//Dbdih::sendINCL_NODEREQ()
void Dbdih::sendMASTER_GCPREQ(Signal* signal, Uint32 nodeId)
@@ -1863,6 +1863,14 @@ void Dbdih::gcpBlockedLab(Signal* signal)
// global checkpoint id and the correct state. We do not wait for any reply
// since the starting node will not send any.
/*-------------------------------------------------------------------------*/
+ Uint32 startVersion = getNodeInfo(c_nodeStartMaster.startNode).m_version;
+
+ if ((getMajor(startVersion) == 4 && startVersion >= NDBD_INCL_NODECONF_VERSION_4) ||
+ (getMajor(startVersion) == 5 && startVersion >= NDBD_INCL_NODECONF_VERSION_5))
+ {
+ c_INCL_NODEREQ_Counter.setWaitingFor(c_nodeStartMaster.startNode);
+ }
+
sendINCL_NODEREQ(signal, c_nodeStartMaster.startNode);
}//Dbdih::gcpBlockedLab()
@@ -2065,6 +2073,13 @@ void Dbdih::execINCL_NODEREQ(Signal* signal)
jamEntry();
Uint32 retRef = signal->theData[0];
Uint32 nodeId = signal->theData[1];
+ if (nodeId == getOwnNodeId() && ERROR_INSERTED(7165))
+ {
+ CLEAR_ERROR_INSERT_VALUE;
+ sendSignalWithDelay(reference(), GSN_INCL_NODEREQ, signal, 5000, signal->getLength());
+ return;
+ }
+
Uint32 tnodeStartFailNr = signal->theData[2];
currentgcp = signal->theData[4];
CRASH_INSERTION(7127);
@@ -2092,6 +2107,15 @@ void Dbdih::execINCL_NODEREQ(Signal* signal)
// id's and the lcp status.
/*-----------------------------------------------------------------------*/
CRASH_INSERTION(7171);
+ Uint32 masterVersion = getNodeInfo(refToNode(cmasterdihref)).m_version;
+
+ if ((NDB_VERSION_MAJOR == 4 && masterVersion >= NDBD_INCL_NODECONF_VERSION_4) ||
+ (NDB_VERSION_MAJOR == 5 && masterVersion >= NDBD_INCL_NODECONF_VERSION_5))
+ {
+ signal->theData[0] = getOwnNodeId();
+ signal->theData[1] = getOwnNodeId();
+ sendSignal(cmasterdihref, GSN_INCL_NODECONF, signal, 2, JBB);
+ }
return;
}//if
if (getNodeStatus(nodeId) != NodeRecord::STARTING) {
@@ -3741,9 +3765,23 @@ void Dbdih::execNODE_FAILREP(Signal* signal)
/*------------------------------------------------------------------------*/
// Verify that a starting node has also crashed. Reset the node start record.
/*-------------------------------------------------------------------------*/
- if (c_nodeStartMaster.startNode != RNIL) {
- ndbrequire(getNodeStatus(c_nodeStartMaster.startNode)!= NodeRecord::ALIVE);
+#if 0
+ /**
+ * Node will crash by itself...
+ * nodeRestart is run then...
+ */
+ if (false && c_nodeStartMaster.startNode != RNIL && getNodeStatus(c_nodeStartMaster.startNode) == NodeRecord::ALIVE)
+ {
+ BlockReference cntrRef = calcNdbCntrBlockRef(c_nodeStartMaster.startNode);
+ SystemError * const sysErr = (SystemError*)&signal->theData[0];
+ sysErr->errorCode = SystemError::StartInProgressError;
+ sysErr->errorRef = reference();
+ sysErr->data1= 0;
+ sysErr->data2= __LINE__;
+ sendSignal(cntrRef, GSN_SYSTEM_ERROR, signal, SystemError::SignalLength, JBA);
+ nodeResetStart();
}//if
+#endif
/*--------------------------------------------------*/
/* */
@@ -5189,15 +5227,16 @@ void Dbdih::removeNodeFromTable(Signal* signal,
/**
* For each of replica record
*/
- Uint32 replicaNo = 0;
+ bool found = false;
ReplicaRecordPtr replicaPtr;
for(replicaPtr.i = fragPtr.p->storedReplicas; replicaPtr.i != RNIL;
- replicaPtr.i = replicaPtr.p->nextReplica, replicaNo++) {
+ replicaPtr.i = replicaPtr.p->nextReplica) {
jam();
ptrCheckGuard(replicaPtr, creplicaFileSize, replicaRecord);
if(replicaPtr.p->procNode == nodeId){
jam();
+ found = true;
noOfRemovedReplicas++;
removeNodeFromStored(nodeId, fragPtr, replicaPtr);
if(replicaPtr.p->lcpOngoingFlag){
@@ -5213,6 +5252,15 @@ void Dbdih::removeNodeFromTable(Signal* signal,
}
}
}
+ if (!found)
+ {
+ jam();
+ /**
+ * Run updateNodeInfo to remove any dead nodes from list of activeNodes
+ * see bug#15587
+ */
+ updateNodeInfo(fragPtr);
+ }
noOfRemainingLcpReplicas += fragPtr.p->noLcpReplicas;
}
@@ -11087,7 +11135,11 @@ void Dbdih::initCommonData()
cnoReplicas = 1;
ndb_mgm_get_int_parameter(p, CFG_DB_NO_REPLICAS, &cnoReplicas);
- cnoReplicas = cnoReplicas > 4 ? 4 : cnoReplicas;
+ if (cnoReplicas > 4)
+ {
+ progError(__LINE__, NDBD_EXIT_INVALID_CONFIG,
+ "Only up to four replicas are supported. Check NoOfReplicas.");
+ }
cgcpDelay = 2000;
ndb_mgm_get_int_parameter(p, CFG_DB_GCP_INTERVAL, &cgcpDelay);
@@ -11675,14 +11727,14 @@ void Dbdih::execCHECKNODEGROUPSREQ(Signal* signal)
break;
case CheckNodeGroups::GetNodeGroupMembers: {
ok = true;
- Uint32 ownNodeGoup =
+ Uint32 ownNodeGroup =
Sysfile::getNodeGroup(sd->nodeId, SYSFILE->nodeGroups);
- sd->output = ownNodeGoup;
+ sd->output = ownNodeGroup;
sd->mask.clear();
NodeGroupRecordPtr ngPtr;
- ngPtr.i = ownNodeGoup;
+ ngPtr.i = ownNodeGroup;
ptrAss(ngPtr, nodeGroupRecord);
for (Uint32 j = 0; j < ngPtr.p->nodeCount; j++) {
jam();
@@ -11690,7 +11742,7 @@ void Dbdih::execCHECKNODEGROUPSREQ(Signal* signal)
}
#if 0
for (int i = 0; i < MAX_NDB_NODES; i++) {
- if (ownNodeGoup ==
+ if (ownNodeGroup ==
Sysfile::getNodeGroup(i, SYSFILE->nodeGroups)) {
sd->mask.set(i);
}
diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
index 94a40adcd4a..1ed383853ba 100644
--- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
+++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
@@ -2885,6 +2885,7 @@ private:
UintR ctransidHash[1024];
Uint32 c_diskless;
+ Uint32 c_error_insert_table_id;
public:
/**
diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
index 2170f890f35..803377f9dd1 100644
--- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
+++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
@@ -3543,6 +3543,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal)
jam();
regTcPtr->activeCreat = ZTRUE;
CRASH_INSERTION(5002);
+ CRASH_INSERTION2(5042, tabptr.i == c_error_insert_table_id);
} else {
regTcPtr->activeCreat = ZFALSE;
}//if
@@ -5880,12 +5881,21 @@ void Dblqh::execABORT(Signal* signal)
warningReport(signal, 8);
return;
}//if
+
+ TcConnectionrec * const regTcPtr = tcConnectptr.p;
+
+ if (ERROR_INSERTED(5100))
+ {
+ SET_ERROR_INSERT_VALUE(5101);
+ return;
+ }
+ CRASH_INSERTION2(5101, regTcPtr->nextReplica != ZNIL);
+
/* ------------------------------------------------------------------------- */
/*A GUIDING DESIGN PRINCIPLE IN HANDLING THESE ERROR SITUATIONS HAVE BEEN */
/*KEEP IT SIMPLE. THUS WE RATHER INSERT A WAIT AND SET THE ABORT_STATE TO */
/*ACTIVE RATHER THAN WRITE NEW CODE TO HANDLE EVERY SPECIAL SITUATION. */
/* ------------------------------------------------------------------------- */
- TcConnectionrec * const regTcPtr = tcConnectptr.p;
if (regTcPtr->nextReplica != ZNIL) {
/* ------------------------------------------------------------------------- */
// We will immediately send the ABORT message also to the next LQH node in line.
@@ -18522,6 +18532,12 @@ Dblqh::execDUMP_STATE_ORD(Signal* signal)
}
}
+
+ if (dumpState->args[0] == DumpStateOrd::LqhErrorInsert5042 && signal->getLength() == 2)
+ {
+ c_error_insert_table_id = dumpState->args[1];
+ SET_ERROR_INSERT_VALUE(5042);
+ }
}//Dblqh::execDUMP_STATE_ORD()
void Dblqh::execSET_VAR_REQ(Signal* signal)
@@ -18562,60 +18578,54 @@ void
Dblqh::execCREATE_TRIG_REQ(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference tupref = calcTupBlockRef(myNodeId);
- sendSignal(tupref, GSN_CREATE_TRIG_REQ, signal, CreateTrigReq::SignalLength, JBB);
+ sendSignal(DBTUP_REF, GSN_CREATE_TRIG_REQ, signal,
+ CreateTrigReq::SignalLength, JBB);
}
void
Dblqh::execCREATE_TRIG_CONF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_CREATE_TRIG_CONF, signal, CreateTrigConf::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_CREATE_TRIG_CONF, signal,
+ CreateTrigConf::SignalLength, JBB);
}
void
Dblqh::execCREATE_TRIG_REF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_CREATE_TRIG_REF, signal, CreateTrigRef::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_CREATE_TRIG_REF, signal,
+ CreateTrigRef::SignalLength, JBB);
}
void
Dblqh::execDROP_TRIG_REQ(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference tupref = calcTupBlockRef(myNodeId);
- sendSignal(tupref, GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB);
+ sendSignal(DBTUP_REF, GSN_DROP_TRIG_REQ, signal,
+ DropTrigReq::SignalLength, JBB);
}
void
Dblqh::execDROP_TRIG_CONF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_DROP_TRIG_CONF, signal, DropTrigConf::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_DROP_TRIG_CONF, signal,
+ DropTrigConf::SignalLength, JBB);
}
void
Dblqh::execDROP_TRIG_REF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_DROP_TRIG_REF, signal, DropTrigRef::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_DROP_TRIG_REF, signal,
+ DropTrigRef::SignalLength, JBB);
}
Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){
diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
index 8218acc0ea7..cb4f1c6244b 100644
--- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
+++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
@@ -141,6 +141,8 @@
#define ZALREADYEXIST 630
#define ZINCONSISTENTHASHINDEX 892
#define ZNOTUNIQUE 893
+
+#define ZINVALID_KEY 290
#endif
class Dbtc: public SimulatedBlock {
diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
index f2646fd4176..d7232030c41 100644
--- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
+++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
@@ -2313,7 +2313,10 @@ Dbtc::handle_special_hash(Uint32 dstHash[4], Uint32* src, Uint32 srcLen,
{
keyPartLenPtr = keyPartLen;
dstPos = xfrm_key(tabPtrI, src, dst, sizeof(Tmp) >> 2, keyPartLenPtr);
- ndbrequire(dstPos);
+ if (unlikely(dstPos == 0))
+ {
+ goto error;
+ }
}
else
{
@@ -2334,6 +2337,10 @@ Dbtc::handle_special_hash(Uint32 dstHash[4], Uint32* src, Uint32 srcLen,
dstHash[1] = tmp[1];
}
return true; // success
+
+error:
+ terrorCode = ZINVALID_KEY;
+ return false;
}
/*
@@ -2941,7 +2948,15 @@ void Dbtc::tckeyreq050Lab(Signal* signal)
UintR tnoOfStandby;
UintR tnodeinfo;
+ terrorCode = 0;
+
hash(signal); /* NOW IT IS TIME TO CALCULATE THE HASH VALUE*/
+
+ if (unlikely(terrorCode))
+ {
+ releaseAtErrorLab(signal);
+ return;
+ }
CacheRecord * const regCachePtr = cachePtr.p;
TcConnectRecord * const regTcPtr = tcConnectptr.p;
@@ -6183,7 +6198,6 @@ void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr)
<< " - place: " << c_apiConTimer_line[apiConnectptr.i]);
switch (apiConnectptr.p->apiConnectstate) {
case CS_STARTED:
- ndbrequire(c_apiConTimer_line[apiConnectptr.i] != 3615);
if(apiConnectptr.p->lqhkeyreqrec == apiConnectptr.p->lqhkeyconfrec){
jam();
/*
@@ -6443,8 +6457,8 @@ void Dbtc::sendAbortedAfterTimeout(Signal* signal, int Tcheck)
warningEvent(buf);
ndbout_c(buf);
ndbrequire(false);
+ releaseAbortResources(signal);
}
- releaseAbortResources(signal);
return;
}//if
TloopCount++;
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
index 470b98fd04c..e16d3df6d8d 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
@@ -445,6 +445,7 @@ Dbtup::commitRecord(Signal* signal,
befOpPtr.p->changeMask.bitOR(attributeMask);
befOpPtr.p->gci = regOperPtr->gci;
+ befOpPtr.p->optype = opType;
operPtr.p = befOpPtr.p;
checkDetachedTriggers(signal,
befOpPtr.p,
@@ -483,6 +484,7 @@ Dbtup::commitRecord(Signal* signal,
befOpPtr.p->pageIndex = befOpPtr.p->pageIndexC;
befOpPtr.p->gci = regOperPtr->gci;
+ befOpPtr.p->optype = opType;
operPtr.p = befOpPtr.p;
checkDetachedTriggers(signal,
befOpPtr.p,
diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
index 7003d70e8b1..ed18a4ddb8b 100644
--- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
+++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
@@ -2030,29 +2030,32 @@ void Qmgr::execAPI_REGREQ(Signal* signal)
}//Qmgr::execAPI_REGREQ()
-void
+void
Qmgr::execAPI_VERSION_REQ(Signal * signal) {
jamEntry();
ApiVersionReq * const req = (ApiVersionReq *)signal->getDataPtr();
-
+
Uint32 senderRef = req->senderRef;
Uint32 nodeId = req->nodeId;
ApiVersionConf * conf = (ApiVersionConf *)req;
if(getNodeInfo(nodeId).m_connected)
+ {
conf->version = getNodeInfo(nodeId).m_version;
+ struct in_addr in= globalTransporterRegistry.get_connect_address(nodeId);
+ conf->inet_addr= in.s_addr;
+ }
else
+ {
conf->version = 0;
+ conf->inet_addr= 0;
+ }
conf->nodeId = nodeId;
- struct in_addr in= globalTransporterRegistry.get_connect_address(nodeId);
- conf->inet_addr= in.s_addr;
- sendSignal(senderRef,
+ sendSignal(senderRef,
GSN_API_VERSION_CONF,
signal,
ApiVersionConf::SignalLength, JBB);
-
-
}
diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp
index 4625cd43640..3fe76e45322 100644
--- a/ndb/src/kernel/vm/SimulatedBlock.cpp
+++ b/ndb/src/kernel/vm/SimulatedBlock.cpp
@@ -1872,6 +1872,8 @@ SimulatedBlock::xfrm_key(Uint32 tab, const Uint32* src,
xfrm_attr(keyAttr.attributeDescriptor, keyAttr.charsetInfo,
src, srcPos, dst, dstPos, dstSize);
keyPartLen[i++] = dstWords;
+ if (unlikely(dstWords == 0))
+ return 0;
}
return dstPos;
@@ -1900,7 +1902,8 @@ SimulatedBlock::xfrm_attr(Uint32 attrDesc, CHARSET_INFO* cs,
Uint32 typeId = AttributeDescriptor::getType(attrDesc);
Uint32 lb, len;
bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
- ndbrequire(ok);
+ if (unlikely(!ok))
+ return 0;
Uint32 xmul = cs->strxfrm_multiply;
if (xmul == 0)
xmul = 1;
@@ -1911,7 +1914,8 @@ SimulatedBlock::xfrm_attr(Uint32 attrDesc, CHARSET_INFO* cs,
Uint32 dstLen = xmul * (srcBytes - lb);
ndbrequire(dstLen <= ((dstSize - dstPos) << 2));
int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
- ndbrequire(n != -1);
+ if (unlikely(n == -1))
+ return 0;
while ((n & 3) != 0)
{
dstPtr[n++] = 0;
diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp
index 9bb238ca90b..a69a61dcda7 100644
--- a/ndb/src/mgmapi/mgmapi.cpp
+++ b/ndb/src/mgmapi/mgmapi.cpp
@@ -336,10 +336,16 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
const Properties* p = parser.parse(ctx, session);
if (p == NULL){
if(!ndb_mgm_is_connected(handle)) {
- return NULL;
+ DBUG_RETURN(NULL);
}
else
{
+ if(ctx.m_status==Parser_t::Eof
+ || ctx.m_status==Parser_t::NoLine)
+ {
+ ndb_mgm_disconnect(handle);
+ DBUG_RETURN(NULL);
+ }
/**
* Print some info about why the parser returns NULL
*/
diff --git a/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/ndb/src/ndbapi/NdbEventOperationImpl.cpp
index 208525bfc15..9c147be9f16 100644
--- a/ndb/src/ndbapi/NdbEventOperationImpl.cpp
+++ b/ndb/src/ndbapi/NdbEventOperationImpl.cpp
@@ -250,10 +250,10 @@ NdbEventOperationImpl::execute()
int hasSubscriber;
int r= m_bufferHandle->prepareAddSubscribeEvent(this,
hasSubscriber /*return value*/);
- m_error.code= 4709;
if (r < 0)
{
+ m_error.code= 4709;
DBUG_RETURN(-1);
}
diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c
index 4a9ac9affb7..5ca8ad7be60 100644
--- a/ndb/src/ndbapi/ndberror.c
+++ b/ndb/src/ndbapi/ndberror.c
@@ -227,6 +227,7 @@ ErrorBundle ErrorCodes[] = {
{ 277, IE, "277" },
{ 278, IE, "278" },
{ 287, IE, "Index corrupted" },
+ { 290, IE, "Corrupt key in TC, unable to xfrm" },
{ 631, IE, "631" },
{ 632, IE, "632" },
{ 702, IE, "Request to non-master" },
@@ -295,7 +296,6 @@ ErrorBundle ErrorCodes[] = {
{ 4608, AE, "You can not takeOverScan unless you have used openScanExclusive"},
{ 4609, AE, "You must call nextScanResult before trying to takeOverScan"},
{ 4232, AE, "Parallelism can only be between 1 and 240" },
- { 290, AE, "Scan not started or has been closed by kernel due to timeout" },
/**
* Event schema errors
diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am
index d83e9614eb5..0533493ba09 100644
--- a/ndb/test/ndbapi/Makefile.am
+++ b/ndb/test/ndbapi/Makefile.am
@@ -35,7 +35,8 @@ testPartitioning \
testBitfield \
DbCreate DbAsyncGenerator \
test_event_multi_table \
-testSRBank
+testSRBank \
+test_event_merge
#flexTimedAsynch
#testBlobs
@@ -80,6 +81,7 @@ DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterfa
DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
test_event_multi_table_SOURCES = test_event_multi_table.cpp
testSRBank_SOURCES = testSRBank.cpp
+test_event_merge_SOURCES = test_event_merge.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel
@@ -160,3 +162,4 @@ testScan.dsp: Makefile \
@$(top_srcdir)/ndb/config/win-includes $@ $(INCLUDES)
@$(top_srcdir)/ndb/config/win-sources $@ $(testScan_SOURCES)
@$(top_srcdir)/ndb/config/win-libraries $@ LINK $(LDADD)
+
diff --git a/ndb/test/ndbapi/testNodeRestart.cpp b/ndb/test/ndbapi/testNodeRestart.cpp
index 6ef3da2d760..92d6c1830ef 100644
--- a/ndb/test/ndbapi/testNodeRestart.cpp
+++ b/ndb/test/ndbapi/testNodeRestart.cpp
@@ -21,6 +21,7 @@
#include <NdbRestarter.hpp>
#include <NdbRestarts.hpp>
#include <Vector.hpp>
+#include <signaldata/DumpStateOrd.hpp>
int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
@@ -409,6 +410,132 @@ int runLateCommit(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_OK;
}
+int runBug15587(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ int loops = ctx->getNumLoops();
+ int records = ctx->getNumRecords();
+ NdbRestarter restarter;
+
+ Uint32 tableId = ctx->getTab()->getTableId();
+ int dump[2] = { DumpStateOrd::LqhErrorInsert5042, 0 };
+ dump[1] = tableId;
+
+ int nodeId = restarter.getDbNodeId(1);
+
+ ndbout << "Restart node " << nodeId << endl;
+
+ if (restarter.restartOneDbNode(nodeId,
+ /** initial */ false,
+ /** nostart */ true,
+ /** abort */ true))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesNoStart(&nodeId, 1))
+ return NDBT_FAILED;
+
+ if (restarter.dumpStateOneNode(nodeId, dump, 2))
+ return NDBT_FAILED;
+
+ if (restarter.startNodes(&nodeId, 1))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesStarted(&nodeId, 1))
+ return NDBT_FAILED;
+
+ ctx->stopTest();
+ return NDBT_OK;
+}
+
+int runBug15632(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ int loops = ctx->getNumLoops();
+ int records = ctx->getNumRecords();
+ NdbRestarter restarter;
+
+ int nodeId = restarter.getDbNodeId(1);
+
+ ndbout << "Restart node " << nodeId << endl;
+
+ if (restarter.restartOneDbNode(nodeId,
+ /** initial */ false,
+ /** nostart */ true,
+ /** abort */ true))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesNoStart(&nodeId, 1))
+ return NDBT_FAILED;
+
+ if (restarter.insertErrorInNode(nodeId, 7165))
+ return NDBT_FAILED;
+
+ if (restarter.startNodes(&nodeId, 1))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesStarted(&nodeId, 1))
+ return NDBT_FAILED;
+
+ if (restarter.restartOneDbNode(nodeId,
+ /** initial */ false,
+ /** nostart */ true,
+ /** abort */ true))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesNoStart(&nodeId, 1))
+ return NDBT_FAILED;
+
+ if (restarter.insertErrorInNode(nodeId, 7171))
+ return NDBT_FAILED;
+
+ if (restarter.startNodes(&nodeId, 1))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesStarted(&nodeId, 1))
+ return NDBT_FAILED;
+
+ ctx->stopTest();
+ return NDBT_OK;
+}
+
+int runBug15685(NDBT_Context* ctx, NDBT_Step* step){
+
+ Ndb* pNdb = GETNDB(step);
+ HugoOperations hugoOps(*ctx->getTab());
+ NdbRestarter restarter;
+
+ HugoTransactions hugoTrans(*ctx->getTab());
+ if (hugoTrans.loadTable(GETNDB(step), 10) != 0){
+ return NDBT_FAILED;
+ }
+
+ if(hugoOps.startTransaction(pNdb) != 0)
+ goto err;
+
+ if(hugoOps.pkUpdateRecord(pNdb, 0, 1, rand()) != 0)
+ goto err;
+
+ if(hugoOps.execute_NoCommit(pNdb) != 0)
+ goto err;
+
+ if (restarter.insertErrorInAllNodes(5100))
+ return NDBT_FAILED;
+
+ hugoOps.execute_Rollback(pNdb);
+
+ if (restarter.waitClusterStarted() != 0)
+ goto err;
+
+ if (restarter.insertErrorInAllNodes(0))
+ return NDBT_FAILED;
+
+ ctx->stopTest();
+ return NDBT_OK;
+
+err:
+ ctx->stopTest();
+ return NDBT_FAILED;
+}
+
+
NDBT_TESTSUITE(testNodeRestart);
TESTCASE("NoLoad",
"Test that one node at a time can be stopped and then restarted "\
@@ -558,6 +685,8 @@ TESTCASE("RestartNFDuringNR",
INITIALIZER(runCheckAllNodesStarted);
INITIALIZER(runLoadTable);
STEP(runRestarts);
+ STEP(runPkUpdateUntilStopped);
+ STEP(runScanUpdateUntilStopped);
FINALIZER(runScanReadVerify);
FINALIZER(runClearTable);
}
@@ -647,6 +776,8 @@ TESTCASE("RestartNodeDuringLCP",
INITIALIZER(runCheckAllNodesStarted);
INITIALIZER(runLoadTable);
STEP(runRestarts);
+ STEP(runPkUpdateUntilStopped);
+ STEP(runScanUpdateUntilStopped);
FINALIZER(runScanReadVerify);
FINALIZER(runClearTable);
}
@@ -671,6 +802,24 @@ TESTCASE("LateCommit",
STEP(runLateCommit);
FINALIZER(runClearTable);
}
+TESTCASE("Bug15587",
+ "Test bug with NF during NR"){
+ INITIALIZER(runLoadTable);
+ STEP(runScanUpdateUntilStopped);
+ STEP(runBug15587);
+ FINALIZER(runClearTable);
+}
+TESTCASE("Bug15632",
+ "Test bug with NF during NR"){
+ INITIALIZER(runLoadTable);
+ STEP(runBug15632);
+ FINALIZER(runClearTable);
+}
+TESTCASE("Bug15685",
+ "Test bug with NF during abort"){
+ STEP(runBug15685);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testNodeRestart);
int main(int argc, const char** argv){
diff --git a/ndb/test/ndbapi/test_event_merge.cpp b/ndb/test/ndbapi/test_event_merge.cpp
new file mode 100644
index 00000000000..1332455cdc5
--- /dev/null
+++ b/ndb/test/ndbapi/test_event_merge.cpp
@@ -0,0 +1,1286 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <ndb_opts.h>
+#include <NdbApi.hpp>
+#include <NdbTest.hpp>
+#include <my_sys.h>
+#include <ndb_version.h>
+
+#if NDB_VERSION_D < MAKE_VERSION(5, 1, 0)
+#define version50
+#else
+#undef version50
+#endif
+
+#if !defined(min) || !defined(max)
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+/*
+ * Test composite operations on same PK via events. The merge of event
+ * data can happen in 2 places:
+ *
+ * 1) In TUP at commit, the detached triggers report a single composite
+ * operation and its post/pre data
+ *
+ * 2) In event API version >= 5.1 separate commits within same GCI are
+ * by default merged. This is required to read blob data via NdbBlob.
+ *
+ * This test program ignores Blob columns in version 5.0.
+ *
+ * There are 5 ways (ignoring NUL operand) to compose 2 ops:
+ * 5.0 bugs 5.1 bugs
+ * INS o DEL = NUL
+ * INS o UPD = INS 5.1
+ * DEL o INS = UPD type=INS 5.1
+ * UPD o DEL = DEL no event
+ * UPD o UPD = UPD
+ */
+
+struct Opts {
+ my_bool abort_on_error;
+ int loglevel;
+ uint loop;
+ uint maxops;
+ uint maxpk;
+ const char* opstr;
+ uint seed;
+ my_bool separate_events;
+ my_bool use_table;
+};
+
+static Opts g_opts;
+static const uint g_maxops = 10000;
+static const uint g_maxpk = 100;
+
+static Ndb_cluster_connection* g_ncc = 0;
+static Ndb* g_ndb = 0;
+static NdbDictionary::Dictionary* g_dic = 0;
+static NdbTransaction* g_con = 0;
+static NdbOperation* g_op = 0;
+
+static const char* g_tabname = "tem1";
+static const char* g_evtname = "tem1ev1";
+static const uint g_charlen = 5;
+static const char* g_csname = "latin1_swedish_ci";
+
+static const NdbDictionary::Table* g_tab = 0;
+static const NdbDictionary::Event* g_evt = 0;
+
+static NdbEventOperation* g_evt_op = 0;
+
+static uint
+urandom(uint n)
+{
+ uint r = (uint)random();
+ if (n != 0)
+ r = r % n;
+ return r;
+}
+
+static int& g_loglevel = g_opts.loglevel; // default log level
+
+#define chkdb(x) \
+ do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; errdb(); if (g_opts.abort_on_error) abort(); return -1; } while (0)
+
+#define chkrc(x) \
+ do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; if (g_opts.abort_on_error) abort(); return -1; } while (0)
+
+#define reqrc(x) \
+ do { if (x) break; ndbout << "line " << __LINE__ << " ASSERT " << #x << endl; abort(); } while (0)
+
+#define ll0(x) \
+ do { if (g_loglevel < 0) break; ndbout << x << endl; } while (0)
+
+#define ll1(x) \
+ do { if (g_loglevel < 1) break; ndbout << x << endl; } while (0)
+
+#define ll2(x) \
+ do { if (g_loglevel < 2) break; ndbout << x << endl; } while (0)
+
+static void
+errdb()
+{
+ uint any = 0;
+ if (g_ndb != 0) {
+ const NdbError& e = g_ndb->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " ndb: error " << e);
+ }
+ if (g_dic != 0) {
+ const NdbError& e = g_dic->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " dic: error " << e);
+ }
+ if (g_con != 0) {
+ const NdbError& e = g_con->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " con: error " << e);
+ }
+ if (g_op != 0) {
+ const NdbError& e = g_op->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " op: error " << e);
+ }
+ if (g_evt_op != 0) {
+ const NdbError& e = g_evt_op->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " evt_op: error " << e);
+ }
+ if (! any)
+ ll0("unknown db error");
+}
+
+struct Col {
+ uint no;
+ const char* name;
+ NdbDictionary::Column::Type type;
+ bool pk;
+ bool nullable;
+ uint length;
+ uint size;
+};
+
+static Col g_col[] = {
+ { 0, "pk1", NdbDictionary::Column::Unsigned, true, false, 1, 4 },
+ { 1, "pk2", NdbDictionary::Column::Char, true, false, g_charlen, g_charlen },
+ { 2, "seq", NdbDictionary::Column::Unsigned, false, false, 1, 4 },
+ { 3, "cc1", NdbDictionary::Column::Char, false, true, g_charlen, g_charlen }
+};
+
+static const uint g_ncol = sizeof(g_col)/sizeof(g_col[0]);
+
+static const Col&
+getcol(uint i)
+{
+ if (i < g_ncol)
+ return g_col[i];
+ assert(false);
+ return g_col[g_ncol];
+}
+
+static const Col&
+getcol(const char* name)
+{
+ uint i;
+ for (i = 0; i < g_ncol; i++)
+ if (strcmp(g_col[i].name, name) == 0)
+ break;
+ return getcol(i);
+}
+
+static int
+createtable()
+{
+ g_tab = 0;
+ NdbDictionary::Table tab(g_tabname);
+ tab.setLogging(false);
+ CHARSET_INFO* cs;
+ chkrc((cs = get_charset_by_name(g_csname, MYF(0))) != 0);
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = g_col[i];
+ NdbDictionary::Column col(c.name);
+ col.setType(c.type);
+ col.setPrimaryKey(c.pk);
+ if (! c.pk)
+ col.setNullable(true);
+ col.setLength(c.length);
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ break;
+ case NdbDictionary::Column::Char:
+ col.setLength(c.length);
+ col.setCharset(cs);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ tab.addColumn(col);
+ }
+ g_dic = g_ndb->getDictionary();
+ if (! g_opts.use_table) {
+ if (g_dic->getTable(g_tabname) != 0)
+ chkdb(g_dic->dropTable(g_tabname) == 0);
+ chkdb(g_dic->createTable(tab) == 0);
+ }
+ chkdb((g_tab = g_dic->getTable(g_tabname)) != 0);
+ g_dic = 0;
+ if (! g_opts.use_table) {
+ // extra row for GCI probe
+ chkdb((g_con = g_ndb->startTransaction()) != 0);
+ chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0);
+ chkdb(g_op->insertTuple() == 0);
+ Uint32 pk1;
+ char pk2[g_charlen];
+ pk1 = g_maxpk;
+ memset(pk2, 0x20, g_charlen);
+ chkdb(g_op->equal("pk1", (char*)&pk1) == 0);
+ chkdb(g_op->equal("pk2", (char*)&pk2[0]) == 0);
+ chkdb(g_con->execute(Commit) == 0);
+ g_ndb->closeTransaction(g_con);
+ g_op = 0;
+ g_con = 0;
+ }
+ return 0;
+}
+
+static int
+droptable()
+{
+ if (! g_opts.use_table) {
+ g_dic = g_ndb->getDictionary();
+ chkdb(g_dic->dropTable(g_tab->getName()) == 0);
+ g_tab = 0;
+ g_dic = 0;
+ }
+ return 0;
+}
+
+struct Data {
+ Uint32 pk1;
+ char pk2[g_charlen];
+ Uint32 seq;
+ char cc1[g_charlen];
+ void* ptr[g_ncol];
+ int ind[g_ncol]; // -1 = no data, 1 = NULL, 0 = not NULL
+ void init() {
+ uint i;
+ pk1 = 0;
+ memset(pk2, 0, sizeof(pk2));
+ seq = 0;
+ memset(cc1, 0, sizeof(cc1));
+ ptr[0] = &pk1;
+ ptr[1] = pk2;
+ ptr[2] = &seq;
+ ptr[3] = cc1;
+ for (i = 0; i < g_ncol; i++)
+ ind[i] = -1;
+ }
+};
+
+static NdbOut&
+operator<<(NdbOut& out, const Data& d)
+{
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = getcol(i);
+ out << (i == 0 ? "" : " ") << c.name << "=";
+ if (d.ind[i] == -1)
+ continue;
+ if (d.ind[i] == 1) {
+ out << "NULL";
+ continue;
+ }
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ out << *(Uint32*)d.ptr[i];
+ break;
+ case NdbDictionary::Column::Char:
+ {
+ char buf[g_charlen + 1];
+ memcpy(buf, d.ptr[i], g_charlen);
+ uint n = g_charlen;
+ while (1) {
+ buf[n] = 0;
+ if (n == 0 || buf[n - 1] != 0x20)
+ break;
+ n--;
+ }
+ out << buf;
+ }
+ break;
+ default:
+ out << "?";
+ break;
+ }
+ }
+ return out;
+}
+
+static const uint g_optypes = 3; // real ops 0-2
+
+/*
+ * Represents single or composite operation or received event. The
+ * post/pre data is either computed here for operations or received from
+ * the event.
+ */
+struct Op { // single or composite
+ enum Kind { OP = 1, EV = 2 };
+ enum Type { NUL = -1, INS, DEL, UPD };
+ Kind kind;
+ Type type;
+ Op* next_op; // within one commit
+ Op* next_com; // next commit chain or next event
+ uint num_op;
+ uint num_com;
+ Data data[2]; // 0-post 1-pre
+ bool match; // matched to event
+ void init() {
+ assert(kind == OP || kind == EV);
+ type = NUL;
+ next_op = next_com = 0;
+ num_op = num_com = 0;
+ data[0].init();
+ data[1].init();
+ match = false;
+ }
+};
+
+static NdbOut&
+operator<<(NdbOut& out, Op::Type t)
+{
+ switch (t) {
+ case Op::NUL:
+ out << "NUL";
+ break;
+ case Op::INS:
+ out << "INS";
+ break;
+ case Op::DEL:
+ out << "DEL";
+ break;
+ case Op::UPD:
+ out << "UPD";
+ break;
+ default:
+ out << (int)t;
+ break;
+ }
+ return out;
+}
+
+static NdbOut&
+operator<<(NdbOut& out, const Op& op)
+{
+ out << "t=" << op.type;
+ out << " " << op.data[0];
+ out << " [" << op.data[1] << "]";
+ return out;
+}
+
+static int
+seteventtype(Op* ev, NdbDictionary::Event::TableEvent te)
+{
+ Op::Type t = Op::NUL;
+ switch (te) {
+ case NdbDictionary::Event::TE_INSERT:
+ t = Op::INS;
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ t = Op::DEL;
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ t = Op::UPD;
+ break;
+ default:
+ ll0("EVT: " << *ev << ": bad event type" << (int)te);
+ return -1;
+ }
+ ev->type = t;
+ return 0;
+}
+
+static uint g_usedops = 0;
+static uint g_usedevs = 0;
+static Op g_oplist[g_maxops];
+static Op g_evlist[g_maxops];
+static uint g_maxcom = 8; // max ops per commit
+
+static Op* g_pk_op[g_maxpk];
+static Op* g_pk_ev[g_maxpk];
+static uint g_seq = 0;
+
+static NdbRecAttr* g_ra[2][g_ncol]; // 0-post 1-pre
+static Op* g_rec_ev;
+static uint g_ev_cnt[g_maxpk];
+
+static uint
+getfreeops()
+{
+ assert(g_opts.maxops >= g_usedops);
+ return g_opts.maxops - g_usedops;
+}
+
+static uint
+getfreeevs()
+{
+ assert(g_opts.maxops >= g_usedevs);
+ return g_opts.maxops - g_usedevs;
+}
+
+static Op*
+getop()
+{
+ if (g_usedops < g_opts.maxops) {
+ Op* op = &g_oplist[g_usedops++];
+ op->kind = Op::OP;
+ op->init();
+ return op;
+ }
+ assert(false);
+ return 0;
+}
+
+static Op*
+getev()
+{
+ if (g_usedevs < g_opts.maxops) {
+ Op* ev = &g_evlist[g_usedevs++];
+ ev->kind = Op::EV;
+ ev->init();
+ return ev;
+ }
+ assert(false);
+ return 0;
+}
+
+static void
+resetmem()
+{
+ int i, j;
+ for (j = 0; j < 2; j++)
+ for (i = 0; i < g_ncol; i++)
+ g_ra[j][i] = 0;
+ g_rec_ev = 0;
+ for (i = 0; i < g_opts.maxpk; i++)
+ g_pk_op[i] = 0;
+ for (i = 0; i < g_opts.maxpk; i++)
+ g_ev_cnt[i] = 0;
+ g_seq = 0;
+ g_usedops = 0;
+ g_usedevs = 0;
+}
+
+struct Comp {
+ Op::Type t1, t2, t3;
+};
+
+static Comp
+g_comp[] = {
+ { Op::INS, Op::DEL, Op::NUL },
+ { Op::INS, Op::UPD, Op::INS },
+ { Op::DEL, Op::INS, Op::UPD },
+ { Op::UPD, Op::DEL, Op::DEL },
+ { Op::UPD, Op::UPD, Op::UPD }
+};
+
+static const uint g_ncomp = sizeof(g_comp)/sizeof(g_comp[0]);
+
+static int
+checkop(const Op* op, Uint32& pk1)
+{
+ const Data (&d)[2] = op->data;
+ Op::Type t = op->type;
+ chkrc(t == Op::NUL || t == Op::INS || t == Op::DEL || t == Op::UPD);
+ { const Col& c = getcol("pk1");
+ chkrc(d[0].ind[c.no] == 0);
+ pk1 = d[0].pk1;
+ chkrc(pk1 < g_opts.maxpk);
+ }
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = getcol(i);
+ if (t != Op::NUL) {
+ if (c.pk) {
+ chkrc(d[0].ind[i] == 0); // even DEL has PK in post data
+ if (t == Op::INS) {
+ chkrc(d[1].ind[i] == -1);
+ } else if (t == Op::DEL) {
+#ifdef ndb_event_cares_about_pk_pre_data
+ chkrc(d[1].ind[i] == -1);
+#endif
+ } else {
+#ifdef ndb_event_cares_about_pk_pre_data
+ chkrc(d[1].ind[i] == 0);
+#endif
+ }
+ } else {
+ if (t == Op::INS) {
+ chkrc(d[0].ind[i] >= 0);
+ chkrc(d[1].ind[i] == -1);
+ } else if (t == Op::DEL) {
+ chkrc(d[0].ind[i] == -1);
+ chkrc(d[1].ind[i] >= 0);
+ } else if (op->kind == Op::OP) {
+ chkrc(d[0].ind[i] >= 0);
+ chkrc(d[1].ind[i] >= 0);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static Comp*
+comptype(Op::Type t1, Op::Type t2) // only non-NUL
+{
+ uint i;
+ for (i = 0; i < g_ncomp; i++)
+ if (g_comp[i].t1 == t1 && g_comp[i].t2 == t2)
+ return &g_comp[i];
+ return 0;
+}
+
+static void
+copycol(const Col& c, const Data& d1, Data& d3)
+{
+ if ((d3.ind[c.no] = d1.ind[c.no]) != -1)
+ memmove(d3.ptr[c.no], d1.ptr[c.no], c.size);
+}
+
+static void
+copykeys(const Data& d1, Data& d3)
+{
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = g_col[i];
+ if (c.pk)
+ copycol(c, d1, d3);
+ }
+}
+
+static void
+copydata(const Data& d1, Data& d3)
+{
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = g_col[i];
+ copycol(c, d1, d3);
+ }
+}
+
+static void
+copyop(const Op* op1, Op* op3)
+{
+ op3->type = op1->type;
+ copydata(op1->data[0], op3->data[0]);
+ copydata(op1->data[1], op3->data[1]);
+ Uint32 pk1_tmp;
+ reqrc(checkop(op3, pk1_tmp) == 0);
+}
+
+// not needed for ops
+static void
+compdata(const Data& d1, const Data& d2, Data& d3) // d2 overrides d1
+{
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = g_col[i];
+ const Data* d = 0;
+ if (d1.ind[i] == -1 && d2.ind[i] == -1)
+ d3.ind[i] = -1;
+ else if (d1.ind[i] == -1 && d2.ind[i] != -1)
+ d = &d2;
+ else if (d1.ind[i] != -1 && d2.ind[i] == -1)
+ d = &d1;
+ else
+ d = &d2;
+ if (d != 0)
+ copycol(c, *d, d3);
+ }
+}
+
+static int
+compop(const Op* op1, const Op* op2, Op* op3) // op1 o op2 = op3
+{
+ Comp* comp;
+ if (op2->type == Op::NUL) {
+ copyop(op1, op3);
+ return 0;
+ }
+ if (op1->type == Op::NUL) {
+ copyop(op2, op3);
+ return 0;
+ }
+ chkrc((comp = comptype(op1->type, op2->type)) != 0);
+ op3->type = comp->t3;
+ copykeys(op2->data[0], op3->data[0]);
+ if (op3->type != Op::DEL)
+ copydata(op2->data[0], op3->data[0]);
+ if (op3->type != Op::INS)
+ copydata(op1->data[1], op3->data[1]);
+ Uint32 pk1_tmp;
+ reqrc(checkop(op3, pk1_tmp) == 0);
+ // not eliminating identical post-pre fields
+ return 0;
+}
+
+static int
+createevent()
+{
+ ll1("createevent");
+ g_evt = 0;
+ g_dic = g_ndb->getDictionary();
+ NdbDictionary::Event evt(g_evtname);
+ evt.setTable(*g_tab);
+ evt.addTableEvent(NdbDictionary::Event::TE_ALL);
+ // pk always
+ evt.addEventColumn("pk1");
+ evt.addEventColumn("pk2");
+ // simple cols
+ evt.addEventColumn("seq");
+ evt.addEventColumn("cc1");
+ if (g_dic->getEvent(evt.getName()) != 0)
+ chkdb(g_dic->dropEvent(evt.getName()) == 0);
+ chkdb(g_dic->createEvent(evt) == 0);
+ chkdb((g_evt = g_dic->getEvent(evt.getName())) != 0);
+ g_dic = 0;
+ return 0;
+}
+
+static int
+dropevent()
+{
+ ll1("dropevent");
+ g_dic = g_ndb->getDictionary();
+ chkdb(g_dic->dropEvent(g_evt->getName()) == 0);
+ g_evt = 0;
+ g_dic = 0;
+ return 0;
+}
+
+static int
+createeventop()
+{
+ ll1("createeventop");
+#ifdef version50
+ uint bsz = 10 * g_opts.maxops;
+ chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName(), bsz)) != 0);
+#else
+ chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName())) != 0);
+#endif
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = g_col[i];
+ Data (&d)[2] = g_rec_ev->data;
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ case NdbDictionary::Column::Char:
+ chkdb((g_ra[0][i] = g_evt_op->getValue(c.name, (char*)d[0].ptr[i])) != 0);
+ chkdb((g_ra[1][i] = g_evt_op->getPreValue(c.name, (char*)d[1].ptr[i])) != 0);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int
+dropeventop()
+{
+ ll1("dropeventop");
+ chkdb(g_ndb->dropEventOperation(g_evt_op) == 0);
+ g_evt_op = 0;
+ return 0;
+}
+
+static int
+waitgci() // wait for event to be installed and for at least 1 GCI to pass
+{
+ const uint ngci = 3;
+ ll1("waitgci " << ngci);
+ Uint32 gci[2];
+ uint i = 0;
+ while (1) {
+ chkdb((g_con = g_ndb->startTransaction()) != 0);
+ { // forced to exec a dummy op
+ Uint32 pk1;
+ char pk2[g_charlen];
+ pk1 = g_maxpk;
+ memset(pk2, 0x20, g_charlen);
+ chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0);
+ chkdb(g_op->readTuple() == 0);
+ chkdb(g_op->equal("pk1", (char*)&pk1) == 0);
+ chkdb(g_op->equal("pk2", (char*)&pk2[0]) == 0);
+ chkdb(g_con->execute(Commit) == 0);
+ g_op = 0;
+ }
+ gci[i] = g_con->getGCI();
+ g_ndb->closeTransaction(g_con);
+ g_con = 0;
+ if (i == 1 && gci[0] + ngci <= gci[1]) {
+ ll1("waitgci: " << gci[0] << " " << gci[1]);
+ break;
+ }
+ i = 1;
+ }
+ return 0;
+}
+
+static int
+makeop(Op* op, Uint32 pk1, Op::Type t, const Op* prev_op)
+{
+ op->type = t;
+ if (t != Op::INS)
+ copydata(prev_op->data[0], op->data[1]);
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = getcol(i);
+ Data (&d)[2] = op->data;
+ if (i == getcol("pk1").no) {
+ d[0].pk1 = pk1;
+ d[0].ind[i] = 0;
+ continue;
+ }
+ if (i == getcol("pk2").no) {
+ sprintf(d[0].pk2, "%-*u", g_charlen, d[0].pk1);
+ d[0].ind[i] = 0;
+ continue;
+ }
+ if (t == Op::DEL) {
+ d[0].ind[i] = -1;
+ continue;
+ }
+ if (i == getcol("seq").no) {
+ d[0].seq = g_seq++;
+ d[0].ind[i] = 0;
+ continue;
+ }
+ uint u;
+ u = urandom(100);
+ if (c.nullable && u < 20) {
+ d[0].ind[i] = 1;
+ continue;
+ }
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ {
+ u = urandom(0);
+ Uint32* p = (Uint32*)d[0].ptr[i];
+ *p = u;
+ }
+ break;
+ case NdbDictionary::Column::Char:
+ {
+ u = urandom(g_charlen);
+ char* p = (char*)d[0].ptr[i];
+ uint j;
+ for (j = 0; j < g_charlen; j++) {
+ uint v = urandom(3);
+ p[j] = j < u ? "abcde"[v] : 0x20;
+ }
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ d[0].ind[i] = 0;
+ }
+ Uint32 pk1_tmp = ~(Uint32)0;
+ chkrc(checkop(op, pk1_tmp) == 0);
+ reqrc(pk1 == pk1_tmp);
+ return 0;
+}
+
+static void
+makeop(Op* tot_op, Op* com_op, Uint32 pk1, Op::Type t)
+{
+ Op tmp_op;
+ tmp_op.kind = Op::OP;
+ Op* op = getop();
+ reqrc(makeop(op, pk1, t, tot_op) == 0);
+ // add to end
+ Op* last_op = com_op;
+ while (last_op->next_op != 0)
+ last_op = last_op->next_op;
+ last_op->next_op = op;
+ // merge into chain head
+ tmp_op.init();
+ reqrc(compop(com_op, op, &tmp_op) == 0);
+ copyop(&tmp_op, com_op);
+ // merge into total op
+ tmp_op.init();
+ reqrc(compop(tot_op, op, &tmp_op) == 0);
+ copyop(&tmp_op, tot_op);
+ // counts
+ com_op->num_op += 1;
+ tot_op->num_op += 1;
+}
+
+static void
+makeops()
+{
+ ll1("makeops");
+ uint resv = g_opts.opstr == 0 ? 2 * g_opts.maxpk : 0; // for final deletes
+ uint next = g_opts.opstr == 0 ? g_maxcom : strlen(g_opts.opstr);
+ Op tmp_op;
+ tmp_op.kind = Op::OP;
+ Uint32 pk1 = 0;
+ while (getfreeops() >= resv + 2 + next && pk1 < g_opts.maxpk) {
+ if (g_opts.opstr == 0)
+ pk1 = urandom(g_opts.maxpk);
+ ll2("makeops: pk1=" << pk1 << " free=" << getfreeops());
+ // total op on the pk so far
+ // optype either NUL=initial/deleted or INS=created
+ Op* tot_op = g_pk_op[pk1];
+ if (tot_op == 0)
+ tot_op = g_pk_op[pk1] = getop(); //1
+ assert(tot_op->type == Op::NUL || tot_op->type == Op::INS);
+ // add new commit chain to end
+ Op* last_com = tot_op;
+ while (last_com->next_com != 0)
+ last_com = last_com->next_com;
+ Op* com_op = getop(); //2
+ last_com->next_com = com_op;
+ // length of random chain
+ uint len = ~0;
+ if (g_opts.opstr == 0)
+ len = 1 + urandom(g_maxcom - 1);
+ ll2("makeops: com chain");
+ uint n = 0;
+ while (1) {
+ // random or from g_opts.opstr
+ Op::Type t;
+ if (g_opts.opstr == 0) {
+ if (n == len)
+ break;
+ do {
+ t = (Op::Type)urandom(g_optypes);
+ } while (tot_op->type == Op::NUL && (t == Op::DEL || t == Op::UPD) ||
+ tot_op->type == Op::INS && t == Op::INS);
+ } else {
+ uint m = strlen(g_opts.opstr);
+ uint k = tot_op->num_com + tot_op->num_op;
+ assert(k < m);
+ char c = g_opts.opstr[k];
+ if (c == 'c') {
+ if (k + 1 == m)
+ pk1 += 1;
+ break;
+ }
+ const char* p = "idu";
+ const char* q = strchr(p, c);
+ assert(q != 0);
+ t = (Op::Type)(q - p);
+ }
+ makeop(tot_op, com_op, pk1, t);
+ assert(tot_op->type == Op::NUL || tot_op->type == Op::INS);
+ n++;
+ }
+ tot_op->num_com += 1;
+ }
+ assert(getfreeops() >= resv);
+ // terminate with DEL if necessary
+ for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
+ Op* tot_op = g_pk_op[pk1];
+ if (tot_op == 0)
+ continue;
+ if (tot_op->type == Op::NUL)
+ continue;
+ assert(g_opts.opstr == 0);
+ Op* last_com = tot_op;
+ while (last_com->next_com != 0)
+ last_com = last_com->next_com;
+ Op* com_op = getop(); //1
+ last_com->next_com = com_op;
+ makeop(tot_op, com_op, pk1, Op::DEL);
+ assert(tot_op->type == Op::NUL);
+ tot_op->num_com += 1;
+ }
+}
+
+static int
+addndbop(Op* op)
+{
+ chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0);
+ switch (op->type) {
+ case Op::INS:
+ chkdb(g_op->insertTuple() == 0);
+ break;
+ case Op::DEL:
+ chkdb(g_op->deleteTuple() == 0);
+ break;
+ case Op::UPD:
+ chkdb(g_op->updateTuple() == 0);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ uint i;
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = getcol(i);
+ const Data& d = op->data[0];
+ if (! c.pk)
+ continue;
+ chkdb(g_op->equal(c.name, (char*)d.ptr[i]) == 0);
+ }
+ if (op->type != Op::DEL) {
+ for (i = 0; i < g_ncol; i++) {
+ const Col& c = getcol(i);
+ const Data& d = op->data[0];
+ if (c.pk)
+ continue;
+ if (d.ind[i] == -1)
+ continue;
+ const char* ptr = d.ind[i] == 0 ? (char*)d.ptr[i] : 0;
+ chkdb(g_op->setValue(c.name, ptr) == 0);
+ }
+ }
+ g_op = 0;
+ return 0;
+}
+
+static int
+runops()
+{
+ ll1("runops");
+ Uint32 pk1;
+ const Op* com_op[g_maxpk];
+ uint left = 0;
+ for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
+ com_op[pk1] = 0;
+ // total op on the pk
+ Op* tot_op = g_pk_op[pk1];
+ if (tot_op == 0)
+ continue;
+ // first commit chain
+ assert(tot_op->next_com != 0);
+ com_op[pk1] = tot_op->next_com;
+ left++;
+ }
+ while (left != 0) {
+ pk1 = urandom(g_opts.maxpk);
+ if (com_op[pk1] == 0)
+ continue;
+ // do the ops in one transaction
+ ll2("runops: pk1=" << pk1);
+ chkdb((g_con = g_ndb->startTransaction()) != 0);
+ // first op in chain
+ Op* op = com_op[pk1]->next_op;
+ assert(op != 0);
+ while (op != 0) {
+ ll2("add op:" << *op);
+ chkrc(addndbop(op) == 0);
+ op = op->next_op;
+ }
+ chkdb(g_con->execute(Commit) == 0);
+ g_ndb->closeTransaction(g_con);
+ g_con = 0;
+ // next chain
+ com_op[pk1] = com_op[pk1]->next_com;
+ if (com_op[pk1] == 0) {
+ assert(left != 0);
+ left--;
+ }
+ }
+ assert(left == 0);
+ return 0;
+}
+
+static int
+matchevent(Op* ev)
+{
+ Op::Type t = ev->type;
+ Data (&d)[2] = ev->data;
+ // get PK
+ Uint32 pk1 = d[0].pk1;
+ chkrc(pk1 < g_opts.maxpk);
+ // on error repeat and print details
+ uint loop = 0;
+ while (loop <= 1) {
+ uint g_loglevel = loop == 0 ? g_opts.loglevel : 2;
+ ll1("matchevent: pk1=" << pk1 << " type=" << t);
+ ll2("EVT: " << *ev);
+ Op* tot_op = g_pk_op[pk1];
+ Op* com_op = tot_op ? tot_op->next_com : 0;
+ uint cnt = 0;
+ bool ok = false;
+ while (com_op != 0) {
+ ll2("COM: " << *com_op);
+ Op* op = com_op->next_op;
+ assert(op != 0);
+ while (op != 0) {
+ ll2("---: " << *op);
+ op = op->next_op;
+ }
+ if (com_op->type != Op::NUL) {
+ if (com_op->type == t) {
+ const Data (&d2)[2] = com_op->data;
+ if (t == Op::INS && d2[0].seq == d[0].seq ||
+ t == Op::DEL && d2[1].seq == d[1].seq ||
+ t == Op::UPD && d2[0].seq == d[0].seq) {
+ if (cnt == g_ev_cnt[pk1]) {
+ if (! com_op->match) {
+ ll2("match pos " << cnt);
+ ok = com_op->match = true;
+ } else {
+ ll2("duplicate match");
+ }
+ } else {
+ ll2("match bad pos event=" << g_ev_cnt[pk1] << " op=" << cnt);
+ }
+ }
+ }
+ cnt++;
+ }
+ com_op = com_op->next_com;
+ }
+ if (ok)
+ return 0;
+ ll2("no match");
+ if (g_loglevel >= 2)
+ return -1;
+ loop++;
+ }
+ return 0;
+}
+
+static int
+matchevents()
+{
+ uint nomatch = 0;
+ Uint32 pk1;
+ for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
+ Op* tot_ev = g_pk_ev[pk1];
+ if (tot_ev == 0)
+ continue;
+ Op* com_ev = tot_ev->next_com;
+ while (com_ev != 0) {
+ if (matchevent(com_ev) < 0)
+ nomatch++;
+ g_ev_cnt[pk1]++;
+ com_ev = com_ev->next_com;
+ }
+ }
+ chkrc(nomatch == 0);
+ return 0;
+}
+
+static int
+matchops()
+{
+ Uint32 pk1;
+ for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
+ Op* tot_op = g_pk_op[pk1];
+ if (tot_op == 0)
+ continue;
+ Op* com_op = tot_op->next_com;
+ while (com_op != 0) {
+ if (com_op->type != Op::NUL && ! com_op->match) {
+ ll0("COM: " << *com_op);
+ Op* op = com_op->next_op;
+ assert(op != 0);
+ while (op != 0) {
+ ll0("---: " << *op);
+ op = op->next_op;
+ }
+ ll0("no matching event");
+ return -1;
+ }
+ com_op = com_op->next_com;
+ }
+ }
+ return 0;
+}
+
+static int
+runevents()
+{
+ ll1("runevents");
+ NdbEventOperation* evt_op;
+ uint npoll = 3;
+ while (npoll != 0) {
+ npoll--;
+ int ret;
+ ll1("poll");
+ ret = g_ndb->pollEvents(1000);
+ if (ret <= 0)
+ continue;
+ while (1) {
+ g_rec_ev->init();
+ Data (&d)[2] = g_rec_ev->data;
+#ifdef version50
+ int overrun = g_opts.maxops;
+ chkdb((ret = g_evt_op->next(&overrun)) >= 0);
+ chkrc(overrun == 0);
+ if (ret == 0)
+ break;
+#else
+ NdbEventOperation* tmp_op = g_ndb->nextEvent();
+ if (tmp_op == 0)
+ break;
+ reqrc(g_evt_op == tmp_op);
+#endif
+ chkrc(seteventtype(g_rec_ev, g_evt_op->getEventType()) == 0);
+ // get indicators
+ { int i, j;
+ for (j = 0; j < 2; j++)
+ for (i = 0; i < g_ncol; i++)
+ d[j].ind[i] = g_ra[j][i]->isNULL();
+ }
+ ll2("runevents: EVT: " << *g_rec_ev);
+ // check basic sanity
+ Uint32 pk1 = ~(Uint32)0;
+ chkrc(checkop(g_rec_ev, pk1) == 0);
+ // add to events
+ chkrc(getfreeevs() >= 2);
+ Op* tot_ev = g_pk_ev[pk1];
+ if (tot_ev == 0)
+ tot_ev = g_pk_ev[pk1] = getev(); //1
+ Op* last_com = tot_ev;
+ while (last_com->next_com != 0)
+ last_com = last_com->next_com;
+ // copy and add
+ Op* ev = getev(); //3
+ copyop(g_rec_ev, ev);
+ last_com->next_com = ev;
+ }
+ }
+ chkrc(matchevents() == 0);
+ chkrc(matchops() == 0);
+ return 0;
+}
+
+static void
+setseed(int n)
+{
+ uint seed;
+ if (n == -1) {
+ if (g_opts.seed == 0)
+ return;
+ if (g_opts.seed != -1)
+ seed = (uint)g_opts.seed;
+ else
+ seed = 1 + (ushort)getpid();
+ } else {
+ if (g_opts.seed != 0)
+ return;
+ seed = n;
+ }
+ ll0("seed=" << seed);
+ srandom(seed);
+}
+
+static int
+runtest()
+{
+ setseed(-1);
+ chkrc(createtable() == 0);
+ chkrc(createevent() == 0);
+ uint n;
+ for (n = 0; n < g_opts.loop; n++) {
+ ll0("loop " << n);
+ setseed(n);
+ resetmem();
+ g_rec_ev = getev();
+ chkrc(createeventop() == 0);
+ chkdb(g_evt_op->execute() == 0);
+ chkrc(waitgci() == 0);
+ makeops();
+ chkrc(runops() == 0);
+ chkrc(runevents() == 0);
+ chkrc(dropeventop() == 0);
+ }
+ chkrc(dropevent() == 0);
+ chkrc(droptable() == 0);
+ return 0;
+}
+
+NDB_STD_OPTS_VARS;
+
+static struct my_option
+my_long_options[] =
+{
+ NDB_STD_OPTS("test_event_merge"),
+ { "abort-on-error", 1008, "Do abort() on any error",
+ (gptr*)&g_opts.abort_on_error, (gptr*)&g_opts.abort_on_error, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "loglevel", 1001, "Logging level in this program (default 0)",
+ (gptr*)&g_opts.loglevel, (gptr*)&g_opts.loglevel, 0,
+ GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ { "loop", 1002, "Number of test loops (default 1, 0=forever)",
+ (gptr*)&g_opts.loop, (gptr*)&g_opts.loop, 0,
+ GET_INT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0 },
+ { "maxops", 1003, "Number of PK operations (default 2000)",
+ (gptr*)&g_opts.maxops, (gptr*)&g_opts.maxops, 0,
+ GET_UINT, REQUIRED_ARG, 2000, 0, g_maxops, 0, 0, 0 },
+ { "maxpk", 1004, "Number of different PK values (default 10)",
+ (gptr*)&g_opts.maxpk, (gptr*)&g_opts.maxpk, 0,
+ GET_UINT, REQUIRED_ARG, 10, 1, g_maxpk, 0, 0, 0 },
+ { "opstr", 1005, "Ops to run e.g. idiucdc (c = commit, default random)",
+ (gptr*)&g_opts.opstr, (gptr*)&g_opts.opstr, 0,
+ GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ { "seed", 1006, "Random seed (0=loop number, default -1=random)",
+ (gptr*)&g_opts.seed, (gptr*)&g_opts.seed, 0,
+ GET_INT, REQUIRED_ARG, -1, 0, 0, 0, 0, 0 },
+ { "separate-events", 1007, "Do not combine events per GCI >5.0",
+ (gptr*)&g_opts.separate_events, (gptr*)&g_opts.separate_events, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "use-table", 1008, "Use existing table 'tem1'",
+ (gptr*)&g_opts.use_table, (gptr*)&g_opts.use_table, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0,
+ 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
+};
+
+static void
+usage()
+{
+ my_print_help(my_long_options);
+}
+
+static int
+checkopts()
+{
+ if (g_opts.opstr != 0) {
+ const char* s = g_opts.opstr;
+ uint n = strlen(s);
+ if (n < 3 || s[0] != 'i' || s[n-2] != 'd' || s[n-1] != 'c')
+ return -1;
+ while (*s != 0)
+ if (strchr("iduc", *s++) == 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+main(int argc, char** argv)
+{
+ ndb_init();
+ const char* progname =
+ strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
+ uint i;
+ ndbout << progname;
+ for (i = 1; i < argc; i++)
+ ndbout << " " << argv[i];
+ ndbout << endl;
+ int ret;
+ ret = handle_options(&argc, &argv, my_long_options, ndb_std_get_one_option);
+ if (ret != 0 || argc != 0 || checkopts() != 0)
+ return NDBT_ProgramExit(NDBT_WRONGARGS);
+ g_ncc = new Ndb_cluster_connection();
+ if (g_ncc->connect(30) == 0) {
+ g_ndb = new Ndb(g_ncc, "TEST_DB");
+ if (g_ndb->init() == 0 && g_ndb->waitUntilReady(30) == 0) {
+ if (runtest() == 0)
+ return NDBT_ProgramExit(NDBT_OK);
+ }
+ }
+ delete g_ndb;
+ delete g_ncc;
+ return NDBT_ProgramExit(NDBT_FAILED);
+}
diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt
index 8b44594a9b5..59f51044b51 100644
--- a/ndb/test/run-test/daily-basic-tests.txt
+++ b/ndb/test/run-test/daily-basic-tests.txt
@@ -413,6 +413,27 @@ max-time: 500
cmd: testScan
args: -n ScanParallelism
+max-time: 500
+cmd: testNodeRestart
+args: -n Bug15587 T1
+
+max-time: 500
+cmd: testNodeRestart
+args: -n Bug15632 T1
+
+max-time: 500
+cmd: testNodeRestart
+args: -n Bug15685 T1
+
+# OLD FLEX
+max-time: 500
+cmd: flexBench
+args: -c 25 -t 10
+
+max-time: 500
+cmd: flexHammer
+args: -r 5 -t 32
+
#
# DICT TESTS
max-time: 1500
diff --git a/ndb/tools/ndb_error_reporter b/ndb/tools/ndb_error_reporter
new file mode 100755
index 00000000000..2b5aadb6171
--- /dev/null
+++ b/ndb/tools/ndb_error_reporter
@@ -0,0 +1,88 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+if(@ARGV < 1)
+{
+ print STDERR "Usage:\n";
+ print STDERR "\tndb_error_reporter config.ini [username] [--fs]\n\n";
+ print STDERR "\tusername is a user that you can use to ssh into\n";
+ print STDERR "\t all of your nodes with.\n\n";
+ print STDERR "\t--fs means include the filesystems in the report\n";
+ print STDERR "\t WARNING: This may require a lot of disk space.\n";
+ print STDERR "\t Only use this option when asked to.\n\n";
+ exit(1);
+}
+
+my $config_file= $ARGV[0];
+my $config_get_fs= 0;
+my $config_username= '';
+if(defined($ARGV[1]))
+{
+ $config_get_fs= 1 if $ARGV[1] eq '--fs';
+ $config_username= $ARGV[1].'@' if $ARGV[1] ne '--fs';
+ $config_get_fs= (defined $ARGV[2] && $ARGV[2] eq '--fs')?1:$config_get_fs;
+}
+
+if(!stat($config_file))
+{
+ print STDERR "Cannot open configuration file.\n\n";
+ exit(1);
+}
+
+my @nodes= split ' ',`ndb_config --config-file=$ARGV[0] --nodes --query=id --type=ndbd`;
+
+push @nodes, split ' ',`ndb_config --config-file=$ARGV[0] --nodes --query=id --type=ndb_mgmd`;
+
+sub config {
+ my $nodeid= shift;
+ my $query= shift;
+ my $res= `ndb_config --config-file=$ARGV[0] --id=$nodeid --query=$query`;
+ chomp $res;
+ $res;
+}
+
+my @t= localtime();
+my $reportdir= sprintf('ndb_error_report_%u%02u%02u%02u%02u%02u',
+ ($t[5]+1900),($t[4]+1),$t[3],$t[2],$t[1],$t[0]);
+
+if(stat($reportdir) || stat($reportdir.'tar.bz2'))
+{
+ print STDERR "It looks like another ndb_error_report process is running.\n";
+ print STDERR "If that is not the case, remove the ndb_error_report directory";
+ print STDERR " and run ndb_error_report again.\n\n";
+ exit(1);
+}
+
+mkdir($reportdir);
+
+foreach my $node (@nodes)
+{
+ print "\n\n Copying data from node $node".
+ (($config_get_fs)?" with filesystem":"").
+ "\n\n";
+ my $recurse= ($config_get_fs)?'-r ':'';
+ system 'scp '.$recurse.$config_username.config($node,'host').
+ ':'.config($node,'datadir')."/ndb_".$node."* ".
+ "$reportdir/\n";
+}
+
+print "\n\n Copying configuration file...\n\n\t$config_file\n\n";
+system "cp $config_file $reportdir/";
+
+my $r = system 'bzip2 2>&1 > /dev/null < /dev/null';
+my $outfile;
+if($r==0)
+{
+ $outfile= "$reportdir.tar.bz2";
+ system "tar c $reportdir|bzip2 > $outfile";
+}
+else
+{
+ $outfile= "$reportdir.tar.gz";
+ system "tar c $reportdir|gzip > $outfile";
+}
+
+system "rm -rf $reportdir";
+
+print "\n\nPlease attach $outfile to your error report\n\n";
diff --git a/ndb/tools/ndb_size.pl b/ndb/tools/ndb_size.pl
index ece0901e0b2..e0085c619f0 100644
--- a/ndb/tools/ndb_size.pl
+++ b/ndb/tools/ndb_size.pl
@@ -146,9 +146,9 @@ foreach(@{$tables})
elsif($type =~ /varchar/ || $type =~ /varbinary/)
{
my $fixed= 1+$size;
- my @dynamic=$dbh->selectrow_array("select avg(length("
- .$dbh->quote($name)
- .")) from `".$table.'`');
+ my @dynamic=$dbh->selectrow_array("select avg(length(`"
+ .$name.
+ ."`)) from `".$table.'`');
$dynamic[0]=0 if !$dynamic[0];
@realsize= ($fixed,$fixed,ceil($dynamic[0]));
}
diff --git a/netware/BUILD/compile-linux-tools b/netware/BUILD/compile-linux-tools
index 26ac1d79f37..14422ea5a3f 100755
--- a/netware/BUILD/compile-linux-tools
+++ b/netware/BUILD/compile-linux-tools
@@ -28,7 +28,8 @@ rm -f */*.linux
./configure --without-innodb --without-docs
# build tools only
-make clean all-local
+make clean
+make
# Create mysql_version.h which was deleted my previous step
./config.status include/mysql_version.h
@@ -55,7 +56,7 @@ make clean all-local
# copying required linux tools
cp extra/comp_err extra/comp_err.linux
cp libmysql/conf_to_src libmysql/conf_to_src.linux
-cp libmysql_r/conf_to_src libmysql_r/conf_to_src.linux
+#cp libmysql_r/conf_to_src libmysql_r/conf_to_src.linux
cp sql/gen_lex_hash sql/gen_lex_hash.linux
cp strings/conf_to_src strings/conf_to_src.linux
diff --git a/netware/libmysql.def b/netware/libmysql.def
index fea117dedd1..8a34754e092 100644
--- a/netware/libmysql.def
+++ b/netware/libmysql.def
@@ -7,5 +7,6 @@ COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Res
DESCRIPTION "MySQL Client Library"
VERSION 4, 0
AUTOUNLOAD
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/my_print_defaults.def b/netware/my_print_defaults.def
index d88c5adf4cc..778a5204ebd 100644
--- a/netware/my_print_defaults.def
+++ b/netware/my_print_defaults.def
@@ -4,7 +4,7 @@
MODULE libc.nlm
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Print Defaults Tool"
-VERSION 5, 0, 8
+VERSION 5, 0, 17
STACKSIZE 32767
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/myisamlog.def b/netware/myisamlog.def
index 3580c870c10..553a818a2ae 100644
--- a/netware/myisamlog.def
+++ b/netware/myisamlog.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL MyISAM Table Log Tool"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL MyISAM Table Log Tool"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/myisampack.def b/netware/myisampack.def
index a6946982236..d1f85fe03f8 100644
--- a/netware/myisampack.def
+++ b/netware/myisampack.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL MyISAM Table Pack Tool"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL MyISAM Table Pack Tool"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/mysql_install_db.def b/netware/mysql_install_db.def
index 1657b7c17af..372bbf15570 100644
--- a/netware/mysql_install_db.def
+++ b/netware/mysql_install_db.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL Install"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Initial Database Installer"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/mysql_test_run.c b/netware/mysql_test_run.c
index 98b7ab7fd8c..6bab2f0149c 100644
--- a/netware/mysql_test_run.c
+++ b/netware/mysql_test_run.c
@@ -349,6 +349,8 @@ void start_master()
add_arg(&al, "--tmpdir=%s", mysql_tmp_dir);
add_arg(&al, "--language=%s", lang_dir);
add_arg(&al, "--log-bin-trust-routine-creators");
+ add_arg(&al, "--log-slow-queries");
+ add_arg(&al, "--log-queries-not-using-indexes");
#ifdef DEBUG //only for debug builds
add_arg(&al, "--debug");
#endif
@@ -523,6 +525,8 @@ void start_slave()
add_arg(&al, "-O");
add_arg(&al, "slave_net_timeout=10");
add_arg(&al, "--log-bin-trust-routine-creators");
+ add_arg(&al, "--log-slow-queries");
+ add_arg(&al, "--log-queries-not-using-indexes");
#ifdef DEBUG //only for debug builds
add_arg(&al, "--debug");
#endif
diff --git a/netware/mysqladmin.def b/netware/mysqladmin.def
index e7f2d90bf9e..6532cab84a0 100644
--- a/netware/mysqladmin.def
+++ b/netware/mysqladmin.def
@@ -6,7 +6,7 @@ SCREENNAME "MySQL Admin[scrollable]"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Admin Tool"
VERSION 4, 0
-STACKSIZE 32767
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/mysqlbinlog.def b/netware/mysqlbinlog.def
index 3e75cf07a57..aced63429c5 100644
--- a/netware/mysqlbinlog.def
+++ b/netware/mysqlbinlog.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL Binary Log Dump Tool[scrollable]"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Binary Log Dump Tool"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/mysqlcheck.def b/netware/mysqlcheck.def
index cb70c1b394d..1b90b2a1dbe 100644
--- a/netware/mysqlcheck.def
+++ b/netware/mysqlcheck.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL Check Tool[scrollable]"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Check Tool"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/mysqld_safe.def b/netware/mysqld_safe.def
index 2a9ef04b47d..ff3f1924906 100644
--- a/netware/mysqld_safe.def
+++ b/netware/mysqld_safe.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL Database Server"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Database Server Monitor"
VERSION 4, 0
+STACKSIZE 32768
MULTIPLE
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/mysqldump.def b/netware/mysqldump.def
index 811c53ce5f6..5d7999c789f 100644
--- a/netware/mysqldump.def
+++ b/netware/mysqldump.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL Dump Tool[scrollable]"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Dump Tool"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/mysqlimport.def b/netware/mysqlimport.def
index dc9af18aa09..f98d8021a73 100644
--- a/netware/mysqlimport.def
+++ b/netware/mysqlimport.def
@@ -6,6 +6,7 @@ SCREENNAME "MySQL Import[scrollable]"
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Import Tool"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/netware/perror.def b/netware/perror.def
index 18c95d8b236..d67bd6191b4 100644
--- a/netware/perror.def
+++ b/netware/perror.def
@@ -5,6 +5,7 @@ MODULE libc.nlm
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Error Code Description Tool"
VERSION 4, 0
+STACKSIZE 32768
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index 5767728fe4f..d4d96d38d14 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -193,6 +193,7 @@ if [ $BASE_SYSTEM = "netware" ] ; then
libname=`basename $i .a`
$MV $i $BASE/lib/$libname.lib
done
+ rm -f $BASE/lib/*.la
fi
copyfileto $BASE/include config.h include/*
@@ -288,6 +289,9 @@ if [ $BASE_SYSTEM = "netware" ] ; then
$BASE/support-files/mysql*.spec \
$BASE/support-files/mysql-log-rotate \
$BASE/support-files/binary-configure \
+ $BASE/support-files/build-tags \
+ $BASE/support-files/MySQL-shared-compat.spec \
+ $BASE/support-files/ndb-config-2-node.ini \
$BASE/INSTALL-BINARY \
$BASE/MySQLEULA.txt
else
diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh
index ea3ca66db6e..53f05c131ac 100644
--- a/scripts/make_win_src_distribution.sh
+++ b/scripts/make_win_src_distribution.sh
@@ -199,7 +199,7 @@ copy_dir_files()
print_debug "Creating directory '$arg'"
mkdir $BASE/$arg
fi
- for i in *.c *.cpp *.h *.ih *.i *.ic *.asm *.def *.hpp *.dsp *.dsw \
+ for i in *.c *.cpp *.h *.ih *.i *.ic *.asm *.def *.hpp \
README INSTALL* LICENSE AUTHORS NEWS ChangeLog \
*.inc *.test *.result *.pem Moscow_leap des_key_file \
*.vcproj *.sln *.dat *.000001 *.require *.opt
@@ -342,7 +342,7 @@ mv $BASE/sql/sql_yacc.cpp-new $BASE/sql/sql_yacc.cpp
#
# Search the tree for plain text files and adapt the line end marker
#
-find $BASE \( -name "*.dsp" -o -name "*.dsw" -o -name "*.cnf" -o -name "*.ini" \
+find $BASE \( -name "*.cnf" -o -name "*.ini" \
-o -name COPYING -o -name ChangeLog -o -name EXCEPTIONS-CLIENT \
-o -name "INSTALL*" -o -name LICENSE -o -name "README*" \
-o -name "*.vcproj" -o -name "*.sln" \) -type f -print \
diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh
index 1c5cd6a4faf..bf53aa78e15 100644
--- a/scripts/mysqlhotcopy.sh
+++ b/scripts/mysqlhotcopy.sh
@@ -252,6 +252,7 @@ if ( defined $opt{regexp} ) {
my $sth_dbs = $dbh->prepare("show databases");
$sth_dbs->execute;
while ( my ($db_name) = $sth_dbs->fetchrow_array ) {
+ next if $db_name =~ m/^information_schema$/i;
push @db_desc, { 'src' => $db_name, 't_regex' => $t_regex } if ( $db_name =~ m/$opt{regexp}/o );
}
}
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index 3d54d000d5f..3d04403f830 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -255,7 +255,10 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
log_info("starting instance %s", instance_name_buff);
if (start_process(old_instance_options, &process_info))
+ {
+ instance_map->unlock();
return; /* error is logged */
+ }
/* allow users to delete instances */
instance_map->unlock();
diff --git a/sql-common/client.c b/sql-common/client.c
index cc90b2a105a..4c2debd41ff 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -715,6 +715,7 @@ void free_old_query(MYSQL *mysql)
init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
mysql->fields= 0;
mysql->field_count= 0; /* For API */
+ mysql->warning_count= 0;
mysql->info= 0;
DBUG_VOID_RETURN;
}
@@ -1495,12 +1496,17 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
static void
mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
{
+ struct st_VioSSLConnectorFd *st=
+ (struct st_VioSSLConnectorFd*) mysql->connector_fd;
DBUG_ENTER("mysql_ssl_free");
+
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
+ if (st)
+ SSL_CTX_free(st->ssl_context);
my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR));
mysql->options.ssl_key = 0;
mysql->options.ssl_cert = 0;
@@ -2479,7 +2485,6 @@ get_info:
DBUG_RETURN(1);
mysql->status= MYSQL_STATUS_GET_RESULT;
mysql->field_count= (uint) field_count;
- mysql->warning_count= 0;
DBUG_PRINT("exit",("ok"));
DBUG_RETURN(0);
}
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 72809ee9b4b..c9d39260761 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -575,18 +575,34 @@ fractional:
/* Get fractional second part */
if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
{
- uint field_length=5;
+ int field_length= 5;
str++; value=(uint) (uchar) (*str - '0');
- while (++str != end &&
- my_isdigit(&my_charset_latin1,str[0]) &&
- field_length--)
- value=value*10 + (uint) (uchar) (*str - '0');
- if (field_length)
+ while (++str != end && my_isdigit(&my_charset_latin1, *str))
+ {
+ if (field_length-- > 0)
+ value= value*10 + (uint) (uchar) (*str - '0');
+ }
+ if (field_length > 0)
value*= (long) log_10_int[field_length];
+ else if (field_length < 0)
+ *was_cut= 1;
date[4]=value;
}
else
date[4]=0;
+
+ /* Check for exponent part: E<gigit> | E<sign><digit> */
+ /* (may occur as result of %g formatting of time value) */
+ if ((end - str) > 1 &&
+ (*str == 'e' || *str == 'E') &&
+ (my_isdigit(&my_charset_latin1, str[1]) ||
+ ((str[1] == '-' || str[1] == '+') &&
+ (end - str) > 2 &&
+ my_isdigit(&my_charset_latin1, str[2]))))
+ {
+ *was_cut= 1;
+ return 1;
+ }
if (internal_format_positions[7] != 255)
{
diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc
index d340b9289ec..471ece77490 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -480,6 +480,8 @@ int ha_example::rnd_pos(byte * buf, byte *pos)
/*
::info() is used to return information to the optimizer.
+ see my_base.h for the complete description
+
Currently this table handler doesn't implement most of the fields
really needed. SHOW also makes use of this data
Another note, you will probably want to have the following in your
diff --git a/sql/field.cc b/sql/field.cc
index 9e73c132d68..1f3649e1b88 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -3953,7 +3953,7 @@ longlong Field_float::val_int(void)
else
#endif
memcpy_fixed((byte*) &j,ptr,sizeof(j));
- return ((longlong) j);
+ return (longlong) rint(j);
}
@@ -4241,7 +4241,7 @@ longlong Field_double::val_int(void)
else
#endif
doubleget(j,ptr);
- return ((longlong) j);
+ return (longlong) rint(j);
}
@@ -5855,44 +5855,52 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
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 necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
- {
+ {
uint conv_errors;
tmpstr.copy(from, length, cs, field_charset, &conv_errors);
from= tmpstr.ptr();
- length= tmpstr.length();
+ length= tmpstr.length();
if (conv_errors)
error= 2;
}
- /*
- Make sure we don't break a multibyte sequence
- as well as don't copy a malformed data.
- */
+ /* Make sure we don't break a multibyte sequence or copy malformed data. */
copy_length= field_charset->cset->well_formed_len(field_charset,
from,from+length,
field_length/
field_charset->mbmaxlen,
&well_formed_error);
memcpy(ptr,from,copy_length);
- if (copy_length < field_length) // Append spaces if shorter
+
+ /* Append spaces if the string was shorter than the field. */
+ if (copy_length < field_length)
field_charset->cset->fill(field_charset,ptr+copy_length,
- field_length-copy_length,
+ field_length-copy_length,
field_charset->pad_char);
-
+
+ /*
+ Check if we lost any important data (anything in a binary string,
+ or any non-space in others).
+ */
if ((copy_length < length) && table->in_use->count_cuted_fields)
- { // Check if we loosed some info
- const char *end=from+length;
- from+= copy_length;
- from+= field_charset->cset->scan(field_charset, from, end,
- MY_SEQ_SPACES);
- if (from != end)
+ {
+ if (binary())
error= 2;
+ else
+ {
+ const char *end=from+length;
+ from+= copy_length;
+ from+= field_charset->cset->scan(field_charset, from, end,
+ MY_SEQ_SPACES);
+ if (from != end)
+ error= 2;
+ }
}
if (error)
{
@@ -6271,12 +6279,15 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
if ((copy_length < length) && table->in_use->count_cuted_fields &&
!error_code)
{
- const char *end= from + length;
- from+= copy_length;
- from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
- /* If we lost only spaces then produce a NOTE, not a WARNING */
- if (from == end)
- level= MYSQL_ERROR::WARN_LEVEL_NOTE;
+ if (!binary())
+ {
+ const char *end= from + length;
+ from+= copy_length;
+ from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
+ /* If we lost only spaces then produce a NOTE, not a WARNING */
+ if (from == end)
+ level= MYSQL_ERROR::WARN_LEVEL_NOTE;
+ }
error_code= WARN_DATA_TRUNCATED;
}
if (error_code)
@@ -6748,7 +6759,10 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
{
flags|= BLOB_FLAG;
if (table)
+ {
table->s->blob_fields++;
+ /* TODO: why do not fill table->s->blob_field array here? */
+ }
}
@@ -8272,6 +8286,350 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
}
+/*
+ Initialize field definition for create
+
+ SYNOPSIS
+ thd Thread handle
+ fld_name Field name
+ fld_type Field type
+ fld_length Field length
+ fld_decimals Decimal (if any)
+ fld_type_modifier Additional type information
+ fld_default_value Field default value (if any)
+ fld_on_update_value The value of ON UPDATE clause
+ fld_comment Field comment
+ fld_change Field change
+ fld_interval_list Interval list (if any)
+ fld_charset Field charset
+ fld_geom_type Field geometry type (if any)
+
+ RETURN
+ FALSE on success
+ TRUE on error
+*/
+
+bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
+ char *fld_length, char *fld_decimals,
+ uint fld_type_modifier, Item *fld_default_value,
+ Item *fld_on_update_value, LEX_STRING *fld_comment,
+ char *fld_change, List<String> *fld_interval_list,
+ CHARSET_INFO *fld_charset, uint fld_geom_type)
+{
+ uint sign_len, allowed_type_modifier= 0;
+ ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
+
+ DBUG_ENTER("create_field::init()");
+
+ field= 0;
+ field_name= fld_name;
+ def= fld_default_value;
+ flags= fld_type_modifier;
+ unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
+ Field::NEXT_NUMBER : Field::NONE);
+ decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0;
+ if (decimals >= NOT_FIXED_DEC)
+ {
+ my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name,
+ NOT_FIXED_DEC-1);
+ DBUG_RETURN(TRUE);
+ }
+
+ sql_type= fld_type;
+ length= 0;
+ change= fld_change;
+ interval= 0;
+ pack_length= key_length= 0;
+ charset= fld_charset;
+ geom_type= (Field::geometry_type) fld_geom_type;
+ interval_list.empty();
+
+ comment= *fld_comment;
+ /*
+ Set flag if this field doesn't have a default value
+ */
+ if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
+ (fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP)
+ flags|= NO_DEFAULT_VALUE_FLAG;
+
+ if (fld_length && !(length= (uint) atoi(fld_length)))
+ fld_length= 0; /* purecov: inspected */
+ sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
+
+ switch (fld_type) {
+ case FIELD_TYPE_TINY:
+ if (!fld_length)
+ length= MAX_TINYINT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_SHORT:
+ if (!fld_length)
+ length= MAX_SMALLINT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_INT24:
+ if (!fld_length)
+ length= MAX_MEDIUMINT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_LONG:
+ if (!fld_length)
+ length= MAX_INT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_LONGLONG:
+ if (!fld_length)
+ length= MAX_BIGINT_WIDTH;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_NULL:
+ break;
+ case FIELD_TYPE_NEWDECIMAL:
+ if (!fld_length && !decimals)
+ length= 10;
+ if (length > DECIMAL_MAX_PRECISION)
+ {
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
+ DECIMAL_MAX_PRECISION);
+ DBUG_RETURN(TRUE);
+ }
+ if (length < decimals)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ length=
+ my_decimal_precision_to_length(length, decimals,
+ fld_type_modifier & UNSIGNED_FLAG);
+ pack_length=
+ my_decimal_get_binary_size(length, decimals);
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ /*
+ Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
+ if they don't have a default value
+ */
+ max_field_charlength= MAX_FIELD_VARCHARLENGTH;
+ break;
+ case MYSQL_TYPE_STRING:
+ break;
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_GEOMETRY:
+ if (fld_default_value)
+ {
+ /* Allow empty as default value. */
+ String str,*res;
+ res= fld_default_value->val_str(&str);
+ if (res->length())
+ {
+ my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
+ fld_name); /* purecov: inspected */
+ DBUG_RETURN(TRUE);
+ }
+ def= 0;
+ }
+ flags|= BLOB_FLAG;
+ break;
+ case FIELD_TYPE_YEAR:
+ if (!fld_length || length != 2)
+ length= 4; /* Default length */
+ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ break;
+ case FIELD_TYPE_FLOAT:
+ /* change FLOAT(precision) to FLOAT or DOUBLE */
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ if (fld_length && !fld_decimals)
+ {
+ uint tmp_length= length;
+ if (tmp_length > PRECISION_FOR_DOUBLE)
+ {
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ else if (tmp_length > PRECISION_FOR_FLOAT)
+ {
+ sql_type= FIELD_TYPE_DOUBLE;
+ length= DBL_DIG+7; /* -[digits].E+### */
+ }
+ else
+ length= FLT_DIG+6; /* -[digits].E+## */
+ decimals= NOT_FIXED_DEC;
+ break;
+ }
+ if (!fld_length && !fld_decimals)
+ {
+ length= FLT_DIG+6;
+ decimals= NOT_FIXED_DEC;
+ }
+ if (length < decimals &&
+ decimals != NOT_FIXED_DEC)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ break;
+ case FIELD_TYPE_DOUBLE:
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ if (!fld_length && !fld_decimals)
+ {
+ length= DBL_DIG+7;
+ decimals= NOT_FIXED_DEC;
+ }
+ if (length < decimals &&
+ decimals != NOT_FIXED_DEC)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ break;
+ case FIELD_TYPE_TIMESTAMP:
+ if (!fld_length)
+ length= 14; /* Full date YYYYMMDDHHMMSS */
+ else if (length != 19)
+ {
+ /*
+ We support only even TIMESTAMP lengths less or equal than 14
+ and 19 as length of 4.1 compatible representation.
+ */
+ length= ((length+1)/2)*2; /* purecov: inspected */
+ length= min(length,14); /* purecov: inspected */
+ }
+ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ if (fld_default_value)
+ {
+ /* Grammar allows only NOW() value for ON UPDATE clause */
+ if (fld_default_value->type() == Item::FUNC_ITEM &&
+ ((Item_func*)fld_default_value)->functype() == Item_func::NOW_FUNC)
+ {
+ unireg_check= (fld_on_update_value ? Field::TIMESTAMP_DNUN_FIELD:
+ Field::TIMESTAMP_DN_FIELD);
+ /*
+ We don't need default value any longer moreover it is dangerous.
+ Everything handled by unireg_check further.
+ */
+ def= 0;
+ }
+ else
+ unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD:
+ Field::NONE);
+ }
+ else
+ {
+ /*
+ If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
+ or ON UPDATE values then for the sake of compatiblity we should treat
+ this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
+ have another TIMESTAMP column with auto-set option before this one)
+ or DEFAULT 0 (in other cases).
+ So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
+ replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
+ information about all TIMESTAMP fields in table will be availiable.
+
+ If we have TIMESTAMP NULL column without explicit DEFAULT value
+ we treat it as having DEFAULT NULL attribute.
+ */
+ unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD :
+ (flags & NOT_NULL_FLAG ? Field::TIMESTAMP_OLD_FIELD :
+ Field::NONE));
+ }
+ break;
+ case FIELD_TYPE_DATE:
+ /* Old date type. */
+ if (protocol_version != PROTOCOL_VERSION-1)
+ sql_type= FIELD_TYPE_NEWDATE;
+ /* fall trough */
+ case FIELD_TYPE_NEWDATE:
+ length= 10;
+ break;
+ case FIELD_TYPE_TIME:
+ length= 10;
+ break;
+ case FIELD_TYPE_DATETIME:
+ length= 19;
+ break;
+ case FIELD_TYPE_SET:
+ {
+ if (fld_interval_list->elements > sizeof(longlong)*8)
+ {
+ my_error(ER_TOO_BIG_SET, MYF(0), fld_name); /* purecov: inspected */
+ DBUG_RETURN(TRUE);
+ }
+ pack_length= get_set_pack_length(fld_interval_list->elements);
+
+ List_iterator<String> it(*fld_interval_list);
+ String *tmp;
+ while ((tmp= it++))
+ interval_list.push_back(tmp);
+ /*
+ Set fake length to 1 to pass the below conditions.
+ Real length will be set in mysql_prepare_table()
+ when we know the character set of the column
+ */
+ length= 1;
+ break;
+ }
+ case FIELD_TYPE_ENUM:
+ {
+ /* Should be safe. */
+ pack_length= get_enum_pack_length(fld_interval_list->elements);
+
+ List_iterator<String> it(*fld_interval_list);
+ String *tmp;
+ while ((tmp= it++))
+ interval_list.push_back(tmp);
+ length= 1; /* See comment for FIELD_TYPE_SET above. */
+ break;
+ }
+ case MYSQL_TYPE_VAR_STRING:
+ DBUG_ASSERT(0); /* Impossible. */
+ break;
+ case MYSQL_TYPE_BIT:
+ {
+ if (!fld_length)
+ length= 1;
+ if (length > MAX_BIT_FIELD_LENGTH)
+ {
+ my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name,
+ MAX_BIT_FIELD_LENGTH);
+ DBUG_RETURN(TRUE);
+ }
+ pack_length= (length + 7) / 8;
+ break;
+ }
+ case FIELD_TYPE_DECIMAL:
+ DBUG_ASSERT(0); /* Was obsolete */
+ }
+
+ if (!(flags & BLOB_FLAG) &&
+ ((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
+ fld_type != FIELD_TYPE_ENUM &&
+ (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) ||
+ (!length &&
+ fld_type != MYSQL_TYPE_STRING &&
+ fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY)))
+ {
+ my_error((fld_type == MYSQL_TYPE_VAR_STRING ||
+ fld_type == MYSQL_TYPE_VARCHAR ||
+ fld_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH :
+ ER_TOO_BIG_DISPLAYWIDTH,
+ MYF(0),
+ fld_name, max_field_charlength); /* purecov: inspected */
+ DBUG_RETURN(TRUE);
+ }
+ fld_type_modifier&= AUTO_INCREMENT_FLAG;
+ if ((~allowed_type_modifier) & fld_type_modifier)
+ {
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+
+ DBUG_RETURN(FALSE); /* success */
+}
+
+
enum_field_types get_blob_type_from_length(ulong length)
{
enum_field_types type;
diff --git a/sql/field.h b/sql/field.h
index ed6bf1c0a9c..67705523088 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -130,7 +130,19 @@ public:
null_bit == field->null_bit);
}
virtual bool eq_def(Field *field);
+
+ /*
+ pack_length() returns size (in bytes) used to store field data in memory
+ (i.e. it returns the maximum size of the field in a row of the table,
+ which is located in RAM).
+ */
virtual uint32 pack_length() const { return (uint32) field_length; }
+
+ /*
+ pack_length_in_rec() returns size (in bytes) used to store field data on
+ storage (i.e. it returns the maximal size of the field in a row of the
+ table, which is located on disk).
+ */
virtual uint32 pack_length_in_rec() const { return pack_length(); }
virtual uint32 sort_length() const { return pack_length(); }
virtual void reset(void) { bzero(ptr,pack_length()); }
@@ -1395,6 +1407,12 @@ public:
void init_for_tmp_table(enum_field_types sql_type_arg,
uint32 max_length, uint32 decimals,
bool maybe_null, bool is_unsigned);
+
+ bool init(THD *thd, char *field_name, enum_field_types type, char *length,
+ char *decimals, uint type_modifier, Item *default_value,
+ Item *on_update_value, LEX_STRING *comment, char *change,
+ List<String> *interval_list, CHARSET_INFO *cs,
+ uint uint_geom_type);
};
diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc
index 1e8fc582eb8..c60d40c2685 100644
--- a/sql/ha_archive.cc
+++ b/sql/ha_archive.cc
@@ -20,7 +20,7 @@
#include "mysql_priv.h"
-#ifdef HAVE_ARCHIVE_DB
+#if defined(HAVE_ARCHIVE_DB)
#include "ha_archive.h"
#include <my_dir.h>
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 56e5fd8923f..744bd242fca 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1218,7 +1218,7 @@ innobase_init(void)
"innobase_buffer_pool_size can't be over 4GB"
" on 32-bit systems");
- DBUG_RETURN(0);
+ goto error;
}
if (innobase_log_file_size > UINT_MAX32) {
@@ -1226,7 +1226,7 @@ innobase_init(void)
"innobase_log_file_size can't be over 4GB"
" on 32-bit systems");
- DBUG_RETURN(0);
+ goto error;
}
}
@@ -2519,6 +2519,12 @@ ha_innobase::open(
DBUG_RETURN(0);
}
+uint
+ha_innobase::max_supported_key_part_length() const
+{
+ return(DICT_MAX_INDEX_COL_LEN - 1);
+}
+
/**********************************************************************
Closes a handle to an InnoDB table. */
@@ -4675,6 +4681,9 @@ create_index(
0, prefix_len);
}
+ /* Even though we've defined max_supported_key_part_length, we
+ still do our own checking using field_lengths to be absolutely
+ sure we don't create too long indexes. */
error = row_create_index_for_mysql(index, trx, field_lengths);
error = convert_error_code_to_mysql(error, NULL);
@@ -5733,6 +5742,7 @@ ha_innobase::update_table_comment(
uint length = (uint) strlen(comment);
char* str;
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+ long flen;
/* We do not know if MySQL can call this function before calling
external_lock(). To be safe, update the thd of the current table
@@ -5752,43 +5762,43 @@ ha_innobase::update_table_comment(
trx_search_latch_release_if_reserved(prebuilt->trx);
str = NULL;
- if (FILE* file = os_file_create_tmpfile()) {
- long flen;
+ /* output the data to a temporary file */
- /* output the data to a temporary file */
- fprintf(file, "InnoDB free: %lu kB",
+ mutex_enter_noninline(&srv_dict_tmpfile_mutex);
+ rewind(srv_dict_tmpfile);
+
+ fprintf(srv_dict_tmpfile, "InnoDB free: %lu kB",
(ulong) fsp_get_available_space_in_free_extents(
prebuilt->table->space));
- dict_print_info_on_foreign_keys(FALSE, file,
+ dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
prebuilt->trx, prebuilt->table);
- flen = ftell(file);
- if (flen < 0) {
- flen = 0;
- } else if (length + flen + 3 > 64000) {
- flen = 64000 - 3 - length;
- }
+ flen = ftell(srv_dict_tmpfile);
+ if (flen < 0) {
+ flen = 0;
+ } else if (length + flen + 3 > 64000) {
+ flen = 64000 - 3 - length;
+ }
- /* allocate buffer for the full string, and
- read the contents of the temporary file */
+ /* allocate buffer for the full string, and
+ read the contents of the temporary file */
- str = my_malloc(length + flen + 3, MYF(0));
+ str = my_malloc(length + flen + 3, MYF(0));
- if (str) {
- char* pos = str + length;
- if (length) {
- memcpy(str, comment, length);
- *pos++ = ';';
- *pos++ = ' ';
- }
- rewind(file);
- flen = (uint) fread(pos, 1, flen, file);
- pos[flen] = 0;
+ if (str) {
+ char* pos = str + length;
+ if (length) {
+ memcpy(str, comment, length);
+ *pos++ = ';';
+ *pos++ = ' ';
}
-
- fclose(file);
+ rewind(srv_dict_tmpfile);
+ flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
+ pos[flen] = 0;
}
+ mutex_exit_noninline(&srv_dict_tmpfile_mutex);
+
prebuilt->trx->op_info = (char*)"";
return(str ? str : (char*) comment);
@@ -5806,6 +5816,7 @@ ha_innobase::get_foreign_key_create_info(void)
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
char* str = 0;
+ long flen;
ut_a(prebuilt != NULL);
@@ -5815,47 +5826,42 @@ ha_innobase::get_foreign_key_create_info(void)
update_thd(current_thd);
- if (FILE* file = os_file_create_tmpfile()) {
- long flen;
+ prebuilt->trx->op_info = (char*)"getting info on foreign keys";
- prebuilt->trx->op_info = (char*)"getting info on foreign keys";
+ /* In case MySQL calls this in the middle of a SELECT query,
+ release possible adaptive hash latch to avoid
+ deadlocks of threads */
- /* In case MySQL calls this in the middle of a SELECT query,
- release possible adaptive hash latch to avoid
- deadlocks of threads */
+ trx_search_latch_release_if_reserved(prebuilt->trx);
- trx_search_latch_release_if_reserved(prebuilt->trx);
+ mutex_enter_noninline(&srv_dict_tmpfile_mutex);
+ rewind(srv_dict_tmpfile);
- /* output the data to a temporary file */
- dict_print_info_on_foreign_keys(TRUE, file,
+ /* output the data to a temporary file */
+ dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
prebuilt->trx, prebuilt->table);
- prebuilt->trx->op_info = (char*)"";
-
- flen = ftell(file);
- if (flen < 0) {
- flen = 0;
- } else if (flen > 64000 - 1) {
- flen = 64000 - 1;
- }
+ prebuilt->trx->op_info = (char*)"";
- /* allocate buffer for the string, and
- read the contents of the temporary file */
+ flen = ftell(srv_dict_tmpfile);
+ if (flen < 0) {
+ flen = 0;
+ } else if (flen > 64000 - 1) {
+ flen = 64000 - 1;
+ }
- str = my_malloc(flen + 1, MYF(0));
+ /* allocate buffer for the string, and
+ read the contents of the temporary file */
- if (str) {
- rewind(file);
- flen = (uint) fread(str, 1, flen, file);
- str[flen] = 0;
- }
+ str = my_malloc(flen + 1, MYF(0));
- fclose(file);
- } else {
- /* unable to create temporary file */
- str = my_strdup(
-"/* Error: cannot display foreign key constraints */", MYF(0));
+ if (str) {
+ rewind(srv_dict_tmpfile);
+ flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
+ str[flen] = 0;
}
+ mutex_exit_noninline(&srv_dict_tmpfile_mutex);
+
return(str);
}
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index eb4e10e545f..58051624f89 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -110,7 +110,7 @@ class ha_innobase: public handler
but currently MySQL does not work with keys
whose size is > MAX_KEY_LENGTH */
uint max_supported_key_length() const { return 3500; }
- uint max_supported_key_part_length() const { return 3500; }
+ uint max_supported_key_part_length() const;
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
bool has_transactions() { return 1;}
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 81d11e0a27c..5d10a758f86 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -2813,8 +2813,26 @@ void ha_ndbcluster::position(const byte *record)
}
*buff++= 0;
}
- memcpy(buff, record + key_part->offset, key_part->length);
- buff += key_part->length;
+
+ size_t len = key_part->length;
+ const byte * ptr = record + key_part->offset;
+ Field *field = key_part->field;
+ if ((field->type() == MYSQL_TYPE_VARCHAR) &&
+ ((Field_varstring*)field)->length_bytes == 1)
+ {
+ /**
+ * Keys always use 2 bytes length
+ */
+ buff[0] = ptr[0];
+ buff[1] = 0;
+ memcpy(buff+2, ptr + 1, len);
+ len += 2;
+ }
+ else
+ {
+ memcpy(buff, ptr, len);
+ }
+ buff += len;
}
}
else
@@ -3333,17 +3351,20 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
DBUG_PRINT("info", ("Table schema version: %d",
tab->getObjectVersion()));
}
- if (m_table != (void *)tab)
- {
- m_table= (void *)tab;
- m_table_version = tab->getObjectVersion();
- }
- else if (m_table_version < tab->getObjectVersion())
+ if (m_table_version < tab->getObjectVersion())
{
/*
The table has been altered, caller has to retry
*/
- DBUG_RETURN(my_errno= HA_ERR_TABLE_DEF_CHANGED);
+ NdbError err= ndb->getNdbError(NDB_INVALID_SCHEMA_OBJECT);
+ DBUG_RETURN(ndb_to_mysql_error(&err));
+ }
+ if (m_table != (void *)tab)
+ {
+ m_table= (void *)tab;
+ m_table_version = tab->getObjectVersion();
+ if (!(my_errno= build_index_list(ndb, table, ILBP_OPEN)))
+ DBUG_RETURN(my_errno);
}
m_table_info= tab_info;
}
@@ -3881,9 +3902,8 @@ int ha_ndbcluster::create(const char *name,
uint pack_length, length, i, pk_length= 0;
const void *data, *pack_data;
char name2[FN_HEADLEN];
- bool create_from_engine= test(info->table_options &
- HA_OPTION_CREATE_FROM_ENGINE);
-
+ bool create_from_engine= (info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
+
DBUG_ENTER("ha_ndbcluster::create");
DBUG_PRINT("enter", ("name: %s", name));
fn_format(name2, name, "", "",2); // Remove the .frm extension
diff --git a/sql/handler.cc b/sql/handler.cc
index 477a6f9bdae..4b4c446f09b 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -60,7 +60,7 @@ handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
HTON_NO_FLAGS };
#endif
-#ifdef HAVE_ARCHIVE_DB
+#if defined(HAVE_ARCHIVE_DB)
#include "ha_archive.h"
extern handlerton archive_hton;
#else
@@ -300,39 +300,56 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type)
case DB_TYPE_HASH:
return new (alloc) ha_hash(table);
#endif
+ case DB_TYPE_MRG_MYISAM:
case DB_TYPE_MRG_ISAM:
return new (alloc) ha_myisammrg(table);
#ifdef HAVE_BERKELEY_DB
case DB_TYPE_BERKELEY_DB:
- return new (alloc) ha_berkeley(table);
+ if (have_berkeley_db == SHOW_OPTION_YES)
+ return new (alloc) ha_berkeley(table);
+ return NULL;
#endif
#ifdef HAVE_INNOBASE_DB
case DB_TYPE_INNODB:
- return new (alloc) ha_innobase(table);
+ if (have_innodb == SHOW_OPTION_YES)
+ return new (alloc) ha_innobase(table);
+ return NULL;
#endif
#ifdef HAVE_EXAMPLE_DB
case DB_TYPE_EXAMPLE_DB:
- return new (alloc) ha_example(table);
+ if (have_example_db == SHOW_OPTION_YES)
+ return new (alloc) ha_example(table);
+ return NULL;
#endif
-#ifdef HAVE_ARCHIVE_DB
+#if defined(HAVE_ARCHIVE_DB)
case DB_TYPE_ARCHIVE_DB:
- return new (alloc) ha_archive(table);
+ if (have_archive_db == SHOW_OPTION_YES)
+ return new (alloc) ha_archive(table);
+ return NULL;
#endif
#ifdef HAVE_BLACKHOLE_DB
case DB_TYPE_BLACKHOLE_DB:
- return new (alloc) ha_blackhole(table);
+ if (have_blackhole_db == SHOW_OPTION_YES)
+ return new (alloc) ha_blackhole(table);
+ return NULL;
#endif
#ifdef HAVE_FEDERATED_DB
case DB_TYPE_FEDERATED_DB:
- return new (alloc) ha_federated(table);
+ if (have_federated_db == SHOW_OPTION_YES)
+ return new (alloc) ha_federated(table);
+ return NULL;
#endif
#ifdef HAVE_CSV_DB
case DB_TYPE_CSV_DB:
- return new (alloc) ha_tina(table);
+ if (have_csv_db == SHOW_OPTION_YES)
+ return new (alloc) ha_tina(table);
+ return NULL;
#endif
#ifdef HAVE_NDBCLUSTER_DB
case DB_TYPE_NDBCLUSTER:
- return new (alloc) ha_ndbcluster(table);
+ if (have_ndbcluster == SHOW_OPTION_YES)
+ return new (alloc) ha_ndbcluster(table);
+ return NULL;
#endif
case DB_TYPE_HEAP:
return new (alloc) ha_heap(table);
@@ -346,8 +363,6 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type)
/* Fall back to MyISAM */
case DB_TYPE_MYISAM:
return new (alloc) ha_myisam(table);
- case DB_TYPE_MRG_MYISAM:
- return new (alloc) ha_myisammrg(table);
}
}
@@ -513,7 +528,7 @@ int ha_panic(enum ha_panic_function flag)
if (have_federated_db == SHOW_OPTION_YES)
error|= federated_db_end();
#endif
-#ifdef HAVE_ARCHIVE_DB
+#if defined(HAVE_ARCHIVE_DB)
if (have_archive_db == SHOW_OPTION_YES)
error|= archive_db_end();
#endif
diff --git a/sql/handler.h b/sql/handler.h
index be188f7cacd..91c5be9ba39 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -672,7 +672,7 @@ public:
key_range *max_key)
{ return (ha_rows) 10; }
virtual void position(const byte *record)=0;
- virtual void info(uint)=0;
+ virtual void info(uint)=0; // see my_base.h for full description
virtual int extra(enum ha_extra_function operation)
{ return 0; }
virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
diff --git a/sql/item.cc b/sql/item.cc
index dadbd31c81f..34dc450b924 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -296,23 +296,6 @@ longlong Item::val_int_from_decimal()
}
-void *Item::operator new(size_t size, Item *reuse, uint *rsize)
-{
- if (reuse && size <= reuse->rsize)
- {
- if (rsize)
- (*rsize)= reuse->rsize;
- reuse->cleanup();
- delete reuse;
- TRASH((void *)reuse, size);
- return (void *)reuse;
- }
- if (rsize)
- (*rsize)= (uint) size;
- return (void *)sql_alloc((uint)size);
-}
-
-
Item::Item():
rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
is_autogenerated_name(TRUE),
@@ -601,16 +584,8 @@ bool Item::eq(const Item *item, bool binary_cmp) const
Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
{
- /*
- Allow conversion from and to "binary".
- Don't allow automatic conversion to non-Unicode charsets,
- as it potentially loses data.
- */
- if (collation.collation != &my_charset_bin &&
- tocs != &my_charset_bin &&
- !(tocs->state & MY_CS_UNICODE))
- return NULL; // safe conversion is not possible
- return new Item_func_conv_charset(this, tocs);
+ Item_func_conv_charset *conv= new Item_func_conv_charset(this, tocs, 1);
+ return conv->safe ? conv : NULL;
}
@@ -700,23 +675,15 @@ Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs)
{
if (const_item())
{
- Item_string *conv;
uint cnv_errors;
- char buf[MAX_FIELD_WIDTH];
- String tmp(buf, sizeof(buf), &my_charset_bin);
- String cstr, *ostr= val_str(&tmp);
- /*
- As safe_charset_converter is not executed for
- a parameter bound to NULL, ostr should never be 0.
- */
- cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &cnv_errors);
- if (cnv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
- cstr.charset(),
- collation.derivation)))
- return NULL;
- conv->str_value.copy();
- conv->str_value.mark_as_const();
- return conv;
+ String *ostr= val_str(&cnvstr);
+ cnvitem->str_value.copy(ostr->ptr(), ostr->length(),
+ ostr->charset(), tocs, &cnv_errors);
+ if (cnv_errors)
+ return NULL;
+ cnvitem->str_value.mark_as_const();
+ cnvitem->max_length= cnvitem->str_value.numchars() * tocs->mbmaxlen;
+ return cnvitem;
}
return NULL;
}
@@ -818,9 +785,41 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
/*****************************************************************************
- Item_splocal methods
+ Item_sp_variable methods
*****************************************************************************/
-double Item_splocal::val_real()
+
+Item_sp_variable::Item_sp_variable(char *sp_var_name_str,
+ uint sp_var_name_length)
+ :m_thd(0)
+#ifndef DBUG_OFF
+ , m_sp(0)
+#endif
+{
+ m_name.str= sp_var_name_str;
+ m_name.length= sp_var_name_length;
+}
+
+
+bool Item_sp_variable::fix_fields(THD *thd, Item **)
+{
+ Item *it;
+
+ m_thd= thd; /* NOTE: this must be set before any this_xxx() */
+ it= this_item();
+
+ DBUG_ASSERT(it->fixed);
+
+ max_length= it->max_length;
+ decimals= it->decimals;
+ unsigned_flag= it->unsigned_flag;
+ fixed= 1;
+ collation.set(it->collation.collation, it->collation.derivation);
+
+ return FALSE;
+}
+
+
+double Item_sp_variable::val_real()
{
DBUG_ASSERT(fixed);
Item *it= this_item();
@@ -830,7 +829,7 @@ double Item_splocal::val_real()
}
-longlong Item_splocal::val_int()
+longlong Item_sp_variable::val_int()
{
DBUG_ASSERT(fixed);
Item *it= this_item();
@@ -840,13 +839,14 @@ longlong Item_splocal::val_int()
}
-String *Item_splocal::val_str(String *sp)
+String *Item_sp_variable::val_str(String *sp)
{
DBUG_ASSERT(fixed);
Item *it= this_item();
String *res= it->val_str(sp);
null_value= it->null_value;
+
if (!res)
return NULL;
@@ -870,11 +870,12 @@ String *Item_splocal::val_str(String *sp)
str_value.set(res->ptr(), res->length(), res->charset());
else
res->mark_as_const();
+
return &str_value;
}
-my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
+my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed);
Item *it= this_item();
@@ -884,73 +885,108 @@ my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
}
-bool Item_splocal::is_null()
+bool Item_sp_variable::is_null()
{
- Item *it= this_item();
- return it->is_null();
+ return this_item()->is_null();
+}
+
+
+/*****************************************************************************
+ Item_splocal methods
+*****************************************************************************/
+
+Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
+ uint sp_var_idx,
+ enum_field_types sp_var_type,
+ uint pos_in_q)
+ :Item_sp_variable(sp_var_name.str, sp_var_name.length),
+ m_var_idx(sp_var_idx), pos_in_query(pos_in_q)
+{
+ maybe_null= TRUE;
+
+ m_type= sp_map_item_type(sp_var_type);
+ m_result_type= sp_map_result_type(sp_var_type);
}
Item *
Item_splocal::this_item()
{
- DBUG_ASSERT(owner == thd->spcont->owner);
- return thd->spcont->get_item(m_offset);
+ DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+ return m_thd->spcont->get_item(m_var_idx);
+}
+
+const Item *
+Item_splocal::this_item() const
+{
+ DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+ return m_thd->spcont->get_item(m_var_idx);
}
Item **
-Item_splocal::this_item_addr(THD *thd, Item **addr)
+Item_splocal::this_item_addr(THD *thd, Item **)
{
- DBUG_ASSERT(owner == thd->spcont->owner);
- return thd->spcont->get_item_addr(m_offset);
+ DBUG_ASSERT(m_sp == thd->spcont->sp);
+
+ return thd->spcont->get_item_addr(m_var_idx);
}
-Item *
-Item_splocal::this_const_item() const
+
+void Item_splocal::print(String *str)
{
- DBUG_ASSERT(owner == thd->spcont->owner);
- return thd->spcont->get_item(m_offset);
+ str->reserve(m_name.length+8);
+ str->append(m_name.str, m_name.length);
+ str->append('@');
+ str->qs_append(m_var_idx);
}
-Item::Type
-Item_splocal::type() const
+
+/*****************************************************************************
+ Item_case_expr methods
+*****************************************************************************/
+
+Item_case_expr::Item_case_expr(int case_expr_id)
+ :Item_sp_variable((char *) STRING_WITH_LEN("case_expr")),
+ m_case_expr_id(case_expr_id)
{
- if (thd && thd->spcont)
- {
- DBUG_ASSERT(owner == thd->spcont->owner);
- return thd->spcont->get_item(m_offset)->type();
- }
- return NULL_ITEM; // Anything but SUBSELECT_ITEM
}
-bool Item_splocal::fix_fields(THD *thd_arg, Item **ref)
+Item *
+Item_case_expr::this_item()
{
- Item *it;
- thd= thd_arg; // Must be set before this_item()
- it= this_item();
- DBUG_ASSERT(it->fixed);
- max_length= it->max_length;
- decimals= it->decimals;
- unsigned_flag= it->unsigned_flag;
- fixed= 1;
- return FALSE;
+ DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+ return m_thd->spcont->get_case_expr(m_case_expr_id);
}
-void Item_splocal::cleanup()
+
+const Item *
+Item_case_expr::this_item() const
{
- fixed= 0;
+ DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+ return m_thd->spcont->get_case_expr(m_case_expr_id);
}
-void Item_splocal::print(String *str)
+Item **
+Item_case_expr::this_item_addr(THD *thd, Item **)
{
- str->reserve(m_name.length+8);
- str->append(m_name.str, m_name.length);
- str->append('@');
- str->qs_append(m_offset);
+ DBUG_ASSERT(m_sp == thd->spcont->sp);
+
+ return thd->spcont->get_case_expr_addr(m_case_expr_id);
+}
+
+
+void Item_case_expr::print(String *str)
+{
+ str->append(STRING_WITH_LEN("case_expr@"));
+ str->qs_append(m_case_expr_id);
}
@@ -1029,12 +1065,6 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
}
-void Item_name_const::cleanup()
-{
- fixed= 0;
-}
-
-
void Item_name_const::print(String *str)
{
str->append(STRING_WITH_LEN("NAME_CONST("));
@@ -1054,6 +1084,7 @@ void Item_name_const::print(String *str)
ref_pointer_array Pointer to array of reference fields
fields All fields in select
ref Pointer to item
+ skip_registered <=> function be must skipped for registered SUM items
NOTES
This is from split_sum_func2() for items that should be split
@@ -1066,8 +1097,13 @@ void Item_name_const::print(String *str)
void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
- List<Item> &fields, Item **ref)
+ List<Item> &fields, Item **ref,
+ bool skip_registered)
{
+ /* An item of type Item_sum is registered <=> ref_by != 0 */
+ if (type() == SUM_FUNC_ITEM && skip_registered &&
+ ((Item_sum *) this)->ref_by)
+ return;
if (type() != SUM_FUNC_ITEM && with_sum_func)
{
/* Will split complicated items and ignore simple ones */
@@ -2104,6 +2140,8 @@ Item_param::Item_param(unsigned pos_in_query_arg) :
value is set.
*/
maybe_null= 1;
+ cnvitem= new Item_string("", 0, &my_charset_bin, DERIVATION_COERCIBLE);
+ cnvstr.set(cnvbuf, sizeof(cnvbuf), &my_charset_bin);
}
@@ -2473,7 +2511,7 @@ longlong Item_param::val_int()
{
switch (state) {
case REAL_VALUE:
- return (longlong) (value.real + (value.real > 0 ? 0.5 : -0.5));
+ return (longlong) rint(value.real);
case INT_VALUE:
return value.integer;
case DECIMAL_VALUE:
@@ -3199,14 +3237,8 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
{
for each outer query Q_k beginning from the inner-most one
{
- if - Q_k is not a group query AND
- - Q_k is not inside an aggregate function
- OR
- - Q_(k-1) is not in a HAVING or SELECT clause of Q_k
- {
- search for a column or derived column named col_ref_i
- [in table T_j] in the FROM clause of Q_k;
- }
+ search for a column or derived column named col_ref_i
+ [in table T_j] in the FROM clause of Q_k;
if such a column is not found
Search for a column or derived column named col_ref_i
@@ -3285,18 +3317,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
place= prev_subselect_item->parsing_place;
/*
- Check table fields only if the subquery is used somewhere out of
- HAVING, or the outer SELECT does not use grouping (i.e. tables are
- accessible).
-
In case of a view, find_field_in_tables() writes the pointer to
the found view field into '*reference', in other words, it
substitutes this Item_field with the found expression.
*/
- if ((place != IN_HAVING ||
- (!select->with_sum_func &&
- select->group_list.elements == 0)) &&
- (from_field= find_field_in_tables(thd, this,
+ if ((from_field= find_field_in_tables(thd, this,
outer_context->
first_name_resolution_table,
outer_context->
@@ -3312,6 +3337,21 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
{
prev_subselect_item->used_tables_cache|= from_field->table->map;
prev_subselect_item->const_item_cache= 0;
+ if (thd->lex->in_sum_func &&
+ thd->lex->in_sum_func->nest_level ==
+ thd->lex->current_select->nest_level)
+ {
+ Item::Type type= (*reference)->type();
+ set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+ select->nest_level);
+ set_field(from_field);
+ fixed= 1;
+ mark_as_dependent(thd, last_checked_context->select_lex,
+ context->select_lex, this,
+ ((type == REF_ITEM || type == FIELD_ITEM) ?
+ (Item_ident*) (*reference) : 0));
+ return FALSE;
+ }
}
else
{
@@ -3463,6 +3503,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
return FALSE;
set_field(from_field);
+ if (thd->lex->in_sum_func &&
+ thd->lex->in_sum_func->nest_level ==
+ thd->lex->current_select->nest_level)
+ set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+ thd->lex->current_select->nest_level);
}
else if (thd->set_query_id && field->query_id != thd->query_id)
{
@@ -3925,6 +3970,9 @@ int Item::save_in_field(Field *field, bool no_conversions)
str_value.set_quick(0, 0, cs);
return set_field_to_null_with_conversions(field, no_conversions);
}
+
+ /* NOTE: If null_value == FALSE, "result" must be not NULL. */
+
field->set_notnull();
error=field->store(result->ptr(),result->length(),cs);
str_value.set_quick(0, 0, cs);
@@ -4618,9 +4666,8 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
aggregate function.
*/
if (((*ref)->with_sum_func && name &&
- (depended_from ||
- !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
- current_sel->having_fix_field))) ||
+ !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
+ current_sel->having_fix_field)) ||
!(*ref)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0),
@@ -5119,10 +5166,17 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
Item_ref *ref= (Item_ref *)arg;
if (ref->ref[0]->type() != FIELD_ITEM)
{
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), "", "VALUES() function");
return TRUE;
}
arg= ref->ref[0];
}
+ /*
+ According to our SQL grammar, VALUES() function can reference
+ only to a column.
+ */
+ DBUG_ASSERT(arg->type() == FIELD_ITEM);
+
Item_field *field_arg= (Item_field *)arg;
if (field_arg->field->table->insert_values)
@@ -5185,7 +5239,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
set field_idx properly.
*/
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
- 0, 0, &field_idx, 0);
+ 0, &field_idx);
thd->set_query_id= save_set_query_id;
triggers= table->triggers;
}
@@ -5266,7 +5320,7 @@ Item_result item_cmp_type(Item_result a,Item_result b)
void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
{
Item *item= *ref;
- Item *new_item;
+ Item *new_item= NULL;
if (item->basic_const_item())
return; // Can't be better
Item_result res_type=item_cmp_type(comp_item->result_type(),
@@ -5299,7 +5353,16 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
break;
}
case ROW_RESULT:
+ if (item->type() == Item::ROW_ITEM && comp_item->type() == Item::ROW_ITEM)
{
+ /*
+ Substitute constants only in Item_rows. Don't affect other Items
+ with ROW_RESULT (eg Item_singlerow_subselect).
+
+ For such Items more optimal is to detect if it is constant and replace
+ it with Item_row. This would optimize queries like this:
+ SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1);
+ */
Item_row *item_row= (Item_row*) item;
Item_row *comp_item_row= (Item_row*) comp_item;
uint col;
@@ -5317,6 +5380,7 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col));
break;
}
+ /* Fallthrough */
case REAL_RESULT:
{ // It must REAL_RESULT
double result= item->val_real();
@@ -5451,7 +5515,7 @@ 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));
+ return (longlong) rint(value);
}
@@ -5822,8 +5886,11 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
{
int delta1= max_length_orig - decimals_orig;
int delta2= item->max_length - item->decimals;
- max_length= min(max(delta1, delta2) + decimals,
- (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7);
+ if (fld_type == MYSQL_TYPE_DECIMAL)
+ max_length= max(delta1, delta2) + decimals;
+ else
+ max_length= min(max(delta1, delta2) + decimals,
+ (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7);
}
else
max_length= (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7;
diff --git a/sql/item.h b/sql/item.h
index c64e6586d5f..eee9bc5b284 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -159,7 +159,7 @@ struct Hybrid_type_traits
{ val->real/= ulonglong2double(u); }
virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
- { return (longlong) val->real; }
+ { return (longlong) rint(val->real); }
virtual double val_real(Hybrid_type *val) const { return val->real; }
virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const;
virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
@@ -326,6 +326,48 @@ struct Name_resolution_context: Sql_alloc
};
+/*
+ Store and restore the current state of a name resolution context.
+*/
+
+class Name_resolution_context_state
+{
+private:
+ TABLE_LIST *save_table_list;
+ TABLE_LIST *save_first_name_resolution_table;
+ TABLE_LIST *save_next_name_resolution_table;
+ bool save_resolve_in_select_list;
+
+public:
+ TABLE_LIST *save_next_local;
+
+public:
+ /* Save the state of a name resolution context. */
+ void save_state(Name_resolution_context *context, TABLE_LIST *table_list)
+ {
+ save_table_list= context->table_list;
+ save_first_name_resolution_table= context->first_name_resolution_table;
+ save_next_name_resolution_table= (context->first_name_resolution_table) ?
+ context->first_name_resolution_table->
+ next_name_resolution_table :
+ NULL;
+ save_resolve_in_select_list= context->resolve_in_select_list;
+ save_next_local= table_list->next_local;
+ }
+
+ /* Restore a name resolution context from saved state. */
+ void restore_state(Name_resolution_context *context, TABLE_LIST *table_list)
+ {
+ table_list->next_local= save_next_local;
+ context->table_list= save_table_list;
+ context->first_name_resolution_table= save_first_name_resolution_table;
+ if (context->first_name_resolution_table)
+ context->first_name_resolution_table->
+ next_name_resolution_table= save_next_name_resolution_table;
+ context->resolve_in_select_list= save_resolve_in_select_list;
+ }
+};
+
/*************************************************************************/
typedef bool (Item::*Item_processor)(byte *arg);
@@ -341,8 +383,6 @@ public:
{ return (void*) sql_alloc((uint) size); }
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
- /* Special for SP local variable assignment - reusing slots */
- static void *operator new(size_t size, Item *reuse, uint *rsize);
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
@@ -600,7 +640,7 @@ public:
List<Item> &fields) {}
/* Called for items that really have to be split */
void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields,
- Item **ref);
+ Item **ref, bool skip_registered);
virtual bool get_date(TIME *ltime,uint fuzzydate);
virtual bool get_time(TIME *ltime);
virtual bool get_date_result(TIME *ltime,uint fuzzydate)
@@ -671,13 +711,13 @@ public:
current value and pointer to current Item otherwise.
*/
virtual Item *this_item() { return this; }
+ virtual const Item *this_item() const { return this; }
+
/*
For SP local variable returns address of pointer to Item representing its
current value and pointer passed via parameter otherwise.
*/
virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
- /* For SPs mostly. */
- virtual Item *this_const_item() const { return const_cast<Item*>(this); }
// Row emulation
virtual uint cols() { return 1; }
@@ -706,21 +746,32 @@ public:
class sp_head;
-/*
- A reference to local SP variable (incl. reference to SP parameter), used in
- runtime.
-
- NOTE
- This item has a "value" item, defined as
- this_item() = thd->spcont->get_item(m_offset)
- and it delegates everything to that item (if !this_item() then this item
- poses as Item_null) except for name, which is the name of SP local
- variable.
-*/
-class Item_splocal : public Item
+/*****************************************************************************
+ The class is a base class for representation of stored routine variables in
+ the Item-hierarchy. There are the following kinds of SP-vars:
+ - local variables (Item_splocal);
+ - CASE expression (Item_case_expr);
+*****************************************************************************/
+
+class Item_sp_variable :public Item
{
- uint m_offset;
+protected:
+ /*
+ THD, which is stored in fix_fields() and is used in this_item() to avoid
+ current_thd use.
+ */
+ THD *m_thd;
+
+public:
+ LEX_STRING m_name;
+
+ /*
+ Buffer, pointing to the string value of the item. We need it to
+ protect internal buffer from changes. See comment to analogous
+ member in Item_param for more details.
+ */
+ String str_value_ptr;
public:
#ifndef DBUG_OFF
@@ -728,11 +779,74 @@ public:
Routine to which this Item_splocal belongs. Used for checking if correct
runtime context is used for variable handling.
*/
- sp_head *owner;
+ sp_head *m_sp;
#endif
- LEX_STRING m_name;
- THD *thd;
+public:
+ Item_sp_variable(char *sp_var_name_str, uint sp_var_name_length);
+
+public:
+ bool fix_fields(THD *thd, Item **);
+
+ double val_real();
+ longlong val_int();
+ String *val_str(String *sp);
+ my_decimal *val_decimal(my_decimal *decimal_value);
+ bool is_null();
+
+public:
+ inline void make_field(Send_field *field);
+
+ inline bool const_item() const;
+
+ inline int save_in_field(Field *field, bool no_conversions);
+ inline bool send(Protocol *protocol, String *str);
+};
+
+/*****************************************************************************
+ Item_sp_variable inline implementation.
+*****************************************************************************/
+
+inline void Item_sp_variable::make_field(Send_field *field)
+{
+ Item *it= this_item();
+
+ if (name)
+ it->set_name(name, (uint) strlen(name), system_charset_info);
+ else
+ it->set_name(m_name.str, m_name.length, system_charset_info);
+ it->make_field(field);
+}
+
+inline bool Item_sp_variable::const_item() const
+{
+ return TRUE;
+}
+
+inline int Item_sp_variable::save_in_field(Field *field, bool no_conversions)
+{
+ return this_item()->save_in_field(field, no_conversions);
+}
+
+inline bool Item_sp_variable::send(Protocol *protocol, String *str)
+{
+ return this_item()->send(protocol, str);
+}
+
+
+/*****************************************************************************
+ A reference to local SP variable (incl. reference to SP parameter), used in
+ runtime.
+*****************************************************************************/
+
+class Item_splocal :public Item_sp_variable
+{
+ uint m_var_idx;
+
+ Type m_type;
+ Item_result m_result_type;
+
+public:
/*
Position of this reference to SP variable in the statement (the
statement itself is in sp_instr_stmt::m_query).
@@ -745,78 +859,94 @@ public:
*/
uint pos_in_query;
- Item_splocal(LEX_STRING name, uint offset, uint pos_in_q=0)
- : m_offset(offset), m_name(name), thd(0), pos_in_query(pos_in_q)
- {
- maybe_null= TRUE;
- }
-
- /* For error printing */
- inline LEX_STRING *my_name(LEX_STRING *get_name)
- {
- if (!get_name)
- return &m_name;
- (*get_name)= m_name;
- return get_name;
- }
+ Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx,
+ enum_field_types sp_var_type, uint pos_in_q= 0);
bool is_splocal() { return 1; } /* Needed for error checking */
Item *this_item();
+ const Item *this_item() const;
Item **this_item_addr(THD *thd, Item **);
- Item *this_const_item() const;
- bool fix_fields(THD *, Item **);
- void cleanup();
+ void print(String *str);
- inline uint get_offset()
- {
- return m_offset;
- }
+public:
+ inline const LEX_STRING *my_name() const;
- // Abstract methods inherited from Item. Just defer the call to
- // the item in the frame
- enum Type type() const;
+ inline uint get_var_idx() const;
- double val_real();
- longlong val_int();
- String *val_str(String *sp);
- my_decimal *val_decimal(my_decimal *);
- bool is_null();
- void print(String *str);
+ inline enum Type type() const;
+ inline Item_result result_type() const;
+};
- void make_field(Send_field *field)
- {
- Item *it= this_item();
+/*****************************************************************************
+ Item_splocal inline implementation.
+*****************************************************************************/
- if (name)
- it->set_name(name, (uint) strlen(name), system_charset_info);
- else
- it->set_name(m_name.str, m_name.length, system_charset_info);
- it->make_field(field);
- }
+inline const LEX_STRING *Item_splocal::my_name() const
+{
+ return &m_name;
+}
- Item_result result_type() const
- {
- return this_const_item()->result_type();
- }
+inline uint Item_splocal::get_var_idx() const
+{
+ return m_var_idx;
+}
- bool const_item() const
- {
- return TRUE;
- }
+inline enum Item::Type Item_splocal::type() const
+{
+ return m_type;
+}
- int save_in_field(Field *field, bool no_conversions)
- {
- return this_item()->save_in_field(field, no_conversions);
- }
+inline Item_result Item_splocal::result_type() const
+{
+ return m_result_type;
+}
- bool send(Protocol *protocol, String *str)
- {
- return this_item()->send(protocol, str);
- }
+
+/*****************************************************************************
+ A reference to case expression in SP, used in runtime.
+*****************************************************************************/
+
+class Item_case_expr :public Item_sp_variable
+{
+public:
+ Item_case_expr(int case_expr_id);
+
+public:
+ Item *this_item();
+ const Item *this_item() const;
+ Item **this_item_addr(THD *thd, Item **);
+
+ inline enum Type type() const;
+ inline Item_result result_type() const;
+
+public:
+ /*
+ NOTE: print() is intended to be used from views and for debug.
+ Item_case_expr can not occur in views, so here it is only for debug
+ purposes.
+ */
+ void print(String *str);
+
+private:
+ int m_case_expr_id;
};
+/*****************************************************************************
+ Item_case_expr inline implementation.
+*****************************************************************************/
+
+inline enum Item::Type Item_case_expr::type() const
+{
+ return this_item()->type();
+}
+
+inline Item_result Item_case_expr::result_type() const
+{
+ return this_item()->result_type();
+}
+
/*
NAME_CONST(given_name, const_value).
@@ -843,7 +973,6 @@ public:
}
bool fix_fields(THD *, Item **);
- void cleanup();
enum Type type() const;
double val_real();
@@ -1084,7 +1213,11 @@ public:
class Item_param :public Item
{
+ char cnvbuf[MAX_FIELD_WIDTH];
+ String cnvstr;
+ Item *cnvitem;
public:
+
enum enum_item_param_state
{
NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
@@ -1350,7 +1483,7 @@ public:
{
return LONGLONG_MAX;
}
- return (longlong) (value+(value > 0 ? 0.5 : -0.5));
+ return (longlong) rint(value);
}
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
@@ -1919,6 +2052,16 @@ public:
}
};
+/*
+ Item_insert_value -- an implementation of VALUES() function.
+ You can use the VALUES(col_name) function in the UPDATE clause
+ to refer to column values from the INSERT portion of the INSERT
+ ... UPDATE statement. In other words, VALUES(col_name) in the
+ UPDATE clause refers to the value of col_name that would be
+ inserted, had no duplicate-key conflict occurred.
+ In all other places this function returns NULL.
+*/
+
class Item_insert_value : public Item_field
{
public:
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 2a7754c0217..15614a32c39 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -25,6 +25,8 @@
#include <m_ctype.h>
#include "sql_select.h"
+static bool convert_constant_item(THD *thd, Field *field, Item **item);
+
static Item_result item_store_type(Item_result a,Item_result b)
{
if (a == STRING_RESULT || b == STRING_RESULT)
@@ -45,14 +47,37 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
type[0]= item_store_type(type[0], items[i]->result_type());
}
-static void agg_cmp_type(Item_result *type, Item **items, uint nitems)
+
+static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
{
uint i;
+ Field *field= NULL;
+ bool all_constant= TRUE;
+
+ /* If the first argument is a FIELD_ITEM, pull out the field. */
+ if (items[0]->type() == Item::FIELD_ITEM)
+ field=((Item_field *)items[0])->field;
+ /* But if it can't be compared as a longlong, we don't really care. */
+ if (field && !field->can_be_compared_as_longlong())
+ field= NULL;
+
type[0]= items[0]->result_type();
- for (i=1 ; i < nitems ; i++)
+ for (i= 1; i < nitems; i++)
+ {
type[0]= item_cmp_type(type[0], items[i]->result_type());
+ if (field && !convert_constant_item(thd, field, &items[i]))
+ all_constant= FALSE;
+ }
+
+ /*
+ If we had a field that can be compared as a longlong, and all constant
+ items, then the aggregate result will be an INT_RESULT.
+ */
+ if (field && all_constant)
+ type[0]= INT_RESULT;
}
+
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
{
@@ -1051,32 +1076,11 @@ void Item_func_between::fix_length_and_dec()
*/
if (!args[0] || !args[1] || !args[2])
return;
- agg_cmp_type(&cmp_type, args, 3);
+ agg_cmp_type(thd, &cmp_type, args, 3);
+
if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV))
return;
-
- /*
- 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
- */
- if (args[0]->type() == FIELD_ITEM)
- {
- Field *field=((Item_field*) args[0])->field;
- if (!thd->is_context_analysis_only() &&
- field->can_be_compared_as_longlong())
- {
- /*
- The following can't be recoded with || as convert_constant_item
- changes the argument
- */
- if (convert_constant_item(thd, field,&args[1]))
- cmp_type=INT_RESULT; // Works for all types.
- if (convert_constant_item(thd, field,&args[2]))
- cmp_type=INT_RESULT; // Works for all types.
- }
- }
}
@@ -1722,6 +1726,7 @@ void Item_func_case::fix_length_and_dec()
{
Item **agg;
uint nagg;
+ THD *thd= current_thd;
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return;
@@ -1753,7 +1758,7 @@ void Item_func_case::fix_length_and_dec()
for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2];
nagg++;
- agg_cmp_type(&cmp_type, agg, nagg);
+ agg_cmp_type(thd, &cmp_type, agg, nagg);
if ((cmp_type == STRING_RESULT) &&
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV))
return;
@@ -2346,7 +2351,7 @@ void Item_func_in::fix_length_and_dec()
uint const_itm= 1;
THD *thd= current_thd;
- agg_cmp_type(&cmp_type, args, arg_count);
+ agg_cmp_type(thd, &cmp_type, args, arg_count);
if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV))
@@ -2671,7 +2676,7 @@ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
List_iterator<Item> li(list);
Item *item;
while ((item= li++))
- item->split_sum_func2(thd, ref_pointer_array, fields, li.ref());
+ item->split_sum_func2(thd, ref_pointer_array, fields, li.ref(), TRUE);
}
@@ -3662,7 +3667,7 @@ void Item_equal::merge(Item_equal *item)
the multiple equality already contains a constant and its
value is not equal to the value of c.
*/
- add(const_item);
+ add(c);
}
cond_false|= item->cond_false;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index bfd32223d4c..b4064fb45b8 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -723,9 +723,9 @@ public:
{
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 */
- return sortcmp(value_res, res, cmp_charset);
+ res= arg->val_str(&tmp);
+ return (value_res ? (res ? sortcmp(value_res, res, cmp_charset) : 1) :
+ (res ? -1 : 0));
}
int compare(cmp_item *c)
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index ef3ebde74e5..272e77a4318 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -280,7 +280,7 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
{
Item **arg, **arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++)
- (*arg)->split_sum_func2(thd, ref_pointer_array, fields, arg);
+ (*arg)->split_sum_func2(thd, ref_pointer_array, fields, arg, TRUE);
}
@@ -735,7 +735,7 @@ longlong Item_func_numhybrid::val_int()
case INT_RESULT:
return int_op();
case REAL_RESULT:
- return (longlong)real_op();
+ return (longlong) rint(real_op());
case STRING_RESULT:
{
int err_not_used;
@@ -4716,7 +4716,7 @@ Item_func_sp::sp_result_field(void) const
share->table_cache_key = empty_name;
share->table_name = empty_name;
}
- field= m_sp->make_field(max_length, name, dummy_table);
+ field= m_sp->create_result_field(max_length, name, dummy_table);
DBUG_RETURN(field);
}
@@ -4729,17 +4729,17 @@ Item_func_sp::sp_result_field(void) const
1 value = NULL or error
*/
-int
+bool
Item_func_sp::execute(Field **flp)
{
- Item *it;
+ THD *thd= current_thd;
Field *f;
- if (execute(&it))
- {
- null_value= 1;
- context->process_error(current_thd);
- return 1;
- }
+
+ /*
+ Get field in virtual tmp table to store result. Create the field if
+ invoked first time.
+ */
+
if (!(f= *flp))
{
*flp= f= sp_result_field();
@@ -4748,20 +4748,33 @@ Item_func_sp::execute(Field **flp)
f->null_ptr= (uchar *)&null_value;
f->null_bit= 1;
}
- it->save_in_field(f, 1);
- return null_value= f->is_null();
+
+ /* Execute function and store the return value in the field. */
+
+ if (execute_impl(thd, f))
+ {
+ null_value= 1;
+ context->process_error(thd);
+ return TRUE;
+ }
+
+ /* Check that the field (the value) is not NULL. */
+
+ null_value= f->is_null();
+
+ return null_value;
}
-int
-Item_func_sp::execute(Item **itp)
+bool
+Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
{
- DBUG_ENTER("Item_func_sp::execute");
- THD *thd= current_thd;
- int res= -1;
+ bool err_status= TRUE;
Sub_statement_state statement_state;
Security_context *save_security_ctx= thd->security_ctx, *save_ctx_func;
+ DBUG_ENTER("Item_func_sp::execute_impl");
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (context->security_ctx)
{
@@ -4778,7 +4791,7 @@ Item_func_sp::execute(Item **itp)
function call into binlog.
*/
thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
- res= m_sp->execute_function(thd, args, arg_count, itp);
+ err_status= m_sp->execute_function(thd, args, arg_count, return_value_fld);
thd->restore_sub_statement_state(&statement_state);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -4788,7 +4801,7 @@ error:
#else
error:
#endif
- DBUG_RETURN(res);
+ DBUG_RETURN(err_status);
}
@@ -4884,7 +4897,7 @@ Item_func_sp::tmp_table_field(TABLE *t_arg)
DBUG_ENTER("Item_func_sp::tmp_table_field");
if (m_sp)
- res= m_sp->make_field(max_length, (const char *)name, t_arg);
+ res= m_sp->create_result_field(max_length, (const char*) name, t_arg);
if (!res)
res= Item_func::tmp_table_field(t_arg);
diff --git a/sql/item_func.h b/sql/item_func.h
index ed39cb86d3e..d81eb5f6ebf 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -199,7 +199,7 @@ public:
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *decimal_value);
longlong val_int()
- { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); }
+ { DBUG_ASSERT(fixed == 1); return (longlong) rint(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); }
@@ -943,7 +943,7 @@ class Item_func_udf_float :public Item_udf_func
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
- return (longlong) Item_func_udf_float::val_real();
+ return (longlong) rint(Item_func_udf_float::val_real());
}
my_decimal *val_decimal(my_decimal *dec_buf)
{
@@ -1374,8 +1374,8 @@ private:
Field *result_field;
char result_buf[64];
- int execute(Item **itp);
- int execute(Field **flp);
+ bool execute(Field **flp);
+ bool execute_impl(THD *thd, Field *return_value_fld);
Field *sp_result_field(void) const;
public:
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 9362518e6ef..75c3f8a2922 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -90,7 +90,7 @@ void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array,
{
Item **arg, **arg_end;
for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
- (*arg)->split_sum_func2(thd, ref_pointer_array, fields, arg);
+ (*arg)->split_sum_func2(thd, ref_pointer_array, fields, arg, TRUE);
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index a8c51bb6662..8056e00e0cf 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -48,6 +48,38 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
}
+String *Item_str_func::check_well_formed_result(String *str)
+{
+ /* Check whether we got a well-formed string */
+ CHARSET_INFO *cs= str->charset();
+ int well_formed_error;
+ uint wlen= cs->cset->well_formed_len(cs,
+ str->ptr(), str->ptr() + str->length(),
+ str->length(), &well_formed_error);
+ if (wlen < str->length())
+ {
+ THD *thd= current_thd;
+ char hexbuf[7];
+ enum MYSQL_ERROR::enum_warning_level level;
+ uint diff= str->length() - wlen;
+ set_if_smaller(diff, 3);
+ octet2hex(hexbuf, str->ptr() + wlen, diff);
+ if (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ null_value= 1;
+ str= 0;
+ }
+ else
+ level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
+ ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
+ }
+ return str;
+}
+
+
double Item_str_func::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -1864,7 +1896,7 @@ String *Item_func_elt::val_str(String *str)
void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields)
{
- item->split_sum_func2(thd, ref_pointer_array, fields, &item);
+ item->split_sum_func2(thd, ref_pointer_array, fields, &item, TRUE);
Item_str_func::split_sum_func(thd, ref_pointer_array, fields);
}
@@ -1984,34 +2016,7 @@ String *Item_func_char::val_str(String *str)
}
str->set_charset(collation.collation);
str->realloc(str->length()); // Add end 0 (for Purify)
-
- /* Check whether we got a well-formed string */
- CHARSET_INFO *cs= collation.collation;
- int well_formed_error;
- uint wlen= cs->cset->well_formed_len(cs,
- str->ptr(), str->ptr() + str->length(),
- str->length(), &well_formed_error);
- if (wlen < str->length())
- {
- THD *thd= current_thd;
- char hexbuf[7];
- enum MYSQL_ERROR::enum_warning_level level;
- uint diff= str->length() - wlen;
- set_if_smaller(diff, 3);
- octet2hex(hexbuf, str->ptr() + wlen, diff);
- if (thd->variables.sql_mode &
- (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
- {
- level= MYSQL_ERROR::WARN_LEVEL_ERROR;
- null_value= 1;
- str= 0;
- }
- else
- level= MYSQL_ERROR::WARN_LEVEL_WARN;
- push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
- ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
- }
- return str;
+ return check_well_formed_result(str);
}
@@ -2311,6 +2316,8 @@ String *Item_func_conv::val_str(String *str)
String *Item_func_conv_charset::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
+ if (use_cached_value)
+ return null_value ? 0 : &str_value;
String *arg= args[0]->val_str(str);
uint dummy_errors;
if (!arg)
@@ -2320,7 +2327,7 @@ String *Item_func_conv_charset::val_str(String *str)
}
null_value= str_value.copy(arg->ptr(),arg->length(),arg->charset(),
conv_charset, &dummy_errors);
- return null_value ? 0 : &str_value;
+ return null_value ? 0 : check_well_formed_result(&str_value);
}
void Item_func_conv_charset::fix_length_and_dec()
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 81f809d2b67..50ec0b36ce8 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -35,6 +35,7 @@ public:
double val_real();
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
+ String *check_well_formed_result(String *str);
};
class Item_func_md5 :public Item_str_func
@@ -651,10 +652,40 @@ public:
class Item_func_conv_charset :public Item_str_func
{
+ bool use_cached_value;
public:
+ bool safe;
CHARSET_INFO *conv_charset; // keep it public
- Item_func_conv_charset(Item *a, CHARSET_INFO *cs) :Item_str_func(a)
- { conv_charset=cs; }
+ Item_func_conv_charset(Item *a, CHARSET_INFO *cs) :Item_str_func(a)
+ { conv_charset= cs; use_cached_value= 0; safe= 0; }
+ Item_func_conv_charset(Item *a, CHARSET_INFO *cs, bool cache_if_const)
+ :Item_str_func(a)
+ {
+ DBUG_ASSERT(args[0]->fixed);
+ conv_charset= cs;
+ if (cache_if_const && args[0]->const_item())
+ {
+ uint errors= 0;
+ String tmp, *str= args[0]->val_str(&tmp);
+ if (!str || str_value.copy(str->ptr(), str->length(),
+ str->charset(), conv_charset, &errors))
+ null_value= 1;
+ use_cached_value= 1;
+ safe= (errors == 0);
+ }
+ else
+ {
+ use_cached_value= 0;
+ /*
+ Conversion from and to "binary" is safe.
+ Conversion to Unicode is safe.
+ Other kind of conversions are potentially lossy.
+ */
+ safe= (args[0]->collation.collation == &my_charset_bin ||
+ cs == &my_charset_bin ||
+ (cs->state & MY_CS_UNICODE));
+ }
+ }
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "convert"; }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f2d6f2b5899..88620634354 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -803,6 +803,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
!(select_lex->next_select()))
{
Item_sum_hybrid *item;
+ nesting_map save_allow_sum_func;
if (func->l_op())
{
/*
@@ -828,6 +829,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
it.replace(item);
}
+ save_allow_sum_func= thd->lex->allow_sum_func;
+ thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
/*
Item_sum_(max|min) can't substitute other item => we can use 0 as
reference, also Item_sum_(max|min) can't be fixed after creation, so
@@ -835,6 +838,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*/
if (item->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR);
+ thd->lex->allow_sum_func= save_allow_sum_func;
/* we added aggregate function => we have to change statistic */
count_field_types(&join->tmp_table_param, join->all_fields, 0);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 506d2a16108..a3a25ec8d6f 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -24,6 +24,234 @@
#include "mysql_priv.h"
#include "sql_select.h"
+/*
+ Prepare an aggregate function item for checking context conditions
+
+ SYNOPSIS
+ init_sum_func_check()
+ thd reference to the thread context info
+
+ DESCRIPTION
+ The function initializes the members of the Item_sum object created
+ for a set function that are used to check validity of the set function
+ occurrence.
+ If the set function is not allowed in any subquery where it occurs
+ an error is reported immediately.
+
+ NOTES
+ This function is to be called for any item created for a set function
+ object when the traversal of trees built for expressions used in the query
+ is performed at the phase of context analysis. This function is to
+ be invoked at the descent of this traversal.
+
+ RETURN
+ TRUE if an error is reported
+ FALSE otherwise
+*/
+
+bool Item_sum::init_sum_func_check(THD *thd)
+{
+ if (!thd->lex->allow_sum_func)
+ {
+ my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
+ MYF(0));
+ return TRUE;
+ }
+ /* Set a reference to the nesting set function if there is any */
+ in_sum_func= thd->lex->in_sum_func;
+ /* Save a pointer to object to be used in items for nested set functions */
+ thd->lex->in_sum_func= this;
+ nest_level= thd->lex->current_select->nest_level;
+ ref_by= 0;
+ aggr_level= -1;
+ max_arg_level= -1;
+ max_sum_func_level= -1;
+ return FALSE;
+}
+
+/*
+ Check constraints imposed on a usage of a set function
+
+ SYNOPSIS
+ check_sum_func()
+ thd reference to the thread context info
+ ref location of the pointer to this item in the embedding expression
+
+ DESCRIPTION
+ The method verifies whether context conditions imposed on a usage
+ of any set function are met for this occurrence.
+ It checks whether the set function occurs in the position where it
+ can be aggregated and, when it happens to occur in argument of another
+ set function, the method checks that these two functions are aggregated in
+ different subqueries.
+ If the context conditions are not met the method reports an error.
+ If the set function is aggregated in some outer subquery the method
+ adds it to the chain of items for such set functions that is attached
+ to the the st_select_lex structure for this subquery.
+
+ NOTES
+ This function is to be called for any item created for a set function
+ object when the traversal of trees built for expressions used in the query
+ is performed at the phase of context analysis. This function is to
+ be invoked at the ascent of this traversal.
+
+ IMPLEMENTATION
+ A number of designated members of the object are used to check the
+ conditions. They are specified in the comment before the Item_sum
+ class declaration.
+ Additionally a bitmap variable called allow_sum_func is employed.
+ It is included into the thd->lex structure.
+ The bitmap contains 1 at n-th position if the set function happens
+ to occur under a construct of the n-th level subquery where usage
+ of set functions are allowed (i.e either in the SELECT list or
+ in the HAVING clause of the corresponding subquery)
+ Consider the query:
+ SELECT SUM(t1.b) FROM t1 GROUP BY t1.a
+ HAVING t1.a IN (SELECT t2.c FROM t2 WHERE AVG(t1.b) > 20) AND
+ t1.a > (SELECT MIN(t2.d) FROM t2);
+ allow_sum_func will contain:
+ for SUM(t1.b) - 1 at the first position
+ for AVG(t1.b) - 1 at the first position, 0 at the second position
+ for MIN(t2.d) - 1 at the first position, 1 at the second position.
+
+ RETURN
+ TRUE if an error is reported
+ FALSE otherwise
+*/
+
+bool Item_sum::check_sum_func(THD *thd, Item **ref)
+{
+ bool invalid= FALSE;
+ nesting_map allow_sum_func= thd->lex->allow_sum_func;
+ /*
+ The value of max_arg_level is updated if an argument of the set function
+ contains a column reference resolved against a subquery whose level is
+ greater than the current value of max_arg_level.
+ max_arg_level cannot be greater than nest level.
+ nest level is always >= 0
+ */
+ if (nest_level == max_arg_level)
+ {
+ /*
+ The function must be aggregated in the current subquery,
+ If it is there under a construct where it is not allowed
+ we report an error.
+ */
+ invalid= !(allow_sum_func & (1 << max_arg_level));
+ }
+ else if (max_arg_level >= 0 || !(allow_sum_func & (1 << nest_level)))
+ {
+ /*
+ The set function can be aggregated only in outer subqueries.
+ Try to find a subquery where it can be aggregated;
+ If we fail to find such a subquery report an error.
+ */
+ if (register_sum_func(thd, ref))
+ return TRUE;
+ invalid= aggr_level < 0 && !(allow_sum_func & (1 << nest_level));
+ }
+ if (!invalid && aggr_level < 0)
+ aggr_level= nest_level;
+ /*
+ By this moment we either found a subquery where the set function is
+ to be aggregated and assigned a value that is >= 0 to aggr_level,
+ or set the value of 'invalid' to TRUE to report later an error.
+ */
+ /*
+ Additionally we have to check whether possible nested set functions
+ are acceptable here: they are not, if the level of aggregation of
+ some of them is less than aggr_level.
+ */
+ invalid= aggr_level <= max_sum_func_level;
+ if (invalid)
+ {
+ my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
+ MYF(0));
+ return TRUE;
+ }
+ if (in_sum_func && in_sum_func->nest_level == nest_level)
+ {
+ /*
+ If the set function is nested adjust the value of
+ max_sum_func_level for the nesting set function.
+ */
+ set_if_bigger(in_sum_func->max_sum_func_level, aggr_level);
+ }
+ thd->lex->in_sum_func= in_sum_func;
+ return FALSE;
+}
+
+/*
+ Attach a set function to the subquery where it must be aggregated
+
+ SYNOPSIS
+ register_sum_func()
+ thd reference to the thread context info
+ ref location of the pointer to this item in the embedding expression
+
+ DESCRIPTION
+ The function looks for an outer subquery where the set function must be
+ aggregated. If it finds such a subquery then aggr_level is set to
+ the nest level of this subquery and the item for the set function
+ is added to the list of set functions used in nested subqueries
+ inner_sum_func_list defined for each subquery. When the item is placed
+ there the field 'ref_by' is set to ref.
+
+ NOTES.
+ Now we 'register' only set functions that are aggregated in outer
+ subqueries. Actually it makes sense to link all set function for
+ a subquery in one chain. It would simplify the process of 'splitting'
+ for set functions.
+
+ RETURN
+ FALSE if the executes without failures (currently always)
+ TRUE otherwise
+*/
+
+bool Item_sum::register_sum_func(THD *thd, Item **ref)
+{
+ SELECT_LEX *sl;
+ SELECT_LEX *aggr_sl= NULL;
+ nesting_map allow_sum_func= thd->lex->allow_sum_func;
+ for (sl= thd->lex->current_select->master_unit()->outer_select() ;
+ sl && sl->nest_level > max_arg_level;
+ sl= sl->master_unit()->outer_select() )
+ {
+ if (aggr_level < 0 && (allow_sum_func & (1 << sl->nest_level)))
+ {
+ /* Found the most nested subquery where the function can be aggregated */
+ aggr_level= sl->nest_level;
+ aggr_sl= sl;
+ }
+ }
+ if (sl && (allow_sum_func & (1 << sl->nest_level)))
+ {
+ /*
+ We reached the subquery of level max_arg_level and checked
+ that the function can be aggregated here.
+ The set function will be aggregated in this subquery.
+ */
+ aggr_level= sl->nest_level;
+ aggr_sl= sl;
+ }
+ if (aggr_level >= 0)
+ {
+ ref_by= ref;
+ /* Add the object to the list of registered objects assigned to aggr_sl */
+ if (!aggr_sl->inner_sum_func_list)
+ next= this;
+ else
+ {
+ next= aggr_sl->inner_sum_func_list->next;
+ aggr_sl->inner_sum_func_list->next= this;
+ }
+ aggr_sl->inner_sum_func_list= this;
+
+ }
+ return FALSE;
+}
+
+
Item_sum::Item_sum(List<Item> &list)
:arg_count(list.elements)
{
@@ -197,13 +425,9 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (!thd->allow_sum_func)
- {
- my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
- MYF(0));
+ if (init_sum_func_check(thd))
return TRUE;
- }
- thd->allow_sum_func=0; // No included group funcs
+
decimals=0;
maybe_null=0;
for (uint i=0 ; i < arg_count ; i++)
@@ -217,7 +441,10 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
max_length=float_length(decimals);
null_value=1;
fix_length_and_dec();
- thd->allow_sum_func=1; // Allow group functions
+
+ if (check_sum_func(thd, ref))
+ return TRUE;
+
fixed= 1;
return FALSE;
}
@@ -258,13 +485,9 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
DBUG_ASSERT(fixed == 0);
Item *item= args[0];
- if (!thd->allow_sum_func)
- {
- my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
- MYF(0));
+
+ if (init_sum_func_check(thd))
return TRUE;
- }
- thd->allow_sum_func=0; // No included group funcs
// 'item' can be changed during fix_fields
if (!item->fixed &&
@@ -300,11 +523,14 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
result_field=0;
null_value=1;
fix_length_and_dec();
- thd->allow_sum_func=1; // Allow group functions
if (item->type() == Item::FIELD_ITEM)
hybrid_field_type= ((Item_field*) item)->field->type();
else
hybrid_field_type= Item::field_type();
+
+ if (check_sum_func(thd, ref))
+ return TRUE;
+
fixed= 1;
return FALSE;
}
@@ -452,7 +678,7 @@ longlong Item_sum_sum::val_int()
&result);
return result;
}
- return (longlong) val_real();
+ return (longlong) rint(val_real());
}
@@ -1285,7 +1511,7 @@ longlong Item_sum_hybrid::val_int()
return sum_int;
}
default:
- return (longlong) Item_sum_hybrid::val_real();
+ return (longlong) rint(Item_sum_hybrid::val_real());
}
}
@@ -2001,7 +2227,7 @@ double Item_avg_field::val_real()
longlong Item_avg_field::val_int()
{
- return (longlong) val_real();
+ return (longlong) rint(val_real());
}
@@ -2979,14 +3205,9 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
uint i; /* for loop variable */
DBUG_ASSERT(fixed == 0);
- if (!thd->allow_sum_func)
- {
- my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
- MYF(0));
+ if (init_sum_func_check(thd))
return TRUE;
- }
- thd->allow_sum_func= 0;
maybe_null= 1;
/*
@@ -3008,8 +3229,11 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
result.set_charset(collation.collation);
result_field= 0;
null_value= 1;
- thd->allow_sum_func= 1;
max_length= thd->variables.group_concat_max_len;
+
+ if (check_sum_func(thd, ref))
+ return TRUE;
+
fixed= 1;
return FALSE;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 87cc248e5e4..a8242d76287 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -23,6 +23,201 @@
#include <my_tree.h>
+/*
+ Class Item_sum is the base class used for special expressions that SQL calls
+ 'set functions'. These expressions are formed with the help of aggregate
+ functions such as SUM, MAX, GROUP_CONCAT etc.
+
+ GENERAL NOTES
+
+ A set function cannot be used in certain positions where expressions are
+ accepted. There are some quite explicable restrictions for the usage of
+ set functions.
+
+ In the query:
+ SELECT AVG(b) FROM t1 WHERE SUM(b) > 20 GROUP by a
+ the usage of the set function AVG(b) is legal, while the usage of SUM(b)
+ is illegal. A WHERE condition must contain expressions that can be
+ evaluated for each row of the table. Yet the expression SUM(b) can be
+ evaluated only for each group of rows with the same value of column a.
+ In the query:
+ SELECT AVG(b) FROM t1 WHERE c > 30 GROUP BY a HAVING SUM(b) > 20
+ both set function expressions AVG(b) and SUM(b) are legal.
+
+ We can say that in a query without nested selects an occurrence of a
+ set function in an expression of the SELECT list or/and in the HAVING
+ clause is legal, while in the WHERE clause it's illegal.
+
+ The general rule to detect whether a set function is legal in a query with
+ nested subqueries is much more complicated.
+
+ Consider the the following query:
+ SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL (SELECT t2.c FROM t2 WHERE SUM(t1.b) < t2.c).
+ The set function SUM(b) is used here in the WHERE clause of the subquery.
+ Nevertheless it is legal since it is under the HAVING clause of the query
+ to which this function relates. The expression SUM(t1.b) is evaluated
+ for each group defined in the main query, not for groups of the subquery.
+
+ The problem of finding the query where to aggregate a particular
+ set function is not so simple as it seems to be.
+
+ In the query:
+ SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL(SELECT t2.c FROM t2 GROUP BY t2.c
+ HAVING SUM(t1.a) < t2.c)
+ the set function can be evaluated for both outer and inner selects.
+ If we evaluate SUM(t1.a) for the outer query then we get the value of t1.a
+ multiplied by the cardinality of a group in table t1. In this case
+ in each correlated subquery SUM(t1.a) is used as a constant. But we also
+ can evaluate SUM(t1.a) for the inner query. In this case t1.a will be a
+ constant for each correlated subquery and summation is performed
+ for each group of table t2.
+ (Here it makes sense to remind that the query
+ SELECT c FROM t GROUP BY a HAVING SUM(1) < a
+ is quite legal in our SQL).
+
+ So depending on what query we assign the set function to we
+ can get different result sets.
+
+ The general rule to detect the query where a set function is to be
+ evaluated can be formulated as follows.
+ Consider a set function S(E) where E is an expression with occurrences
+ of column references C1, ..., CN. Resolve these column references against
+ subqueries that contain the set function S(E). Let Q be the innermost
+ subquery of those subqueries. (It should be noted here that S(E)
+ in no way can be evaluated in the subquery embedding the subquery Q,
+ otherwise S(E) would refer to at least one unbound column reference)
+ If S(E) is used in a construct of Q where set functions are allowed then
+ we evaluate S(E) in Q.
+ Otherwise we look for a innermost subquery containing S(E) of those where
+ usage of S(E) is allowed.
+
+ Let's demonstrate how this rule is applied to the following queries.
+
+ 1. SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL(SELECT t2.b FROM t2 GROUP BY t2.b
+ HAVING t2.b > ALL(SELECT t3.c FROM t3 GROUP BY t3.c
+ HAVING SUM(t1.a+t2.b) < t3.c))
+ For this query the set function SUM(t1.a+t2.b) depends on t1.a and t2.b
+ with t1.a defined in the outermost query, and t2.b defined for its
+ subquery. The set function is in the HAVING clause of the subquery and can
+ be evaluated in this subquery.
+
+ 2. SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL(SELECT t2.b FROM t2
+ WHERE t2.b > ALL (SELECT t3.c FROM t3 GROUP BY t3.c
+ HAVING SUM(t1.a+t2.b) < t3.c))
+ Here the set function SUM(t1.a+t2.b)is in the WHERE clause of the second
+ subquery - the most upper subquery where t1.a and t2.b are defined.
+ If we evaluate the function in this subquery we violate the context rules.
+ So we evaluate the function in the third subquery (over table t3) where it
+ is used under the HAVING clause.
+
+ 3. SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL(SELECT t2.b FROM t2
+ WHERE t2.b > ALL (SELECT t3.c FROM t3
+ WHERE SUM(t1.a+t2.b) < t3.c))
+ In this query evaluation of SUM(t1.a+t2.b) is not legal neither in the second
+ nor in the third subqueries. So this query is invalid.
+
+ Mostly set functions cannot be nested. In the query
+ SELECT t1.a from t1 GROUP BY t1.a HAVING AVG(SUM(t1.b)) > 20
+ the expression SUM(b) is not acceptable, though it is under a HAVING clause.
+ Yet it is acceptable in the query:
+ SELECT t.1 FROM t1 GROUP BY t1.a HAVING SUM(t1.b) > 20.
+
+ An argument of a set function does not have to be a reference to a table
+ column as we saw it in examples above. This can be a more complex expression
+ SELECT t1.a FROM t1 GROUP BY t1.a HAVING SUM(t1.b+1) > 20.
+ The expression SUM(t1.b+1) has a very clear semantics in this context:
+ we sum up the values of t1.b+1 where t1.b varies for all values within a
+ group of rows that contain the same t1.a value.
+
+ A set function for an outer query yields a constant within a subquery. So
+ the semantics of the query
+ SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+ HAVING AVG(t2.c+SUM(t1.b)) > 20)
+ is still clear. For a group of the rows with the same t1.a values we
+ calculate the value of SUM(t1.b). This value 's' is substituted in the
+ the subquery:
+ SELECT t2.c FROM t2 GROUP BY t2.c HAVING AVG(t2.c+s)
+ than returns some result set.
+
+ By the same reason the following query with a subquery
+ SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c
+ HAVING AVG(SUM(t1.b)) > 20)
+ is also acceptable.
+
+ IMPLEMENTATION NOTES
+
+ Three methods were added to the class to check the constraints specified
+ in the previous section. These methods utilize several new members.
+
+ The field 'nest_level' contains the number of the level for the subquery
+ containing the set function. The main SELECT is of level 0, its subqueries
+ are of levels 1, the subqueries of the latter are of level 2 and so on.
+
+ The field 'aggr_level' is to contain the nest level of the subquery
+ where the set function is aggregated.
+
+ The field 'max_arg_level' is for the maximun of the nest levels of the
+ unbound column references occurred in the set function. A column reference
+ is unbound within a set function if it is not bound by any subquery
+ used as a subexpression in this function. A column reference is bound by
+ a subquery if it is a reference to the column by which the aggregation
+ of some set function that is used in the subquery is calculated.
+ For the set function used in the query
+ SELECT t1.a FROM t1 GROUP BY t1.a
+ HAVING t1.a > ALL(SELECT t2.b FROM t2 GROUP BY t2.b
+ HAVING t2.b > ALL(SELECT t3.c FROM t3 GROUP BY t3.c
+ HAVING SUM(t1.a+t2.b) < t3.c))
+ the value of max_arg_level is equal to 1 since t1.a is bound in the main
+ query, and t2.b is bound by the first subquery whose nest level is 1.
+ Obviously a set function cannot be aggregated in the subquery whose
+ nest level is less than max_arg_level. (Yet it can be aggregated in the
+ subqueries whose nest level is greater than max_arg_level.)
+ In the query
+ SELECT t.a FROM t1 HAVING AVG(t1.a+(SELECT MIN(t2.c) FROM t2))
+ the value of the max_arg_level for the AVG set function is 0 since
+ the reference t2.c is bound in the subquery.
+
+ The field 'max_sum_func_level' is to contain the maximum of the
+ nest levels of the set functions that are used as subexpressions of
+ the arguments of the given set function, but not aggregated in any
+ subquery within this set function. A nested set function s1 can be
+ used within set function s0 only if s1.max_sum_func_level <
+ s0.max_sum_func_level. Set function s1 is considered as nested
+ for set function s0 if s1 is not calculated in any subquery
+ within s0.
+
+ A set function that is used as a subexpression in an argument of another
+ set function refers to the latter via the field 'in_sum_func'.
+
+ The condition imposed on the usage of set functions are checked when
+ we traverse query subexpressions with the help of the recursive method
+ fix_fields. When we apply this method to an object of the class
+ Item_sum, first, on the descent, we call the method init_sum_func_check
+ that initialize members used at checking. Then, on the ascent, we
+ call the method check_sum_func that validates the set function usage
+ and reports an error if it is illegal.
+ The method register_sum_func serves to link the items for the set functions
+ that are aggregated in the embedding (sub)queries. Circular chains of such
+ functions are attached to the corresponding st_select_lex structures
+ through the field inner_sum_func_list.
+
+ Exploiting the fact that the members mentioned above are used in one
+ recursive function we could have allocated them on the thread stack.
+ Yet we don't do it now.
+
+ We assume that the nesting level of subquries does not exceed 127.
+ TODO: to catch queries where the limit is exceeded to make the
+ code clean here.
+
+*/
+
class Item_sum :public Item_result_field
{
public:
@@ -33,7 +228,14 @@ public:
};
Item **args, *tmp_args[2];
+ Item **ref_by; /* pointer to a ref to the object used to register it */
+ Item_sum *next; /* next in the circular chain of registered objects */
uint arg_count;
+ Item_sum *in_sum_func; /* embedding set function if any */
+ int8 nest_level; /* number of the nesting level of the set function */
+ int8 aggr_level; /* nesting level of the aggregating subquery */
+ int8 max_arg_level; /* max level of unbound column references */
+ int8 max_sum_func_level;/* max level of aggregation for embedded functions */
bool quick_group; /* If incremental update of fields */
void mark_as_sum_func();
@@ -111,6 +313,9 @@ public:
virtual Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
bool walk (Item_processor processor, byte *argument);
+ bool init_sum_func_check(THD *thd);
+ bool check_sum_func(THD *thd, Item **ref);
+ bool register_sum_func(THD *thd, Item **ref);
};
@@ -126,7 +331,7 @@ public:
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
- return (longlong) val_real(); /* Real as default */
+ return (longlong) rint(val_real()); /* Real as default */
}
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
@@ -392,7 +597,7 @@ public:
bool add();
double val_real();
// In SPs we might force the "wrong" type with select into a declare variable
- longlong val_int() { return (longlong)val_real(); }
+ longlong val_int() { return (longlong) rint(val_real()); }
my_decimal *val_decimal(my_decimal *);
String *val_str(String *str);
void reset_field();
@@ -421,7 +626,7 @@ public:
enum Type type() const {return FIELD_VARIANCE_ITEM; }
double val_real();
longlong val_int()
- { /* can't be fix_fields()ed */ return (longlong) val_real(); }
+ { /* can't be fix_fields()ed */ return (longlong) rint(val_real()); }
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
bool is_null() { (void) val_int(); return null_value; }
@@ -699,7 +904,7 @@ class Item_sum_udf_float :public Item_udf_sum
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
- return (longlong) Item_sum_udf_float::val_real();
+ return (longlong) rint(Item_sum_udf_float::val_real());
}
double val_real();
String *val_str(String*str);
diff --git a/sql/lock.cc b/sql/lock.cc
index fe8dcb3aa5e..d0bfcfd7272 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -423,6 +423,127 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
}
+/*
+ Find duplicate lock in tables.
+
+ SYNOPSIS
+ mysql_lock_have_duplicate()
+ thd The current thread.
+ needle The table to check for duplicate lock.
+ haystack The list of tables to search for the dup lock.
+
+ NOTE
+ This is mainly meant for MERGE tables in INSERT ... SELECT
+ situations. The 'real', underlying tables can be found only after
+ the table is opened. The easier way is to check this after the
+ tables are locked.
+
+ RETURN
+ 1 A table from 'tables' matches a lock on 'table'.
+ 0 No duplicate lock is present.
+ -1 Error.
+*/
+
+TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
+ TABLE_LIST *haystack)
+{
+ uint count;
+ uint dup_pos;
+ TABLE *write_lock_used; /* dummy */
+ TABLE **tables1;
+ TABLE **tables2;
+ TABLE **table_ptr;
+ TABLE_LIST *tlist_ptr;
+ MYSQL_LOCK *sql_lock1;
+ MYSQL_LOCK *sql_lock2;
+ THR_LOCK_DATA **lock_data1;
+ THR_LOCK_DATA **end_data1;
+ THR_LOCK_DATA **lock_data2;
+ THR_LOCK_DATA **end_data2;
+ THR_LOCK *lock1;
+ DBUG_ENTER("mysql_lock_have_duplicate");
+
+ /* Table may not be defined for derived or view tables. */
+ if (! needle->table)
+ DBUG_RETURN(NULL);
+
+ /* Get lock(s) for needle. */
+ tables1= &needle->table;
+ if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used)))
+ goto err0;
+
+ /* Count real tables in list. */
+ count=0;
+ for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
+ if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
+ count++;
+ /* Allocate a table array. */
+ if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count)))
+ goto err1;
+ table_ptr= tables2;
+ /* Assign table pointers. */
+ for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
+ if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
+ *(table_ptr++)= tlist_ptr->table;
+ /* Get lock(s) for haystack. */
+ if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used)))
+ goto err1;
+
+ /* Initialize duplicate position to an impossible value. */
+ dup_pos= UINT_MAX;
+ /*
+ Find a duplicate lock.
+ In case of merge tables, sql_lock1 can have more than 1 lock.
+ */
+ for (lock_data1= sql_lock1->locks,
+ end_data1= lock_data1 + sql_lock1->lock_count;
+ lock_data1 < end_data1;
+ lock_data1++)
+ {
+ lock1= (*lock_data1)->lock;
+ for (lock_data2= sql_lock2->locks,
+ end_data2= lock_data2 + sql_lock2->lock_count;
+ lock_data2 < end_data2;
+ lock_data2++)
+ {
+ if ((*lock_data2)->lock == lock1)
+ {
+ DBUG_PRINT("ingo", ("duplicate lock found"));
+ /* Change duplicate position to the real value. */
+ dup_pos= lock_data2 - sql_lock2->locks;
+ goto end;
+ }
+ }
+ }
+
+ end:
+ tlist_ptr= NULL; /* In case that no duplicate was found. */
+ if (dup_pos != UINT_MAX)
+ {
+ /* Duplicate found. Search the matching TABLE_LIST object. */
+ count= 0;
+ for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
+ {
+ if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
+ {
+ count+= tlist_ptr->table->file->lock_count();
+ if (count > dup_pos)
+ break;
+ }
+ }
+ }
+ my_free((gptr) sql_lock2, MYF(0));
+ my_free((gptr) sql_lock1, MYF(0));
+ DBUG_RETURN(tlist_ptr);
+
+ err1:
+ my_free((gptr) sql_lock1, MYF(0));
+ err0:
+ /* This non-null but special value indicates error, if caller cares. */
+ DBUG_RETURN(needle);
+}
+
+
/* unlock a set of external */
static int unlock_external(THD *thd, TABLE **table,uint count)
@@ -460,6 +581,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
MYSQL_LOCK *sql_lock;
THR_LOCK_DATA **locks;
TABLE **to;
+ DBUG_ENTER("get_lock_data");
*write_lock_used=0;
for (i=tables=lock_count=0 ; i < count ; i++)
@@ -488,7 +610,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
my_malloc(sizeof(*sql_lock)+
sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count,
MYF(0))))
- return 0;
+ DBUG_RETURN(0);
locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
to=sql_lock->table=(TABLE**) (locks+tables);
sql_lock->table_count=lock_count;
@@ -508,7 +630,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
{
my_error(ER_OPEN_AS_READONLY, MYF(0), table->alias);
my_free((gptr) sql_lock,MYF(0));
- return 0;
+ DBUG_RETURN(0);
}
}
THR_LOCK_DATA **org_locks = locks;
@@ -518,7 +640,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
for ( ; org_locks != locks ; org_locks++)
(*org_locks)->debug_print_param= (void *) table;
}
- return sql_lock;
+ DBUG_RETURN(sql_lock);
}
@@ -601,6 +723,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
char key[MAX_DBKEY_LENGTH];
char *db= table_list->db;
uint key_length;
+ HASH_SEARCH_STATE state;
DBUG_ENTER("lock_table_name");
DBUG_PRINT("enter",("db: %s name: %s", db, table_list->table_name));
@@ -611,9 +734,9 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
/* Only insert the table if we haven't insert it already */
- for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ for (table=(TABLE*) hash_first(&open_cache, (byte*)key, key_length, &state);
table ;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ table = (TABLE*) hash_next(&open_cache, (byte*)key, key_length, &state))
if (table->in_use == thd)
DBUG_RETURN(0);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 4f5a0032531..ca2cda0f7c6 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -42,8 +42,13 @@
/* TODO convert all these three maps to Bitmap classes */
typedef ulonglong table_map; /* Used for table bits in join */
-typedef Bitmap<64> key_map; /* Used for finding keys */
+#if MAX_INDEXES <= 64
+typedef Bitmap<64> key_map; /* Used for finding keys */
+#else
+typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
+#endif
typedef ulong key_part_map; /* Used for finding key parts */
+typedef ulong nesting_map; /* Used for flags of nesting constructs */
/*
Used to identify NESTED_JOIN structures within a join (applicable only to
structures that have not been simplified away and embed more the one
@@ -660,6 +665,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
KEY_CACHE *dst_cache);
+TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
bool mysql_xa_recover(THD *thd);
@@ -791,18 +797,15 @@ find_field_in_tables(THD *thd, Item_ident *item,
bool check_privileges, bool register_tree_change);
Field *
find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
- const char *name, const char *item_name,
- const char *table_name, const char *db_name,
- uint length, Item **ref,
- bool check_grants_table, bool check_grants_view,
- bool allow_rowid,
+ const char *name, uint length,
+ const char *item_name, const char *db_name,
+ const char *table_name, Item **ref,
+ bool check_privileges, bool allow_rowid,
uint *cached_field_index_ptr,
bool register_tree_change, TABLE_LIST **actual_table);
Field *
-find_field_in_table(THD *thd, TABLE *table, const char *name,
- uint length, bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr,
- Security_context *sctx);
+find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
+ bool allow_rowid, uint *cached_field_index_ptr);
#ifdef HAVE_OPENSSL
#include <openssl/des.h>
@@ -918,8 +921,9 @@ create_field * new_create_field(THD *thd, char *field_name, enum_field_types typ
uint uint_geom_type);
void store_position_for_column(const char *name);
bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
-Name_resolution_context *make_join_on_context(THD *thd, TABLE_LIST *left_op,
- TABLE_LIST *right_op);
+bool push_new_name_resolution_context(THD *thd,
+ TABLE_LIST *left_op,
+ TABLE_LIST *right_op);
void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
bool add_proc_to_list(THD *thd, Item *item);
@@ -982,7 +986,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
uint offset_to_list,
const char *db_name,
const char *table_name);
-TABLE_LIST *unique_table(TABLE_LIST *table, TABLE_LIST *table_list);
+TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table);
@@ -1101,8 +1105,8 @@ void unhex_type2(TYPELIB *lib);
uint check_word(TYPELIB *lib, const char *val, const char *end,
const char **end_of_word);
-bool is_keyword(const char *name, uint len);
+bool is_keyword(const char *name, uint len);
#define MY_DB_OPT_FILE "db.opt"
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
@@ -1270,6 +1274,8 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
void mysql_lock_abort(THD *thd, TABLE *table);
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
+TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
+ TABLE_LIST *haystack);
bool lock_global_read_lock(THD *thd);
void unlock_global_read_lock(THD *thd);
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
@@ -1362,7 +1368,7 @@ int calc_weekday(long daynr,bool sunday_first_day_of_week);
uint calc_week(TIME *l_time, uint week_behaviour, uint *year);
void find_date(char *pos,uint *vek,uint flag);
TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
-TYPELIB *typelib(List<String> &strings);
+TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings);
ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
const char *newname);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 857658207ba..1f32a8285d1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -385,6 +385,7 @@ my_bool sp_automatic_privileges= 1;
static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
#endif
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
+uint mysqld_port_timeout;
uint delay_key_write_options, protocol_version;
uint lower_case_table_names;
uint tc_heuristic_recover= 0;
@@ -1357,7 +1358,12 @@ static void network_init(void)
struct sockaddr_un UNIXaddr;
#endif
int arg=1;
+ int ret;
+ uint waited;
+ uint this_wait;
+ uint retry;
DBUG_ENTER("server_init");
+ LINT_INIT(ret);
set_ports();
@@ -1383,8 +1389,26 @@ static void network_init(void)
*/
(void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
#endif /* __WIN__ */
- if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
- sizeof(IPaddr)) < 0)
+ /*
+ Sometimes the port is not released fast enough when stopping and
+ restarting the server. This happens quite often with the test suite
+ on busy Linux systems. Retry to bind the address at these intervals:
+ Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ...
+ Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...
+ Limit the sequence by mysqld_port_timeout (set --port-open-timeout=#).
+ */
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ if (((ret= bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
+ sizeof(IPaddr))) >= 0) ||
+ (socket_errno != SOCKET_EADDRINUSE) ||
+ (waited >= mysqld_port_timeout))
+ break;
+ sql_print_information("Retrying bind on TCP/IP port %u", mysqld_port);
+ this_wait= retry * retry / 3 + 1;
+ sleep(this_wait);
+ }
+ if (ret < 0)
{
DBUG_PRINT("error",("Got error: %d from bind",socket_errno));
sql_perror("Can't start server: Bind on TCP/IP port");
@@ -4552,7 +4576,8 @@ enum options_mysqld
OPT_TIMED_MUTEXES,
OPT_OLD_STYLE_USER_LIMITS,
OPT_LOG_SLOW_ADMIN_STATEMENTS,
- OPT_TABLE_LOCK_WAIT_TIMEOUT
+ OPT_TABLE_LOCK_WAIT_TIMEOUT,
+ OPT_PORT_OPEN_TIMEOUT
};
@@ -4637,7 +4662,7 @@ Disable with --skip-bdb (will save memory).",
{"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE,
- "Don't use client side character set value sent during handshake.",
+ "Don't ignore client side character set value sent during handshake.",
(gptr*) &opt_character_set_client_handshake,
(gptr*) &opt_character_set_client_handshake,
0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
@@ -5092,6 +5117,10 @@ Disable with --skip-ndbcluster (will save memory).",
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number to use for connection.", (gptr*) &mysqld_port,
(gptr*) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"port-open-timeout", OPT_PORT_OPEN_TIMEOUT,
+ "Maximum time in seconds to wait for the port to become free. "
+ "(Default: no wait)", (gptr*) &mysqld_port_timeout,
+ (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"relay-log", OPT_RELAY_LOG,
"The location and name to use for relay logs.",
(gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0,
@@ -6323,7 +6352,7 @@ static void mysql_init_variables(void)
#else
have_example_db= SHOW_OPTION_NO;
#endif
-#ifdef HAVE_ARCHIVE_DB
+#if defined(HAVE_ARCHIVE_DB)
have_archive_db= SHOW_OPTION_YES;
#else
have_archive_db= SHOW_OPTION_NO;
@@ -6358,7 +6387,7 @@ static void mysql_init_variables(void)
#else
have_openssl=SHOW_OPTION_NO;
#endif
-#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH)
+#ifdef HAVE_BROKEN_REALPATH
have_symlink=SHOW_OPTION_NO;
#else
have_symlink=SHOW_OPTION_YES;
@@ -6913,8 +6942,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_MYISAM_STATS_METHOD:
{
ulong method_conv;
- myisam_stats_method_str= argument;
int method;
+ LINT_INIT(method_conv);
+
+ myisam_stats_method_str= argument;
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
{
fprintf(stderr, "Invalid value of myisam_stats_method: %s.\n", argument);
@@ -7051,7 +7082,7 @@ static void get_options(int argc,char **argv)
usage();
exit(0);
}
-#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH)
+#if defined(HAVE_BROKEN_REALPATH)
my_use_symdir=0;
my_disable_symlinks=1;
have_symlink=SHOW_OPTION_NO;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 12b00a62012..7c5274eb5eb 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3136,10 +3136,10 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
/* F=F-covered by first(I) */
bitmap_union(&covered_fields, &(*ror_scan_mark)->covered_fields);
all_covered= bitmap_is_subset(&param->needed_fields, &covered_fields);
- } while (!all_covered && (++ror_scan_mark < ror_scans_end));
-
- if (!all_covered)
- DBUG_RETURN(NULL); /* should not happen actually */
+ } while ((++ror_scan_mark < ror_scans_end) && !all_covered);
+
+ if (!all_covered || (ror_scan_mark - tree->ror_scans) == 1)
+ DBUG_RETURN(NULL);
/*
Ok, [tree->ror_scans .. ror_scan) holds covering index_intersection with
@@ -3172,6 +3172,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
trp->is_covering= TRUE;
trp->read_cost= total_cost;
trp->records= records;
+ trp->cpk_scan= NULL;
DBUG_PRINT("info",
("Returning covering ROR-intersect plan: cost %g, records %lu",
@@ -7201,6 +7202,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
{
select_items_it.rewind();
cur_used_key_parts.clear_all();
+ uint max_key_part= 0;
while ((item= select_items_it++))
{
item_field= (Item_field*) item; /* (SA5) already checked above. */
@@ -7218,7 +7220,19 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
cur_group_prefix_len+= cur_part->store_length;
cur_used_key_parts.set_bit(key_part_nr);
++cur_group_key_parts;
+ max_key_part= max(max_key_part,key_part_nr);
}
+ /*
+ Check that used key parts forms a prefix of the index.
+ To check this we compare bits in all_parts and cur_parts.
+ all_parts have all bits set from 0 to (max_key_part-1).
+ cur_parts have bits set for only used keyparts.
+ */
+ ulonglong all_parts, cur_parts;
+ all_parts= (1<<max_key_part) - 1;
+ cur_parts= cur_used_key_parts.to_ulonglong() >> 1;
+ if (all_parts != cur_parts)
+ goto next_index;
}
else
DBUG_ASSERT(FALSE);
diff --git a/sql/share/charsets/latin5.xml b/sql/share/charsets/latin5.xml
index 67e5873c503..5004f045889 100644
--- a/sql/share/charsets/latin5.xml
+++ b/sql/share/charsets/latin5.xml
@@ -112,11 +112,6 @@
<collation name="latin5_turkish_ci">
-<!--
-# Note: all accented characters are compared separately (this
-# is different from the default latin1 character set, where
-# e.g. a = ä = á, etc.).
--->
<map>
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
@@ -130,10 +125,10 @@
9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB
AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB
BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB
- CC CD CE CF D0 D1 D2 44 D3 D4 D5 D6 D7 D8 D9 DA
- 49 DB DC DD DE DF 53 E0 E1 E2 E3 E4 5B 4C 58 E5
- CC CD CE CF D0 D1 D2 44 D3 D4 D5 D6 D7 D8 D9 DA
- 49 DB DC DD DE DF 53 FA E1 E2 E3 E4 5B 4B 58 FF
+ 41 41 41 41 41 41 41 44 46 46 46 46 4C 4C 4C 4C
+ 49 51 52 52 52 52 53 E0 52 5A 5A 5A 5B 4C 58 57
+ 41 41 41 41 41 41 41 44 46 46 46 46 4C 4C 4C 4C
+ 49 51 52 52 52 52 53 FA 52 5A 5A 5A 5B 4B 58 5F
</map>
</collation>
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index f67ad3a9fd2..185b4326c5c 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -4590,7 +4590,7 @@ ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 21000
nla "De gebruikte SELECT commando's hebben een verschillend aantal kolommen"
eng "The used SELECT statements have a different number of columns"
est "Tulpade arv kasutatud SELECT lausetes ei kattu"
- ger "Die verwendeten SELECT-Befehle liefern eine unterschiedliche Anzahl von Feldern zurück"
+ ger "Die verwendeten SELECT-Befehle liefern unterschiedliche Anzahlen von Feldern zurück"
ita "La SELECT utilizzata ha un numero di colonne differente"
por "Os comandos SELECT usados têm diferente número de colunas"
rus "éÓÐÏÌØÚÏ×ÁÎÎÙÅ ÏÐÅÒÁÔÏÒÙ ×ÙÂÏÒËÉ (SELECT) ÄÁÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
@@ -5274,7 +5274,7 @@ ER_VIEW_SELECT_TMPTABLE
ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.64s'"
ER_VIEW_WRONG_LIST
eng "View's SELECT and view's field list have different column counts"
- ger "SELECT- und Feldliste der Views haben eine unterschiedliche Anzahl von Spalten"
+ ger "SELECT- und Feldliste der Views haben unterschiedliche Anzahlen von Spalten"
rus "View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
ukr "View SELECT ¦ ÐÅÒÅÌ¦Ë ÓÔÏ×ÂÃ¦× view ÍÁÀÔØ Ò¦ÚÎÕ Ë¦ÌØ˦ÓÔØ ÓËÏ×Âæ×"
ER_WARN_VIEW_MERGE
@@ -5375,7 +5375,7 @@ ER_WSAS_FAILED
eng "WSAStartup Failed"
ger "WSAStartup fehlgeschlagen"
ER_DIFF_GROUPS_PROC
- eng "Can't handle procedures with differents groups yet"
+ eng "Can't handle procedures with different groups yet"
ger "Kann Prozeduren mit unterschiedlichen Gruppen noch nicht verarbeiten"
ER_NO_GROUP_FOR_PROC
eng "Select must have a group with this procedure"
@@ -5485,7 +5485,7 @@ ER_CANT_CREATE_GEOMETRY_OBJECT 22003
ger "Kann kein Geometrieobjekt aus den Daten machen, die Sie dem GEOMETRY-Feld übergeben haben"
ER_FAILED_ROUTINE_BREAK_BINLOG
eng "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes"
- ger "Eine Routine, die weder NO SQL noch READS SQL DATA in der Deklaration hat, schlug fehl und Binärlogging ist aktiv. Wenn Nicht-Transaktions-Tabellen atualisiert wurden, enthält das Binärlog ihre Änderungen nicht"
+ ger "Eine Routine, die weder NO SQL noch READS SQL DATA in der Deklaration hat, schlug fehl und Binärlogging ist aktiv. Wenn Nicht-Transaktions-Tabellen aktualisiert wurden, enthält das Binärlog ihre Änderungen nicht"
ER_BINLOG_UNSAFE_ROUTINE
eng "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)"
ger "Diese Routine hat weder DETERMINISTIC, NO SQL noch READS SQL DATA in der Deklaration und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_routine_creators verwenden)"
@@ -5595,8 +5595,13 @@ ER_SP_BAD_VAR_SHADOW 42000
eng "Variable '%-.64s' must be quoted with `...`, or renamed"
ger "Variable '%-.64s' muss mit `...` geschützt oder aber umbenannt werden"
ER_TRG_NO_DEFINER
- eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
+ eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
+ ger "Kein Definierer-Attribut für Trigger '%-.64s'.'%-.64s'. Der Trigger wird mit der Autorisierung des Aufrufers aktiviert, der möglicherweise keine zureichenden Berechtigungen hat. Bitte legen Sie den Trigger neu an."
ER_OLD_FILE_FORMAT
- eng "'%-.64s' has an old format, you should re-create the '%s' object(s)"
+ eng "'%-.64s' has an old format, you should re-create the '%s' object(s)"
+ ger "'%-.64s' hat altes Format, Sie sollten die '%s'-Objekt(e) neu erzeugen"
ER_SP_RECURSION_LIMIT
eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.64s"
+ ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.64s überschritten"
+ER_SP_PROC_TABLE_CORRUPT
+ eng "Failed to load routine %s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
diff --git a/sql/sp.cc b/sql/sp.cc
index 983addb2db7..a9b1a462d5f 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -470,7 +470,7 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
bzero(&table, sizeof(table));
table.in_use= thd;
table.s = &table.share_not_to_be_used;
- field= sp->make_field(0, 0, &table);
+ field= sp->create_result_field(0, 0, &table);
field->sql_type(result);
delete field;
}
@@ -1201,6 +1201,12 @@ struct Sroutine_hash_entry
for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
*/
Sroutine_hash_entry *next;
+ /*
+ Uppermost view which directly or indirectly uses this routine.
+ 0 if routine is not used in view. Note that it also can be 0 if
+ statement uses routine both via view and directly.
+ */
+ TABLE_LIST *belong_to_view;
};
@@ -1255,9 +1261,11 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
SYNOPSIS
add_used_routine()
- lex - LEX representing statement
- arena - arena in which memory for new element will be allocated
- key - key for the hash representing set
+ lex LEX representing statement
+ arena Arena in which memory for new element will be allocated
+ key Key for the hash representing set
+ belong_to_view Uppermost view which uses this routine
+ (0 if routine is not used by view)
NOTES
Will also add element to end of 'LEX::sroutines_list' list.
@@ -1280,7 +1288,8 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
*/
static bool add_used_routine(LEX *lex, Query_arena *arena,
- const LEX_STRING *key)
+ const LEX_STRING *key,
+ TABLE_LIST *belong_to_view)
{
if (!hash_search(&lex->sroutines, (byte *)key->str, key->length))
{
@@ -1294,6 +1303,7 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
memcpy(rn->key.str, key->str, key->length);
my_hash_insert(&lex->sroutines, (byte *)rn);
lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
+ rn->belong_to_view= belong_to_view;
return TRUE;
}
return FALSE;
@@ -1324,7 +1334,7 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
sp_name *rt, char rt_type)
{
rt->set_routine_type(rt_type);
- (void)add_used_routine(lex, arena, &rt->m_sroutines_key);
+ (void)add_used_routine(lex, arena, &rt->m_sroutines_key, 0);
lex->sroutines_list_own_last= lex->sroutines_list.next;
lex->sroutines_list_own_elements= lex->sroutines_list.elements;
}
@@ -1394,20 +1404,23 @@ void sp_update_sp_used_routines(HASH *dst, HASH *src)
SYNOPSIS
sp_update_stmt_used_routines()
- thd - thread context
- lex - LEX representing statement
- src - hash representing set from which routines will be added
+ thd Thread context
+ lex LEX representing statement
+ src Hash representing set from which routines will be added
+ belong_to_view Uppermost view which uses these routines, 0 if none
NOTE
It will also add elements to end of 'LEX::sroutines_list' list.
*/
-static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
+static void
+sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src,
+ TABLE_LIST *belong_to_view)
{
for (uint i=0 ; i < src->records ; i++)
{
Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
- (void)add_used_routine(lex, thd->stmt_arena, &rt->key);
+ (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
}
}
@@ -1418,19 +1431,21 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
SYNOPSIS
sp_update_stmt_used_routines()
- thd Thread context
- lex LEX representing statement
- src List representing set from which routines will be added
+ thd Thread context
+ lex LEX representing statement
+ src List representing set from which routines will be added
+ belong_to_view Uppermost view which uses these routines, 0 if none
NOTE
It will also add elements to end of 'LEX::sroutines_list' list.
*/
-static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src)
+static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src,
+ TABLE_LIST *belong_to_view)
{
for (Sroutine_hash_entry *rt= (Sroutine_hash_entry *)src->first;
rt; rt= rt->next)
- (void)add_used_routine(lex, thd->stmt_arena, &rt->key);
+ (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
}
@@ -1448,21 +1463,23 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src)
first_no_prelock - If true, don't add tables or cache routines used by
the body of the first routine (i.e. *start)
will be executed in non-prelocked mode.
+ tabs_changed - Set to TRUE some tables were added, FALSE otherwise
NOTE
If some function is missing this won't be reported here.
Instead this fact will be discovered during query execution.
RETURN VALUE
- TRUE - some tables were added
- FALSE - no tables were added.
+ 0 - success
+ non-0 - failure
*/
-static bool
+static int
sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
Sroutine_hash_entry *start,
- bool first_no_prelock)
+ bool first_no_prelock, bool *tabs_changed)
{
- bool result= FALSE;
+ int ret= 0;
+ bool tabschnd= 0; /* Set if tables changed */
bool first= TRUE;
DBUG_ENTER("sp_cache_routines_and_add_tables_aux");
@@ -1483,25 +1500,68 @@ sp_cache_routines_and_add_tables_aux(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, &name, &sp) == SP_OK)
+ switch ((ret= db_find_routine(thd, type, &name, &sp)))
{
- if (type == TYPE_ENUM_FUNCTION)
- sp_cache_insert(&thd->sp_func_cache, sp);
- else
- sp_cache_insert(&thd->sp_proc_cache, sp);
+ case SP_OK:
+ {
+ if (type == TYPE_ENUM_FUNCTION)
+ sp_cache_insert(&thd->sp_func_cache, sp);
+ else
+ sp_cache_insert(&thd->sp_proc_cache, sp);
+ }
+ break;
+ case SP_KEY_NOT_FOUND:
+ ret= SP_OK;
+ break;
+ case SP_OPEN_TABLE_FAILED:
+ /*
+ Force it to attempt opening it again on subsequent calls;
+ otherwise we will get one error message the first time, and
+ then ER_SP_PROC_TABLE_CORRUPT (below) on subsequent tries.
+ */
+ mysql_proc_table_exists= 1;
+ /* Fall through */
+ default:
+ /*
+ Any error when loading an existing routine is either some problem
+ with the mysql.proc table, or a parse error because the contents
+ has been tampered with (in which case we clear that error).
+ */
+ if (ret == SP_PARSE_ERROR)
+ thd->clear_error();
+ /*
+ If we cleared the parse error, or when db_find_routine() flagged
+ an error with it's return value without calling my_error(), we
+ set the generic "mysql.proc table corrupt" error here.
+ */
+ if (!thd->net.report_error)
+ {
+ char n[NAME_LEN*2+2];
+
+ /* m_qname.str is not always \0 terminated */
+ memcpy(n, name.m_qname.str, name.m_qname.length);
+ n[name.m_qname.length]= '\0';
+ my_error(ER_SP_PROC_TABLE_CORRUPT, MYF(0), n, ret);
+ }
+ break;
}
}
if (sp)
{
if (!(first && first_no_prelock))
{
- sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines);
- result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last);
+ sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines,
+ rt->belong_to_view);
+ tabschnd|=
+ sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
+ rt->belong_to_view);
}
}
first= FALSE;
}
- DBUG_RETURN(result);
+ if (tabs_changed) /* it can be NULL */
+ *tabs_changed= tabschnd;
+ DBUG_RETURN(ret);
}
@@ -1516,18 +1576,20 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
lex - LEX representing statement
first_no_prelock - If true, don't add tables or cache routines used by
the body of the first routine (i.e. *start)
+ tabs_changed - Set to TRUE some tables were added, FALSE otherwise
RETURN VALUE
- TRUE - some tables were added
- FALSE - no tables were added.
+ 0 - success
+ non-0 - failure
*/
-bool
-sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock)
+int
+sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock,
+ bool *tabs_changed)
{
return sp_cache_routines_and_add_tables_aux(thd, lex,
(Sroutine_hash_entry *)lex->sroutines_list.first,
- first_no_prelock);
+ first_no_prelock, tabs_changed);
}
@@ -1538,19 +1600,25 @@ sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock)
SYNOPSIS
sp_cache_routines_and_add_tables_for_view()
- thd - thread context
- lex - LEX representing statement
- aux_lex - LEX representing view
+ thd Thread context
+ lex LEX representing statement
+ view Table list element representing view
+
+ RETURN VALUE
+ 0 - success
+ non-0 - failure
*/
-void
-sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
+int
+sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view)
{
Sroutine_hash_entry **last_cached_routine_ptr=
(Sroutine_hash_entry **)lex->sroutines_list.next;
- sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines_list);
- (void)sp_cache_routines_and_add_tables_aux(thd, lex,
- *last_cached_routine_ptr, FALSE);
+ sp_update_stmt_used_routines(thd, lex, &view->view->sroutines_list,
+ view->top_table());
+ return sp_cache_routines_and_add_tables_aux(thd, lex,
+ *last_cached_routine_ptr, FALSE,
+ NULL);
}
@@ -1561,16 +1629,23 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
SYNOPSIS
sp_cache_routines_and_add_tables_for_triggers()
- thd - thread context
- lex - LEX respresenting statement
- triggers - triggers of the table
+ thd thread context
+ lex LEX respresenting statement
+ table Table list element for table with trigger
+
+ RETURN VALUE
+ 0 - success
+ non-0 - failure
*/
-void
+int
sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
- Table_triggers_list *triggers)
+ TABLE_LIST *table)
{
- if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key))
+ int ret= 0;
+ Table_triggers_list *triggers= table->table->triggers;
+ if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key,
+ table->belong_to_view))
{
Sroutine_hash_entry **last_cached_routine_ptr=
(Sroutine_hash_entry **)lex->sroutines_list.next;
@@ -1580,17 +1655,20 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
{
if (triggers->bodies[i][j])
{
- (void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd,
- &lex->query_tables_last);
+ (void)triggers->bodies[i][j]->
+ add_used_tables_to_table_list(thd, &lex->query_tables_last,
+ table->belong_to_view);
sp_update_stmt_used_routines(thd, lex,
- &triggers->bodies[i][j]->m_sroutines);
+ &triggers->bodies[i][j]->m_sroutines,
+ table->belong_to_view);
}
}
}
- (void)sp_cache_routines_and_add_tables_aux(thd, lex,
- *last_cached_routine_ptr,
- FALSE);
+ ret= sp_cache_routines_and_add_tables_aux(thd, lex,
+ *last_cached_routine_ptr,
+ FALSE, NULL);
}
+ return ret;
}
diff --git a/sql/sp.h b/sql/sp.h
index 7f314b8903e..53343e0fb25 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -84,12 +84,13 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
sp_name *rt, char rt_type);
void sp_remove_not_own_routines(LEX *lex);
void sp_update_sp_used_routines(HASH *dst, HASH *src);
-bool sp_cache_routines_and_add_tables(THD *thd, LEX *lex,
- bool first_no_prelock);
-void sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex,
- LEX *aux_lex);
-void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
- Table_triggers_list *triggers);
+int sp_cache_routines_and_add_tables(THD *thd, LEX *lex,
+ bool first_no_prelock,
+ bool *tabs_changed);
+int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex,
+ TABLE_LIST *view);
+int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
+ TABLE_LIST *table);
extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 576830a6587..d6db9a47748 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -52,6 +52,81 @@ sp_map_result_type(enum enum_field_types type)
}
}
+
+Item::Type
+sp_map_item_type(enum enum_field_types type)
+{
+ switch (type) {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ return Item::INT_ITEM;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return Item::DECIMAL_ITEM;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ return Item::REAL_ITEM;
+ default:
+ return Item::STRING_ITEM;
+ }
+}
+
+
+/*
+ Return a string representation of the Item value.
+
+ NOTE: this is a legacy-compatible implementation. It fails if the value
+ contains non-ordinary symbols, which should be escaped.
+
+ SYNOPSIS
+ item a pointer to the Item
+ str string buffer for representation of the value
+
+ RETURN
+ NULL on error
+ a pointer to valid a valid string on success
+*/
+
+static String *
+sp_get_item_value(Item *item, String *str)
+{
+ Item_result result_type= item->result_type();
+
+ switch (item->result_type()) {
+ case REAL_RESULT:
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ return item->val_str(str);
+
+ case STRING_RESULT:
+ {
+ char buf_holder[STRING_BUFFER_USUAL_SIZE];
+ String buf(buf_holder, sizeof(buf_holder), &my_charset_latin1);
+ String *result= item->val_str(str);
+
+ if (!result)
+ return NULL;
+
+ buf.append('_');
+ buf.append(result->charset()->csname);
+ buf.append('\'');
+ buf.append(*result);
+ buf.append('\'');
+ str->copy(buf);
+
+ return str;
+ }
+
+ case ROW_RESULT:
+ default:
+ return NULL;
+ }
+}
+
+
/*
SYNOPSIS
sp_get_flags_for_command()
@@ -78,7 +153,11 @@ sp_get_flags_for_command(LEX *lex)
}
/* fallthrough */
case SQLCOM_ANALYZE:
+ case SQLCOM_OPTIMIZE:
+ case SQLCOM_PRELOAD_KEYS:
+ case SQLCOM_ASSIGN_TO_KEYCACHE:
case SQLCOM_CHECKSUM:
+ case SQLCOM_CHECK:
case SQLCOM_HA_READ:
case SQLCOM_SHOW_BINLOGS:
case SQLCOM_SHOW_BINLOG_EVENTS:
@@ -113,6 +192,9 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_WARNS:
case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_FUNC_CODE:
+ case SQLCOM_REPAIR:
+ case SQLCOM_BACKUP_TABLE:
+ case SQLCOM_RESTORE_TABLE:
flags= sp_head::MULTI_RESULTS;
break;
/*
@@ -176,7 +258,7 @@ sp_get_flags_for_command(LEX *lex)
/*
- Prepare Item for execution (call of fix_fields)
+ Prepare an Item for evaluation (call of fix_fields).
SYNOPSIS
sp_prepare_func_item()
@@ -188,14 +270,15 @@ sp_get_flags_for_command(LEX *lex)
prepared item
*/
-static Item *
+Item *
sp_prepare_func_item(THD* thd, Item **it_addr)
{
- Item *it= *it_addr;
DBUG_ENTER("sp_prepare_func_item");
- it_addr= it->this_item_addr(thd, it_addr);
+ it_addr= (*it_addr)->this_item_addr(thd, it_addr);
- if (!it->fixed && (*it_addr)->fix_fields(thd, it_addr))
+ if (!(*it_addr)->fixed &&
+ ((*it_addr)->fix_fields(thd, it_addr) ||
+ (*it_addr)->check_cols(1)))
{
DBUG_PRINT("info", ("fix_fields() failed"));
DBUG_RETURN(NULL);
@@ -204,202 +287,62 @@ sp_prepare_func_item(THD* thd, Item **it_addr)
}
-/* Macro to switch arena in sp_eval_func_item */
-#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena) \
- do \
- { \
- if (condition) \
- thd->set_n_backup_active_arena(thd->spcont->callers_arena, \
- backup_arena); \
- new_command; \
- if (condition) \
- thd->restore_active_arena(thd->spcont->callers_arena, \
- backup_arena); \
- } while(0)
-
/*
- Evaluate an item and store it in the returned item
+ Evaluate an expression and store the result in the field.
SYNOPSIS
- sp_eval_func_item()
- name - current thread object
- it_addr - pointer to the item to evaluate
- type - type of the item we evaluating
- reuse - used if we would like to reuse existing item
- instead of allocation of the new one
- use_callers_arena - TRUE if we want to use caller's arena
- rather then current one.
- DESCRIPTION
- We use this function to evaluate result for stored functions
- and stored procedure parameters. It is also used to evaluate and
- (re) allocate variables.
+ sp_eval_expr()
+ thd - current thread object
+ expr_item - the root item of the expression
+ result_field - the field to store the result
RETURN VALUES
- Evaluated item is returned
+ FALSE on success
+ TRUE on error
*/
-Item *
-sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
- Item *reuse, bool use_callers_arena)
+bool
+sp_eval_expr(THD *thd, Field *result_field, Item *expr_item)
{
- DBUG_ENTER("sp_eval_func_item");
- Item *it= sp_prepare_func_item(thd, it_addr);
- uint rsize;
- Query_arena backup_arena;
- Item *old_item_next, *old_free_list, **p_free_list;
- DBUG_PRINT("info", ("type: %d", type));
-
- if (!it)
- DBUG_RETURN(NULL);
-
- if (reuse)
- {
- old_item_next= reuse->next;
- p_free_list= use_callers_arena ? &thd->spcont->callers_arena->free_list :
- &thd->free_list;
- old_free_list= *p_free_list;
- }
+ DBUG_ENTER("sp_eval_expr");
- switch (sp_map_result_type(type)) {
- case INT_RESULT:
- {
- longlong i= it->val_int();
+ if (!(expr_item= sp_prepare_func_item(thd, &expr_item)))
+ DBUG_RETURN(TRUE);
- if (it->null_value)
- {
- DBUG_PRINT("info", ("INT_RESULT: null"));
- goto return_null_item;
- }
- DBUG_PRINT("info", ("INT_RESULT: %d", i));
- CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i),
- use_callers_arena, &backup_arena);
- break;
- }
- case REAL_RESULT:
- {
- double d= it->val_real();
- uint8 decimals;
- uint32 max_length;
+ bool err_status= FALSE;
- if (it->null_value)
- {
- DBUG_PRINT("info", ("REAL_RESULT: null"));
- goto return_null_item;
- }
+ /*
+ Set THD flags to emit warnings/errors in case of overflow/type errors
+ during saving the item into the field.
- /*
- There's some difference between Item::new_item() and the
- constructor; the former crashes, the latter works... weird.
- */
- decimals= it->decimals;
- max_length= it->max_length;
- DBUG_PRINT("info", ("REAL_RESULT: %g", d));
- CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d),
- use_callers_arena, &backup_arena);
- it->decimals= decimals;
- it->max_length= max_length;
- break;
- }
- case DECIMAL_RESULT:
- {
- my_decimal value, *val= it->val_decimal(&value);
- if (it->null_value)
- goto return_null_item;
- CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val),
- use_callers_arena, &backup_arena);
-#ifndef DBUG_OFF
- {
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
- DBUG_PRINT("info", ("DECIMAL_RESULT: %s",
- dbug_decimal_as_string(dbug_buff, val)));
- }
-#endif
- break;
- }
- case STRING_RESULT:
- {
- char buffer[MAX_FIELD_WIDTH];
- String tmp(buffer, sizeof(buffer), it->collation.collation);
- String *s= it->val_str(&tmp);
+ Save original values and restore them after save.
+ */
+
+ enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
+ bool save_abort_on_warning= thd->abort_on_warning;
+ bool save_no_trans_update= thd->no_trans_update;
- if (type == MYSQL_TYPE_NULL || it->null_value)
- {
- DBUG_PRINT("info", ("STRING_RESULT: null"));
- goto return_null_item;
- }
- DBUG_PRINT("info",("STRING_RESULT: %.*s",
- s->length(), s->c_ptr_quick()));
- /*
- Reuse mechanism in sp_eval_func_item() is only employed for assignments
- to local variables and OUT/INOUT SP parameters repsesented by
- Item_splocal. Usually we have some expression, which needs
- to be calculated and stored into the local variable. However in the
- case if "it" equals to "reuse", there is no "calculation" step. So,
- no reason to employ reuse mechanism to save variable into itself.
- */
- if (it == reuse)
- DBUG_RETURN(it);
+ thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
+ thd->abort_on_warning=
+ thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES);
+ thd->no_trans_update= 0;
- /*
- For some functions, 's' is now pointing to an argument of the
- function, which might be a local variable that is to be reused.
- In this case, new(reuse, &rsize) below will call the destructor
- and 's' ends up pointing to freed memory.
- A somewhat ugly fix is to simply copy the string to our local one
- (which is unused by most functions anyway), but only if 's' is
- pointing somewhere else than to 'tmp' or 'it->str_value'.
- */
- if (reuse && s != &tmp && s != &it->str_value)
- {
- if (tmp.copy((const String)(*s)))
- DBUG_RETURN(NULL);
- s= &tmp;
- }
+ /* Save the value in the field. Convert the value if needed. */
- CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
- Item_string(it->collation.collation),
- use_callers_arena, &backup_arena);
- /*
- We have to use special constructor and allocate string
- on system heap here. This is because usual Item_string
- constructor would allocate memory in the callers arena.
- This would lead to the memory leak in SP loops.
- See Bug #11333 "Stored Procedure: Memory blow up on
- repeated SELECT ... INTO query" for sample of such SP.
- TODO: Usage of the system heap gives significant overhead,
- however usual "reuse" mechanism does not work here, as
- Item_string has no max size. That is, if we have a loop, which
- has string variable with constantly increasing size, we would have
- to allocate new pieces of memory again and again on each iteration.
- In future we should probably reserve some area of memory for
- not-very-large strings and reuse it. But for large strings
- we would have to use system heap anyway.
- */
- ((Item_string*) it)->set_str_with_copy(s->ptr(), s->length());
- break;
- }
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- }
- goto end;
+ expr_item->save_in_field(result_field, 0);
-return_null_item:
- CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
- use_callers_arena, &backup_arena);
-end:
- it->rsize= rsize;
+ thd->count_cuted_fields= save_count_cuted_fields;
+ thd->abort_on_warning= save_abort_on_warning;
+ thd->no_trans_update= save_no_trans_update;
- if (reuse && it == reuse)
+ if (thd->net.report_error)
{
- /*
- The Item constructor registered itself in the arena free list,
- while the item slot is reused, so we have to restore the list.
- */
- it->next= old_item_next;
- *p_free_list= old_free_list;
+ /* Return error status if something went wrong. */
+ err_status= TRUE;
}
- DBUG_RETURN(it);
+
+ DBUG_RETURN(err_status);
}
@@ -484,9 +427,11 @@ sp_head::operator delete(void *ptr, size_t size)
sp_head::sp_head()
:Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
- m_flags(0), m_returns_cs(NULL), m_recursion_level(0), m_next_cached_sp(0),
+ m_flags(0), m_recursion_level(0), m_next_cached_sp(0),
m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this)
{
+ m_return_field_def.charset = NULL;
+
extern byte *
sp_table_key(const byte *ptr, uint *plen, my_bool first);
DBUG_ENTER("sp_head::sp_head");
@@ -505,6 +450,7 @@ sp_head::init(LEX *lex)
DBUG_ENTER("sp_head::init");
lex->spcont= m_pcont= new sp_pcontext(NULL);
+
/*
Altough trg_table_fields list is used only in triggers we init for all
types of stored procedures to simplify reset_lex()/restore_lex() code.
@@ -516,7 +462,7 @@ sp_head::init(LEX *lex)
m_body.str= m_defstr.str= 0;
m_qname.length= m_db.length= m_name.length= m_params.length=
m_body.length= m_defstr.length= 0;
- m_returns_cs= NULL;
+ m_return_field_def.charset= NULL;
DBUG_VOID_RETURN;
}
@@ -575,12 +521,13 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
DBUG_VOID_RETURN;
}
-TYPELIB *
-sp_head::create_typelib(List<String> *src)
+
+static TYPELIB *
+create_typelib(MEM_ROOT *mem_root, create_field *field_def, List<String> *src)
{
TYPELIB *result= NULL;
- CHARSET_INFO *cs= m_returns_cs;
- DBUG_ENTER("sp_head::clone_typelib");
+ CHARSET_INFO *cs= field_def->charset;
+ DBUG_ENTER("create_typelib");
if (src->elements)
{
result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
@@ -625,6 +572,7 @@ sp_head::create_typelib(List<String> *src)
return result;
}
+
int
sp_head::create(THD *thd)
{
@@ -712,17 +660,30 @@ sp_head::destroy()
*/
Field *
-sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
+sp_head::create_result_field(uint field_max_length, const char *field_name,
+ TABLE *table)
{
+ uint field_length;
Field *field;
- DBUG_ENTER("sp_head::make_field");
-
- field= ::make_field((char *)0,
- !m_returns_len ? max_length : m_returns_len,
- (uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
- m_geom_returns, Field::NONE,
- m_returns_typelib,
- name ? name : (const char *)m_name.str, dummy);
+
+ DBUG_ENTER("sp_head::create_result_field");
+
+ field_length= !m_return_field_def.length ?
+ field_max_length : m_return_field_def.length;
+
+ field= ::make_field((char*) 0, /* field ptr */
+ field_length, /* field [max] length */
+ (uchar*) "", /* null ptr */
+ 0, /* null bit */
+ m_return_field_def.pack_flag,
+ m_return_field_def.sql_type,
+ m_return_field_def.charset,
+ m_return_field_def.geom_type,
+ Field::NONE, /* unreg check */
+ m_return_field_def.interval,
+ field_name ? field_name : (const char *) m_name.str,
+ table);
+
DBUG_RETURN(field);
}
@@ -820,12 +781,14 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
variables with NAME_CONST('sp_var_name', value) calls.
RETURN
- 0 Ok, thd->query{_length} either has been appropriately replaced or
- there is no need for replacements.
- 1 Out of memory error.
+ FALSE on success
+ thd->query{_length} either has been appropriately replaced or there
+ is no need for replacements.
+ TRUE out of memory error.
*/
-static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
+static bool
+subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
{
DBUG_ENTER("subst_spvars");
if (thd->prelocked_mode == NON_PRELOCKED && mysql_bin_log.is_open())
@@ -835,7 +798,7 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
String qbuf(buffer, sizeof(buffer), &my_charset_bin);
int prev_pos, res;
- /* Find all instances of item_splocal used in this statement */
+ /* Find all instances of Item_splocal used in this statement */
for (Item *item= instr->free_list; item; item= item->next)
{
if (item->is_splocal())
@@ -846,7 +809,7 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
}
}
if (!sp_vars_uses.elements())
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
/* Sort SP var refs by their occurences in the query */
sp_vars_uses.sort(cmp_splocal_locations);
@@ -862,7 +825,12 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
splocal < sp_vars_uses.back(); splocal++)
{
Item *val;
- (*splocal)->thd= thd; // fix_fields() is not yet done
+
+ char str_buffer[STRING_BUFFER_USUAL_SIZE];
+ String str_value_holder(str_buffer, sizeof(str_buffer),
+ &my_charset_latin1);
+ String *str_value;
+
/* append the text between sp ref occurences */
res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length;
@@ -871,24 +839,33 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
res|= qbuf.append(STRING_WITH_LEN("',"));
+ res|= (*splocal)->fix_fields(thd, (Item **) splocal);
+
+ if (res)
+ break;
+
val= (*splocal)->this_item();
DBUG_PRINT("info", ("print %p", val));
- val->print(&qbuf);
+ str_value= sp_get_item_value(val, &str_value_holder);
+ if (str_value)
+ res|= qbuf.append(*str_value);
+ else
+ res|= qbuf.append(STRING_WITH_LEN("NULL"));
res|= qbuf.append(')');
if (res)
break;
}
res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos);
if (res)
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
if (!(pbuf= thd->strmake(qbuf.ptr(), qbuf.length())))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
thd->query= pbuf;
thd->query_length= qbuf.length();
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -910,7 +887,7 @@ void sp_head::recursion_level_error(THD *thd)
{
my_error(ER_SP_RECURSION_LIMIT, MYF(0),
thd->variables.max_sp_recursion_depth,
- m_name);
+ m_name.str);
}
else
my_error(ER_SP_NO_RECURSION, MYF(0));
@@ -922,17 +899,19 @@ void sp_head::recursion_level_error(THD *thd)
Assume the parameters already set.
RETURN
- -1 on error
+ FALSE on success
+ TRUE on error
*/
-int sp_head::execute(THD *thd)
+bool
+sp_head::execute(THD *thd)
{
DBUG_ENTER("sp_head::execute");
char olddb[128];
bool dbchanged;
sp_rcontext *ctx;
- int ret= 0;
+ bool err_status= FALSE;
uint ip= 0;
ulong save_sql_mode;
Query_arena *old_arena;
@@ -948,9 +927,7 @@ int sp_head::execute(THD *thd)
/* Use some extra margin for possible SP recursion and functions */
if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char*)&old_packet))
- {
- DBUG_RETURN(-1);
- }
+ DBUG_RETURN(TRUE);
/* init per-instruction memroot */
init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
@@ -979,7 +956,8 @@ int sp_head::execute(THD *thd)
dbchanged= FALSE;
if (m_db.length &&
- (ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0, &dbchanged)))
+ (err_status= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0,
+ &dbchanged)))
goto done;
if ((ctx= thd->spcont))
@@ -1057,7 +1035,7 @@ int sp_head::execute(THD *thd)
if (thd->prelocked_mode == NON_PRELOCKED)
thd->user_var_events_alloc= thd->mem_root;
- ret= i->execute(thd, &ip);
+ err_status= i->execute(thd, &ip);
/*
If this SP instruction have sent eof, it has caused no_send_error to be
@@ -1080,16 +1058,15 @@ int sp_head::execute(THD *thd)
}
/* we should cleanup free_list and memroot, used by instruction */
- thd->free_items();
+ thd->cleanup_after_query();
free_root(&execute_mem_root, MYF(0));
/*
Check if an exception has occurred and a handler has been found
- Note: We havo to check even if ret==0, since warnings (and some
- errors don't return a non-zero value.
- We also have to check even if thd->killed != 0, since some
- errors return with this even when a handler has been found
- (e.g. "bad data").
+ Note: We have to check even if err_status == FALSE, since warnings (and
+ some errors) don't return a non-zero value. We also have to check even
+ if thd->killed != 0, since some errors return with this even when a
+ handler has been found (e.g. "bad data").
*/
if (ctx)
{
@@ -1100,13 +1077,12 @@ int sp_head::execute(THD *thd)
break;
case SP_HANDLER_CONTINUE:
thd->restore_active_arena(&execute_arena, &backup_arena);
- ctx->save_variables(hf);
thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
ctx->push_hstack(ip);
// Fall through
default:
ip= hip;
- ret= 0;
+ err_status= FALSE;
ctx->clear_handler();
ctx->enter_handler(hip);
thd->clear_error();
@@ -1114,7 +1090,7 @@ int sp_head::execute(THD *thd)
continue;
}
}
- } while (ret == 0 && !thd->killed);
+ } while (!err_status && !thd->killed);
thd->restore_active_arena(&execute_arena, &backup_arena);
@@ -1135,25 +1111,30 @@ int sp_head::execute(THD *thd)
state= EXECUTED;
done:
- DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
- ret, thd->killed, thd->query_error));
+ DBUG_PRINT("info", ("err_status: %d killed: %d query_error: %d",
+ err_status, thd->killed, thd->query_error));
if (thd->killed)
- ret= -1;
- /* If the DB has changed, the pointer has changed too, but the
- original thd->db will then have been freed */
+ err_status= TRUE;
+ /*
+ If the DB has changed, the pointer has changed too, but the
+ original thd->db will then have been freed
+ */
if (dbchanged)
{
- /* No access check when changing back to where we came from.
- (It would generate an error from mysql_change_db() when olddb=="") */
+ /*
+ No access check when changing back to where we came from.
+ (It would generate an error from mysql_change_db() when olddb=="")
+ */
if (! thd->killed)
- ret= mysql_change_db(thd, olddb, 1);
+ err_status|= mysql_change_db(thd, olddb, 1);
}
m_flags&= ~IS_INVOKED;
- DBUG_PRINT("info", ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x",
- (ulong) m_first_instance,
- (ulong) m_first_instance->m_first_free_instance,
- (ulong) this, m_recursion_level, m_flags));
+ DBUG_PRINT("info",
+ ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x",
+ (ulong) m_first_instance,
+ (ulong) m_first_instance->m_first_free_instance,
+ (ulong) this, m_recursion_level, m_flags));
/*
Check that we have one of following:
@@ -1173,7 +1154,7 @@ int sp_head::execute(THD *thd)
m_first_instance->m_first_free_instance->m_recursion_level ==
m_recursion_level + 1));
m_first_instance->m_first_free_instance= this;
- DBUG_RETURN(ret);
+ DBUG_RETURN(err_status);
}
@@ -1185,33 +1166,41 @@ int sp_head::execute(THD *thd)
SYNOPSIS
sp_head::execute_function()
- thd Thread handle
- argp Passed arguments (these are items from containing statement?)
- argcount Number of passed arguments. We need to check if this is
- correct.
- resp OUT Put result item here (q: is it a constant Item always?)
+ thd Thread handle
+ argp Passed arguments (these are items from containing
+ statement?)
+ argcount Number of passed arguments. We need to check if this is
+ correct.
+ return_value_fld Save result here.
RETURN
- 0 on OK
- other on error
+ FALSE on success
+ TRUE on error
*/
-int
-sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
+bool
+sp_head::execute_function(THD *thd, Item **argp, uint argcount,
+ Field *return_value_fld)
{
- Item **param_values;
+ Item_cache **param_values;
ulonglong binlog_save_options;
bool need_binlog_call;
- DBUG_ENTER("sp_head::execute_function");
- DBUG_PRINT("info", ("function %s", m_name.str));
- uint csize = m_pcont->max_pvars();
- uint params = m_pcont->current_pvars();
- uint hmax = m_pcont->max_handlers();
- uint cmax = m_pcont->max_cursors();
+ uint params;
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
- uint i;
- int ret= -1; // Assume error
+ bool err_status= FALSE;
+
+ DBUG_ENTER("sp_head::execute_function");
+ DBUG_PRINT("info", ("function %s", m_name.str));
+
+ params = m_pcont->context_pvars();
+
+ /*
+ Check that the function is called with all specified arguments.
+
+ If it is not, use my_error() to report an error, or it will not terminate
+ the invoking query properly.
+ */
if (argcount != params)
{
@@ -1221,37 +1210,56 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
*/
my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
"FUNCTION", m_qname.str, params, argcount);
- goto end;
+ DBUG_RETURN(TRUE);
}
- if (!(param_values= (Item**)thd->alloc(sizeof(Item*)*argcount)))
- DBUG_RETURN(-1);
+ /* Allocate param_values to be used for dumping the call into binlog. */
+
+ if (!(param_values= (Item_cache**)thd->alloc(sizeof(Item_cache*)*argcount)))
+ DBUG_RETURN(TRUE);
// QQ Should have some error checking here? (types, etc...)
- if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
- goto end;
+
+ if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) ||
+ nctx->init(thd))
+ {
+ delete nctx; /* Delete nctx if it was init() that failed. */
+ DBUG_RETURN(TRUE);
+ }
+
#ifndef DBUG_OFF
- nctx->owner= this;
+ nctx->sp= this;
#endif
- for (i= 0 ; i < argcount ; i++)
+
+ /* Pass arguments. */
+
{
- sp_pvar_t *pvar = m_pcont->find_pvar(i);
- Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE);
- param_values[i]= it;
+ uint i;
+
+ for (i= 0 ; i < argcount ; i++)
+ {
+ if (!argp[i]->fixed && argp[i]->fix_fields(thd, &argp[i]))
+ {
+ err_status= TRUE;
+ break;
+ }
- if (!it)
- goto end; // EOM error
- nctx->push_item(it);
- }
+ param_values[i]= Item_cache::get_cache(argp[i]->result_type());
+ param_values[i]->store(argp[i]);
+ if (nctx->set_variable(thd, i, param_values[i]))
+ {
+ err_status= TRUE;
+ break;
+ }
+ }
+ }
- /*
- The rest of the frame are local variables which are all IN.
- Push NULLs to get the right size (and make the reuse mechanism work) -
- the will be initialized by set instructions in each frame.
- */
- for (; i < csize ; i++)
- nctx->push_item(NULL);
+ if (err_status)
+ {
+ delete nctx;
+ DBUG_RETURN(TRUE);
+ }
thd->spcont= nctx;
@@ -1264,7 +1272,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
}
thd->options&= ~OPTION_BIN_LOG;
- ret= execute(thd);
+ err_status= execute(thd);
thd->options= binlog_save_options;
if (need_binlog_call)
@@ -1280,9 +1288,18 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
bufstr.append('(');
for (uint i=0; i < argcount; i++)
{
+ String str_value_holder;
+ String *str_value;
+
if (i)
bufstr.append(',');
- param_values[i]->print(&bufstr);
+
+ str_value= sp_get_item_value(param_values[i], &str_value_holder);
+
+ if (str_value)
+ bufstr.append(*str_value);
+ else
+ bufstr.append(STRING_WITH_LEN("NULL"));
}
bufstr.append(')');
@@ -1298,26 +1315,22 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
reset_dynamic(&thd->user_var_events);
}
- if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
+ if (m_type == TYPE_ENUM_FUNCTION && !err_status)
{
/* We need result only in function but not in trigger */
- Item *it= nctx->get_result();
- if (it)
- *resp= sp_eval_func_item(thd, &it, m_returns, NULL, FALSE);
- else
+ if (!nctx->is_return_value_set())
{
my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
- ret= -1;
+ err_status= TRUE;
}
}
nctx->pop_all_cursors(); // To avoid memory leaks after an error
- delete nctx; // Doesn't do anything
+ delete nctx;
thd->spcont= octx;
-end:
- DBUG_RETURN(ret);
+ DBUG_RETURN(err_status);
}
@@ -1349,17 +1362,15 @@ static Item_func_get_user_var *item_is_user_var(Item *it)
- copy back values of INOUT and OUT parameters
RETURN
- 0 Ok
- -1 Error
+ FALSE on success
+ TRUE on error
*/
-int sp_head::execute_procedure(THD *thd, List<Item> *args)
+bool
+sp_head::execute_procedure(THD *thd, List<Item> *args)
{
- int ret= 0;
- uint csize = m_pcont->max_pvars();
- uint params = m_pcont->current_pvars();
- uint hmax = m_pcont->max_handlers();
- uint cmax = m_pcont->max_cursors();
+ bool err_status= FALSE;
+ uint params = m_pcont->context_pvars();
sp_rcontext *save_spcont, *octx;
sp_rcontext *nctx = NULL;
DBUG_ENTER("sp_head::execute_procedure");
@@ -1369,16 +1380,21 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
{
my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
m_qname.str, params, args->elements);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
save_spcont= octx= thd->spcont;
if (! octx)
{ // Create a temporary old context
- if (!(octx= new sp_rcontext(octx, csize, hmax, cmax)))
- DBUG_RETURN(-1);
+ if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) ||
+ octx->init(thd))
+ {
+ delete octx; /* Delete octx if it was init() that failed. */
+ DBUG_RETURN(TRUE);
+ }
+
#ifndef DBUG_OFF
- octx->owner= 0;
+ octx->sp= 0;
#endif
thd->spcont= octx;
@@ -1386,63 +1402,62 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->spcont->callers_arena= thd;
}
- if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
+ if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
+ nctx->init(thd))
{
+ delete nctx; /* Delete nctx if it was init() that failed. */
thd->spcont= save_spcont;
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
#ifndef DBUG_OFF
- nctx->owner= this;
+ nctx->sp= this;
#endif
- if (csize > 0 || hmax > 0 || cmax > 0)
+ if (params > 0)
{
- Item_null *nit= NULL; // Re-use this, and only create if needed
- uint i;
- List_iterator<Item> li(*args);
- Item *it;
+ List_iterator<Item> it_args(*args);
- /* Evaluate SP arguments (i.e. get the values passed as parameters) */
- // QQ: Should do type checking?
DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str));
- for (i = 0 ; (it= li++) && i < params ; i++)
+
+ for (uint i= 0 ; i < params ; i++)
{
+ Item *arg_item= it_args++;
sp_pvar_t *pvar= m_pcont->find_pvar(i);
- if (pvar)
+ if (!arg_item)
+ break;
+
+ if (!pvar)
+ continue;
+
+ if (pvar->mode != sp_param_in)
{
- if (pvar->mode != sp_param_in)
- {
- if (!it->is_splocal() && !item_is_user_var(it))
- {
- my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
- ret= -1;
- break;
- }
- }
- if (pvar->mode == sp_param_out)
- {
- if (! nit)
- {
- if (!(nit= new Item_null()))
- {
- ret= -1;
- break;
- }
- }
- nctx->push_item(nit); // OUT
- }
- else
- {
- Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE);
-
- if (!it2)
- {
- ret= -1; // Eval failed
- break;
- }
- nctx->push_item(it2); // IN or INOUT
- }
+ if (!arg_item->is_splocal() && !item_is_user_var(arg_item))
+ {
+ my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
+ err_status= TRUE;
+ break;
+ }
+ }
+
+ if (pvar->mode == sp_param_out)
+ {
+ Item_null *null_item= new Item_null();
+
+ if (!null_item ||
+ nctx->set_variable(thd, i, null_item))
+ {
+ err_status= TRUE;
+ break;
+ }
+ }
+ else
+ {
+ if (nctx->set_variable(thd, i, *it_args.ref()))
+ {
+ err_status= TRUE;
+ break;
+ }
}
}
@@ -1455,20 +1470,12 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
close_thread_tables(thd, 0, 0);
DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str));
-
- /*
- The rest of the frame are local variables which are all IN.
- Push NULLs to get the right size (and make the reuse mechanism work) -
- the will be initialized by set instructions in each frame.
- */
- for (; i < csize ; i++)
- nctx->push_item(NULL);
}
thd->spcont= nctx;
- if (! ret)
- ret= execute(thd);
+ if (!err_status)
+ err_status= execute(thd);
/*
In the case when we weren't able to employ reuse mechanism for
@@ -1478,75 +1485,67 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
*/
thd->spcont->callers_arena= octx->callers_arena;
- if (!ret && csize > 0)
+ if (!err_status && params > 0)
{
- List_iterator<Item> li(*args);
- Item *it;
+ List_iterator<Item> it_args(*args);
/*
Copy back all OUT or INOUT values to the previous frame, or
set global user variables
*/
- for (uint i = 0 ; (it= li++) && i < params ; i++)
+ for (uint i= 0 ; i < params ; i++)
{
+ Item *arg_item= it_args++;
+
+ if (!arg_item)
+ break;
+
sp_pvar_t *pvar= m_pcont->find_pvar(i);
- if (pvar->mode != sp_param_in)
+ if (pvar->mode == sp_param_in)
+ continue;
+
+ if (arg_item->is_splocal())
{
- if (it->is_splocal())
- {
- // Have to copy the item to the caller's mem_root
- Item *copy;
- uint offset= static_cast<Item_splocal *>(it)->get_offset();
- Item *val= nctx->get_item(i);
- Item *orig= octx->get_item(offset);
-
- /*
- We might need to allocate new item if we weren't able to
- employ reuse mechanism. Then we should do it on the callers arena.
- */
- copy= sp_eval_func_item(thd, &val, pvar->type, orig, TRUE); // Copy
-
- if (!copy)
- {
- ret= -1;
- break;
- }
- if (copy != orig)
- octx->set_item(offset, copy);
- }
- else
+ if (octx->set_variable(thd,
+ ((Item_splocal*) arg_item)->get_var_idx(),
+ nctx->get_item(i)))
+ {
+ err_status= TRUE;
+ break;
+ }
+ }
+ else
+ {
+ Item_func_get_user_var *guv= item_is_user_var(arg_item);
+
+ if (guv)
{
- Item_func_get_user_var *guv= item_is_user_var(it);
-
- if (guv)
- {
- Item *item= nctx->get_item(i);
- Item_func_set_user_var *suv;
-
- suv= new Item_func_set_user_var(guv->get_name(), item);
- /*
- we do not check suv->fixed, because it can't be fixed after
- creation
- */
- suv->fix_fields(thd, &item);
- suv->fix_length_and_dec();
- suv->check();
- suv->update();
- }
+ Item *item= nctx->get_item(i);
+ Item_func_set_user_var *suv;
+
+ suv= new Item_func_set_user_var(guv->get_name(), item);
+ /*
+ Item_func_set_user_var is not fixed after construction,
+ call fix_fields().
+ */
+ if ((err_status= test(!suv || suv->fix_fields(thd, &item) ||
+ suv->check() || suv->update())))
+ break;
}
}
+
}
}
if (!save_spcont)
- delete octx; // Does nothing
+ delete octx;
nctx->pop_all_cursors(); // To avoid memory leaks after an error
- delete nctx; // Does nothing
+ delete nctx;
thd->spcont= save_spcont;
- DBUG_RETURN(ret);
+ DBUG_RETURN(err_status);
}
@@ -1582,6 +1581,15 @@ sp_head::reset_lex(THD *thd)
sublex->trg_chistics= oldlex->trg_chistics;
sublex->trg_table_fields.empty();
sublex->sp_lex_in_use= FALSE;
+
+ /* Reset type info. */
+
+ sublex->charset= NULL;
+ sublex->length= NULL;
+ sublex->dec= NULL;
+ sublex->interval_list.empty();
+ sublex->type= 0;
+
DBUG_VOID_RETURN;
}
@@ -1676,6 +1684,55 @@ sp_head::check_backpatch(THD *thd)
return 0;
}
+
+/*
+ Prepare an instance of create_field for field creation (fill all necessary
+ attributes).
+
+ SYNOPSIS
+ sp_head::fill_field_definition()
+ thd [IN] Thread handle
+ lex [IN] Yacc parsing context
+ field_type [IN] Field type
+ field_def [OUT] An instance of create_field to be filled
+
+ RETURN
+ FALSE on success
+ TRUE on error
+*/
+
+bool
+sp_head::fill_field_definition(THD *thd, LEX *lex,
+ enum enum_field_types field_type,
+ create_field *field_def)
+{
+ LEX_STRING cmt = { 0, 0 };
+ uint unused1= 0;
+ int unused2= 0;
+
+ if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
+ lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
+ &lex->interval_list,
+ (lex->charset ? lex->charset : default_charset_info),
+ lex->uint_geom_type))
+ return TRUE;
+
+ if (field_def->interval_list.elements)
+ field_def->interval= create_typelib(mem_root, field_def,
+ &field_def->interval_list);
+
+ sp_prepare_create_field(thd, field_def);
+
+ if (prepare_create_field(field_def, &unused1, &unused2, &unused2,
+ HA_CAN_GEOMETRY))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
void
sp_head::set_info(longlong created, longlong modified,
st_sp_chistics *chistics, ulong sql_mode)
@@ -2104,7 +2161,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
cleanup_items() is called in sp_head::execute()
*/
- return res;
+ return res || thd->net.report_error;
}
@@ -2213,7 +2270,27 @@ sp_instr_set::execute(THD *thd, uint *nextp)
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
- int res= thd->spcont->set_item_eval(thd, m_offset, &m_value, m_type);
+ int res= thd->spcont->set_variable(thd, m_offset, m_value);
+
+ if (res && thd->spcont->found_handler_here())
+ {
+ /*
+ Failed to evaluate the value, and a handler has been found. Reset the
+ variable to NULL.
+ */
+
+ if (thd->spcont->set_variable(thd, m_offset, 0))
+ {
+ /* If this also failed, let's abort. */
+
+ sp_rcontext *spcont= thd->spcont;
+
+ thd->spcont= 0; /* Avoid handlers */
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ spcont->clear_handler();
+ thd->spcont= spcont;
+ }
+ }
*nextp = m_ip+1;
return res;
@@ -2483,20 +2560,22 @@ sp_instr_freturn::execute(THD *thd, uint *nextp)
int
sp_instr_freturn::exec_core(THD *thd, uint *nextp)
{
- Item *it;
- int res;
+ /*
+ Change <next instruction pointer>, so that this will be the last
+ instruction in the stored function.
+ */
- it= sp_eval_func_item(thd, &m_value, m_type, NULL, TRUE);
- if (! it)
- res= -1;
- else
- {
- res= 0;
- thd->spcont->set_result(it);
- }
*nextp= UINT_MAX;
- return res;
+ /*
+ Evaluate the value of return expression and store it in current runtime
+ context.
+
+ NOTE: It's necessary to evaluate result item right here, because we must
+ do it in scope of execution the current context/block.
+ */
+
+ return thd->spcont->set_return_value(thd, m_value);
}
void
@@ -2619,7 +2698,6 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp)
*nextp= m_dest;
else
{
- thd->spcont->restore_variables(m_frame);
*nextp= thd->spcont->pop_hstack();
}
thd->spcont->exit_handler();
@@ -2937,6 +3015,65 @@ sp_instr_error::print(String *str)
}
+/**************************************************************************
+ sp_instr_set_case_expr class implementation
+**************************************************************************/
+
+int
+sp_instr_set_case_expr::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_set_case_expr::execute");
+
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+
+int
+sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
+{
+ int res= thd->spcont->set_case_expr(thd, m_case_expr_id, m_case_expr);
+
+ if (res &&
+ !thd->spcont->get_case_expr(m_case_expr_id) &&
+ thd->spcont->found_handler_here())
+ {
+ /*
+ Failed to evaluate the value, the case expression is still not
+ initialized, and a handler has been found. Set to NULL so we can continue.
+ */
+
+ Item *null_item= new Item_null();
+
+ if (!null_item ||
+ thd->spcont->set_case_expr(thd, m_case_expr_id, null_item))
+ {
+ /* If this also failed, we have to abort. */
+
+ sp_rcontext *spcont= thd->spcont;
+
+ thd->spcont= 0; /* Avoid handlers */
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ spcont->clear_handler();
+ thd->spcont= spcont;
+ }
+ }
+
+ *nextp = m_ip+1;
+
+ return res; /* no error */
+}
+
+
+void
+sp_instr_set_case_expr::print(String *str)
+{
+ str->append(STRING_WITH_LEN("set_case_expr "));
+ str->qs_append(m_case_expr_id);
+ str->append(' ');
+ m_case_expr->print(str);
+}
+
+
/* ------------------------------------------------------------------ */
/*
@@ -3109,10 +3246,12 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
SYNOPSIS
add_used_tables_to_table_list()
- thd - thread context
- query_tables_last_ptr - (in/out) pointer the next_global member of last
- element of the list where tables will be added
- (or to its root).
+ thd [in] Thread context
+ query_tables_last_ptr [in/out] Pointer to the next_global member of
+ last element of the list where tables
+ will be added (or to its root).
+ belong_to_view [in] Uppermost view which uses this routine,
+ 0 if none.
DESCRIPTION
Converts multi-set of tables used by this routine to table list and adds
@@ -3127,7 +3266,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
bool
sp_head::add_used_tables_to_table_list(THD *thd,
- TABLE_LIST ***query_tables_last_ptr)
+ TABLE_LIST ***query_tables_last_ptr,
+ TABLE_LIST *belong_to_view)
{
uint i;
Query_arena *arena, backup;
@@ -3170,6 +3310,7 @@ sp_head::add_used_tables_to_table_list(THD *thd,
table->lock_type= stab->lock_type;
table->cacheable_table= 1;
table->prelocking_placeholder= 1;
+ table->belong_to_view= belong_to_view;
/* Everyting else should be zeroed */
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 6f4a2de1518..2eebd35f6dc 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -33,6 +33,9 @@
Item_result
sp_map_result_type(enum enum_field_types type);
+Item::Type
+sp_map_item_type(enum enum_field_types type);
+
uint
sp_get_flags_for_command(LEX *lex);
@@ -123,12 +126,9 @@ public:
/* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
int m_type;
uint m_flags; // Boolean attributes of a stored routine
- enum enum_field_types m_returns; // For FUNCTIONs only
- Field::geometry_type m_geom_returns;
- CHARSET_INFO *m_returns_cs; // For FUNCTIONs only
- TYPELIB *m_returns_typelib; // For FUNCTIONs only
- uint m_returns_len; // For FUNCTIONs only
- uint m_returns_pack; // For FUNCTIONs only
+
+ create_field m_return_field_def; /* This is used for FUNCTIONs only. */
+
uchar *m_tmp_query; // Temporary pointer to sub query string
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
st_sp_chistics *m_chistics;
@@ -202,9 +202,6 @@ public:
void
init_strings(THD *thd, LEX *lex, sp_name *name);
- TYPELIB *
- create_typelib(List<String> *src);
-
int
create(THD *thd);
@@ -214,10 +211,10 @@ public:
void
destroy();
- int
- execute_function(THD *thd, Item **args, uint argcount, Item **resp);
+ bool
+ execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
- int
+ bool
execute_procedure(THD *thd, List<Item> *args);
int
@@ -278,7 +275,12 @@ public:
char *create_string(THD *thd, ulong *lenp);
- Field *make_field(uint max_length, const char *name, TABLE *dummy);
+ Field *create_result_field(uint field_max_length, const char *field_name,
+ TABLE *table);
+
+ bool fill_field_definition(THD *thd, LEX *lex,
+ enum enum_field_types field_type,
+ create_field *field_def);
void set_info(longlong created, longlong modified,
st_sp_chistics *chistics, ulong sql_mode);
@@ -308,7 +310,8 @@ public:
/* Add tables used by routine to the table list. */
bool add_used_tables_to_table_list(THD *thd,
- TABLE_LIST ***query_tables_last_ptr);
+ TABLE_LIST ***query_tables_last_ptr,
+ TABLE_LIST *belong_to_view);
/*
Check if this stored routine contains statements disallowed
@@ -363,7 +366,7 @@ private:
*/
HASH m_sptabs;
- int
+ bool
execute(THD *thd);
/*
@@ -1074,6 +1077,31 @@ private:
}; // class sp_instr_error : public sp_instr
+class sp_instr_set_case_expr :public sp_instr
+{
+public:
+
+ sp_instr_set_case_expr(uint ip, sp_pcontext *ctx, uint case_expr_id,
+ Item *case_expr, LEX *lex)
+ :sp_instr(ip, ctx), m_case_expr_id(case_expr_id), m_case_expr(case_expr),
+ m_lex_keeper(lex, TRUE)
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+private:
+
+ uint m_case_expr_id;
+ Item *m_case_expr;
+ sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_set_case_expr : public sp_instr
+
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool
sp_change_security_context(THD *thd, sp_head *sp,
@@ -1086,8 +1114,10 @@ TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
thr_lock_type locktype);
+Item *
+sp_prepare_func_item(THD* thd, Item **it_addr);
-Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
- Item *reuse, bool use_callers_arena);
+bool
+sp_eval_expr(THD *thd, Field *result_field, Item *expr_item);
#endif /* _SP_HEAD_H_ */
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 147173ab4d8..a8bd8cd2aa0 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -51,21 +51,26 @@ sp_cond_check(LEX_STRING *sqlstate)
}
sp_pcontext::sp_pcontext(sp_pcontext *prev)
- : Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
- m_handlers(0), m_parent(prev)
+ :Sql_alloc(), m_total_pvars(0), m_csubsize(0), m_hsubsize(0),
+ m_handlers(0), m_parent(prev), m_pboundary(0)
{
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
+ VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int), 16, 8));
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8));
VOID(my_init_dynamic_array(&m_handler, sizeof(sp_cond_type_t *), 16, 8));
m_label.empty();
m_children.empty();
if (!prev)
+ {
m_poffset= m_coffset= 0;
+ m_num_case_exprs= 0;
+ }
else
{
- m_poffset= prev->current_pvars();
+ m_poffset= prev->m_poffset + prev->m_total_pvars;
m_coffset= prev->current_cursors();
+ m_num_case_exprs= prev->get_num_case_exprs();
}
}
@@ -81,6 +86,7 @@ sp_pcontext::destroy()
m_children.empty();
m_label.empty();
delete_dynamic(&m_pvar);
+ delete_dynamic(&m_case_expr_id_lst);
delete_dynamic(&m_cond);
delete_dynamic(&m_cursor);
delete_dynamic(&m_handler);
@@ -99,16 +105,19 @@ sp_pcontext::push_context()
sp_pcontext *
sp_pcontext::pop_context()
{
- uint submax= max_pvars();
+ m_parent->m_total_pvars= m_parent->m_total_pvars + m_total_pvars;
- if (submax > m_parent->m_psubsize)
- m_parent->m_psubsize= submax;
- submax= max_handlers();
+ uint submax= max_handlers();
if (submax > m_parent->m_hsubsize)
m_parent->m_hsubsize= submax;
+
submax= max_cursors();
if (submax > m_parent->m_csubsize)
m_parent->m_csubsize= submax;
+
+ if (m_num_case_exprs > m_parent->m_num_case_exprs)
+ m_parent->m_num_case_exprs= m_num_case_exprs;
+
return m_parent;
}
@@ -150,7 +159,7 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx)
sp_pvar_t *
sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped)
{
- uint i= m_pvar.elements;
+ uint i= m_pvar.elements - m_pboundary;
while (i--)
{
@@ -191,26 +200,29 @@ sp_pcontext::find_pvar(uint offset)
return NULL; // index out of bounds
}
-void
+sp_pvar_t *
sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type,
sp_param_mode_t mode)
{
sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
- if (p)
- {
- if (m_pvar.elements == m_psubsize)
- m_psubsize+= 1;
- p->name.str= name->str;
- p->name.length= name->length;
- p->type= type;
- p->mode= mode;
- p->offset= current_pvars();
- p->dflt= NULL;
- insert_dynamic(&m_pvar, (gptr)&p);
- }
+ if (!p)
+ return NULL;
+
+ ++m_total_pvars;
+
+ p->name.str= name->str;
+ p->name.length= name->length;
+ p->type= type;
+ p->mode= mode;
+ p->offset= current_pvars();
+ p->dflt= NULL;
+ insert_dynamic(&m_pvar, (gptr)&p);
+
+ return p;
}
+
sp_label_t *
sp_pcontext::push_label(char *name, uint ip)
{
@@ -354,6 +366,29 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
return FALSE;
}
+
+void
+sp_pcontext::retrieve_field_definitions(List<create_field> *field_def_lst)
+{
+ /* Put local/context fields in the result list. */
+
+ for (uint i = 0; i < m_pvar.elements; ++i)
+ {
+ sp_pvar_t *var_def;
+ get_dynamic(&m_pvar, (gptr) &var_def, i);
+
+ field_def_lst->push_back(&var_def->field_def);
+ }
+
+ /* Put the fields of the enclosed contexts in the result list. */
+
+ List_iterator_fast<sp_pcontext> li(m_children);
+ sp_pcontext *ctx;
+
+ while ((ctx = li++))
+ ctx->retrieve_field_definitions(field_def_lst);
+}
+
/*
Find a cursor by offset from the top.
This is only used for debugging.
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index b8dd1742f7e..6d803362d86 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -34,8 +34,16 @@ typedef struct sp_pvar
LEX_STRING name;
enum enum_field_types type;
sp_param_mode_t mode;
- uint offset; // Offset in current frame
+
+ /*
+ offset -- basically, this is an index of variable in the scope of root
+ parsing context. This means, that all variables in a stored routine
+ have distinct indexes/offsets.
+ */
+ uint offset;
+
Item *dflt;
+ create_field field_def;
} sp_pvar_t;
@@ -114,9 +122,9 @@ class sp_pcontext : public Sql_alloc
//
inline uint
- max_pvars()
+ total_pvars()
{
- return m_psubsize + m_pvar.elements;
+ return m_total_pvars;
}
inline uint
@@ -155,16 +163,15 @@ class sp_pcontext : public Sql_alloc
p->dflt= it;
}
- void
+ sp_pvar_t *
push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
- // Pop the last 'num' slots of the frame
- inline void
- pop_pvar(uint num = 1)
- {
- while (num--)
- pop_dynamic(&m_pvar);
- }
+ /*
+ Retrieve definitions of fields from the current context and its
+ children.
+ */
+ void
+ retrieve_field_definitions(List<create_field> *field_def_lst);
// Find by name
sp_pvar_t *
@@ -174,6 +181,55 @@ class sp_pcontext : public Sql_alloc
sp_pvar_t *
find_pvar(uint offset);
+ /*
+ Set the current scope boundary (for default values).
+ The argument is the number of variables to skip.
+ */
+ inline void
+ declare_var_boundary(uint n)
+ {
+ m_pboundary= n;
+ }
+
+ /*
+ CASE expressions support.
+ */
+
+ inline int
+ register_case_expr()
+ {
+ return m_num_case_exprs++;
+ }
+
+ inline int
+ get_num_case_exprs() const
+ {
+ return m_num_case_exprs;
+ }
+
+ inline bool
+ push_case_expr_id(int case_expr_id)
+ {
+ return insert_dynamic(&m_case_expr_id_lst, (gptr) &case_expr_id);
+ }
+
+ inline void
+ pop_case_expr_id()
+ {
+ pop_dynamic(&m_case_expr_id_lst);
+ }
+
+ inline int
+ get_current_case_expr_id() const
+ {
+ int case_expr_id;
+
+ get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (gptr) &case_expr_id,
+ m_case_expr_id_lst.elements - 1);
+
+ return case_expr_id;
+ }
+
//
// Labels
//
@@ -270,8 +326,18 @@ class sp_pcontext : public Sql_alloc
protected:
+ /*
+ m_total_pvars -- number of variables (including all types of arguments)
+ in this context including all children contexts.
+
+ m_total_pvars >= m_pvar.elements.
+
+ m_total_pvars of the root parsing context contains number of all
+ variables (including arguments) in all enclosed contexts.
+ */
+ uint m_total_pvars;
+
// The maximum sub context's framesizes
- uint m_psubsize;
uint m_csubsize;
uint m_hsubsize;
uint m_handlers; // No. of handlers in this context
@@ -280,10 +346,31 @@ private:
sp_pcontext *m_parent; // Parent context
- uint m_poffset; // Variable offset for this context
+ /*
+ m_poffset -- basically, this is an index of the first variable in this
+ parsing context.
+
+ m_poffset is 0 for root context.
+
+ Since now each variable is stored in separate place, no reuse is done,
+ so m_poffset is different for all enclosed contexts.
+ */
+ uint m_poffset;
+
uint m_coffset; // Cursor offset for this context
+ /*
+ Boundary for finding variables in this context. This is the number
+ of variables currently "invisible" to default clauses.
+ This is normally 0, but will be larger during parsing of
+ DECLARE ... DEFAULT, to get the scope right for DEFAULT values.
+ */
+ uint m_pboundary;
+
+ int m_num_case_exprs;
+
DYNAMIC_ARRAY m_pvar; // Parameters/variables
+ DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */
DYNAMIC_ARRAY m_cond; // Conditions
DYNAMIC_ARRAY m_cursor; // Cursors
DYNAMIC_ARRAY m_handler; // Handlers, for checking of duplicates
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index ccb38358049..eca87e69f8e 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -29,41 +29,137 @@
#include "sp_rcontext.h"
#include "sp_pcontext.h"
-sp_rcontext::sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax)
- : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
- m_ihsp(0), m_hfound(-1), m_ccount(0), m_prev_ctx(prev)
+
+sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
+ Field *return_value_fld,
+ sp_rcontext *prev_runtime_ctx)
+ :m_root_parsing_ctx(root_parsing_ctx),
+ m_var_table(0),
+ m_var_items(0),
+ m_return_value_fld(return_value_fld),
+ m_return_value_set(FALSE),
+ m_hcount(0),
+ m_hsp(0),
+ m_ihsp(0),
+ m_hfound(-1),
+ m_ccount(0),
+ m_case_expr_holders(0),
+ m_prev_runtime_ctx(prev_runtime_ctx)
{
- m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
- m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
- m_hstack= (uint *)sql_alloc(hmax * sizeof(uint));
- m_in_handler= (uint *)sql_alloc(hmax * sizeof(uint));
- m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *));
- m_saved.empty();
}
-int
-sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr,
- enum_field_types type)
+sp_rcontext::~sp_rcontext()
+{
+ if (m_var_table)
+ free_blobs(m_var_table);
+}
+
+
+/*
+ Initialize sp_rcontext instance.
+
+ SYNOPSIS
+ thd Thread handle
+ RETURN
+ FALSE on success
+ TRUE on error
+*/
+
+bool sp_rcontext::init(THD *thd)
+{
+ if (init_var_table(thd) || init_var_items())
+ return TRUE;
+
+ return
+ !(m_handler=
+ (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handlers() *
+ sizeof(sp_handler_t))) ||
+ !(m_hstack=
+ (uint*)thd->alloc(m_root_parsing_ctx->max_handlers() *
+ sizeof(uint))) ||
+ !(m_in_handler=
+ (uint*)thd->alloc(m_root_parsing_ctx->max_handlers() *
+ sizeof(uint))) ||
+ !(m_cstack=
+ (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursors() *
+ sizeof(sp_cursor*))) ||
+ !(m_case_expr_holders=
+ (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() *
+ sizeof (Item_cache*)));
+}
+
+
+/*
+ Create and initialize a table to store SP-vars.
+
+ SYNOPSIS
+ thd Thread handler.
+ RETURN
+ FALSE on success
+ TRUE on error
+*/
+
+bool
+sp_rcontext::init_var_table(THD *thd)
{
- Item *it;
- Item *reuse_it;
- /* sp_eval_func_item will use callers_arena */
- int res;
-
- reuse_it= get_item(idx);
- it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE);
- if (! it)
- res= -1;
- else
+ List<create_field> field_def_lst;
+
+ if (!m_root_parsing_ctx->total_pvars())
+ return FALSE;
+
+ m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
+
+ DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->total_pvars());
+
+ if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
+ return TRUE;
+
+ m_var_table->copy_blobs= TRUE;
+ m_var_table->alias= "";
+
+ return FALSE;
+}
+
+
+/*
+ Create and initialize an Item-adapter (Item_field) for each SP-var field.
+
+ RETURN
+ FALSE on success
+ TRUE on error
+*/
+
+bool
+sp_rcontext::init_var_items()
+{
+ uint idx;
+ uint num_vars= m_root_parsing_ctx->total_pvars();
+
+ if (!(m_var_items= (Item**) sql_alloc(num_vars * sizeof (Item *))))
+ return TRUE;
+
+ for (idx = 0; idx < num_vars; ++idx)
{
- res= 0;
- set_item(idx, it);
+ if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx])))
+ return TRUE;
}
- return res;
+ return FALSE;
}
+
+bool
+sp_rcontext::set_return_value(THD *thd, Item *return_value_item)
+{
+ DBUG_ASSERT(m_return_value_fld);
+
+ m_return_value_set = TRUE;
+
+ return sp_eval_expr(thd, m_return_value_fld, return_value_item);
+}
+
+
bool
sp_rcontext::find_handler(uint sql_errno,
MYSQL_ERROR::enum_warning_level level)
@@ -117,32 +213,14 @@ sp_rcontext::find_handler(uint sql_errno,
}
if (found < 0)
{
- if (m_prev_ctx)
- return m_prev_ctx->find_handler(sql_errno, level);
+ if (m_prev_runtime_ctx)
+ return m_prev_runtime_ctx->find_handler(sql_errno, level);
return FALSE;
}
m_hfound= found;
return TRUE;
}
-void
-sp_rcontext::save_variables(uint fp)
-{
- while (fp < m_count)
- {
- m_saved.push_front(m_frame[fp]);
- m_frame[fp++]= NULL; // Prevent reuse
- }
-}
-
-void
-sp_rcontext::restore_variables(uint fp)
-{
- uint i= m_count;
-
- while (i-- > fp)
- m_frame[i]= m_saved.pop();
-}
void
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
@@ -150,6 +228,7 @@ sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i);
}
+
void
sp_rcontext::pop_cursors(uint count)
{
@@ -160,6 +239,40 @@ sp_rcontext::pop_cursors(uint count)
}
+int
+sp_rcontext::set_variable(THD *thd, uint var_idx, Item *value)
+{
+ return set_variable(thd, m_var_table->field[var_idx], value);
+}
+
+
+int
+sp_rcontext::set_variable(THD *thd, Field *field, Item *value)
+{
+ if (!value)
+ {
+ field->set_null();
+ return 0;
+ }
+
+ return sp_eval_expr(thd, field, value);
+}
+
+
+Item *
+sp_rcontext::get_item(uint var_idx)
+{
+ return m_var_items[var_idx];
+}
+
+
+Item **
+sp_rcontext::get_item_addr(uint var_idx)
+{
+ return m_var_items + var_idx;
+}
+
+
/*
*
* sp_cursor
@@ -263,6 +376,102 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
}
+/*
+ Create an instance of appropriate Item_cache class depending on the
+ specified type in the callers arena.
+
+ SYNOPSIS
+ thd thread handler
+ result_type type of the expression
+
+ RETURN
+ Pointer to valid object on success
+ NULL on error
+
+ NOTE
+ We should create cache items in the callers arena, as they are used
+ between in several instructions.
+*/
+
+Item_cache *
+sp_rcontext::create_case_expr_holder(THD *thd, Item_result result_type)
+{
+ Item_cache *holder;
+ Query_arena current_arena;
+
+ thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
+
+ holder= Item_cache::get_cache(result_type);
+
+ thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);
+
+ return holder;
+}
+
+
+/*
+ Set CASE expression to the specified value.
+
+ SYNOPSIS
+ thd thread handler
+ case_expr_id identifier of the CASE expression
+ case_expr_item a value of the CASE expression
+
+ RETURN
+ FALSE on success
+ TRUE on error
+
+ NOTE
+ The idea is to reuse Item_cache for the expression of the one CASE
+ statement. This optimization takes place when there is CASE statement
+ inside of a loop. So, in other words, we will use the same object on each
+ iteration instead of creating a new one for each iteration.
+
+ TODO
+ Hypothetically, a type of CASE expression can be different for each
+ iteration. For instance, this can happen if the expression contains a
+ session variable (something like @@VAR) and its type is changed from one
+ iteration to another.
+
+ In order to cope with this problem, we check type each time, when we use
+ already created object. If the type does not match, we re-create Item.
+ This also can (should?) be optimized.
+*/
+
+int
+sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item)
+{
+ if (!(case_expr_item= sp_prepare_func_item(thd, &case_expr_item)))
+ return TRUE;
+
+ if (!m_case_expr_holders[case_expr_id] ||
+ m_case_expr_holders[case_expr_id]->result_type() !=
+ case_expr_item->result_type())
+ {
+ m_case_expr_holders[case_expr_id]=
+ create_case_expr_holder(thd, case_expr_item->result_type());
+ }
+
+ m_case_expr_holders[case_expr_id]->store(case_expr_item);
+
+ return FALSE;
+}
+
+
+Item *
+sp_rcontext::get_case_expr(int case_expr_id)
+{
+ return m_case_expr_holders[case_expr_id];
+}
+
+
+Item **
+sp_rcontext::get_case_expr_addr(int case_expr_id)
+{
+ return (Item**) m_case_expr_holders + case_expr_id;
+}
+
+
/***************************************************************************
Select_fetch_into_spvars
****************************************************************************/
@@ -294,11 +503,8 @@ bool Select_fetch_into_spvars::send_data(List<Item> &items)
*/
for (; pv= pv_iter++, item= item_iter++; )
{
- Item *reuse= thd->spcont->get_item(pv->offset);
- /* Evaluate a new item on the arena of the calling instruction */
- Item *it= sp_eval_func_item(thd, &item, pv->type, reuse, TRUE);
-
- thd->spcont->set_item(pv->offset, it);
+ if (thd->spcont->set_variable(thd, pv->offset, item))
+ return TRUE;
}
return FALSE;
}
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index d54188aa96f..c3c05228eef 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -43,12 +43,22 @@ typedef struct
/*
- This is a run context? of one SP ?
- THis is
- - a stack of cursors?
- - a stack of handlers?
- - a stack of Items ?
- - a stack of instruction locations in SP?
+ This class is a runtime context of a Stored Routine. It is used in an
+ execution and is intended to contain all dynamic objects (i.e. objects, which
+ can be changed during execution), such as:
+ - stored routine variables;
+ - cursors;
+ - handlers;
+
+ Runtime context is used with sp_head class. sp_head class is intended to
+ contain all static things, related to the stored routines (code, for example).
+ sp_head instance creates runtime context for the execution of a stored
+ routine.
+
+ There is a parsing context (an instance of sp_pcontext class), which is used
+ on parsing stage. However, now it contains some necessary for an execution
+ things, such as definition of used stored routine variables. That's why
+ runtime context needs a reference to the parsing context.
*/
class sp_rcontext : public Sql_alloc
@@ -68,62 +78,34 @@ class sp_rcontext : public Sql_alloc
#ifndef DBUG_OFF
/*
- Routine to which this Item_splocal belongs. Used for checking if correct
- runtime context is used for variable handling.
+ The routine for which this runtime context is created. Used for checking
+ if correct runtime context is used for variable handling.
*/
- sp_head *owner;
+ sp_head *sp;
#endif
- sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax);
+ sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld,
+ sp_rcontext *prev_runtime_ctx);
+ bool init(THD *thd);
- ~sp_rcontext()
- {
- // Not needed?
- //sql_element_free(m_frame);
- //m_saved.empty();
- }
-
- inline void
- push_item(Item *i)
- {
- if (m_count < m_fsize)
- m_frame[m_count++]= i;
- }
+ ~sp_rcontext();
- inline void
- set_item(uint idx, Item *i)
- {
- if (idx < m_count)
- m_frame[idx]= i;
- }
-
- /* Returns 0 on success, -1 on (eval) failure */
int
- set_item_eval(THD *thd, uint idx, Item **i, enum_field_types type);
-
- inline Item *
- get_item(uint idx)
- {
- return m_frame[idx];
- }
+ set_variable(THD *thd, uint var_idx, Item *value);
- inline Item **
- get_item_addr(uint idx)
- {
- return m_frame + idx;
- }
+ Item *
+ get_item(uint var_idx);
+ Item **
+ get_item_addr(uint var_idx);
- inline void
- set_result(Item *it)
- {
- m_result= it;
- }
+ bool
+ set_return_value(THD *thd, Item *return_value_item);
- inline Item *
- get_result()
+ inline bool
+ is_return_value_set() const
{
- return m_result;
+ return m_return_value_set;
}
inline void
@@ -195,14 +177,6 @@ class sp_rcontext : public Sql_alloc
m_ihsp-= 1;
}
- // Save variables starting at fp and up
- void
- save_variables(uint fp);
-
- // Restore variables down to fp
- void
- restore_variables(uint fp);
-
void
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
@@ -221,13 +195,42 @@ class sp_rcontext : public Sql_alloc
return m_cstack[i];
}
+ /*
+ CASE expressions support.
+ */
+
+ int
+ set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item);
+
+ Item *
+ get_case_expr(int case_expr_id);
+
+ Item **
+ get_case_expr_addr(int case_expr_id);
+
private:
+ sp_pcontext *m_root_parsing_ctx;
- uint m_count;
- uint m_fsize;
- Item **m_frame;
+ /* Virtual table for storing variables. */
+ TABLE *m_var_table;
- Item *m_result; // For FUNCTIONs
+ /*
+ Collection of Item_field proxies, each of them points to the corresponding
+ field in m_var_table.
+ */
+ Item **m_var_items;
+
+ /*
+ This is a pointer to a field, which should contain return value for stored
+ functions (only). For stored procedures, this pointer is NULL.
+ */
+ Field *m_return_value_fld;
+
+ /*
+ Indicates whether the return value (in m_return_value_fld) has been set
+ during execution.
+ */
+ bool m_return_value_set;
sp_handler_t *m_handler; // Visible handlers
uint m_hcount; // Stack pointer for m_handler
@@ -236,13 +239,22 @@ private:
uint *m_in_handler; // Active handler, for recursion check
uint m_ihsp; // Stack pointer for m_in_handler
int m_hfound; // Set by find_handler; -1 if not found
- List<Item> m_saved; // Saved variables during handler exec.
sp_cursor **m_cstack;
uint m_ccount;
- sp_rcontext *m_prev_ctx; // Previous context (NULL if none)
+ Item_cache **m_case_expr_holders;
+
+ /* Previous runtime context (NULL if none) */
+ sp_rcontext *m_prev_runtime_ctx;
+
+private:
+ bool init_var_table(THD *thd);
+ bool init_var_items();
+
+ Item_cache *create_case_expr_holder(THD *thd, Item_result result_type);
+ int set_variable(THD *thd, Field *field, Item *value);
}; // class sp_rcontext : public Sql_alloc
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 8d3bb316630..061020e1952 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -68,6 +68,7 @@ static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
static ulong get_sort(uint count,...);
static void init_check_host(void);
+static void rebuild_check_host(void);
static ACL_USER *find_acl_user(const char *host, const char *user,
my_bool exact);
static bool update_user_table(THD *thd, TABLE *table,
@@ -1095,10 +1096,8 @@ static void acl_insert_user(const char *user, const char *host,
qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
- /* We must free acl_check_hosts as its memory is mapped to acl_user */
- delete_dynamic(&acl_wild_hosts);
- hash_free(&acl_check_hosts);
- init_check_host();
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
}
@@ -1283,7 +1282,7 @@ static void init_check_host(void)
if (j == acl_wild_hosts.elements) // If new
(void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host);
}
- else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host,
+ else if (!hash_search(&acl_check_hosts,(byte*) acl_user->host.hostname,
(uint) strlen(acl_user->host.hostname)))
{
if (my_hash_insert(&acl_check_hosts,(byte*) acl_user))
@@ -1300,6 +1299,22 @@ static void init_check_host(void)
}
+/*
+ Rebuild lists used for checking of allowed hosts
+
+ We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding,
+ dropping or renaming user, since they contain pointers to elements of
+ 'acl_user' array, which are invalidated by drop operation, and use
+ ACL_USER::host::hostname as a key, which is changed by rename.
+*/
+void rebuild_check_host(void)
+{
+ delete_dynamic(&acl_wild_hosts);
+ hash_free(&acl_check_hosts);
+ init_check_host();
+}
+
+
/* Return true if there is no users that can match the given host */
bool acl_check_host(const char *host, const char *ip)
@@ -2229,14 +2244,14 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
char helping [NAME_LEN*2+USERNAME_LENGTH+3];
uint len;
GRANT_NAME *grant_name,*found=0;
+ HASH_SEARCH_STATE state;
len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
- for (grant_name=(GRANT_NAME*) hash_search(name_hash,
- (byte*) helping,
- len) ;
+ for (grant_name= (GRANT_NAME*) hash_first(name_hash, (byte*) helping,
+ len, &state);
grant_name ;
grant_name= (GRANT_NAME*) hash_next(name_hash,(byte*) helping,
- len))
+ len, &state))
{
if (exact)
{
@@ -2761,8 +2776,9 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
TABLE_LIST *dummy;
Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
+ column->column.length(),
column->column.ptr(), NULL, NULL,
- column->column.length(), 0, 1, 1, 0,
+ NULL, TRUE, FALSE,
&unused_field_idx, FALSE, &dummy);
if (f == (Field*)0)
{
@@ -3616,11 +3632,28 @@ err:
}
+/*
+ Check column rights in given security context
+
+ SYNOPSIS
+ check_grant_column()
+ thd thread handler
+ grant grant information structure
+ db_name db name
+ table_name table name
+ name column name
+ length column name length
+ sctx security context
+
+ RETURN
+ FALSE OK
+ TRUE access denied
+*/
+
bool check_grant_column(THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name,
- const char *name, uint length, uint show_tables)
+ const char *name, uint length, Security_context *sctx)
{
- Security_context *sctx= thd->security_ctx;
GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column;
ulong want_access= grant->want_privilege & ~grant->privilege;
@@ -3651,28 +3684,74 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
rw_unlock(&LOCK_grant);
DBUG_RETURN(0);
}
-#ifdef NOT_USED
- if (show_tables && (grant_column || grant->privilege & COL_ACLS))
- {
- rw_unlock(&LOCK_grant); /* purecov: deadcode */
- DBUG_RETURN(0); /* purecov: deadcode */
- }
-#endif
err:
rw_unlock(&LOCK_grant);
- if (!show_tables)
+ char command[128];
+ get_privilege_desc(command, sizeof(command), want_access);
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
+ command,
+ sctx->priv_user,
+ sctx->host_or_ip,
+ name,
+ table_name);
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Check the access right to a column depending on the type of table.
+
+ SYNOPSIS
+ check_column_grant_in_table_ref()
+ thd thread handler
+ table_ref table reference where to check the field
+ name name of field to check
+ length length of name
+
+ DESCRIPTION
+ Check the access rights to a column depending on the type of table
+ reference where the column is checked. The function provides a
+ generic interface to check column access rights that hides the
+ heterogeneity of the column representation - whether it is a view
+ or a stored table colum.
+
+ RETURN
+ FALSE OK
+ TRUE access denied
+*/
+
+bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
+ const char *name, uint length)
+{
+ GRANT_INFO *grant;
+ const char *db_name;
+ const char *table_name;
+ Security_context *sctx= test(table_ref->security_ctx) ?
+ table_ref->security_ctx : thd->security_ctx;
+
+ if (table_ref->view || table_ref->field_translation)
{
- char command[128];
- get_privilege_desc(command, sizeof(command), want_access);
- my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
- command,
- sctx->priv_user,
- sctx->host_or_ip,
- name,
- table_name);
+ /* View or derived information schema table. */
+ grant= &(table_ref->grant);
+ db_name= table_ref->view_db.str;
+ table_name= table_ref->view_name.str;
}
- DBUG_RETURN(1);
+ else
+ {
+ /* Normal or temporary table. */
+ TABLE *table= table_ref->table;
+ grant= &(table->grant);
+ db_name= table->s->db;
+ table_name= table->s->table_name;
+ }
+
+ if (grant->want_privilege)
+ return check_grant_column(thd, grant, db_name, table_name, name,
+ length, sctx);
+ else
+ return FALSE;
+
}
@@ -5177,6 +5256,9 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
}
}
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
+
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -5201,7 +5283,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
{
- int result= 0;
+ int result;
String wrong_users;
LEX_USER *user_from;
LEX_USER *user_to;
@@ -5233,6 +5315,9 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
}
}
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
+
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 0e50737f84c..c8fadb73b0c 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -204,7 +204,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_command, uint number, bool dont_print_error);
bool check_grant_column (THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name,
- const char *name, uint length, uint show_command=0);
+ const char *name, uint length, Security_context *sctx);
+bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
+ const char *name, uint length);
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
const char* db_name, const char *table_name,
Field_iterator *fields);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 598e6d46a60..be3b64a5ef6 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -698,6 +698,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
SYNOPSIS
unique_table()
+ thd thread handle
table table which should be checked
table_list list of tables
@@ -723,7 +724,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
0 if table is unique
*/
-TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
+TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
{
TABLE_LIST *res;
const char *d_name, *t_name;
@@ -758,9 +759,10 @@ TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
for (;;)
{
- if (!(res= find_table_in_global_list(table_list, d_name, t_name)) ||
- (!res->table || res->table != table->table) &&
- (res->select_lex && !res->select_lex->exclude_from_table_unique_test))
+ if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
+ (! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
+ ((!res->table || res->table != table->table) &&
+ res->select_lex && !res->select_lex->exclude_from_table_unique_test))
break;
/*
If we found entry of this table or or table of SELECT which already
@@ -1083,6 +1085,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
char key[MAX_DBKEY_LENGTH];
uint key_length;
char *alias= table_list->alias;
+ HASH_SEARCH_STATE state;
DBUG_ENTER("open_table");
/* find a unused table in the open table cache */
@@ -1245,9 +1248,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
- for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
+ &state);
table && table->in_use ;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
+ &state))
{
if (table->s->version != refresh_version)
{
@@ -1619,10 +1624,12 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
{
char *key= table->s->table_cache_key;
uint key_length= table->s->key_length;
- for (TABLE *search=(TABLE*) hash_search(&open_cache,
- (byte*) key,key_length) ;
+ HASH_SEARCH_STATE state;
+ for (TABLE *search= (TABLE*) hash_first(&open_cache, (byte*) key,
+ key_length, &state);
search ;
- search = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ search= (TABLE*) hash_next(&open_cache, (byte*) key,
+ key_length, &state))
{
if (search->locked_by_flush ||
search->locked_by_name && wait_for_name_lock ||
@@ -1984,15 +1991,25 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
thd->lex->sroutines_list.elements)
{
- bool first_no_prelocking, need_prelocking;
+ bool first_no_prelocking, need_prelocking, tabs_changed;
TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
DBUG_ASSERT(thd->lex->query_tables == *start);
sp_get_prelocking_info(thd, &need_prelocking, &first_no_prelocking);
- if ((sp_cache_routines_and_add_tables(thd, thd->lex,
- first_no_prelocking) ||
- *start) && need_prelocking)
+ if (sp_cache_routines_and_add_tables(thd, thd->lex,
+ first_no_prelocking,
+ &tabs_changed))
+ {
+ /*
+ Serious error during reading stored routines from mysql.proc table.
+ Something's wrong with the table or its contents, and an error has
+ been emitted; we must abort.
+ */
+ result= -1;
+ goto err;
+ }
+ else if ((tabs_changed || *start) && need_prelocking)
{
query_tables_last_own= save_query_tables_last;
*start= thd->lex->query_tables;
@@ -2116,9 +2133,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
tables->lock_type >= TL_WRITE_ALLOW_WRITE)
{
if (!query_tables_last_own)
- query_tables_last_own= thd->lex->query_tables_last;
- sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
- tables->table->triggers);
+ query_tables_last_own= thd->lex->query_tables_last;
+ if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
+ tables))
+ {
+ /*
+ Serious error during reading stored routines from mysql.proc table.
+ Something's wrong with the table or its contents, and an error has
+ been emitted; we must abort.
+ */
+ result= -1;
+ goto err;
+ }
}
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
}
@@ -2139,9 +2165,20 @@ process_view_routines:
/* We have at least one table in TL here. */
if (!query_tables_last_own)
query_tables_last_own= thd->lex->query_tables_last;
- sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables->view);
+ if (sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables))
+ {
+ /*
+ Serious error during reading stored routines from mysql.proc table.
+ Something's wrong with the table or its contents, and an error has
+ been emitted; we must abort.
+ */
+ result= -1;
+ goto err;
+ }
}
}
+
+ err:
thd->proc_info=0;
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
@@ -2683,47 +2720,6 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-/*
- Check column rights in given security context
-
- SYNOPSIS
- check_grant_column_in_sctx()
- thd thread handler
- grant grant information structure
- db db name
- table table name
- name column name
- length column name length
- check_grants need to check grants
- sctx 0 or security context
-
- RETURN
- FALSE OK
- TRUE access denied
-*/
-
-static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
- const char *db, const char *table,
- const char *name, uint length,
- bool check_grants,
- Security_context *sctx)
-{
- if (!check_grants)
- return FALSE;
- Security_context *save_security_ctx= thd->security_ctx;
- bool res;
- if (sctx)
- {
- thd->security_ctx= sctx;
- }
- res= check_grant_column(thd, grant, db, table, name, length);
- thd->security_ctx= save_security_ctx;
- return res;
-}
-#endif
-
-
/*
Find a field by name in a view that uses merge algorithm.
@@ -2732,11 +2728,10 @@ static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
thd thread handler
table_list view to search for 'name'
name name of field
- item_name name of item if it will be created (VIEW)
length length of name
+ item_name name of item if it will be created (VIEW)
ref expression substituted in VIEW should be passed
using this reference (return view_ref_found)
- check_grants do check columns grants for view?
register_tree_change TRUE if ref is not stack variable and we
need register changes in item tree
@@ -2748,8 +2743,8 @@ static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
static Field *
find_field_in_view(THD *thd, TABLE_LIST *table_list,
- const char *name, const char *item_name,
- uint length, Item **ref, bool check_grants,
+ const char *name, uint length,
+ const char *item_name, Item **ref,
bool register_tree_change)
{
DBUG_ENTER("find_field_in_view");
@@ -2766,24 +2761,13 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
{
if (!my_strcasecmp(system_charset_info, field_it.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*) (field_it.item()))->field);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grant_column_in_sctx(thd, &table_list->grant,
- table_list->view_db.str,
- table_list->view_name.str, name, length,
- check_grants,
- table_list->security_ctx))
- DBUG_RETURN(WRONG_GRANT);
-#endif
// in PS use own arena or data will be freed after prepare
if (register_tree_change)
arena= thd->activate_stmt_arena_if_needed(&backup);
+ /*
+ create_item() may, or may not create a new Item, depending on
+ the column reference. See create_view_field() for details.
+ */
Item *item= field_it.create_item(thd);
if (register_tree_change && arena)
thd->restore_active_arena(arena, &backup);
@@ -2825,7 +2809,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
length [in] length of name
ref [in/out] if 'name' is resolved to a view field, ref is
set to point to the found view field
- check_grants [in] do check columns grants?
register_tree_change [in] TRUE if ref is not stack variable and we
need register changes in item tree
actual_table [out] the original table reference where the field
@@ -2846,8 +2829,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
static Field *
find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
- uint length, Item **ref, bool check_grants,
- bool register_tree_change,
+ uint length, Item **ref, bool register_tree_change,
TABLE_LIST **actual_table)
{
List_iterator_fast<Natural_join_column>
@@ -2872,23 +2854,16 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
break;
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grants && nj_col->check_grants(thd, name, length))
- DBUG_RETURN(WRONG_GRANT);
-#endif
-
if (nj_col->view_field)
{
Item *item;
- /*
- The found field is a view field, we do as in find_field_in_view()
- and return a pointer to pointer to the Item of that field.
- */
if (register_tree_change)
arena= thd->activate_stmt_arena_if_needed(&backup);
-
+ /*
+ create_item() may, or may not create a new Item, depending on the
+ column reference. See create_view_field() for details.
+ */
item= nj_col->create_item(thd);
-
if (register_tree_change && arena)
thd->restore_active_arena(arena, &backup);
@@ -2934,7 +2909,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
table table where to search for the field
name name of field
length length of name
- check_grants do check columns grants?
allow_rowid do allow finding of "_rowid" field?
cached_field_index_ptr cached position in field list (used to speedup
lookup for fields in prepared tables)
@@ -2946,9 +2920,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
Field *
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
- bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr,
- Security_context *sctx)
+ bool allow_rowid, uint *cached_field_index_ptr)
{
Field **field_ptr, *field;
uint cached_field_index= *cached_field_index_ptr;
@@ -2987,13 +2959,6 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
update_field_dependencies(thd, field, table);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grant_column_in_sctx(thd, &table->grant,
- table->s->db, table->s->table_name,
- name, length,
- check_grants, sctx))
- field= WRONG_GRANT;
-#endif
DBUG_RETURN(field);
}
@@ -3006,14 +2971,13 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
thd [in] thread handler
table_list [in] table reference to search
name [in] name of field
+ length [in] field length of name
item_name [in] name of item if it will be created (VIEW)
- table_name [in] optional table name that qualifies the field
db_name [in] optional database name that qualifies the
- length [in] field length of name
+ table_name [in] optional table name that qualifies the field
ref [in/out] if 'name' is resolved to a view field, ref
is set to point to the found view field
- check_grants_table [in] do check columns grants for table?
- check_grants_view [in] do check columns grants for view?
+ check_privileges [in] check privileges
allow_rowid [in] do allow finding of "_rowid" field?
cached_field_index_ptr [in] cached position in field list (used to
speedup lookup for fields in prepared tables)
@@ -3043,11 +3007,11 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
Field *
find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
- const char *name, const char *item_name,
- const char *table_name, const char *db_name,
- uint length, Item **ref,
- bool check_grants_table, bool check_grants_view,
- bool allow_rowid, uint *cached_field_index_ptr,
+ const char *name, uint length,
+ const char *item_name, const char *db_name,
+ const char *table_name, Item **ref,
+ bool check_privileges, bool allow_rowid,
+ uint *cached_field_index_ptr,
bool register_tree_change, TABLE_LIST **actual_table)
{
Field *fld;
@@ -3092,8 +3056,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
if (table_list->field_translation)
{
/* 'table_list' is a view or an information schema table. */
- if ((fld= find_field_in_view(thd, table_list, name, item_name, length,
- ref, check_grants_view,
+ if ((fld= find_field_in_view(thd, table_list, name, length, item_name, ref,
register_tree_change)))
*actual_table= table_list;
}
@@ -3102,20 +3065,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
/* 'table_list' is a stored table. */
DBUG_ASSERT(table_list->table);
if ((fld= find_field_in_table(thd, table_list->table, name, length,
- check_grants_table, allow_rowid,
- cached_field_index_ptr,
- table_list->security_ctx)))
+ allow_rowid,
+ cached_field_index_ptr)))
*actual_table= table_list;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* check for views with temporary table algorithm */
- if (check_grants_view && table_list->view &&
- fld && fld != WRONG_GRANT &&
- check_grant_column(thd, &table_list->grant,
- table_list->view_db.str,
- table_list->view_name.str,
- name, length))
- fld= WRONG_GRANT;
-#endif
}
else
{
@@ -3132,11 +3084,10 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
TABLE_LIST *table;
while ((table= it++))
{
- if ((fld= find_field_in_table_ref(thd, table, name, item_name,
- table_name, db_name, length, ref,
- check_grants_table,
- check_grants_view,
- allow_rowid, cached_field_index_ptr,
+ if ((fld= find_field_in_table_ref(thd, table, name, length, item_name,
+ db_name, table_name, ref,
+ check_privileges, allow_rowid,
+ cached_field_index_ptr,
register_tree_change, actual_table)))
DBUG_RETURN(fld);
}
@@ -3149,11 +3100,16 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
directly the top-most NATURAL/USING join.
*/
fld= find_field_in_natural_join(thd, table_list, name, length, ref,
- /* TIMOUR_TODO: check this with Sanja */
- check_grants_table || check_grants_view,
register_tree_change, actual_table);
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* Check if there are sufficient access rights to the found field. */
+ if (fld && check_privileges &&
+ check_column_grant_in_table_ref(thd, *actual_table, name, length))
+ fld= WRONG_GRANT;
+#endif
+
DBUG_RETURN(fld);
}
@@ -3235,21 +3191,11 @@ find_field_in_tables(THD *thd, Item_ident *item,
*/
if (table_ref->table && !table_ref->view)
found= find_field_in_table(thd, table_ref->table, name, length,
- test(table_ref->table->
- grant.want_privilege) &&
- check_privileges,
- 1, &(item->cached_field_index),
- table_ref->security_ctx);
+ TRUE, &(item->cached_field_index));
else
- found= find_field_in_table_ref(thd, table_ref, name, item->name,
- NULL, NULL, length, ref,
- (table_ref->table &&
- test(table_ref->table->grant.
- want_privilege) &&
- check_privileges),
- (test(table_ref->grant.want_privilege) &&
- check_privileges),
- 1, &(item->cached_field_index),
+ found= find_field_in_table_ref(thd, table_ref, name, length, item->name,
+ NULL, NULL, ref, check_privileges,
+ TRUE, &(item->cached_field_index),
register_tree_change,
&actual_table);
if (found)
@@ -3289,17 +3235,9 @@ find_field_in_tables(THD *thd, Item_ident *item,
for (; cur_table != last_table ;
cur_table= cur_table->next_name_resolution_table)
{
- Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name,
- table_name, db,
- length, ref,
- (cur_table->table &&
- test(cur_table->table->grant.
- want_privilege) &&
- check_privileges),
- (test(cur_table->grant.
- want_privilege)
- && check_privileges),
- allow_rowid,
+ Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length,
+ item->name, db, table_name, ref,
+ check_privileges, allow_rowid,
&(item->cached_field_index),
register_tree_change,
&actual_table);
@@ -3707,7 +3645,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
{
bool is_created_1;
bool found= FALSE;
- if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created_1)))
+ if (!(nj_col_1= it_1.get_or_create_column_ref(&is_created_1)))
goto err;
field_name_1= nj_col_1->name();
@@ -3728,7 +3666,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
bool is_created_2;
Natural_join_column *cur_nj_col_2;
const char *cur_field_name_2;
- if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, &is_created_2)))
+ if (!(cur_nj_col_2= it_2.get_or_create_column_ref(&is_created_2)))
goto err;
cur_field_name_2= cur_nj_col_2->name();
@@ -3920,13 +3858,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
/* Append the columns of the first join operand. */
for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
{
- if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created)))
- goto err;
- /*
- The following assert checks that mark_common_columns() was run and
- we created the list table_ref_1->join_columns.
- */
- DBUG_ASSERT(!is_created);
+ nj_col_1= it_1.get_natural_column_ref();
if (nj_col_1->is_common)
{
natural_using_join->join_columns->push_back(nj_col_1);
@@ -3972,13 +3904,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
/* Append the non-equi-join columns of the second join operand. */
for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
{
- if (!(nj_col_2= it_2.get_or_create_column_ref(thd, &is_created)))
- goto err;
- /*
- The following assert checks that mark_common_columns() was run and
- we created the list table_ref_2->join_columns.
- */
- DBUG_ASSERT(!is_created);
+ nj_col_2= it_2.get_natural_column_ref();
if (!nj_col_2->is_common)
non_join_columns->push_back(nj_col_2);
else
@@ -4318,11 +4244,13 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
{
reg2 Item *item;
bool save_set_query_id= thd->set_query_id;
+ nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
List_iterator<Item> it(fields);
DBUG_ENTER("setup_fields");
thd->set_query_id=set_query_id;
- thd->allow_sum_func= allow_sum_func;
+ if (allow_sum_func)
+ thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
thd->where= THD::DEFAULT_WHERE;
/*
@@ -4345,6 +4273,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
if (!item->fixed && item->fix_fields(thd, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
{
+ thd->lex->allow_sum_func= save_allow_sum_func;
thd->set_query_id= save_set_query_id;
DBUG_RETURN(TRUE); /* purecov: inspected */
}
@@ -4355,6 +4284,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
thd->used_tables|= item->used_tables();
}
+ thd->lex->allow_sum_func= save_allow_sum_func;
thd->set_query_id= save_set_query_id;
DBUG_RETURN(test(thd->net.report_error));
}
@@ -4712,8 +4642,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
because it was already created and stored with the natural join.
*/
Natural_join_column *nj_col;
- if (!(nj_col= field_iterator.get_or_create_column_ref(thd,
- &is_created)))
+ if (!(nj_col= field_iterator.get_or_create_column_ref(&is_created)))
DBUG_RETURN(TRUE);
DBUG_ASSERT(nj_col->table_field && !is_created);
field_table= nj_col->table_ref->table;
@@ -5138,11 +5067,14 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
for (;;)
{
+ HASH_SEARCH_STATE state;
result= signalled= 0;
- for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
+ &state);
table;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
+ &state))
{
THD *in_use;
table->s->version=0L; /* Free when thread is ready */
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 3965079988b..cf3ba9c8c40 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -977,21 +977,31 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
goto err;
}
- /*
- Test if the query is a SELECT
- (pre-space is removed in dispatch_command).
-
- First '/' looks like comment before command it is not
- frequently appeared in real lihe, consequently we can
- check all such queries, too.
- */
- if ((my_toupper(system_charset_info, sql[0]) != 'S' ||
- my_toupper(system_charset_info, sql[1]) != 'E' ||
- my_toupper(system_charset_info,sql[2]) !='L') &&
- sql[0] != '/')
{
- DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
- goto err;
+ uint i= 0;
+ /*
+ Skip '(' characters in queries like following:
+ (select a from t1) union (select a from t1);
+ */
+ while (sql[i]=='(')
+ i++;
+
+ /*
+ Test if the query is a SELECT
+ (pre-space is removed in dispatch_command)
+
+ First '/' looks like comment before command it is not
+ frequently appeared in real lihe, consequently we can
+ check all such queries, too.
+ */
+ if ((my_toupper(system_charset_info, sql[i]) != 'S' ||
+ my_toupper(system_charset_info, sql[i + 1]) != 'E' ||
+ my_toupper(system_charset_info, sql[i + 2]) != 'L') &&
+ sql[i] != '/')
+ {
+ DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
+ goto err;
+ }
}
STRUCT_LOCK(&structure_guard_mutex);
@@ -2184,7 +2194,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
tables_used;
tables_used= tables_used->next_global, n++, block_table++)
{
- if (tables_used->derived)
+ if (tables_used->derived && !tables_used->view)
{
DBUG_PRINT("qcache", ("derived table skipped"));
n--;
@@ -3040,6 +3050,7 @@ my_bool Query_cache::move_by_type(byte **border,
}
case Query_cache_block::TABLE:
{
+ HASH_SEARCH_STATE record_idx;
DBUG_PRINT("qcache", ("block 0x%lx TABLE", (ulong) block));
if (*border == 0)
break;
@@ -3057,7 +3068,7 @@ my_bool Query_cache::move_by_type(byte **border,
byte *key;
uint key_length;
key=query_cache_table_get_key((byte*) block, &key_length, 0);
- hash_search(&tables, (byte*) key, key_length);
+ hash_first(&tables, (byte*) key, key_length, &record_idx);
block->destroy();
new_block->init(len);
@@ -3091,7 +3102,7 @@ my_bool Query_cache::move_by_type(byte **border,
/* Fix pointer to table name */
new_block->table()->table(new_block->table()->db() + tablename_offset);
/* Fix hash to point at moved block */
- hash_replace(&tables, tables.current_record, (byte*) new_block);
+ hash_replace(&tables, &record_idx, (byte*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
@@ -3099,6 +3110,7 @@ my_bool Query_cache::move_by_type(byte **border,
}
case Query_cache_block::QUERY:
{
+ HASH_SEARCH_STATE record_idx;
DBUG_PRINT("qcache", ("block 0x%lx QUERY", (ulong) block));
if (*border == 0)
break;
@@ -3116,7 +3128,7 @@ my_bool Query_cache::move_by_type(byte **border,
byte *key;
uint key_length;
key=query_cache_query_get_key((byte*) block, &key_length, 0);
- hash_search(&queries, (byte*) key, key_length);
+ hash_first(&queries, (byte*) key, key_length, &record_idx);
// Move table of used tables
memmove((char*) new_block->table(0), (char*) block->table(0),
ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
@@ -3184,7 +3196,7 @@ my_bool Query_cache::move_by_type(byte **border,
net->query_cache_query= (gptr) new_block;
}
/* Fix hash to point at moved block */
- hash_replace(&queries, queries.current_record, (byte*) new_block);
+ hash_replace(&queries, &record_idx, (byte*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
break;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b65f353e492..ed2089546da 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -183,6 +183,7 @@ THD::THD()
spcont(NULL)
{
stmt_arena= this;
+ thread_stack= 0;
db= 0;
catalog= (char*)"std"; // the only catalog we have for now
main_security_ctx.init();
@@ -472,10 +473,12 @@ void THD::awake(THD::killed_state state_to_set)
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
+ {
thr_alarm_kill(real_id);
#ifdef SIGNAL_WITH_VIO_CLOSE
- close_active_vio();
+ close_active_vio();
#endif
+ }
if (mysys_var)
{
pthread_mutex_lock(&mysys_var->mutex);
@@ -1502,10 +1505,10 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
my_var *mv= gl++;
if (mv->local)
{
- Item_splocal *var;
- (void)local_vars.push_back(var= new Item_splocal(mv->s, mv->offset));
+ Item_splocal *var= new Item_splocal(mv->s, mv->offset, mv->type);
+ (void)local_vars.push_back(var);
#ifndef DBUG_OFF
- var->owner= mv->owner;
+ var->m_sp= mv->sp;
#endif
}
else
@@ -1577,7 +1580,6 @@ Statement::Statement(enum enum_state state_arg, ulong id_arg,
:Query_arena(&main_mem_root, state_arg),
id(id_arg),
set_query_id(1),
- allow_sum_func(0),
lex(&main_lex),
query(0),
query_length(0),
@@ -1598,7 +1600,6 @@ void Statement::set_statement(Statement *stmt)
{
id= stmt->id;
set_query_id= stmt->set_query_id;
- allow_sum_func= stmt->allow_sum_func;
lex= stmt->lex;
query= stmt->query;
query_length= stmt->query_length;
@@ -1778,8 +1779,8 @@ bool select_dumpvar::send_data(List<Item> &items)
{
if ((yy=var_li++))
{
- if (thd->spcont->set_item_eval(current_thd,
- yy->get_offset(), it.ref(), zz->type))
+ if (thd->spcont->set_variable(current_thd, yy->get_var_idx(),
+ *it.ref()))
DBUG_RETURN(1);
}
}
@@ -1814,6 +1815,7 @@ void TMP_TABLE_PARAM::init()
group_parts= group_length= group_null_parts= 0;
quick_group= 1;
table_charset= 0;
+ precomputed_group_by= 0;
}
@@ -1947,6 +1949,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
backup->last_insert_id= last_insert_id;
backup->next_insert_id= next_insert_id;
backup->insert_id_used= insert_id_used;
+ backup->clear_next_insert_id= clear_next_insert_id;
backup->limit_found_rows= limit_found_rows;
backup->examined_row_count= examined_row_count;
backup->sent_row_count= sent_row_count;
@@ -1998,6 +2001,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
last_insert_id= backup->last_insert_id;
next_insert_id= backup->next_insert_id;
insert_id_used= backup->insert_id_used;
+ clear_next_insert_id= backup->clear_next_insert_id;
limit_found_rows= backup->limit_found_rows;
sent_row_count= backup->sent_row_count;
client_capabilities= backup->client_capabilities;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 0346801b0dc..c025b4f0774 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -218,7 +218,6 @@ class MYSQL_LOG: public TC_LOG
uint file_id;
uint open_count; // For replication
int readers_count;
- bool reset_pending;
bool write_error, inited;
bool need_start_event;
/*
@@ -780,19 +779,6 @@ public:
field list can not contain duplicates.
*/
bool set_query_id;
- /*
- This variable is used in post-parse stage to declare that sum-functions,
- or functions which have sense only if GROUP BY is present, are allowed.
- For example in queries
- SELECT MIN(i) FROM foo
- SELECT GROUP_CONCAT(a, b, MIN(i)) FROM ... GROUP BY ...
- MIN(i) have no sense.
- Though it's grammar-related issue, it's hard to catch it out during the
- parse stage because GROUP BY clause goes in the end of query. This
- variable is mainly used in setup_fields/fix_fields.
- See item_sum.cc for details.
- */
- bool allow_sum_func;
LEX_STRING name; /* name for named prepared statements */
LEX *lex; // parse tree descriptor
@@ -1090,7 +1076,7 @@ public:
ha_rows cuted_fields, sent_row_count, examined_row_count;
ulong client_capabilities;
uint in_sub_stmt;
- bool enable_slow_log, insert_id_used;
+ bool enable_slow_log, insert_id_used, clear_next_insert_id;
my_bool no_send_ok;
SAVEPOINT *savepoints;
};
@@ -1230,14 +1216,16 @@ public:
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
#endif
}
-#ifdef USING_TRANSACTIONS
st_transactions()
{
+#ifdef USING_TRANSACTIONS
bzero((char*)this, sizeof(*this));
xid_state.xid.null();
init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
- }
+#else
+ xid_state.xa_state= XA_NOTR;
#endif
+ }
} transaction;
Field *dupp_field;
#ifndef __WIN__
@@ -1820,11 +1808,18 @@ public:
uint convert_blob_length;
CHARSET_INFO *table_charset;
bool schema_table;
+ /*
+ True if GROUP BY and its aggregate functions are already computed
+ by a table access method (e.g. by loose index scan). In this case
+ query execution should not perform aggregation and should treat
+ aggregate functions as normal functions.
+ */
+ bool precomputed_group_by;
TMP_TABLE_PARAM()
:copy_field(0), group_parts(0),
group_length(0), group_null_parts(0), convert_blob_length(0),
- schema_table(0)
+ schema_table(0), precomputed_group_by(0)
{}
~TMP_TABLE_PARAM()
{
@@ -2091,7 +2086,7 @@ public:
Routine to which this Item_splocal belongs. Used for checking if correct
runtime context is used for variable handling.
*/
- sp_head *owner;
+ sp_head *sp;
#endif
bool local;
uint offset;
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index bde6522a38b..2500b213f4c 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1162,10 +1162,12 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
DBUG_RETURN(1);
}
end:
- x_free(thd->db);
+ if (!(thd->slave_thread))
+ x_free(thd->db);
if (dbname && dbname[0] == 0)
{
- x_free(dbname);
+ if (!(thd->slave_thread))
+ x_free(dbname);
thd->db= NULL;
thd->db_length= 0;
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 983f0931ef9..d8a8f28b92b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -293,6 +293,7 @@ cleanup:
if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
+ free_underlaid_joins(thd, select_lex);
if (transactional_table)
{
if (ha_autocommit_or_rollback(thd,error >= 0))
@@ -304,7 +305,6 @@ cleanup:
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
- free_underlaid_joins(thd, select_lex);
if (error < 0)
{
thd->row_count_func= deleted;
@@ -333,7 +333,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
- thd->allow_sum_func= 0;
+ thd->lex->allow_sum_func= 0;
if (setup_tables(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
table_list, conds, &select_lex->leaf_tables,
@@ -348,7 +348,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
}
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
{
update_non_unique_table_error(table_list, "DELETE", duplicate);
DBUG_RETURN(TRUE);
@@ -438,7 +438,7 @@ bool mysql_multi_delete_prepare(THD *thd)
*/
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(target_tbl->correspondent_table,
+ if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
lex->query_tables)))
{
update_non_unique_table_error(target_tbl->correspondent_table,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index a291a824e61..736be2310cb 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -108,11 +108,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
{ // Part field list
SELECT_LEX *select_lex= &thd->lex->select_lex;
Name_resolution_context *context= &select_lex->context;
- TABLE_LIST *save_next_local;
- TABLE_LIST *save_table_list;
- TABLE_LIST *save_first_name_resolution_table;
- TABLE_LIST *save_next_name_resolution_table;
- bool save_resolve_in_select_list;
+ Name_resolution_context_state ctx_state;
int res;
if (fields.elements != values.elements)
@@ -125,14 +121,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
select_lex->no_wrap_view_item= TRUE;
/* Save the state of the current name resolution context. */
- save_table_list= context->table_list;
- save_first_name_resolution_table= context->first_name_resolution_table;
- save_next_name_resolution_table= (context->first_name_resolution_table) ?
- context->first_name_resolution_table->
- next_name_resolution_table :
- NULL;
- save_resolve_in_select_list= context->resolve_in_select_list;
- save_next_local= table_list->next_local;
+ ctx_state.save_state(context, table_list);
/*
Perform name resolution only in the first table - 'table_list',
@@ -143,13 +132,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
res= setup_fields(thd, 0, fields, 1, 0, 0);
/* Restore the current context. */
- table_list->next_local= save_next_local;
- context->table_list= save_table_list;
- context->first_name_resolution_table= save_first_name_resolution_table;
- if (context->first_name_resolution_table)
- context->first_name_resolution_table->
- next_name_resolution_table= save_next_name_resolution_table;
- context->resolve_in_select_list= save_resolve_in_select_list;
+ ctx_state.restore_state(context, table_list);
thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
@@ -274,19 +257,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
*/
bool log_on= (thd->options & OPTION_BIN_LOG) ||
(!(thd->security_ctx->master_access & SUPER_ACL));
- bool transactional_table;
+ bool transactional_table, joins_freed= FALSE;
uint value_count;
ulong counter = 1;
ulonglong id;
COPY_INFO info;
TABLE *table= 0;
- TABLE_LIST *save_table_list;
- TABLE_LIST *save_next_local;
- TABLE_LIST *save_first_name_resolution_table;
- TABLE_LIST *save_next_name_resolution_table;
List_iterator_fast<List_item> its(values_list);
List_item *values;
Name_resolution_context *context;
+ Name_resolution_context_state ctx_state;
#ifndef EMBEDDED_LIBRARY
char *query= thd->query;
#endif
@@ -367,13 +347,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
context= &thd->lex->select_lex.context;
/* Save the state of the current name resolution context. */
- save_table_list= context->table_list;
- save_first_name_resolution_table= context->first_name_resolution_table;
- save_next_name_resolution_table= (context->first_name_resolution_table) ?
- context->first_name_resolution_table->
- next_name_resolution_table :
- NULL;
- save_next_local= table_list->next_local;
+ ctx_state.save_state(context, table_list);
/*
Perform name resolution only in the first table - 'table_list',
@@ -397,16 +371,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
its.rewind ();
/* Restore the current context. */
- table_list->next_local= save_next_local;
- context->first_name_resolution_table= save_first_name_resolution_table;
- if (context->first_name_resolution_table)
- context->first_name_resolution_table->
- next_name_resolution_table= save_next_name_resolution_table;
+ ctx_state.restore_state(context, table_list);
/*
Fill in the given fields and dump it to the table file
*/
-
info.records= info.deleted= info.copied= info.updated= 0;
info.ignore= ignore;
info.handle_duplicates=duplic;
@@ -544,6 +513,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->row_count++;
}
+ free_underlaid_joins(thd, &thd->lex->select_lex);
+ joins_freed= TRUE;
+
/*
Now all rows are inserted. Time to update logs and sends response to
user
@@ -642,7 +614,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->row_count_func= info.copied+info.deleted+info.updated;
::send_ok(thd, (ulong) thd->row_count_func, id, buff);
}
- free_underlaid_joins(thd, &thd->lex->select_lex);
thd->abort_on_warning= 0;
DBUG_RETURN(FALSE);
@@ -651,7 +622,8 @@ abort:
if (lock_type == TL_WRITE_DELAYED)
end_delayed_insert(thd);
#endif
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ if (!joins_freed)
+ free_underlaid_joins(thd, &thd->lex->select_lex);
thd->abort_on_warning= 0;
DBUG_RETURN(TRUE);
}
@@ -814,11 +786,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
Name_resolution_context *context= &select_lex->context;
- TABLE_LIST *save_table_list;
- TABLE_LIST *save_next_local;
- TABLE_LIST *save_first_name_resolution_table;
- TABLE_LIST *save_next_name_resolution_table;
- bool save_resolve_in_select_list;
+ Name_resolution_context_state ctx_state;
bool insert_into_view= (table_list->view != 0);
bool res= 0;
DBUG_ENTER("mysql_prepare_insert");
@@ -858,15 +826,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
/* Save the state of the current name resolution context. */
- save_table_list= context->table_list;
- /* Here first_name_resolution_table points to the first select table. */
- save_first_name_resolution_table= context->first_name_resolution_table;
- save_next_name_resolution_table= (context->first_name_resolution_table) ?
- context->first_name_resolution_table->
- next_name_resolution_table :
- NULL;
- save_resolve_in_select_list= context->resolve_in_select_list;
- save_next_local= table_list->next_local;
+ ctx_state.save_state(context, table_list);
/*
Perform name resolution only in the first table - 'table_list',
@@ -891,23 +851,17 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
*/
if (select_lex->group_list.elements == 0)
{
- context->table_list->next_local= save_next_local;
+ context->table_list->next_local= ctx_state.save_next_local;
/* first_name_resolution_table was set by resolve_in_table_list_only() */
context->first_name_resolution_table->
- next_name_resolution_table= save_next_local;
+ next_name_resolution_table= ctx_state.save_next_local;
}
if (!res)
res= setup_fields(thd, 0, update_values, 1, 0, 0);
}
/* Restore the current context. */
- table_list->next_local= save_next_local;
- context->table_list= save_table_list;
- context->first_name_resolution_table= save_first_name_resolution_table;
- if (context->first_name_resolution_table)
- context->first_name_resolution_table->
- next_name_resolution_table= save_next_name_resolution_table;
- context->resolve_in_select_list= save_resolve_in_select_list;
+ ctx_state.restore_state(context, table_list);
if (res)
DBUG_RETURN(res);
@@ -919,7 +873,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
{
Item *fake_conds= 0;
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
{
update_non_unique_table_error(table_list, "INSERT", duplicate);
DBUG_RETURN(TRUE);
@@ -2176,17 +2130,10 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
/* Save the state of the current name resolution context. */
Name_resolution_context *context= &lex->select_lex.context;
- TABLE_LIST *save_table_list;
- TABLE_LIST *save_next_local;
- TABLE_LIST *save_first_name_resolution_table;
- TABLE_LIST *save_next_name_resolution_table;
- save_table_list= context->table_list;
- save_first_name_resolution_table= context->first_name_resolution_table;
- save_next_name_resolution_table= (context->first_name_resolution_table) ?
- context->first_name_resolution_table->
- next_name_resolution_table :
- NULL;
- save_next_local= table_list->next_local;
+ Name_resolution_context_state ctx_state;
+
+ /* Save the state of the current name resolution context. */
+ ctx_state.save_state(context, table_list);
/* Perform name resolution only in the first table - 'table_list'. */
table_list->next_local= 0;
@@ -2202,20 +2149,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
if (lex->select_lex.group_list.elements == 0)
{
- context->table_list->next_local= save_next_local;
+ context->table_list->next_local= ctx_state.save_next_local;
/* first_name_resolution_table was set by resolve_in_table_list_only() */
context->first_name_resolution_table->
- next_name_resolution_table= save_next_local;
+ next_name_resolution_table= ctx_state.save_next_local;
}
res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
/* Restore the current context. */
- table_list->next_local= save_next_local;
- context->first_name_resolution_table= save_first_name_resolution_table;
- if (context->first_name_resolution_table)
- context->first_name_resolution_table->
- next_name_resolution_table= save_next_name_resolution_table;
-
+ ctx_state.restore_state(context, table_list);
}
lex->current_select= lex_current_select_save;
@@ -2232,7 +2174,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
query
*/
if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
- unique_table(table_list, table_list->next_global))
+ unique_table(thd, table_list, table_list->next_global))
{
/* Using same table for INSERT and SELECT */
lex->current_select->options|= OPTION_BUFFER_RESULT;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index ac2d7e82fcf..946b6a28430 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -182,6 +182,9 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->sroutines_list.empty();
lex->sroutines_list_own_last= lex->sroutines_list.next;
lex->sroutines_list_own_elements= 0;
+ lex->nest_level=0 ;
+ lex->allow_sum_func= 0;
+ lex->in_sum_func= NULL;
DBUG_VOID_RETURN;
}
@@ -1127,6 +1130,11 @@ void st_select_lex::init_query()
/*
Add the name resolution context of the current (sub)query to the
stack of contexts for the whole query.
+ TODO:
+ push_context may return an error if there is no memory for a new
+ element in the stack, however this method has no return value,
+ thus push_context should be moved to a place where query
+ initialization is checked for failure.
*/
parent_lex->push_context(&context);
cond_count= with_wild= 0;
@@ -1139,6 +1147,7 @@ void st_select_lex::init_query()
first_cond_optimization= 1;
parsing_place= NO_MATTER;
exclude_from_table_unique_test= no_wrap_view_item= FALSE;
+ nest_level= 0;
link_next= 0;
}
@@ -1158,6 +1167,7 @@ void st_select_lex::init_select()
interval_list.empty();
use_index.empty();
ftfunc_list_alloc.empty();
+ inner_sum_func_list= 0;
ftfunc_list= &ftfunc_list_alloc;
linkage= UNSPECIFIED_TYPE;
order_list.elements= 0;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 372bbc5576b..5ba47d768fb 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -528,6 +528,8 @@ public:
ulong table_join_options;
uint in_sum_expr;
uint select_number; /* number of select (used for EXPLAIN) */
+ int nest_level; /* nesting level of select */
+ Item_sum *inner_sum_func_list; /* list of sum func in nested selects */
uint with_wild; /* item list contain '*' */
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
@@ -738,8 +740,8 @@ typedef struct st_lex
TABLE_LIST **query_tables_last;
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
- char *create_view_start;
- char *create_view_select_start;
+ /* Position (first character index) of SELECT of CREATE VIEW statement */
+ uint create_view_select_start;
/*
The definer of the object being created (view, trigger, stored routine).
@@ -776,12 +778,23 @@ typedef struct st_lex
SQL_LIST proc_list, auxilliary_table_list, save_list;
create_field *last_field;
+ Item_sum *in_sum_func;
udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options
HA_CREATE_INFO create_info;
LEX_MASTER_INFO mi; // used by CHANGE MASTER
USER_RESOURCES mqh;
ulong type;
+ /*
+ This variable is used in post-parse stage to declare that sum-functions,
+ or functions which have sense only if GROUP BY is present, are allowed.
+ For example in a query
+ SELECT ... FROM ...WHERE MIN(i) == 1 GROUP BY ... HAVING MIN(i) > 2
+ MIN(i) in the WHERE clause is not allowed in the opposite to MIN(i)
+ in the HAVING clause. Due to possible nesting of select construct
+ the variable can contain 0 or 1 for each nest level.
+ */
+ nesting_map allow_sum_func;
enum_sql_command sql_command, orig_sql_command;
thr_lock_type lock_option;
enum SSL_type ssl_type; /* defined in violite.h */
@@ -800,6 +813,7 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt, start_transaction_opt;
+ int nest_level;
/*
In LEX representing update which were transformed to multi-update
stores total number of tables. For LEX representing multi-delete
@@ -1006,9 +1020,9 @@ typedef struct st_lex
}
void cleanup_after_one_table_open();
- void push_context(Name_resolution_context *context)
+ bool push_context(Name_resolution_context *context)
{
- context_stack.push_front(context);
+ return context_stack.push_front(context);
}
void pop_context()
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 285f1d6e501..b2bcc4ea401 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -266,10 +266,21 @@ protected:
ls.elements= elm;
}
public:
- base_list_iterator(base_list &list_par)
- :list(&list_par), el(&list_par.first), prev(0), current(0)
+ base_list_iterator()
+ :list(0), el(0), prev(0), current(0)
{}
+ base_list_iterator(base_list &list_par)
+ { init(list_par); }
+
+ inline void init(base_list &list_par)
+ {
+ list= &list_par;
+ el= &list_par.first;
+ prev= 0;
+ current= 0;
+ }
+
inline void *next(void)
{
prev=el;
@@ -364,6 +375,8 @@ template <class T> class List_iterator :public base_list_iterator
{
public:
List_iterator(List<T> &a) : base_list_iterator(a) {}
+ List_iterator() : base_list_iterator() {}
+ inline void init(List<T> &a) { base_list_iterator::init(a); }
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
@@ -385,6 +398,8 @@ protected:
public:
inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
+ inline List_iterator_fast() : base_list_iterator() {}
+ inline void init(List<T> &a) { base_list_iterator::init(a); }
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
inline void rewind(void) { base_list_iterator::rewind(); }
void sublist(List<T> &list_arg, uint el_arg)
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 2a0145af9c7..4f3bfee5d3a 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -178,7 +178,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table is marked to be 'used for insert' in which case we should never
mark this table as as 'const table' (ie, one that has only one row).
*/
- if (unique_table(table_list, table_list->next_global))
+ if (unique_table(thd, table_list, table_list->next_global))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
DBUG_RETURN(TRUE);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 065406d1f0c..9cdb288c045 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -797,6 +797,9 @@ static int check_connection(THD *thd)
DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
+#ifdef SIGNAL_WITH_VIO_CLOSE
+ thd->set_active_vio(net->vio);
+#endif
if (!thd->main_security_ctx.host) // If TCP/IP connection
{
@@ -2615,7 +2618,8 @@ mysql_execute_command(THD *thd)
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_backup_table(thd, first_table);
-
+ select_lex->table_list.first= (byte*) first_table;
+ lex->query_tables=all_tables;
break;
}
case SQLCOM_RESTORE_TABLE:
@@ -2627,6 +2631,8 @@ mysql_execute_command(THD *thd)
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_restore_table(thd, first_table);
+ select_lex->table_list.first= (byte*) first_table;
+ lex->query_tables=all_tables;
break;
}
case SQLCOM_ASSIGN_TO_KEYCACHE:
@@ -2830,7 +2836,7 @@ mysql_execute_command(THD *thd)
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(create_table, select_tables)))
+ if ((duplicate= unique_table(thd, create_table, select_tables)))
{
update_non_unique_table_error(create_table, "CREATE", duplicate);
res= 1;
@@ -2846,7 +2852,7 @@ mysql_execute_command(THD *thd)
tab= tab->next_local)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(tab, select_tables)))
+ if ((duplicate= unique_table(thd, tab, select_tables)))
{
update_non_unique_table_error(tab, "CREATE", duplicate);
res= 1;
@@ -3129,6 +3135,8 @@ end_with_restore_list:
mysql_bin_log.write(&qinfo);
}
}
+ select_lex->table_list.first= (byte*) first_table;
+ lex->query_tables=all_tables;
break;
}
case SQLCOM_CHECK:
@@ -3139,6 +3147,8 @@ end_with_restore_list:
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_check_table(thd, first_table, &lex->check_opt);
+ select_lex->table_list.first= (byte*) first_table;
+ lex->query_tables=all_tables;
break;
}
case SQLCOM_ANALYZE:
@@ -3159,6 +3169,8 @@ end_with_restore_list:
mysql_bin_log.write(&qinfo);
}
}
+ select_lex->table_list.first= (byte*) first_table;
+ lex->query_tables=all_tables;
break;
}
@@ -3182,6 +3194,8 @@ end_with_restore_list:
mysql_bin_log.write(&qinfo);
}
}
+ select_lex->table_list.first= (byte*) first_table;
+ lex->query_tables=all_tables;
break;
}
case SQLCOM_UPDATE:
@@ -4131,14 +4145,6 @@ end_with_restore_list:
}
}
#endif
- if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
- !(lex->sphead->m_flags & sp_head::HAS_RETURN))
- {
- my_error(ER_SP_NORETURN, MYF(0), name);
- delete lex->sphead;
- lex->sphead= 0;
- goto error;
- }
/*
We need to copy name and db in order to use them for
@@ -4844,11 +4850,15 @@ end_with_restore_list:
reset_one_shot_variables(thd);
/*
- The return value for ROW_COUNT() is "implementation dependent" if
- the statement is not DELETE, INSERT or UPDATE (or a CALL executing
- such a statement), but -1 is what JDBC and ODBC wants.
+ The return value for ROW_COUNT() is "implementation dependent" if the
+ statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
+ wants.
+
+ We do not change the value for a CALL or EXECUTE statement, so the value
+ generated by the last called (or executed) statement is preserved.
*/
- if (lex->sql_command != SQLCOM_CALL && uc_update_queries[lex->sql_command]<2)
+ if (lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE &&
+ uc_update_queries[lex->sql_command]<2)
thd->row_count_func= -1;
DBUG_RETURN(res || thd->net.report_error);
@@ -5417,6 +5427,8 @@ mysql_new_select(LEX *lex, bool move_down)
select_lex->parent_lex= lex; /* Used in init_query. */
select_lex->init_query();
select_lex->init_select();
+ lex->nest_level++;
+ select_lex->nest_level= lex->nest_level;
/*
Don't evaluate this subquery during statement prepare even if
it's a constant one. The flag is switched off in the end of
@@ -5757,9 +5769,10 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
buf, "TIMESTAMP");
}
- if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
- type_modifier, default_value, on_update_value,
- comment, change, interval_list, cs, uint_geom_type)))
+ if (!(new_field= new create_field()) ||
+ new_field->init(thd, field_name, type, length, decimals, type_modifier,
+ default_value, on_update_value, comment, change,
+ interval_list, cs, uint_geom_type))
DBUG_RETURN(1);
lex->create_list.push_back(new_field);
@@ -5767,327 +5780,6 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
DBUG_RETURN(0);
}
-/*****************************************************************************
-** Create field definition for create
-** Return 0 on failure, otherwise return create_field instance
-******************************************************************************/
-
-create_field *
-new_create_field(THD *thd, char *field_name, enum_field_types type,
- char *length, char *decimals,
- uint type_modifier,
- Item *default_value, Item *on_update_value,
- LEX_STRING *comment,
- char *change, List<String> *interval_list, CHARSET_INFO *cs,
- uint uint_geom_type)
-{
- register create_field *new_field;
- uint sign_len, allowed_type_modifier=0;
- ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
- DBUG_ENTER("new_create_field");
-
- if (!(new_field=new create_field()))
- DBUG_RETURN(NULL);
- new_field->field=0;
- new_field->field_name=field_name;
- new_field->def= default_value;
- new_field->flags= type_modifier;
- new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
- Field::NEXT_NUMBER : Field::NONE);
- new_field->decimals= decimals ? (uint)atoi(decimals) : 0;
- if (new_field->decimals >= NOT_FIXED_DEC)
- {
- my_error(ER_TOO_BIG_SCALE, MYF(0), new_field->decimals, field_name,
- NOT_FIXED_DEC-1);
- DBUG_RETURN(NULL);
- }
-
- new_field->sql_type=type;
- new_field->length=0;
- new_field->change=change;
- new_field->interval=0;
- new_field->pack_length= new_field->key_length= 0;
- new_field->charset=cs;
- new_field->geom_type= (Field::geometry_type) uint_geom_type;
-
- new_field->comment=*comment;
- /*
- Set flag if this field doesn't have a default value
- */
- if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
- (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP)
- new_field->flags|= NO_DEFAULT_VALUE_FLAG;
-
- if (length && !(new_field->length= (uint) atoi(length)))
- length=0; /* purecov: inspected */
- sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
-
- switch (type) {
- case FIELD_TYPE_TINY:
- if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
- allowed_type_modifier= AUTO_INCREMENT_FLAG;
- break;
- case FIELD_TYPE_SHORT:
- if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
- allowed_type_modifier= AUTO_INCREMENT_FLAG;
- break;
- case FIELD_TYPE_INT24:
- if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
- allowed_type_modifier= AUTO_INCREMENT_FLAG;
- break;
- case FIELD_TYPE_LONG:
- if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
- allowed_type_modifier= AUTO_INCREMENT_FLAG;
- break;
- case FIELD_TYPE_LONGLONG:
- if (!length) new_field->length=MAX_BIGINT_WIDTH;
- allowed_type_modifier= AUTO_INCREMENT_FLAG;
- break;
- case FIELD_TYPE_NULL:
- break;
- case FIELD_TYPE_NEWDECIMAL:
- if (!length && !new_field->decimals)
- new_field->length= 10;
- if (new_field->length > DECIMAL_MAX_PRECISION)
- {
- my_error(ER_TOO_BIG_PRECISION, MYF(0), new_field->length, field_name,
- DECIMAL_MAX_PRECISION);
- DBUG_RETURN(NULL);
- }
- if (new_field->length < new_field->decimals)
- {
- my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
- DBUG_RETURN(NULL);
- }
- new_field->length=
- my_decimal_precision_to_length(new_field->length, new_field->decimals,
- type_modifier & UNSIGNED_FLAG);
- new_field->pack_length=
- my_decimal_get_binary_size(new_field->length, new_field->decimals);
- break;
- case MYSQL_TYPE_VARCHAR:
- /*
- Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
- if they don't have a default value
- */
- max_field_charlength= MAX_FIELD_VARCHARLENGTH;
- break;
- case MYSQL_TYPE_STRING:
- break;
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_LONG_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_GEOMETRY:
- if (default_value) // Allow empty as default value
- {
- String str,*res;
- res=default_value->val_str(&str);
- if (res->length())
- {
- my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
- field_name); /* purecov: inspected */
- DBUG_RETURN(NULL);
- }
- new_field->def=0;
- }
- new_field->flags|=BLOB_FLAG;
- break;
- case FIELD_TYPE_YEAR:
- if (!length || new_field->length != 2)
- new_field->length=4; // Default length
- new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- break;
- case FIELD_TYPE_FLOAT:
- /* change FLOAT(precision) to FLOAT or DOUBLE */
- allowed_type_modifier= AUTO_INCREMENT_FLAG;
- if (length && !decimals)
- {
- uint tmp_length=new_field->length;
- if (tmp_length > PRECISION_FOR_DOUBLE)
- {
- my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
- DBUG_RETURN(NULL);
- }
- else if (tmp_length > PRECISION_FOR_FLOAT)
- {
- new_field->sql_type=FIELD_TYPE_DOUBLE;
- new_field->length=DBL_DIG+7; // -[digits].E+###
- }
- else
- new_field->length=FLT_DIG+6; // -[digits].E+##
- new_field->decimals= NOT_FIXED_DEC;
- break;
- }
- if (!length && !decimals)
- {
- new_field->length = FLT_DIG+6;
- new_field->decimals= NOT_FIXED_DEC;
- }
- if (new_field->length < new_field->decimals &&
- new_field->decimals != NOT_FIXED_DEC)
- {
- my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
- DBUG_RETURN(NULL);
- }
- break;
- case FIELD_TYPE_DOUBLE:
- allowed_type_modifier= AUTO_INCREMENT_FLAG;
- if (!length && !decimals)
- {
- new_field->length = DBL_DIG+7;
- new_field->decimals=NOT_FIXED_DEC;
- }
- if (new_field->length < new_field->decimals &&
- new_field->decimals != NOT_FIXED_DEC)
- {
- my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
- DBUG_RETURN(NULL);
- }
- break;
- case FIELD_TYPE_TIMESTAMP:
- if (!length)
- new_field->length= 14; // Full date YYYYMMDDHHMMSS
- else if (new_field->length != 19)
- {
- /*
- We support only even TIMESTAMP lengths less or equal than 14
- and 19 as length of 4.1 compatible representation.
- */
- new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
- new_field->length= min(new_field->length,14); /* purecov: inspected */
- }
- new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- if (default_value)
- {
- /* Grammar allows only NOW() value for ON UPDATE clause */
- if (default_value->type() == Item::FUNC_ITEM &&
- ((Item_func*)default_value)->functype() == Item_func::NOW_FUNC)
- {
- new_field->unireg_check= (on_update_value?Field::TIMESTAMP_DNUN_FIELD:
- Field::TIMESTAMP_DN_FIELD);
- /*
- We don't need default value any longer moreover it is dangerous.
- Everything handled by unireg_check further.
- */
- new_field->def= 0;
- }
- else
- new_field->unireg_check= (on_update_value?Field::TIMESTAMP_UN_FIELD:
- Field::NONE);
- }
- else
- {
- /*
- If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
- or ON UPDATE values then for the sake of compatiblity we should treat
- this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
- have another TIMESTAMP column with auto-set option before this one)
- or DEFAULT 0 (in other cases).
- So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
- replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
- information about all TIMESTAMP fields in table will be availiable.
-
- If we have TIMESTAMP NULL column without explicit DEFAULT value
- we treat it as having DEFAULT NULL attribute.
- */
- new_field->unireg_check= (on_update_value ?
- Field::TIMESTAMP_UN_FIELD :
- (new_field->flags & NOT_NULL_FLAG ?
- Field::TIMESTAMP_OLD_FIELD:
- Field::NONE));
- }
- break;
- case FIELD_TYPE_DATE: // Old date type
- if (protocol_version != PROTOCOL_VERSION-1)
- new_field->sql_type=FIELD_TYPE_NEWDATE;
- /* fall trough */
- case FIELD_TYPE_NEWDATE:
- new_field->length=10;
- break;
- case FIELD_TYPE_TIME:
- new_field->length=10;
- break;
- case FIELD_TYPE_DATETIME:
- new_field->length=19;
- break;
- case FIELD_TYPE_SET:
- {
- if (interval_list->elements > sizeof(longlong)*8)
- {
- my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
- DBUG_RETURN(NULL);
- }
- new_field->pack_length= get_set_pack_length(interval_list->elements);
-
- List_iterator<String> it(*interval_list);
- String *tmp;
- while ((tmp= it++))
- new_field->interval_list.push_back(tmp);
- /*
- Set fake length to 1 to pass the below conditions.
- Real length will be set in mysql_prepare_table()
- when we know the character set of the column
- */
- new_field->length= 1;
- break;
- }
- case FIELD_TYPE_ENUM:
- {
- // Should be safe
- new_field->pack_length= get_enum_pack_length(interval_list->elements);
-
- List_iterator<String> it(*interval_list);
- String *tmp;
- while ((tmp= it++))
- new_field->interval_list.push_back(tmp);
- new_field->length= 1; // See comment for FIELD_TYPE_SET above.
- break;
- }
- case MYSQL_TYPE_VAR_STRING:
- DBUG_ASSERT(0); // Impossible
- break;
- case MYSQL_TYPE_BIT:
- {
- if (!length)
- new_field->length= 1;
- if (new_field->length > MAX_BIT_FIELD_LENGTH)
- {
- my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name,
- MAX_BIT_FIELD_LENGTH);
- DBUG_RETURN(NULL);
- }
- 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) &&
- ((new_field->length > max_field_charlength && type != FIELD_TYPE_SET &&
- type != FIELD_TYPE_ENUM &&
- (type != MYSQL_TYPE_VARCHAR || default_value)) ||
- (!new_field->length &&
- type != MYSQL_TYPE_STRING &&
- type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
- {
- my_error((type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_VARCHAR ||
- type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH :
- ER_TOO_BIG_DISPLAYWIDTH,
- MYF(0),
- field_name, max_field_charlength); /* purecov: inspected */
- DBUG_RETURN(NULL);
- }
- type_modifier&= AUTO_INCREMENT_FLAG;
- if ((~allowed_type_modifier) & type_modifier)
- {
- my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
- DBUG_RETURN(NULL);
- }
- DBUG_RETURN(new_field);
-}
-
/* Store position for column in ALTER TABLE .. ADD column */
@@ -6581,36 +6273,39 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
/*
- Create a new name resolution context for a JOIN ... ON clause.
+ Push a new name resolution context for a JOIN ... ON clause to the
+ context stack of a query block.
SYNOPSIS
- make_join_on_context()
+ push_new_name_resolution_context()
thd pointer to current thread
left_op left operand of the JOIN
right_op rigth operand of the JOIN
DESCRIPTION
Create a new name resolution context for a JOIN ... ON clause,
- and set the first and last leaves of the list of table references
- to be used for name resolution.
+ set the first and last leaves of the list of table references
+ to be used for name resolution, and push the newly created
+ context to the stack of contexts of the query.
RETURN
- A new context if all is OK
- NULL - if a memory allocation error occured
+ FALSE if all is OK
+ TRUE if a memory allocation error occured
*/
-Name_resolution_context *
-make_join_on_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op)
+bool
+push_new_name_resolution_context(THD *thd,
+ TABLE_LIST *left_op, TABLE_LIST *right_op)
{
Name_resolution_context *on_context;
if (!(on_context= new (thd->mem_root) Name_resolution_context))
- return NULL;
+ return TRUE;
on_context->init();
on_context->first_name_resolution_table=
left_op->first_leaf_for_name_resolution();
on_context->last_name_resolution_table=
right_op->last_leaf_for_name_resolution();
- return on_context;
+ return thd->lex->push_context(on_context);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index d405f0791fb..ffbbf0c6476 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2129,7 +2129,8 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
lex->result->cleanup();
lex->result->set_thd(thd);
}
- thd->allow_sum_func= 0;
+ lex->allow_sum_func= 0;
+ lex->in_sum_func= NULL;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 52070aa8983..ad6375290cd 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -274,21 +274,20 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array,
ORDER *order,
ORDER *group, bool *hidden_group_fields)
{
- bool save_allow_sum_func;
int res;
+ nesting_map save_allow_sum_func=thd->lex->allow_sum_func ;
DBUG_ENTER("setup_without_group");
- save_allow_sum_func= thd->allow_sum_func;
- thd->allow_sum_func= 0;
+ thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level);
res= setup_conds(thd, tables, leaves, conds);
- thd->allow_sum_func= save_allow_sum_func;
+ thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
order);
- thd->allow_sum_func= 0;
+ thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level);
res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields,
group, hidden_group_fields);
- thd->allow_sum_func= save_allow_sum_func;
+ thd->lex->allow_sum_func= save_allow_sum_func;
DBUG_RETURN(res);
}
@@ -355,8 +354,9 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having)
{
+ nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
thd->where="having clause";
- thd->allow_sum_func=1;
+ thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level;
select_lex->having_fix_field= 1;
bool having_fix_rc= (!having->fixed &&
(having->fix_fields(thd, &having) ||
@@ -366,6 +366,18 @@ JOIN::prepare(Item ***rref_pointer_array,
DBUG_RETURN(-1); /* purecov: inspected */
if (having->with_sum_func)
having->split_sum_func(thd, ref_pointer_array, all_fields);
+ thd->lex->allow_sum_func= save_allow_sum_func;
+ }
+ if (select_lex->inner_sum_func_list)
+ {
+ Item_sum *end=select_lex->inner_sum_func_list;
+ Item_sum *item_sum= end;
+ do
+ {
+ item_sum= item_sum->next;
+ item_sum->split_sum_func2(thd, ref_pointer_array,
+ all_fields, item_sum->ref_by, FALSE);
+ } while (item_sum != end);
}
if (!thd->lex->view_prepare_mode)
@@ -1007,6 +1019,20 @@ JOIN::optimize()
}
having= 0;
+ /*
+ The loose index scan access method guarantees that all grouping or
+ duplicate row elimination (for distinct) is already performed
+ during data retrieval, and that all MIN/MAX functions are already
+ computed for each group. Thus all MIN/MAX functions should be
+ treated as regular functions, and there is no need to perform
+ grouping in the main execution loop.
+ Notice that currently loose index scan is applicable only for
+ single table queries, thus it is sufficient to test only the first
+ join_tab element of the plan for its access method.
+ */
+ if (join_tab->is_using_loose_index_scan())
+ tmp_table_param.precomputed_group_by= TRUE;
+
/* Create a tmp table if distinct or if the sort is too complicated */
if (need_tmp)
{
@@ -1410,6 +1436,15 @@ JOIN::exec()
else
{
/* group data to new table */
+
+ /*
+ If the access method is loose index scan then all MIN/MAX
+ functions are precomputed, and should be treated as regular
+ functions. See extended comment in JOIN::exec.
+ */
+ if (curr_join->join_tab->is_using_loose_index_scan())
+ curr_join->tmp_table_param.precomputed_group_by= TRUE;
+
if (!(curr_tmp_table=
exec_tmp_table2= create_tmp_table(thd,
&curr_join->tmp_table_param,
@@ -5197,7 +5232,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
join->const_table_map|=RAND_TABLE_BIT;
{ // Check const tables
COND *const_cond=
- make_cond_for_table(cond,join->const_table_map,(table_map) 0);
+ make_cond_for_table(cond,
+ join->const_table_map,
+ (table_map) 0);
DBUG_EXECUTE("where",print_where(const_cond,"constants"););
for (JOIN_TAB *tab= join->join_tab+join->const_tables;
tab < join->join_tab+join->tables ; tab++)
@@ -8152,7 +8189,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
uint convert_blob_length)
{
Item::Type orig_type= type;
- Item *orig_item;
+ Item *orig_item= 0;
if (type != Item::FIELD_ITEM &&
item->real_item()->type() == Item::FIELD_ITEM &&
@@ -8203,10 +8240,12 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
}
else
result= create_tmp_field_from_field(thd, (*from_field= field->field),
- item->name, table,
- modify_item ? field :
- NULL,
- convert_blob_length);
+ orig_item ? orig_item->name :
+ item->name,
+ table,
+ modify_item ? field :
+ NULL,
+ convert_blob_length);
if (orig_type == Item::REF_ITEM && orig_modify)
((Item_ref*)orig_item)->set_result_field(result);
return result;
@@ -8279,6 +8318,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
MEM_ROOT *mem_root_save, own_root;
TABLE *table;
uint i,field_count,null_count,null_pack_length;
+ uint copy_func_count= param->func_count;
uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
uint blob_count,group_null_items, string_count;
uint temp_pool_slot=MY_BIT_NONE;
@@ -8342,6 +8382,16 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
field_count=param->field_count+param->func_count+param->sum_func_count;
hidden_field_count=param->hidden_field_count;
+ /*
+ When loose index scan is employed as access method, it already
+ computes all groups and the result of all aggregate functions. We
+ make space for the items of the aggregate function in the list of
+ functions TMP_TABLE_PARAM::items_to_copy, so that the values of
+ these items are stored in the temporary table.
+ */
+ if (param->precomputed_group_by)
+ copy_func_count+= param->sum_func_count;
+
init_sql_alloc(&own_root, TABLE_ALLOC_BLOCK_SIZE, 0);
if (!multi_alloc_root(&own_root,
@@ -8349,7 +8399,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
&reg_field, sizeof(Field*) * (field_count+1),
&blob_field, sizeof(uint)*(field_count+1),
&from_field, sizeof(Field*)*field_count,
- &copy_func, sizeof(*copy_func)*(param->func_count+1),
+ &copy_func, sizeof(*copy_func)*(copy_func_count+1),
&param->keyinfo, sizeof(*param->keyinfo),
&key_part_info,
sizeof(*key_part_info)*(param->group_parts+1),
@@ -8877,6 +8927,7 @@ err:
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
{
uint field_count= field_list.elements;
+ uint blob_count= 0;
Field **field;
create_field *cdef; /* column definition */
uint record_length= 0;
@@ -8893,6 +8944,12 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
table->s= s= &table->share_not_to_be_used;
s->fields= field_count;
+ if (!(s->blob_field= (uint*)thd->alloc((field_list.elements + 1) *
+ sizeof(uint))))
+ return 0;
+
+ s->blob_ptr_size= mi_portable_sizeof_char_ptr;
+
/* Create all fields and calculate the total length of record */
List_iterator_fast<create_field> it(field_list);
while ((cdef= it++))
@@ -8908,9 +8965,15 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
record_length+= (**field).pack_length();
if (! ((**field).flags & NOT_NULL_FLAG))
++null_count;
+
+ if ((*field)->flags & BLOB_FLAG)
+ s->blob_field[blob_count++]= (uint) (field - table->field);
+
++field;
}
*field= NULL; /* mark the end of the list */
+ s->blob_field[blob_count]= 0; /* mark the end of the list */
+ s->blob_fields= blob_count;
null_pack_length= (null_count + 7)/8;
s->reclength= record_length + null_pack_length;
@@ -9241,11 +9304,13 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
Next_select_func setup_end_select_func(JOIN *join)
{
TABLE *table= join->tmp_table;
+ TMP_TABLE_PARAM *tmp_tbl= &join->tmp_table_param;
Next_select_func end_select;
+
/* Set up select_end */
if (table)
{
- if (table->group && join->tmp_table_param.sum_func_count)
+ if (table->group && tmp_tbl->sum_func_count)
{
if (table->s->keys)
{
@@ -9258,7 +9323,7 @@ Next_select_func setup_end_select_func(JOIN *join)
end_select=end_unique_update;
}
}
- else if (join->sort_and_group)
+ else if (join->sort_and_group && !tmp_tbl->precomputed_group_by)
{
DBUG_PRINT("info",("Using end_write_group"));
end_select=end_write_group;
@@ -9267,19 +9332,27 @@ Next_select_func setup_end_select_func(JOIN *join)
{
DBUG_PRINT("info",("Using end_write"));
end_select=end_write;
+ if (tmp_tbl->precomputed_group_by)
+ {
+ /*
+ A preceding call to create_tmp_table in the case when loose
+ index scan is used guarantees that
+ TMP_TABLE_PARAM::items_to_copy has enough space for the group
+ by functions. It is OK here to use memcpy since we copy
+ Item_sum pointers into an array of Item pointers.
+ */
+ memcpy(tmp_tbl->items_to_copy + tmp_tbl->func_count,
+ join->sum_funcs,
+ sizeof(Item*)*tmp_tbl->sum_func_count);
+ tmp_tbl->items_to_copy[tmp_tbl->func_count+tmp_tbl->sum_func_count]= 0;
+ }
}
}
else
{
- /* Test if data is accessed via QUICK_GROUP_MIN_MAX_SELECT. */
- bool is_using_quick_group_min_max_select=
- (join->join_tab->select && join->join_tab->select->quick &&
- (join->join_tab->select->quick->get_type() ==
- QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
-
if ((join->sort_and_group ||
(join->procedure && join->procedure->flags & PROC_GROUP)) &&
- !is_using_quick_group_min_max_select)
+ !tmp_tbl->precomputed_group_by)
end_select= end_send_group;
else
end_select= end_send;
@@ -10553,7 +10626,6 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
copy_fields(&join->tmp_table_param);
copy_funcs(join->tmp_table_param.items_to_copy);
-
#ifdef TO_BE_DELETED
if (!table->uniques) // If not unique handling
{
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 2f53c9a3b35..4aa238641e5 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -140,6 +140,12 @@ typedef struct st_join_table {
nested_join_map embedding_map;
void cleanup();
+ inline bool is_using_loose_index_scan()
+ {
+ return (select && select->quick &&
+ (select->quick->get_type() ==
+ QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
+ }
} JOIN_TAB;
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
@@ -400,7 +406,6 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
ulonglong select_options, ha_rows rows_limit,
char* alias);
-TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9449224c01a..089314078a6 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -898,7 +898,6 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
}
key_info= table->key_info;
- file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
bzero((char*) &create_info, sizeof(create_info));
file->update_create_info(&create_info);
primary_key= share->primary_key;
@@ -2046,6 +2045,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
int error= 1;
db_type not_used;
Open_tables_state open_tables_state_backup;
+ bool save_view_prepare_mode= lex->view_prepare_mode;
+ lex->view_prepare_mode= TRUE;
DBUG_ENTER("get_all_tables");
LINT_INIT(end);
@@ -2070,6 +2071,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
bool res;
lex->all_selects_list= lsel;
+ /*
+ Restore thd->temporary_tables to be able to process
+ temporary tables(only for 'show index' & 'show columns').
+ This should be changed when processing of temporary tables for
+ I_S tables will be done.
+ */
+ thd->temporary_tables= open_tables_state_backup.temporary_tables;
res= open_normal_and_derived_tables(thd, show_table_list,
MYSQL_LOCK_IGNORE_FLUSH);
/*
@@ -2089,6 +2097,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
show_table_list->view_db.str :
show_table_list->db),
show_table_list->alias));
+ thd->temporary_tables= 0;
close_thread_tables(thd);
show_table_list->table= 0;
goto err;
@@ -2223,6 +2232,7 @@ err:
lex->derived_tables= derived_tables;
lex->all_selects_list= old_all_select_lex;
lex->query_tables_last= save_query_tables_last;
+ lex->view_prepare_mode= save_view_prepare_mode;
*save_query_tables_last= 0;
lex->sql_command= save_sql_command;
DBUG_RETURN(error);
@@ -2316,6 +2326,12 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
there was errors during opening tables
*/
const char *error= thd->net.last_error;
+ if (tables->view)
+ table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
+ else if (tables->schema_table)
+ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
+ else
+ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
table->field[20]->store(error, strlen(error), cs);
thd->clear_error();
}
@@ -2603,7 +2619,9 @@ 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);
is_blob= (field->type() == FIELD_TYPE_BLOB);
- if (field->has_charset() || is_blob)
+ if (field->has_charset() || is_blob ||
+ field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
+ field->real_type() == MYSQL_TYPE_STRING) // For binary type
{
longlong char_max_len= is_blob ?
(longlong) field->max_length() / field->charset()->mbminlen :
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 67c3e0c62f2..0659f684afe 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -24,7 +24,7 @@
#define NOT_FIXED_DEC 31
#endif
-#define STRING_WITH_LEN(X) ((char*) X), (sizeof(X)-1)
+#define STRING_WITH_LEN(X) ((const char*) X), ((uint) (sizeof(X) - 1))
class String;
int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index e8ffdc23ec5..ba4a606537f 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -725,7 +725,14 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
*/
if (!interval)
{
- interval= sql_field->interval= typelib(sql_field->interval_list);
+ /*
+ Create the typelib in prepared statement memory if we're
+ executing one.
+ */
+ MEM_ROOT *stmt_root= thd->stmt_arena->mem_root;
+
+ interval= sql_field->interval= typelib(stmt_root,
+ sql_field->interval_list);
List_iterator<String> it(sql_field->interval_list);
String conv, *tmp;
for (uint i= 0; (tmp= it++); i++)
@@ -736,7 +743,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
uint cnv_errs;
conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
- interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(),
+ interval->type_names[i]= strmake_root(stmt_root, conv.ptr(),
conv.length());
interval->type_lengths[i]= conv.length();
}
@@ -756,8 +763,22 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
*/
if (sql_field->def && cs != sql_field->def->collation.collation)
{
- if (!(sql_field->def=
- sql_field->def->safe_charset_converter(cs)))
+ Query_arena backup_arena;
+ bool need_to_change_arena= !thd->stmt_arena->is_conventional();
+ if (need_to_change_arena)
+ {
+ /* Asser that we don't do that at every PS execute */
+ DBUG_ASSERT(thd->stmt_arena->is_first_stmt_execute() ||
+ thd->stmt_arena->is_first_sp_execute());
+ thd->set_n_backup_active_arena(thd->stmt_arena, &backup_arena);
+ }
+
+ sql_field->def= sql_field->def->safe_charset_converter(cs);
+
+ if (need_to_change_arena)
+ thd->restore_active_arena(thd->stmt_arena, &backup_arena);
+
+ if (! sql_field->def)
{
/* Could not convert */
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
@@ -2201,18 +2222,14 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
*/
lex->query_tables= table;
lex->query_tables_last= &table->next_global;
- lex->query_tables_own_last= 0;;
+ lex->query_tables_own_last= 0;
thd->no_warnings_for_error= no_warnings_for_error;
+ if (view_operator_func == NULL)
+ table->required_type=FRMTYPE_TABLE;
open_and_lock_tables(thd, table);
thd->no_warnings_for_error= 0;
table->next_global= save_next_global;
table->next_local= save_next_local;
- /* if view are unsupported */
- if (table->view && view_operator_func == NULL)
- {
- result_code= HA_ADMIN_NOT_BASE_TABLE;
- goto send_result;
- }
thd->open_options&= ~extra_open_options;
if (prepare_func)
@@ -3379,7 +3396,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
DBUG_RETURN(TRUE);
}
- def->def=alter->def; // Use new default
+ if ((def->def=alter->def)) // Use new default
+ def->flags&= ~NO_DEFAULT_VALUE_FLAG;
+ else
+ def->flags|= NO_DEFAULT_VALUE_FLAG;
alter_it.remove();
}
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index d3fda132f50..5f2d269ed1e 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -21,7 +21,7 @@
#include "parse_file.h"
static const LEX_STRING triggers_file_type=
- {STRING_WITH_LEN("TRIGGERS")};
+ {(char *) STRING_WITH_LEN("TRIGGERS")};
const char * const triggers_file_ext= ".TRG";
@@ -34,17 +34,17 @@ const char * const triggers_file_ext= ".TRG";
static File_option triggers_file_parameters[]=
{
{
- {STRING_WITH_LEN("triggers") },
+ {(char *) STRING_WITH_LEN("triggers") },
offsetof(class Table_triggers_list, definitions_list),
FILE_OPTIONS_STRLIST
},
{
- {STRING_WITH_LEN("sql_modes") },
+ {(char *) STRING_WITH_LEN("sql_modes") },
offsetof(class Table_triggers_list, definition_modes_list),
FILE_OPTIONS_ULLLIST
},
{
- {STRING_WITH_LEN("definers") },
+ {(char *) STRING_WITH_LEN("definers") },
offsetof(class Table_triggers_list, definers_list),
FILE_OPTIONS_STRLIST
},
@@ -53,7 +53,7 @@ static File_option triggers_file_parameters[]=
File_option sql_modes_parameters=
{
- {STRING_WITH_LEN("sql_modes") },
+ {(char*) STRING_WITH_LEN("sql_modes") },
offsetof(class Table_triggers_list, definition_modes_list),
FILE_OPTIONS_ULLLIST
};
@@ -78,18 +78,14 @@ struct st_trigname
};
static const LEX_STRING trigname_file_type=
- {STRING_WITH_LEN("TRIGGERNAME")};
+ {(char *) STRING_WITH_LEN("TRIGGERNAME")};
const char * const trigname_file_ext= ".TRN";
static File_option trigname_file_parameters[]=
{
{
- /*
- FIXME: Length specified for "trigger_table" key is erroneous, problem
- caused by this are reported as BUG#14090 and should be fixed ASAP.
- */
- {STRING_WITH_LEN("trigger_table")},
+ {(char *) STRING_WITH_LEN("trigger_table")},
offsetof(struct st_trigname, trigger_table),
FILE_OPTIONS_ESTRING
},
@@ -162,6 +158,17 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
But do we want this ?
*/
+ /*
+ Note that once we will have check for TRIGGER privilege in place we won't
+ need second part of condition below, since check_access() function also
+ checks that db is specified.
+ */
+ if (!thd->lex->spname->m_db.length || create && !tables->db_length)
+ {
+ my_error(ER_NO_DB_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
if (!create &&
!(tables= add_table_for_trigger(thd, thd->lex->spname)))
DBUG_RETURN(TRUE);
@@ -292,6 +299,9 @@ end:
definer. The caller is responsible to provide memory for
storing LEX_STRING object.
+ NOTE
+ Assumes that trigger name is fully qualified.
+
RETURN VALUE
False - success
True - error
@@ -314,9 +324,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
/* Trigger must be in the same schema as target table. */
- if (my_strcasecmp(table_alias_charset, table->s->db,
- lex->spname->m_db.str ? lex->spname->m_db.str :
- thd->db))
+ if (my_strcasecmp(table_alias_charset, table->s->db, lex->spname->m_db.str))
{
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
return 1;
@@ -1017,7 +1025,6 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
{
- const char *db= !trig->m_db.str ? thd->db : trig->m_db.str;
LEX *lex= thd->lex;
char path_buff[FN_REFLEN];
LEX_STRING path;
@@ -1025,7 +1032,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
struct st_trigname trigname;
DBUG_ENTER("add_table_for_trigger");
- strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/",
+ strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", trig->m_db.str, "/",
trig->m_name.str, trigname_file_ext, NullS);
path.length= unpack_filename(path_buff, path_buff);
path.str= path_buff;
@@ -1054,7 +1061,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
/* We need to reset statement table list to be PS/SP friendly. */
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
- DBUG_RETURN(sp_add_to_query_tables(thd, lex, db,
+ DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
trigname.trigger_table.str, TL_WRITE));
}
@@ -1130,7 +1137,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
trg_action_time_type time_type,
bool old_row_is_record1)
{
- int res= 0;
+ bool err_status= FALSE;
sp_head *sp_trigger= bodies[event][time_type];
if (sp_trigger)
@@ -1194,7 +1201,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
#endif // NO_EMBEDDED_ACCESS_CHECKS
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
- res= sp_trigger->execute_function(thd, 0, 0, 0);
+ err_status= sp_trigger->execute_function(thd, 0, 0, 0);
thd->restore_sub_statement_state(&statement_state);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1202,7 +1209,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
#endif // NO_EMBEDDED_ACCESS_CHECKS
}
- return res;
+ return err_status;
}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 6be42d7b868..51002683897 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -117,8 +117,8 @@ public:
void set_table(TABLE *new_table);
friend class Item_trigger_field;
- friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
- Table_triggers_list *triggers);
+ friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
+ TABLE_LIST *table);
private:
bool prepare_record1_accessors(TABLE *table);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 039aa0f71fa..2ff8a4bc244 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -465,7 +465,12 @@ int mysql_update(THD *thd,
}
else if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
{
- thd->fatal_error(); // Force error message
+ /*
+ If (ignore && error == HA_ERR_FOUND_DUPP_KEY) we don't have to
+ do anything; otherwise...
+ */
+ if (error != HA_ERR_FOUND_DUPP_KEY)
+ thd->fatal_error(); /* Other handler errors are fatal */
table->file->print_error(error,MYF(0));
error= 1;
break;
@@ -522,6 +527,7 @@ int mysql_update(THD *thd,
if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
+ free_underlaid_joins(thd, select_lex);
if (transactional_table)
{
if (ha_autocommit_or_rollback(thd, error >= 0))
@@ -534,7 +540,6 @@ int mysql_update(THD *thd,
thd->lock=0;
}
- free_underlaid_joins(thd, select_lex);
if (error < 0)
{
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -596,7 +601,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
tables.table= table;
tables.alias= table_list->alias;
- thd->allow_sum_func= 0;
+ thd->lex->allow_sum_func= 0;
if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
table_list, conds, &select_lex->leaf_tables,
@@ -611,7 +616,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
/* Check that we are not using table that we are updating in a sub select */
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
@@ -834,7 +839,7 @@ reopen_tables:
tl->lock_type != TL_READ_NO_INSERT)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(tl, table_list)))
+ if ((duplicate= unique_table(thd, tl, table_list)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
DBUG_RETURN(TRUE);
@@ -1021,8 +1026,7 @@ int multi_update::prepare(List<Item> &not_used_values,
{
TABLE *table=table_ref->table;
if (!(tables_to_update & table->map) &&
- find_table_in_local_list(update_tables, table_ref->db,
- table_ref->table_name))
+ unique_table(thd, table_ref, update_tables))
table->no_cache= 1; // Disable row cache
}
DBUG_RETURN(thd->is_fatal_error != 0);
@@ -1259,7 +1263,12 @@ bool multi_update::send_data(List<Item> &not_used_values)
updated--;
if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
{
- thd->fatal_error(); // Force error message
+ /*
+ If (ignore && error == HA_ERR_FOUND_DUPP_KEY) we don't have to
+ do anything; otherwise...
+ */
+ if (error != HA_ERR_FOUND_DUPP_KEY)
+ thd->fatal_error(); /* Other handler errors are fatal */
table->file->print_error(error,MYF(0));
DBUG_RETURN(1);
}
@@ -1280,22 +1289,23 @@ bool multi_update::send_data(List<Item> &not_used_values)
int error;
TABLE *tmp_table= tmp_tables[offset];
fill_record(thd, tmp_table->field+1, *values_for_table[offset], 1);
- found++;
/* Store pointer to row */
memcpy((char*) tmp_table->field[0]->ptr,
(char*) table->file->ref, table->file->ref_length);
/* Write row, ignoring duplicated updates to a row */
- if ((error= tmp_table->file->write_row(tmp_table->record[0])) &&
- (error != HA_ERR_FOUND_DUPP_KEY &&
- error != HA_ERR_FOUND_DUPP_UNIQUE))
+ if (error= tmp_table->file->write_row(tmp_table->record[0]))
{
- if (create_myisam_from_heap(thd, tmp_table, tmp_table_param + offset,
- error, 1))
+ if (error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE &&
+ create_myisam_from_heap(thd, tmp_table,
+ tmp_table_param + offset, error, 1))
{
do_update=0;
DBUG_RETURN(1); // Not a table_is_full error
}
}
+ else
+ found++;
}
}
DBUG_RETURN(0);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index e03d3b22b89..4f62a80cfd4 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -350,15 +350,6 @@ bool mysql_create_view(THD *thd,
*/
for (tbl= lex->query_tables; tbl; tbl= tbl->next_global)
{
- /* is this table temporary and is not view? */
- if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view &&
- !tbl->schema_table)
- {
- my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias);
- res= TRUE;
- goto err;
- }
-
/* is this table view and the same view which we creates now? */
if (tbl->view &&
strcmp(tbl->view_db.str, view->db) == 0 &&
@@ -370,11 +361,29 @@ bool mysql_create_view(THD *thd,
}
/*
- Copy the privileges of the underlying VIEWs which were filled by
- fill_effective_table_privileges
- (they were not copied at derived tables processing)
+ tbl->table can be NULL when tbl is a placeholder for a view
+ that is indirectly referenced via a stored function from the
+ view being created. We don't check these indirectly
+ referenced views in CREATE VIEW so they don't have table
+ object.
*/
- tbl->table->grant.privilege= tbl->grant.privilege;
+ if (tbl->table)
+ {
+ /* is this table temporary and is not view? */
+ if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view &&
+ !tbl->schema_table)
+ {
+ my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias);
+ res= TRUE;
+ goto err;
+ }
+ /*
+ Copy the privileges of the underlying VIEWs which were filled by
+ fill_effective_table_privileges
+ (they were not copied at derived tables processing)
+ */
+ tbl->table->grant.privilege= tbl->grant.privilege;
+ }
}
/* prepare select to resolve all fields */
@@ -641,10 +650,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
/* fill structure */
view->query.str= (char*)str.ptr();
view->query.length= str.length()-1; // we do not need last \0
- view->source.str= thd->lex->create_view_select_start;
+ view->source.str= thd->query + thd->lex->create_view_select_start;
view->source.length= (thd->query_length -
- (thd->lex->create_view_select_start -
- thd->lex->create_view_start));
+ thd->lex->create_view_select_start);
view->file_version= 1;
view->calc_md5(md5);
view->md5.str= md5;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 671e2b1740d..25e10362ece 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1350,41 +1350,11 @@ create_function_tail:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
- LEX_STRING cmt = { 0, 0 };
- create_field *new_field;
- uint unused1= 0;
- int unused2= 0;
-
- if (!(new_field= new_create_field(YYTHD, (char*) "",
- (enum enum_field_types)$8,
- lex->length, lex->dec, lex->type,
- (Item *)0, (Item *) 0, &cmt, 0,
- &lex->interval_list,
- (lex->charset ? lex->charset :
- default_charset_info),
- lex->uint_geom_type)))
- YYABORT;
-
- sp->m_returns_cs= new_field->charset;
-
- if (new_field->interval_list.elements)
- {
- new_field->interval=
- sp->create_typelib(&new_field->interval_list);
- }
- sp_prepare_create_field(YYTHD, new_field);
- if (prepare_create_field(new_field, &unused1, &unused2, &unused2,
- HA_CAN_GEOMETRY))
- YYABORT;
-
- sp->m_returns= new_field->sql_type;
- sp->m_returns_cs= new_field->charset;
- sp->m_returns_len= new_field->length;
- sp->m_returns_pack= new_field->pack_flag;
- sp->m_returns_typelib= new_field->interval;
- sp->m_geom_returns= new_field->geom_type;
- new_field->interval= NULL;
+ if (sp->fill_field_definition(YYTHD, lex,
+ (enum enum_field_types) $8,
+ &sp->m_return_field_def))
+ YYABORT;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
@@ -1407,6 +1377,11 @@ create_function_tail:
YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
sp->init_strings(YYTHD, lex, lex->spname);
+ if (!(sp->m_flags & sp_head::HAS_RETURN))
+ {
+ my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
+ YYABORT;
+ }
/* Restore flag if it was cleared above */
if (sp->m_old_cmq)
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
@@ -1501,8 +1476,28 @@ sp_fdparams:
| sp_fdparam
;
+sp_init_param:
+ /* Empty */
+ {
+ LEX *lex= Lex;
+
+ lex->length= 0;
+ lex->dec= 0;
+ lex->type= 0;
+
+ lex->default_value= 0;
+ lex->on_update_value= 0;
+
+ lex->comment= null_lex_str;
+ lex->charset= NULL;
+
+ lex->interval_list.empty();
+ lex->uint_geom_type= 0;
+ }
+ ;
+
sp_fdparam:
- ident type
+ ident sp_init_param type
{
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
@@ -1512,7 +1507,17 @@ sp_fdparam:
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
YYABORT;
}
- spc->push_pvar(&$1, (enum enum_field_types)$2, sp_param_in);
+ sp_pvar_t *pvar= spc->push_pvar(&$1, (enum enum_field_types)$3,
+ sp_param_in);
+
+ if (lex->sphead->fill_field_definition(YYTHD, lex,
+ (enum enum_field_types) $3,
+ &pvar->field_def))
+ {
+ YYABORT;
+ }
+ pvar->field_def.field_name= pvar->name.str;
+ pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
}
;
@@ -1528,18 +1533,27 @@ sp_pdparams:
;
sp_pdparam:
- sp_opt_inout ident type
+ sp_opt_inout sp_init_param ident type
{
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_pvar(&$2, TRUE))
+ if (spc->find_pvar(&$3, TRUE))
{
- my_error(ER_SP_DUP_PARAM, MYF(0), $2.str);
+ my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
YYABORT;
}
- spc->push_pvar(&$2, (enum enum_field_types)$3,
- (sp_param_mode_t)$1);
+ sp_pvar_t *pvar= spc->push_pvar(&$3, (enum enum_field_types)$4,
+ (sp_param_mode_t)$1);
+
+ if (lex->sphead->fill_field_definition(YYTHD, lex,
+ (enum enum_field_types) $4,
+ &pvar->field_def))
+ {
+ YYABORT;
+ }
+ pvar->field_def.field_name= pvar->name.str;
+ pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
}
;
@@ -1591,39 +1605,60 @@ sp_decls:
;
sp_decl:
- DECLARE_SYM sp_decl_idents type
- { Lex->sphead->reset_lex(YYTHD); }
- sp_opt_default
+ DECLARE_SYM sp_decl_idents
{
LEX *lex= Lex;
- sp_pcontext *ctx= lex->spcont;
- uint max= ctx->context_pvars();
- enum enum_field_types type= (enum enum_field_types)$3;
- Item *it= $5;
- bool has_default= (it != NULL);
- for (uint i = max-$2 ; i < max ; i++)
+ lex->sphead->reset_lex(YYTHD);
+ lex->spcont->declare_var_boundary($2);
+ }
+ type
+ sp_opt_default
+ {
+ LEX *lex= Lex;
+ sp_pcontext *pctx= lex->spcont;
+ uint num_vars= pctx->context_pvars();
+ enum enum_field_types var_type= (enum enum_field_types) $4;
+ Item *dflt_value_item= $5;
+ create_field *create_field_op;
+
+ if (!dflt_value_item)
{
- sp_instr_set *in;
- uint off= ctx->pvar_context2index(i);
-
- ctx->set_type(off, type);
- if (! has_default)
- it= new Item_null(); /* QQ Set to the type with null_value? */
- in = new sp_instr_set(lex->sphead->instructions(),
- ctx,
- off,
- it, type, lex,
- (i == max - 1));
-
- /*
- The last instruction is assigned to be responsible for
- freeing LEX.
- */
- lex->sphead->add_instr(in);
- ctx->set_default(off, it);
+ dflt_value_item= new Item_null();
+ /* QQ Set to the var_type with null_value? */
+ }
+
+ for (uint i = num_vars-$2 ; i < num_vars ; i++)
+ {
+ uint var_idx= pctx->pvar_context2index(i);
+ sp_pvar_t *pvar= pctx->find_pvar(var_idx);
+
+ if (!pvar)
+ YYABORT;
+
+ pvar->type= var_type;
+ pvar->dflt= dflt_value_item;
+
+ if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
+ &pvar->field_def))
+ {
+ YYABORT;
+ }
+
+ pvar->field_def.field_name= pvar->name.str;
+ pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
+
+ /* The last instruction is responsible for freeing LEX. */
+
+ lex->sphead->add_instr(
+ new sp_instr_set(lex->sphead->instructions(), pctx, var_idx,
+ dflt_value_item, var_type, lex,
+ (i == num_vars - 1)));
}
+
+ pctx->declare_var_boundary(0);
lex->sphead->restore_lex(YYTHD);
+
$$.vars= $2;
$$.conds= $$.hndlrs= $$.curs= 0;
}
@@ -1846,6 +1881,8 @@ sp_hcond:
sp_decl_idents:
ident
{
+ /* NOTE: field definition is filled in sp_decl section. */
+
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
@@ -1859,6 +1896,8 @@ sp_decl_idents:
}
| sp_decl_idents ',' ident
{
+ /* NOTE: field definition is filled in sp_decl section. */
+
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
@@ -1936,8 +1975,8 @@ sp_proc_stmt:
{
sp_instr_freturn *i;
- i= new sp_instr_freturn(sp->instructions(), lex->spcont,
- $3, sp->m_returns, lex);
+ i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3,
+ sp->m_return_field_def.sql_type, lex);
sp->add_instr(i);
sp->m_flags|= sp_head::HAS_RETURN;
}
@@ -1953,25 +1992,27 @@ sp_proc_stmt:
{ Lex->sphead->reset_lex(YYTHD); }
expr WHEN_SYM
{
- /* We "fake" this by using an anonymous variable which we
- set to the expression. Note that all WHENs are evaluate
- at the same frame level, so we then know that it's the
- top-most variable in the frame. */
LEX *lex= Lex;
- uint offset= lex->spcont->current_pvars();
- sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
- lex->spcont, offset, $3,
- MYSQL_TYPE_STRING, lex, TRUE);
- LEX_STRING dummy={(char*)"", 0};
-
- lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
- lex->sphead->add_instr(i);
- lex->sphead->m_flags|= sp_head::IN_SIMPLE_CASE;
- lex->sphead->restore_lex(YYTHD);
+ sp_head *sp= lex->sphead;
+ sp_pcontext *parsing_ctx= lex->spcont;
+ int case_expr_id= parsing_ctx->register_case_expr();
+
+ if (parsing_ctx->push_case_expr_id(case_expr_id))
+ YYABORT;
+
+ sp->add_instr(
+ new sp_instr_set_case_expr(sp->instructions(),
+ parsing_ctx,
+ case_expr_id,
+ $3,
+ lex));
+
+ sp->m_flags|= sp_head::IN_SIMPLE_CASE;
+ sp->restore_lex(YYTHD);
}
sp_case END CASE_SYM
{
- Lex->spcont->pop_pvar();
+ Lex->spcont->pop_case_expr_id();
}
| sp_labeled_control
{}
@@ -2282,20 +2323,20 @@ sp_case:
i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
else
{ /* Simple case: <caseval> = <whenval> */
- LEX_STRING ivar;
- ivar.str= (char *)"_tmp_";
- ivar.length= 5;
- Item_splocal *var= new Item_splocal(ivar,
- ctx->current_pvars()-1);
+ Item_case_expr *var;
+ Item *expr;
+
+ var= new Item_case_expr(ctx->get_current_case_expr_id());
+
#ifndef DBUG_OFF
if (var)
- var->owner= sp;
+ var->m_sp= sp;
#endif
- Item *expr= new Item_func_eq(var, $2);
+
+ expr= new Item_func_eq(var, $2);
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
- lex->variables_used= 1;
}
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
sp->add_instr(i);
@@ -3374,7 +3415,6 @@ alter:
THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
- lex->create_view_start= thd->query;
lex->create_view_mode= VIEW_ALTER;
/* first table in list is target VIEW name */
lex->select_lex.add_table_to_list(thd, $6, NULL, 0);
@@ -3773,11 +3813,6 @@ optimize:
OPTIMIZE opt_no_write_to_binlog table_or_tables
{
LEX *lex=Lex;
- if (lex->sphead)
- {
- my_error(ER_SP_BADSTATEMENT, MYF(0), "OPTIMIZE TABLE");
- YYABORT;
- }
lex->sql_command = SQLCOM_OPTIMIZE;
lex->no_write_to_binlog= $2;
lex->check_opt.init();
@@ -4396,16 +4431,14 @@ simple_expr:
{
if ($3->is_splocal())
{
- LEX_STRING *name;
Item_splocal *il= static_cast<Item_splocal *>($3);
- name= il->my_name(NULL);
- my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str);
+ my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
YYABORT;
}
$$= new Item_default_value(Lex->current_context(), $3);
}
- | VALUES '(' simple_ident ')'
+ | VALUES '(' simple_ident_nospvar ')'
{ $$= new Item_insert_value(Lex->current_context(), $3); }
| FUNC_ARG0 '(' ')'
{
@@ -5175,10 +5208,8 @@ join_table:
{
YYERROR_UNLESS($1 && ($$=$3));
/* Change the current name resolution context to a local context. */
- Name_resolution_context *on_context;
- if (!(on_context= make_join_on_context(YYTHD,$1,$3)))
+ if (push_new_name_resolution_context(YYTHD, $1, $3))
YYABORT;
- Lex->push_context(on_context);
}
expr
{
@@ -5190,10 +5221,8 @@ join_table:
{
YYERROR_UNLESS($1 && ($$=$3));
/* Change the current name resolution context to a local context. */
- Name_resolution_context *on_context;
- if (!(on_context= make_join_on_context(YYTHD,$1,$3)))
+ if (push_new_name_resolution_context(YYTHD, $1, $3))
YYABORT;
- Lex->push_context(on_context);
}
expr
{
@@ -5220,10 +5249,8 @@ join_table:
ON
{
/* Change the current name resolution context to a local context. */
- Name_resolution_context *on_context;
- if (!(on_context= make_join_on_context(YYTHD,$1,$5)))
+ if (push_new_name_resolution_context(YYTHD, $1, $5))
YYABORT;
- Lex->push_context(on_context);
}
expr
{
@@ -5253,10 +5280,8 @@ join_table:
ON
{
/* Change the current name resolution context to a local context. */
- Name_resolution_context *on_context;
- if (!(on_context= make_join_on_context(YYTHD,$1,$5)))
+ if (push_new_name_resolution_context(YYTHD, $1, $5))
YYABORT;
- Lex->push_context(on_context);
}
expr
{
@@ -5317,10 +5342,9 @@ table_factor:
ON
{
/* Change the current name resolution context to a local context. */
- Name_resolution_context *on_context;
- if (!(on_context= make_join_on_context(YYTHD,$3,$7)))
+ if (push_new_name_resolution_context(YYTHD, $3, $7))
YYABORT;
- Lex->push_context(on_context);
+
}
expr '}'
{
@@ -5877,7 +5901,7 @@ select_var_ident:
var_list.push_back(var= new my_var($1,1,t->offset,t->type));
#ifndef DBUG_OFF
if (var)
- var->owner= lex->sphead;
+ var->sp= lex->sphead;
#endif
}
}
@@ -7179,11 +7203,12 @@ simple_ident:
{
/* We're compiling a stored procedure and found a variable */
Item_splocal *splocal;
- splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev -
+ splocal= new Item_splocal($1, spv->offset, spv->type,
+ lex->tok_start_prev -
lex->sphead->m_tmp_query);
#ifndef DBUG_OFF
if (splocal)
- splocal->owner= lex->sphead;
+ splocal->m_sp= lex->sphead;
#endif
$$ = (Item*) splocal;
lex->variables_used= 1;
@@ -8875,6 +8900,7 @@ subselect_end:
LEX *lex=Lex;
lex->pop_context();
lex->current_select = lex->current_select->return_after_parsing();
+ lex->nest_level--;
};
definer:
@@ -8978,7 +9004,6 @@ view_tail:
THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
- lex->create_view_start= thd->query;
/* first table in list is target VIEW name */
if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))
YYABORT;
@@ -9009,11 +9034,21 @@ view_list:
view_select:
SELECT_SYM remember_name select_init2
{
- Lex->create_view_select_start= $2;
+ THD *thd=YYTHD;
+ LEX *lex= thd->lex;
+ char *stmt_beg= (lex->sphead ?
+ (char *)lex->sphead->m_tmp_query :
+ thd->query);
+ lex->create_view_select_start= $2 - stmt_beg;
}
| '(' remember_name select_paren ')' union_opt
{
- Lex->create_view_select_start= $2;
+ THD *thd=YYTHD;
+ LEX *lex= thd->lex;
+ char *stmt_beg= (lex->sphead ?
+ (char *)lex->sphead->m_tmp_query :
+ thd->query);
+ lex->create_view_select_start= $2 - stmt_beg;
}
;
diff --git a/sql/table.cc b/sql/table.cc
index 8068a839052..fc75568b615 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1247,15 +1247,15 @@ fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types,
} /* fix_type_pointers */
-TYPELIB *typelib(List<String> &strings)
+TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings)
{
- TYPELIB *result=(TYPELIB*) sql_alloc(sizeof(TYPELIB));
+ TYPELIB *result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
if (!result)
return 0;
result->count=strings.elements;
result->name="";
uint nbytes= (sizeof(char*) + sizeof(uint)) * (result->count + 1);
- if (!(result->type_names= (const char**) sql_alloc(nbytes)))
+ if (!(result->type_names= (const char**) alloc_root(mem_root, nbytes)))
return 0;
result->type_lengths= (uint*) (result->type_names + result->count + 1);
List_iterator<String> it(strings);
@@ -1403,13 +1403,12 @@ File create_frm(THD *thd, my_string name, const char *db,
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags|= O_EXCL | O_NOFOLLOW;
-#if SIZEOF_OFF_T > 4
/* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */
- if (create_info->max_rows > ~(ulong) 0)
- create_info->max_rows= ~(ulong) 0;
- if (create_info->min_rows > ~(ulong) 0)
- create_info->min_rows= ~(ulong) 0;
-#endif
+ if (create_info->max_rows > UINT_MAX32)
+ create_info->max_rows= UINT_MAX32;
+ if (create_info->min_rows > UINT_MAX32)
+ create_info->min_rows= UINT_MAX32;
+
/*
Ensure that raid_chunks can't be larger than 255, as this would cause
problems with drop database
@@ -2606,60 +2605,6 @@ GRANT_INFO *Natural_join_column::grant()
}
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
-/*
- Check the access rights for the current join column.
- columns.
-
- SYNOPSIS
- Natural_join_column::check_grants()
-
- DESCRIPTION
- Check the access rights to a column from a natural join in a generic
- way that hides the heterogeneity of the column representation - whether
- it is a view or a stored table colum.
-
- RETURN
- FALSE The column can be accessed
- TRUE There are no access rights to all equivalent columns
-*/
-
-bool
-Natural_join_column::check_grants(THD *thd, const char *name, uint length)
-{
- GRANT_INFO *grant;
- const char *db_name;
- const char *table_name;
- Security_context *save_security_ctx= thd->security_ctx;
- Security_context *new_sctx= table_ref->security_ctx;
- bool res;
-
- if (view_field)
- {
- DBUG_ASSERT(table_field == NULL);
- grant= &(table_ref->grant);
- db_name= table_ref->view_db.str;
- table_name= table_ref->view_name.str;
- }
- else
- {
- DBUG_ASSERT(table_field && view_field == NULL);
- grant= &(table_ref->table->grant);
- db_name= table_ref->table->s->db;
- table_name= table_ref->table->s->table_name;
- }
-
- if (new_sctx)
- thd->security_ctx= new_sctx;
- res= check_grant_column(thd, grant, db_name, table_name, name, length);
- thd->security_ctx= save_security_ctx;
- return res;
-}
-#endif
-
-
void Field_iterator_view::set(TABLE_LIST *table)
{
DBUG_ASSERT(table->field_translation);
@@ -2702,8 +2647,9 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
if (view->schema_table_reformed)
{
/*
- In case of SHOW command (schema_table_reformed set) all items are
- fixed
+ Translation table items are always Item_fields and already fixed
+ ('mysql_schema_table' function). So we can return directly the
+ field. This case happens only for 'show & where' commands.
*/
DBUG_ASSERT(field && field->fixed);
DBUG_RETURN(field);
@@ -2735,21 +2681,14 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
void Field_iterator_natural_join::set(TABLE_LIST *table_ref)
{
DBUG_ASSERT(table_ref->join_columns);
- delete column_ref_it;
-
- /*
- TODO: try not to allocate new iterator every time. If we have to,
- then check for out of memory condition.
- */
- column_ref_it= new List_iterator_fast<Natural_join_column>
- (*(table_ref->join_columns));
- cur_column_ref= (*column_ref_it)++;
+ column_ref_it.init(*(table_ref->join_columns));
+ cur_column_ref= column_ref_it++;
}
void Field_iterator_natural_join::next()
{
- cur_column_ref= (*column_ref_it)++;
+ cur_column_ref= column_ref_it++;
DBUG_ASSERT(!cur_column_ref || ! cur_column_ref->table_field ||
cur_column_ref->table_ref->table ==
cur_column_ref->table_field->table);
@@ -2876,7 +2815,6 @@ GRANT_INFO *Field_iterator_table_ref::grant()
SYNOPSIS
Field_iterator_table_ref::get_or_create_column_ref()
- thd [in] pointer to current thread
is_created [out] set to TRUE if the column was created,
FALSE if we return an already created colum
@@ -2889,7 +2827,7 @@ GRANT_INFO *Field_iterator_table_ref::grant()
*/
Natural_join_column *
-Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created)
+Field_iterator_table_ref::get_or_create_column_ref(bool *is_created)
{
Natural_join_column *nj_col;
@@ -2923,6 +2861,41 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created)
}
+/*
+ Return an existing reference to a column of a natural/using join.
+
+ SYNOPSIS
+ Field_iterator_table_ref::get_natural_column_ref()
+
+ DESCRIPTION
+ The method should be called in contexts where it is expected that
+ all natural join columns are already created, and that the column
+ being retrieved is a Natural_join_column.
+
+ RETURN
+ # Pointer to a column of a natural join (or its operand)
+ NULL No memory to allocate the column
+*/
+
+Natural_join_column *
+Field_iterator_table_ref::get_natural_column_ref()
+{
+ Natural_join_column *nj_col;
+
+ DBUG_ASSERT(field_it == &natural_join_it);
+ /*
+ The field belongs to a NATURAL join, therefore the column reference was
+ already created via one of the two constructor calls above. In this case
+ we just return the already created column reference.
+ */
+ nj_col= natural_join_it.column_ref();
+ DBUG_ASSERT(nj_col &&
+ (!nj_col->table_field ||
+ nj_col->table_ref->table == nj_col->table_field->table));
+ return nj_col;
+}
+
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
diff --git a/sql/table.h b/sql/table.h
index d919b9a4203..ce0616a6833 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -407,9 +407,6 @@ public:
const char *table_name();
const char *db_name();
GRANT_INFO *grant();
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- bool check_grants(THD *thd, const char *name, uint length);
-#endif
};
@@ -734,11 +731,11 @@ public:
class Field_iterator_natural_join: public Field_iterator
{
- List_iterator_fast<Natural_join_column> *column_ref_it;
+ List_iterator_fast<Natural_join_column> column_ref_it;
Natural_join_column *cur_column_ref;
public:
- Field_iterator_natural_join() :column_ref_it(NULL), cur_column_ref(NULL) {}
- ~Field_iterator_natural_join() { delete column_ref_it; }
+ Field_iterator_natural_join() :cur_column_ref(NULL) {}
+ ~Field_iterator_natural_join() {}
void set(TABLE_LIST *table);
void next();
bool end_of_fields() { return !cur_column_ref; }
@@ -785,7 +782,8 @@ public:
GRANT_INFO *grant();
Item *create_item(THD *thd) { return field_it->create_item(thd); }
Field *field() { return field_it->field(); }
- Natural_join_column *get_or_create_column_ref(THD *thd, bool *is_created);
+ Natural_join_column *get_or_create_column_ref(bool *is_created);
+ Natural_join_column *get_natural_column_ref();
};
diff --git a/sql/tztime.cc b/sql/tztime.cc
index e73d3f237ad..3a9d9a60aed 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2443,6 +2443,7 @@ scan_tz_dir(char * name_end)
int
main(int argc, char **argv)
{
+#ifndef __NETWARE__
MY_INIT(argv[0]);
if (argc != 2 && argc != 3)
@@ -2501,6 +2502,10 @@ main(int argc, char **argv)
free_root(&tz_storage, MYF(0));
}
+#else
+ fprintf(stderr, "This tool has not been ported to NetWare\n");
+#endif /* __NETWARE__ */
+
return 0;
}
diff --git a/sql/unireg.h b/sql/unireg.h
index 8f21dd1d2db..b932a2f320c 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -48,13 +48,9 @@
#define MAX_ALIAS_NAME 256
#define MAX_FIELD_NAME 34 /* Max colum name length +2 */
#define MAX_SYS_VAR_LENGTH 32
-#define MAX_KEY 64 /* Max used keys */
+#define MAX_KEY MAX_INDEXES /* Max used keys */
#define MAX_REF_PARTS 16 /* Max parts used as ref */
-#if SIZEOF_CHARP > 4
-#define MAX_KEY_LENGTH 3072 /* max possible key, if 64 bits */
-#else
-#define MAX_KEY_LENGTH 1024 /* max possible key, if 32 bits */
-#endif
+#define MAX_KEY_LENGTH 3072 /* max possible key */
#if SIZEOF_OFF_T > 4
#define MAX_REFLENGTH 8 /* Max length for record ref */
#else
diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c
index 4768e42a0b0..b18e5ee59d2 100644
--- a/strings/ctype-uca.c
+++ b/strings/ctype-uca.c
@@ -6706,6 +6706,14 @@ static const char esperanto[]=
"& U < \\u016d <<< \\u016c";
/*
+ A simplified version of Hungarian, without consonant contractions.
+*/
+static const char hungarian[]=
+ "&O < \\u00F6 <<< \\u00D6 << \\u0151 <<< \\u0150"
+ "&U < \\u00FC <<< \\u00DC << \\u0171 <<< \\u0170";
+
+
+/*
Unicode Collation Algorithm:
Collation element (weight) scanner,
for consequent scan of collations
@@ -8627,6 +8635,39 @@ CHARSET_INFO my_charset_ucs2_esperanto_uca_ci=
};
+CHARSET_INFO my_charset_ucs2_hungarian_uca_ci=
+{
+ 146,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE,
+ "ucs2", /* cs name */
+ "ucs2_hungarian_ci",/* name */
+ "", /* comment */
+ hungarian, /* tailoring */
+ NULL, /* ctype */
+ NULL, /* to_lower */
+ NULL, /* to_upper */
+ NULL, /* sort_order */
+ NULL, /* contractions */
+ NULL, /* sort_order_big*/
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ my_unicase_default, /* caseinfo */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 8, /* strxfrm_multiply */
+ 1, /* caseup_multiply */
+ 1, /* casedn_multiply */
+ 2, /* mbminlen */
+ 2, /* mbmaxlen */
+ 9, /* min_sort_char */
+ 0xFFFF, /* max_sort_char */
+ ' ', /* pad char */
+ 0, /* escape_with_backslash_is_dangerous */
+ &my_charset_ucs2_handler,
+ &my_collation_ucs2_uca_handler
+};
+
+
#endif
@@ -9252,6 +9293,38 @@ CHARSET_INFO my_charset_utf8_esperanto_uca_ci=
&my_collation_any_uca_handler
};
+CHARSET_INFO my_charset_utf8_hungarian_uca_ci=
+{
+ 210,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE,
+ "utf8", /* cs name */
+ "utf8_hungarian_ci",/* name */
+ "", /* comment */
+ hungarian, /* tailoring */
+ ctype_utf8, /* ctype */
+ NULL, /* to_lower */
+ NULL, /* to_upper */
+ NULL, /* sort_order */
+ NULL, /* contractions */
+ NULL, /* sort_order_big*/
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ my_unicase_default, /* caseinfo */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 8, /* strxfrm_multiply */
+ 1, /* caseup_multiply */
+ 1, /* casedn_multiply */
+ 1, /* mbminlen */
+ 3, /* mbmaxlen */
+ 9, /* min_sort_char */
+ 0xFFFF, /* max_sort_char */
+ ' ', /* pad char */
+ 0, /* escape_with_backslash_is_dangerous */
+ &my_charset_utf8_handler,
+ &my_collation_any_uca_handler
+};
+
#endif /* HAVE_CHARSET_utf8 */
#endif /* HAVE_UCA_COLLATIONS */
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index 80a7bd84601..e2629f445cb 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -1373,14 +1373,50 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs,
return (int) (t_is_prefix ? t-te : ((se-s) - (te-t)));
}
-static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs,
+static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)),
const uchar *s, uint slen,
const uchar *t, uint tlen,
my_bool diff_if_only_endspace_difference
__attribute__((unused)))
{
- /* TODO: Needs to be fixed to handle end space! */
- return my_strnncoll_ucs2_bin(cs,s,slen,t,tlen,0);
+ const uchar *se, *te;
+ uint minlen;
+
+ /* extra safety to make sure the lengths are even numbers */
+ slen= (slen >> 1) << 1;
+ tlen= (tlen >> 1) << 1;
+
+ se= s + slen;
+ te= t + tlen;
+
+ for (minlen= min(slen, tlen); minlen; minlen-= 2)
+ {
+ int s_wc= s[0] * 256 + s[1];
+ int t_wc= t[0] * 256 + t[1];
+ if ( s_wc != t_wc )
+ return s_wc > t_wc ? 1 : -1;
+
+ s+= 2;
+ t+= 2;
+ }
+
+ if (slen != tlen)
+ {
+ int swap= 1;
+ if (slen < tlen)
+ {
+ s= t;
+ se= te;
+ swap= -1;
+ }
+
+ for ( ; s < se ; s+= 2)
+ {
+ if (s[0] || s[1] != ' ')
+ return (s[0] == 0 && s[1] < ' ') ? -swap : swap;
+ }
+ }
+ return 0;
}
diff --git a/strings/decimal.c b/strings/decimal.c
index 0c1f03016e0..5fb37d374a2 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -1069,9 +1069,9 @@ int decimal2longlong(decimal_t *from, longlong *to)
}
}
/* boundary case: 9223372036854775808 */
- if (unlikely(from->sign==0 && x < 0 && -x < 0))
+ if (unlikely(from->sign==0 && x == LONGLONG_MIN))
{
- *to= -1-x;
+ *to= LONGLONG_MAX;
return E_DEC_OVERFLOW;
}
@@ -2675,7 +2675,8 @@ void test_pr(const char *s1, int prec, int dec, char filler, const char *orig,
int slen= sizeof(s2);
int res;
- sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler);
+ sprintf(s, filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'",
+ s1, prec, dec, filler);
end= strend(s1);
string2decimal(s1, &a, &end);
res= decimal2string(&a, s2, &slen, prec, dec, filler);
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
index 6dbffdc9778..1892e8b4a46 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -56,12 +56,18 @@ if test -z "$basedir"
then
basedir=@prefix@
bindir=@bindir@
- datadir=@localstatedir@
+ if test -z "$datadir"
+ then
+ datadir=@localstatedir@
+ fi
sbindir=@sbindir@
libexecdir=@libexecdir@
else
bindir="$basedir/bin"
- datadir="$basedir/data"
+ if test -z "$datadir"
+ then
+ datadir="$basedir/data"
+ fi
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
fi
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 4c52b4cee6b..912c6f9e051 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -35,7 +35,7 @@ Release: %{release}
License: %{license}
Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/mysql-%{mysql_version}.tar.gz
URL: http://www.mysql.com/
-Packager: Lenz Grimmer <build@mysql.com>
+Packager: MySQL Production Engineering Team <build@mysql.com>
Vendor: MySQL AB
Provides: msqlormysql MySQL-server mysql
BuildRequires: ncurses-devel
@@ -325,7 +325,13 @@ fi
make test-force || true
# Save mysqld-max
-mv sql/mysqld sql/mysqld-max
+# check if mysqld was installed in .libs/
+if test -f sql/.libs/mysqld
+then
+ cp sql/.libs/mysqld sql/mysqld-max
+else
+ cp sql/mysqld sql/mysqld-max
+fi
nm --numeric-sort sql/mysqld-max > sql/mysqld-max.sym
# Save the perror binary so it supports the NDB error codes (BUG#13740)
mv extra/perror extra/perror.ndb
@@ -363,14 +369,19 @@ BuildMySQL "--disable-shared \
--with-client-ldflags='-all-static' \
$USE_OTHER_LIBC_DIR \
%else
- --with-zlib-dir=bundled \
%endif
+ --with-zlib-dir=bundled \
--with-comment=\"MySQL Community Edition - Standard (GPL)\" \
--with-server-suffix='%{server_suffix}' \
--with-archive-storage-engine \
--with-innodb \
--with-big-tables"
-nm --numeric-sort sql/mysqld > sql/mysqld.sym
+if test -f sql/.libs/mysqld
+then
+ nm --numeric-sort sql/.libs/mysqld > sql/mysqld.sym
+else
+ nm --numeric-sort sql/mysqld > sql/mysqld.sym
+fi
# We might want to save the config log file
if test -n "$MYSQL_CONFLOG_DEST"
@@ -679,6 +690,8 @@ fi
%{_libdir}/mysql/libndbclient.a
%{_libdir}/mysql/libndbclient.la
%{_libdir}/mysql/libvio.a
+%{_libdir}/mysql/libz.a
+%{_libdir}/mysql/libz.la
%files shared
%defattr(-, root, root, 0755)
@@ -707,6 +720,20 @@ fi
# itself - note that they must be ordered by date (important when
# merging BK trees)
%changelog
+* Fri Dec 12 2005 Rodrigo Novo <rodrigo@mysql.com>
+
+- Added zlib to the list of (static) libraries installed
+- Added check against libtool wierdness (WRT: sql/mysqld || sql/.libs/mysqld)
+- Compile MySQL with bundled zlib
+- Fixed %packager name to "MySQL Production Engineering Team"
+
+* Mon Dec 05 2005 Joerg Bruehe <joerg@mysql.com>
+
+- Avoid using the "bundled" zlib on "shared" builds:
+ As it is not installed (on the build system), this gives dependency
+ problems with "libtool" causing the build to fail.
+ (Change was done on Nov 11, but left uncommented.)
+
* Tue Nov 22 2005 Joerg Bruehe <joerg@mysql.com>
- Extend the file existence check for "init.d/mysql" on un-install
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index ce732690700..216961b3a80 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -36,7 +36,7 @@
#define VER "2.1"
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
-#define MAX_KEY 64
+#define MAX_KEY MAX_INDEXES
#define MAX_SERVER_ARGS 64
/* set default options */
@@ -14590,6 +14590,40 @@ static void test_bug14845()
myquery(rc);
}
+
+/*
+ Bug #15510: mysql_warning_count returns 0 after mysql_stmt_fetch which
+ should warn
+*/
+static void test_bug15510()
+{
+ MYSQL_STMT *stmt;
+ MYSQL_RES *res;
+ int rc;
+ const char *query= "select 1 from dual where 1/0";
+
+ myheader("test_bug15510");
+
+ rc= mysql_query(mysql, "set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'");
+ myquery(rc);
+
+ stmt= mysql_stmt_init(mysql);
+
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(mysql_warning_count(mysql));
+
+ /* Cleanup */
+ mysql_stmt_close(stmt);
+ rc= mysql_query(mysql, "set @@sql_mode=''");
+ myquery(rc);
+}
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -14849,6 +14883,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug13488", test_bug13488 },
{ "test_bug13524", test_bug13524 },
{ "test_bug14845", test_bug14845 },
+ { "test_bug15510", test_bug15510},
{ 0, 0 }
};
diff --git a/vio/vio.c b/vio/vio.c
index ff93cff959f..bc286b2d2bb 100644
--- a/vio/vio.c
+++ b/vio/vio.c
@@ -87,7 +87,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
#ifdef HAVE_OPENSSL
if (type == VIO_TYPE_SSL)
{
- vio->viodelete =vio_ssl_delete;
+ vio->viodelete =vio_delete;
vio->vioerrno =vio_ssl_errno;
vio->read =vio_ssl_read;
vio->write =vio_ssl_write;
diff --git a/vio/vio_priv.h b/vio/vio_priv.h
index c1c78cc6efa..eb495025ddd 100644
--- a/vio/vio_priv.h
+++ b/vio/vio_priv.h
@@ -28,7 +28,6 @@ void vio_ignore_timeout(Vio *vio, uint which, uint timeout);
#ifdef HAVE_OPENSSL
#include "my_net.h" /* needed because of struct in_addr */
-void vio_ssl_delete(Vio* vio);
int vio_ssl_read(Vio *vio,gptr buf, int size);
int vio_ssl_write(Vio *vio,const gptr buf,int size);
void vio_ssl_timeout(Vio *vio, uint which, uint timeout);
diff --git a/vio/viossl.c b/vio/viossl.c
index e6af07c4b0b..1273814c551 100644
--- a/vio/viossl.c
+++ b/vio/viossl.c
@@ -69,25 +69,6 @@ report_errors()
DBUG_VOID_RETURN;
}
-/*
- Delete a vio object
-
- SYNPOSIS
- vio_ssl_delete()
- vio Vio object. May be 0.
-*/
-
-
-void vio_ssl_delete(Vio * vio)
-{
- if (vio)
- {
- if (vio->type != VIO_CLOSED)
- vio_close(vio);
- my_free((gptr) vio,MYF(0));
- }
-}
-
int vio_ssl_errno(Vio *vio __attribute__((unused)))
{
diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c
index 766d835d2c0..4ee27f1e491 100644
--- a/vio/viosslfactories.c
+++ b/vio/viosslfactories.c
@@ -191,9 +191,6 @@ void netware_ssl_cleanup()
/* NetWare SSL initialization */
static void netware_ssl_init()
{
- /* initialize OpenSSL library */
- SSL_library_init();
-
/* cleanup OpenSSL library */
NXVmRegisterExitHandler(netware_ssl_cleanup, NULL);
}
@@ -228,16 +225,17 @@ new_VioSSLConnectorFd(const char* key_file,
ptr->ssl_method= 0;
/* FIXME: constants! */
-#ifdef __NETWARE__
- netware_ssl_init();
-#endif
-
if (!ssl_algorithms_added)
{
DBUG_PRINT("info", ("todo: OpenSSL_add_all_algorithms()"));
ssl_algorithms_added = TRUE;
+ SSL_library_init();
OpenSSL_add_all_algorithms();
}
+#ifdef __NETWARE__
+ netware_ssl_init();
+#endif
+
if (!ssl_error_strings_loaded)
{
DBUG_PRINT("info", ("todo:SSL_load_error_strings()"));
@@ -319,17 +317,18 @@ new_VioSSLAcceptorFd(const char *key_file,
/* FIXME: constants! */
ptr->session_id_context= ptr;
-#ifdef __NETWARE__
- netware_ssl_init();
-#endif
-
if (!ssl_algorithms_added)
{
DBUG_PRINT("info", ("todo: OpenSSL_add_all_algorithms()"));
ssl_algorithms_added = TRUE;
+ SSL_library_init();
OpenSSL_add_all_algorithms();
}
+#ifdef __NETWARE__
+ netware_ssl_init();
+#endif
+
if (!ssl_error_strings_loaded)
{
DBUG_PRINT("info", ("todo: SSL_load_error_strings()"));
diff --git a/zlib/Makefile.am b/zlib/Makefile.am
index e94d184a841..11b1991fa62 100644
--- a/zlib/Makefile.am
+++ b/zlib/Makefile.am
@@ -18,6 +18,8 @@
pkglib_LTLIBRARIES=libz.la
+libz_la_LDFLAGS= -version-info 3:3:2
+
noinst_HEADERS= crc32.h deflate.h inffast.h inffixed.h inflate.h \
inftrees.h trees.h zconf.h zlib.h zutil.h