diff options
148 files changed, 3094 insertions, 1137 deletions
diff --git a/Docs/Makefile.am b/Docs/Makefile.am index b1f69381774..542c82d8f58 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -18,11 +18,11 @@ noinst_SCRIPTS = Support/generate-text-files.pl EXTRA_DIST = $(noinst_SCRIPTS) mysql.info INSTALL-BINARY -all: txt_files - -txt_files: ../INSTALL-SOURCE ../INSTALL-WIN-SOURCE ../EXCEPTIONS-CLIENT \ +TXT_FILES= ../INSTALL-SOURCE ../INSTALL-WIN-SOURCE ../EXCEPTIONS-CLIENT \ INSTALL-BINARY ../support-files/MacOSX/ReadMe.txt +all-local: $(TXT_FILES) + # make sure that "make install" installs the info page, too # automake only seems to take care of this automatically, # if we're building the info page from texi directly. @@ -30,28 +30,37 @@ install-data-hook: mysql.info $(mkinstalldirs) $(DESTDIR)$(infodir) $(INSTALL_DATA) $(srcdir)/mysql.info $(DESTDIR)$(infodir) -CLEAN_FILES: $(txt_files) - touch $(txt_files) +uninstall-local: + @RM@ -f $(DESTDIR)$(infodir)/mysql.info + +# Problems with "make distclean", works differently for make files +# generated by different versions of the automake. Some require the +# generated files explicitly in DISTCLEANFILES. +DISTCLEANFILES = $(TXT_FILES) + +# This target is not used in builds, just for convinience +CLEAN_FILES: $(TXT_FILES) + touch $(TXT_FILES) GT = $(srcdir)/Support/generate-text-files.pl ../INSTALL-SOURCE: mysql.info $(GT) - perl -w $(GT) mysql.info "installing-source" "windows-source-build" > $@ + perl -w $(GT) $< "installing-source" "windows-source-build" > $@ ../INSTALL-WIN-SOURCE: mysql.info $(GT) - perl -w $(GT) mysql.info "windows-source-build" "post-installation" > $@ + perl -w $(GT) $< "windows-source-build" "post-installation" > $@ # We put the description for the binary installation here so that # people who download source wont have to see it. It is moved up to # the toplevel by the script that makes the binary tar files. INSTALL-BINARY: mysql.info $(GT) - perl -w $(GT) mysql.info "installing-binary" "installing-source" > $@ + perl -w $(GT) $< "installing-binary" "installing-source" > $@ ../EXCEPTIONS-CLIENT: mysql.info $(GT) - perl -w $(GT) mysql.info "mysql-floss-license-exception" "function-index" > $@ + perl -w $(GT) $< "mysql-floss-license-exception" "function-index" > $@ ../support-files/MacOSX/ReadMe.txt: mysql.info $(GT) - perl -w $(GT) mysql.info "mac-os-x-installation" "netware-installation" > $@ + perl -w $(GT) $< "mac-os-x-installation" "netware-installation" > $@ # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/Makefile.am b/Makefile.am index 16cd8fcffd1..e78a762af53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,8 @@ AUTOMAKE_OPTIONS = foreign # These are built from source in the Docs directory -EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT +EXTRA_DIST = INSTALL-SOURCE INSTALL-WIN-SOURCE \ + README COPYING EXCEPTIONS-CLIENT SUBDIRS = . include @docs_dirs@ @zlib_dir@ @yassl_dir@ \ @readline_topdir@ sql-common \ @thread_dirs@ pstack \ @@ -37,16 +38,19 @@ DIST_SUBDIRS = . include @docs_dirs@ zlib \ BUILD netware os2 @libmysqld_dirs@\ @bench_dirs@ support-files server-tools tools -# Relink after clean -linked_sources = linked_client_sources linked_server_sources \ - linked_libmysql_sources linked_libmysql_r_sources \ - linked_libmysqld_sources linked_libmysqldex_sources \ +# Run these targets before any others, also make part of clean target, +# to make sure we create new links after a clean. +BUILT_SOURCES = linked_client_sources linked_server_sources \ + @linked_client_targets@ \ + @linked_libmysqld_targets@ \ linked_include_sources @linked_netware_sources@ -CLEANFILES = $(linked_sources) - -# This is just so that the linking is done early. -all-local: $(linked_sources) +# The db.h file is a bit special, see note in "configure.in". +# In the case we didn't compile with bdb, a dummy file is put +# there, but will not be removed by the bdb make file becuase +# it will never be called. +CLEANFILES = $(BUILT_SOURCES) bdb/build_unix/db.h +DISTCLEANFILES = ac_available_languages_fragment linked_include_sources: cd include; $(MAKE) link_sources @@ -76,13 +80,8 @@ linked_netware_sources: cd @netware_dir@; $(MAKE) link_sources echo timestamp > linked_netware_sources -#avoid recursive make calls in sql directory linked_server_sources: - cd sql; rm -f mini_client_errors.c;\ - @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c;\ - rm -f pack.c;@LN_CP_F@ ../sql-common/pack.c pack.c;\ - rm -f client.c;@LN_CP_F@ ../sql-common/client.c client.c;\ - rm -f my_time.c;@LN_CP_F@ ../sql-common/my_time.c my_time.c + cd sql; $(MAKE) link_sources echo timestamp > linked_server_sources # Create permission databases @@ -94,7 +93,7 @@ bin-dist: all # Remove BK's "SCCS" subdirectories from source distribution dist-hook: - rm -rf `find $(distdir) -type d -name SCCS` + rm -rf `find $(distdir) -type d -name SCCS -print` tags: support-files/build-tags diff --git a/client/Makefile.am b/client/Makefile.am index cf9d2884ded..804f194085f 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -56,12 +56,12 @@ DEFS = -DUNDEF_THREADS_HACK link_sources: for f in $(sql_src) ; do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(top_srcdir)/sql/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/sql/$$f $$f; \ done; \ for f in $(strings_src) ; do \ rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(top_srcdir)/strings/$$f $(srcdir)/$$f; \ + @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \ done; # Don't update the files from bitkeeper diff --git a/client/mysql.cc b/client/mysql.cc index b2c9666f8b0..c5f0b6cd09a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -527,7 +527,7 @@ static struct my_option my_long_options[] = {"help", 'I', "Synonym for -?", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"auto-rehash", OPT_AUTO_REHASH, diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index ec136402bd8..53bf59af67a 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -127,7 +127,7 @@ static TYPELIB command_typelib= static struct my_option my_long_options[] = { #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"count", 'c', diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 6cba3c0cb44..7eb26d30cf9 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -647,7 +647,7 @@ static struct my_option my_long_options[] = { #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif /* diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 2eb3e55c2e9..1324060eb55 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -63,7 +63,7 @@ static struct my_option my_long_options[] = (gptr*) &opt_all_in_1, (gptr*) &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"auto-repair", OPT_AUTO_REPAIR, diff --git a/client/mysqldump.c b/client/mysqldump.c index b92b971ea4f..47ec9a72108 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -173,7 +173,7 @@ static struct my_option my_long_options[] = "Allow creation of column names that are keywords.", (gptr*) &opt_keywords, (gptr*) &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"character-sets-dir", OPT_CHARSETS_DIR, @@ -1841,12 +1841,13 @@ DELIMITER ;;\n"); while ((row= mysql_fetch_row(result))) { fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n\ -/*!50003 CREATE TRIGGER %s %s %s ON %s FOR EACH ROW%s */;;\n\n", +/*!50003 CREATE TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n\n", row[6], /* sql_mode */ quote_name(row[0], name_buff, 0), /* Trigger */ row[4], /* Timing */ row[1], /* Event */ result_table, + (strchr(" \t\n\r", *(row[3]))) ? "" : " ", row[3] /* Statement */); } if (mysql_num_rows(result)) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 19d4ef16ef9..958f987d16b 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -59,7 +59,7 @@ static char *shared_memory_base_name=0; static struct my_option my_long_options[] = { #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"character-sets-dir", OPT_CHARSETS_DIR, diff --git a/client/mysqlshow.c b/client/mysqlshow.c index 8f6be6cf70b..8369d918d6f 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -157,7 +157,7 @@ int main(int argc, char **argv) static struct my_option my_long_options[] = { #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"character-sets-dir", 'c', "Directory where character sets are.", diff --git a/client/mysqltest.c b/client/mysqltest.c index 58c0928c36d..f6d28101fa0 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3314,20 +3314,23 @@ static int handle_error(const char *query, struct st_query *q, ((q->expected_errno[i].type == ERR_SQLSTATE) && (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0))) { - if (q->expected_errors == 1) + if (!disable_result_log) { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds, "ERROR ", 6); - replace_dynstr_append(ds, err_sqlstate); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, err_error); - dynstr_append_mem(ds,"\n",1); + if (q->expected_errors == 1) + { + /* Only log error if there is one possible error */ + dynstr_append_mem(ds, "ERROR ", 6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds,"\n",1); + } + /* Don't log error if we may not get an error */ + else if (q->expected_errno[0].type == ERR_SQLSTATE || + (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0)) + dynstr_append(ds,"Got one of the listed errors\n"); } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) - dynstr_append(ds,"Got one of the listed errors\n"); /* OK */ DBUG_RETURN(0); } @@ -3335,11 +3338,14 @@ static int handle_error(const char *query, struct st_query *q, DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append(ds, err_sqlstate); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, err_error); - dynstr_append_mem(ds, "\n", 1); + if (!disable_result_log) + { + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds, "\n", 1); + } if (i) { diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am index af1bf8b2c97..ae6755f1c5c 100644 --- a/cmd-line-utils/libedit/Makefile.am +++ b/cmd-line-utils/libedit/Makefile.am @@ -2,8 +2,8 @@ # Makefile for the GNU readline library. # Copyright (C) 1994,1996,1997 Free Software Foundation, Inc. -ASRC=vi.c emacs.c common.c -AHDR=vi.h emacs.h common.h +ASRC = $(srcdir)/vi.c $(srcdir)/emacs.c $(srcdir)/common.c +AHDR = vi.h emacs.h common.h INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(srcdir)/../.. -I.. @@ -42,16 +42,16 @@ SUFFIXES = .sh $< > $@-t @MV@ $@-t $@ -vi.h: vi.c makelist - sh ./makelist -h ./vi.c > $@.tmp && \ +vi.h: $(srcdir)/vi.c makelist + sh ./makelist -h $(srcdir)/vi.c > $@.tmp && \ mv $@.tmp $@ -emacs.h: emacs.c makelist - sh ./makelist -h ./emacs.c > $@.tmp && \ +emacs.h: $(srcdir)/emacs.c makelist + sh ./makelist -h $(srcdir)/emacs.c > $@.tmp && \ mv $@.tmp $@ -common.h: common.c makelist - sh ./makelist -h ./common.c > $@.tmp && \ +common.h: $(srcdir)/common.c makelist + sh ./makelist -h $(srcdir)/common.c > $@.tmp && \ mv $@.tmp $@ help.c: ${ASRC} makelist diff --git a/config/ac-macros/zlib.m4 b/config/ac-macros/zlib.m4 index 22cf9542cf0..ec55f19b98f 100644 --- a/config/ac-macros/zlib.m4 +++ b/config/ac-macros/zlib.m4 @@ -19,7 +19,7 @@ INCLUDES="$INCLUDES $ZLIB_INCLUDES" LIBS="$LIBS $ZLIB_LIBS" AC_CACHE_VAL([mysql_cv_compress], [AC_TRY_LINK([#include <zlib.h>], - [return compress(0, (unsigned long*) 0, "", 0);], + [return zlibCompileFlags();], [mysql_cv_compress="yes" AC_MSG_RESULT([ok])], [mysql_cv_compress="no"]) diff --git a/configure.in b/configure.in index ab6d5e4c0be..efcaf82934d 100644 --- a/configure.in +++ b/configure.in @@ -6,8 +6,7 @@ AC_PREREQ(2.52)dnl Minimum Autoconf version required. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -# Don't forget to also update the NDB lines below. -AM_INIT_AUTOMAKE(mysql, 5.1.2-alpha) +AM_INIT_AUTOMAKE(mysql, 5.1.3-alpha) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -61,7 +60,6 @@ AC_DEFINE_UNQUOTED([DOT_FRM_VERSION], [$DOT_FRM_VERSION], [Version of .frm files]) AC_SUBST(SHARED_LIB_VERSION) AC_SUBST(AVAILABLE_LANGUAGES) -AC_SUBST(AVAILABLE_LANGUAGES_ERRORS) # Canonicalize the configuration name. @@ -2182,6 +2180,7 @@ then AC_MSG_WARN([extra-tools disabled because --enable-thread-safe-client wasn't used]) else tools_dirs="tools" + AC_CONFIG_FILES(tools/Makefile) fi fi @@ -2203,9 +2202,12 @@ MYSQL_CHECK_OPENSSL MYSQL_CHECK_YASSL libmysqld_dirs= +linked_libmysqld_targets= if test "$with_embedded_server" = "yes" then libmysqld_dirs=libmysqld + linked_libmysqld_targets="linked_libmysqld_sources linked_libmysqldex_sources" + AC_CONFIG_FILES(libmysqld/Makefile libmysqld/examples/Makefile) # We can't build embedded library without building the server, because # we depend on libmysys, libmystrings, libmyisam, etc. with_server=yes @@ -2214,6 +2216,7 @@ fi # mysql_config --libmysqld-libs will print out something like # -L/path/to/lib/mysql -lmysqld -lmyisam -lmysys -lmystrings -ldbug ... AC_SUBST([libmysqld_dirs]) +AC_SUBST([linked_libmysqld_targets]) # Shall we build the docs? AC_ARG_WITH(docs, @@ -2318,7 +2321,7 @@ then readline_basedir="libedit" readline_dir="$readline_topdir/$readline_basedir" readline_link="\$(top_builddir)/cmd-line-utils/libedit/libedit.a" - readline_h_ln_cmd="\$(LN) -s \$(top_builddir)/cmd-line-utils/libedit/readline readline" + readline_h_ln_cmd="\$(LN) -s \$(top_srcdir)/cmd-line-utils/libedit/readline readline" compile_libedit=yes AC_DEFINE_UNQUOTED(HAVE_HIST_ENTRY, 1) AC_DEFINE_UNQUOTED(USE_LIBEDIT_INTERFACE, 1) @@ -2328,7 +2331,7 @@ then readline_basedir="readline" readline_dir="$readline_topdir/$readline_basedir" readline_link="\$(top_builddir)/cmd-line-utils/readline/libreadline.a" - readline_h_ln_cmd="\$(LN) -s \$(top_builddir)/cmd-line-utils/readline readline" + readline_h_ln_cmd="\$(LN) -s \$(top_srcdir)/cmd-line-utils/readline readline" compile_readline=yes AC_DEFINE_UNQUOTED(USE_NEW_READLINE_INTERFACE, 1) else @@ -2433,6 +2436,7 @@ if test "$THREAD_SAFE_CLIENT" != "no" then sql_client_dirs="libmysql_r $sql_client_dirs" linked_client_targets="$linked_client_targets linked_libmysql_r_sources" + AC_CONFIG_FILES(libmysql_r/Makefile) AC_DEFINE([THREAD_SAFE_CLIENT], [1], [Should be client be thread safe]) fi @@ -2532,12 +2536,11 @@ AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl storage/myisam/Makefile storage/myisammrg/Makefile dnl os2/Makefile os2/include/Makefile os2/include/sys/Makefile dnl man/Makefile BUILD/Makefile vio/Makefile dnl - libmysql_r/Makefile libmysqld/Makefile libmysqld/examples/Makefile dnl libmysql/Makefile client/Makefile dnl pstack/Makefile pstack/aout/Makefile sql/Makefile sql/share/Makefile dnl sql/handlerton.cc sql-common/Makefile SSL/Makefile dnl dbug/Makefile scripts/Makefile dnl - include/Makefile sql-bench/Makefile tools/Makefile dnl + include/Makefile sql-bench/Makefile dnl server-tools/Makefile server-tools/instance-manager/Makefile dnl tests/Makefile Docs/Makefile support-files/Makefile dnl support-files/MacOSX/Makefile mysql-test/Makefile dnl diff --git a/extra/Makefile.am b/extra/Makefile.am index feb96cdaf24..a2b4dce374a 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -23,6 +23,9 @@ BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \ $(top_builddir)/include/mysqld_ername.h pkginclude_HEADERS= $(BUILT_SOURCES) CLEANFILES = $(BUILT_SOURCES) +# We never use SUBDIRS here, but needed for automake 1.6.3 +# to generate code to handle DIST_SUBDIRS +SUBDIRS= DIST_SUBDIRS= yassl # This will build mysqld_error.h and sql_state.h diff --git a/extra/yassl/Makefile.am b/extra/yassl/Makefile.am index 7c1f2ea5acb..41c4d84f24f 100644 --- a/extra/yassl/Makefile.am +++ b/extra/yassl/Makefile.am @@ -1,2 +1,2 @@ SUBDIRS = taocrypt src -EXTRA_DIST = yassl.dsp yassl.dsw mySTL/*.hpp +EXTRA_DIST = yassl.dsp yassl.dsw $(wildcard mySTL/*.hpp) diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am index 4ebb9a2d862..df96018e1cf 100644 --- a/extra/yassl/src/Makefile.am +++ b/extra/yassl/src/Makefile.am @@ -4,5 +4,5 @@ noinst_LIBRARIES = libyassl.a libyassl_a_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 = ../include/*.hpp ../include/openssl/*.h +EXTRA_DIST = $(wildcard ../include/*.hpp) $(wildcard ../include/openssl/*.h) AM_CXXFLAGS = -DYASSL_PURE_C diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am index 9ce083e9e56..0319fc6057b 100644 --- a/extra/yassl/taocrypt/src/Makefile.am +++ b/extra/yassl/taocrypt/src/Makefile.am @@ -11,5 +11,5 @@ libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ template_instnt.cpp libtaocrypt_a_LIBADD = libtaoint_a-integer.o -EXTRA_DIST = ../include/*.hpp +EXTRA_DIST = $(wildcard ../include/*.hpp) AM_CXXFLAGS = -DYASSL_PURE_C diff --git a/include/Makefile.am b/include/Makefile.am index 8c3a575453d..d2605628a7d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -38,20 +38,12 @@ CLEANFILES = mysql_version.h my_config.h readline # Some include files that may be moved and patched by configure DISTCLEANFILES = sched.h $(CLEANFILES) -all-local: my_config.h - -# Since we include my_config.h it better exist from the beginning link_sources: - $(CP) ../config.h my_config.h -$(RM) -fr readline @readline_h_ln_cmd@ -# Keep automake happy - my_config.h: ../config.h $(CP) ../config.h my_config.h - -$(RM) -fr readline - @readline_h_ln_cmd@ # These files should not be included in distributions since they are # generated by configure from the .h.in files diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index 403ff415378..319a9913255 100644 --- a/libmysql/Makefile.am +++ b/libmysql/Makefile.am @@ -43,33 +43,33 @@ link_sources: vs=`echo $(vio_objects) | sed "s;\.lo;.c;g"`; \ scs=`echo $(sql_cmn_objects) | sed "s;\.lo;.c;g"`; \ for f in $$ss; do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \ done; \ for f in $$vs $(vioheaders); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../vio/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/vio/$$f $$f; \ done; \ for f in $$scs; do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../sql-common/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/sql-common/$$f $$f; \ done; \ for f in $(mystringsextra); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \ done; \ for f in $$ds; do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../dbug/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/dbug/$$f $$f; \ done; \ for f in $$ms $(mysysheaders); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../mysys/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/mysys/$$f $$f; \ done; \ - rm -f $(srcdir)/net.c; \ - @LN_CP_F@ $(srcdir)/../sql/net_serv.cc $(srcdir)/net.c ; \ - rm -f $(srcdir)/password.c; \ - @LN_CP_F@ $(srcdir)/../sql/password.c $(srcdir)/password.c + rm -f net.c; \ + @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc net.c ; \ + rm -f password.c; \ + @LN_CP_F@ $(top_srcdir)/sql/password.c password.c # This part requires GNUmake # diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am index 6ab09368cc5..ee6dd4cfded 100644 --- a/libmysql_r/Makefile.am +++ b/libmysql_r/Makefile.am @@ -39,6 +39,6 @@ libmysqlclient_r_la_LDFLAGS = $(target_ldflags) link_sources: set -x; \ for f in `cd $(libmysql_dir) && echo *.[ch]`; do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(libmysql_dir)/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(libmysql_dir)/$$f $$f; \ done diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 14125c79e10..da0418eaf9c 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -143,19 +143,19 @@ endif link_sources: set -x; \ for f in $(sqlsources); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/sql/$$f $$f; \ done; \ for f in $(libmysqlsources); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../libmysql/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/libmysql/$$f $$f; \ done; \ for f in $(sqlstoragesources); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ `find $(srcdir)/../sql -name $$f` $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ `find $(srcdir)/../sql -name $$f` $$f; \ done; \ - rm -f $(srcdir)/client_settings.h; \ - @LN_CP_F@ $(srcdir)/../libmysql/client_settings.h $(srcdir)/client_settings.h; + rm -f client_settings.h; \ + @LN_CP_F@ $(top_srcdir)/libmysql/client_settings.h client_settings.h clean-local: diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am index 0bd3f06a9f3..bbfa4d87181 100644 --- a/libmysqld/examples/Makefile.am +++ b/libmysqld/examples/Makefile.am @@ -21,14 +21,15 @@ tests_sources = $(mysql_client_test_embedded_SOURCES) CLEANFILES = $(client_sources) $(tests_sources) link_sources: + set -x; \ for f in $(client_sources); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../../client/$$f $(srcdir)/$$f; \ - done; + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/client/$$f $$f; \ + done; \ for f in $(tests_sources); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../../tests/$$f $(srcdir)/$$f; \ - done; + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/tests/$$f $$f; \ + done DEFS = -DEMBEDDED_LIBRARY INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \ diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 2142a84419e..a63b4cbf178 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -85,6 +85,9 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib +uninstall-local: + @RM@ -f -r $(DESTDIR)$(testdir) + std_data/client-key.pem: @CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data std_data/client-cert.pem: diff --git a/mysql-test/include/is_debug_build.inc b/mysql-test/include/is_debug_build.inc new file mode 100644 index 00000000000..23a2814e2bb --- /dev/null +++ b/mysql-test/include/is_debug_build.inc @@ -0,0 +1,4 @@ +-- require r/is_debug_build.require +--disable_query_log +select instr(version(), "debug") > 0; +--enable_query_log diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 817be3a2e7c..8da18df1954 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -68,12 +68,12 @@ select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)); CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)) 2004 Warnings: -Warning 1292 Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33' +Warning 1292 Truncated incorrect BINARY(4) value: '2004-01-22 21:45:33' select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)) 2004 Warnings: -Warning 1292 Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33' +Warning 1292 Truncated incorrect BINARY(4) value: '2004-01-22 21:45:33' select CAST(0xb3 as signed); CAST(0xb3 as signed) 179 @@ -165,17 +165,17 @@ cast(_latin1'ab' AS char) as c1, cast(_latin1'a ' AS char) as c2, cast(_latin1'abc' AS char(2)) as c3, cast(_latin1'a ' AS char(2)) as c4, -cast(_latin1'a' AS char(2)) as c5; +hex(cast(_latin1'a' AS char(2))) as c5; c1 c2 c3 c4 c5 -ab a ab a a +ab a ab a 6100 Warnings: -Warning 1292 Truncated incorrect CHAR(2) value: 'abc' -Warning 1292 Truncated incorrect CHAR(2) value: 'a ' +Warning 1292 Truncated incorrect BINARY(2) value: 'abc' +Warning 1292 Truncated incorrect BINARY(2) value: 'a ' select cast(1000 as CHAR(3)); cast(1000 as CHAR(3)) 100 Warnings: -Warning 1292 Truncated incorrect CHAR(3) value: '1000' +Warning 1292 Truncated incorrect BINARY(3) value: '1000' create table t1 select cast(_latin1'ab' AS char) as c1, cast(_latin1'a ' AS char) as c2, @@ -183,11 +183,11 @@ cast(_latin1'abc' AS char(2)) as c3, cast(_latin1'a ' AS char(2)) as c4, cast(_latin1'a' AS char(2)) as c5; Warnings: -Warning 1292 Truncated incorrect CHAR(2) value: 'abc' -Warning 1292 Truncated incorrect CHAR(2) value: 'a ' -select * from t1; -c1 c2 c3 c4 c5 -ab a ab a a +Warning 1292 Truncated incorrect BINARY(2) value: 'abc' +Warning 1292 Truncated incorrect BINARY(2) value: 'a ' +select c1,c2,c3,c4,hex(c5) from t1; +c1 c2 c3 c4 hex(c5) +ab a ab a 6100 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -274,9 +274,9 @@ aac aac aab aab aaa aaa Warnings: -Warning 1292 Truncated incorrect CHAR(2) value: 'aaa' -Warning 1292 Truncated incorrect CHAR(2) value: 'aab' -Warning 1292 Truncated incorrect CHAR(2) value: 'aac' +Warning 1292 Truncated incorrect BINARY(2) value: 'aaa' +Warning 1292 Truncated incorrect BINARY(2) value: 'aab' +Warning 1292 Truncated incorrect BINARY(2) value: 'aac' SELECT a, CAST(a AS UNSIGNED) FROM t1 ORDER BY CAST(a AS CHAR) ; a CAST(a AS UNSIGNED) aaa 3 @@ -288,9 +288,9 @@ aaa aa aab aa aac aa Warnings: -Warning 1292 Truncated incorrect CHAR(2) value: 'aaa' -Warning 1292 Truncated incorrect CHAR(2) value: 'aab' -Warning 1292 Truncated incorrect CHAR(2) value: 'aac' +Warning 1292 Truncated incorrect BINARY(2) value: 'aaa' +Warning 1292 Truncated incorrect BINARY(2) value: 'aab' +Warning 1292 Truncated incorrect BINARY(2) value: 'aac' DROP TABLE t1; select date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour); date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour) diff --git a/mysql-test/r/is_debug_build.require b/mysql-test/r/is_debug_build.require new file mode 100644 index 00000000000..4d77bcdc1ed --- /dev/null +++ b/mysql-test/r/is_debug_build.require @@ -0,0 +1,2 @@ +instr(version(), "debug") > 0 +1 diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 3b3db08303a..bb89ff29b8a 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2494,3 +2494,59 @@ drop view v2; drop view v0; drop view v1; drop table t1; +SET @old_sql_mode = @@SQL_MODE; +SET SQL_MODE = IGNORE_SPACE; +CREATE TABLE t1 (a INT); +CREATE TRIGGER tr1 BEFORE INSERT ON t1 +FOR EACH ROW +BEGIN +SET new.a = 0; +END| +SET SQL_MODE = @old_sql_mode; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; +DELIMITER ;; +/*!50003 SET SESSION SQL_MODE="IGNORE_SPACE" */;; +/*!50003 CREATE TRIGGER `tr1` BEFORE INSERT ON `t1` FOR EACH ROW BEGIN +SET new.a = 0; +END */;; + +DELIMITER ; +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!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 TRIGGER tr1; +DROP TABLE t1; diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result index 84dbe975a59..ee88b7c8007 100644 --- a/mysql-test/r/ndb_alter_table.result +++ b/mysql-test/r/ndb_alter_table.result @@ -179,8 +179,7 @@ a b c 2 two two alter table t1 drop index c; select * from t1 where b = 'two'; -a b c -2 two two +ERROR HY000: Table definition has changed, please retry transaction select * from t1 where b = 'two'; a b c 2 two two diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 2b1ad3c4227..3a3ee5735f0 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -582,3 +582,4 @@ Konstantin Osipov Moscow, Russia Prepared statements (4.1), Cursors (5.0) Petr Chardin Moscow, Russia Instance Manager (5.0) Sergey Vojtovich Izhevsk, Russia Plugins infrastructure (5.1) Alexander Nozdrin Moscow, Russia Bugfixing (Stored Procedures, 5.0) +Per-Erik Martin Uppsala, Sweden Stored Procedures (5.0) diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result new file mode 100644 index 00000000000..e6c4ffe1731 --- /dev/null +++ b/mysql-test/r/sp-code.result @@ -0,0 +1,62 @@ +create procedure empty() +begin +end; +show procedure code empty; +Pos Instruction +drop procedure empty; +create function almost_empty() +returns int +return 0; +show function code almost_empty; +Pos Instruction +0 freturn 3 0 +drop function almost_empty; +create procedure code_sample(x int, out err int, out nulls int) +begin +declare count int default 0; +set nulls = 0; +begin +declare c cursor for select name from t1; +declare exit handler for not found close c; +open c; +loop +begin +declare n varchar(20); +declare continue handler for sqlexception set err=1; +fetch c into n; +if isnull(n) then +set nulls = nulls + 1; +else +set count = count + 1; +update t2 set idx = count where name=n; +end if; +end; +end loop; +end; +select t.name, t.idx from t2 t order by idx asc; +end// +show procedure code code_sample; +Pos Instruction +0 set count@3 0 +1 set nulls@2 0 +2 cpush c@0 +3 hpush_jump 6 4 EXIT +4 cclose c@0 +5 hreturn 0 19 +6 copen c@0 +7 set n@4 NULL +8 hpush_jump 11 5 CONTINUE +9 set err@1 1 +10 hreturn 5 +11 cfetch c@0 n@4 +12 jump_if_not 15 isnull(n@4) +13 set nulls@2 (nulls@2 + 1) +14 jump 17 +15 set count@3 (count@3 + 1) +16 stmt 4 "update t2 set idx = count where name=n" +17 hpop 1 +18 jump 7 +19 hpop 1 +20 cpop 1 +21 stmt 0 "select t.name, t.idx from t2 t order ..." +drop procedure code_sample; diff --git a/mysql-test/r/sp-dynamic.result b/mysql-test/r/sp-dynamic.result index 8fe469431cc..cf07f540608 100644 --- a/mysql-test/r/sp-dynamic.result +++ b/mysql-test/r/sp-dynamic.result @@ -33,6 +33,8 @@ begin execute stmt; end| prepare stmt from "call p1()"| +set @SAVE_SP_RECURSION_LEVELS=@@max_sp_recursion_depth| +set @@max_sp_recursion_depth=100| execute stmt| ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner execute stmt| @@ -40,11 +42,18 @@ ERROR HY000: The prepared statement contains a stored routine call that refers t execute stmt| ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner call p1()| -ERROR HY000: Recursive stored routines are not allowed. +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +call p1()| +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +call p1()| +ERROR HY000: The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner +set @@max_sp_recursion_depth=@SAVE_SP_RECURSION_LEVELS| +call p1()| +ERROR HY000: Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine p1 call p1()| -ERROR HY000: Recursive stored routines are not allowed. +ERROR HY000: Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine p1 call p1()| -ERROR HY000: Recursive stored routines are not allowed. +ERROR HY000: Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine p1 drop procedure p1| create procedure p1() begin diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 858f7d0bb16..963f14820be 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -708,7 +708,7 @@ return (i in (100, 200, bug11394(i-1), 400)); end if; end| select bug11394(2)| -ERROR HY000: Recursive stored routines are not allowed. +ERROR HY000: Recursive stored functions and triggers are not allowed. drop function bug11394| create function bug11394_1(i int) returns int begin @@ -719,7 +719,7 @@ return (select bug11394_1(i-1)); end if; end| select bug11394_1(2)| -ERROR HY000: Recursive stored routines are not allowed. +ERROR HY000: Recursive stored functions and triggers are not allowed. drop function bug11394_1| create function bug11394_2(i int) returns int return i| select bug11394_2(bug11394_2(10))| @@ -733,7 +733,10 @@ call bug11394(i - 1,(select 1)); end if; end| call bug11394(2, 1)| -ERROR HY000: Recursive stored routines are not allowed. +ERROR HY000: Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine bug11394 +set @@max_sp_recursion_depth=10| +call bug11394(2, 1)| +set @@max_sp_recursion_depth=default| drop procedure bug11394| CREATE PROCEDURE BUG_12490() HELP CONTENTS; ERROR 0A000: HELP is not allowed in stored procedures diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 93332af21a9..c3b4039d12d 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3417,6 +3417,9 @@ Table Create Table tm1 CREATE TEMPORARY TABLE `tm1` ( `spv1` decimal(6,3) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop procedure bug12589_1| +drop procedure bug12589_2| +drop procedure bug12589_3| drop table if exists t3| drop procedure if exists bug7049_1| drop procedure if exists bug7049_2| @@ -3667,4 +3670,203 @@ call bug14845()| a 0 drop procedure bug14845| +drop procedure if exists bug13549_1| +drop procedure if exists bug13549_2| +CREATE PROCEDURE `bug13549_2`() +begin +call bug13549_1(); +end| +CREATE PROCEDURE `bug13549_1`() +begin +declare done int default 0; +set done= not done; +end| +CALL bug13549_2()| +drop procedure bug13549_2| +drop procedure bug13549_1| +drop function if exists bug10100f| +drop procedure if exists bug10100p| +drop procedure if exists bug10100t| +drop procedure if exists bug10100pt| +drop procedure if exists bug10100pv| +drop procedure if exists bug10100pd| +drop procedure if exists bug10100pc| +create function bug10100f(prm int) returns int +begin +if prm > 1 then +return prm * bug10100f(prm - 1); +end if; +return 1; +end| +create procedure bug10100p(prm int, inout res int) +begin +set res = res * prm; +if prm > 1 then +call bug10100p(prm - 1, res); +end if; +end| +create procedure bug10100t(prm int) +begin +declare res int; +set res = 1; +call bug10100p(prm, res); +select res; +end| +create table t3 (a int)| +insert into t3 values (0)| +create view v1 as select a from t3; +create procedure bug10100pt(level int, lim int) +begin +if level < lim then +update t3 set a=level; +FLUSH TABLES; +call bug10100pt(level+1, lim); +else +select * from t3; +end if; +end| +create procedure bug10100pv(level int, lim int) +begin +if level < lim then +update v1 set a=level; +FLUSH TABLES; +call bug10100pv(level+1, lim); +else +select * from v1; +end if; +end| +prepare stmt2 from "select * from t3;"; +create procedure bug10100pd(level int, lim int) +begin +if level < lim then +select level; +prepare stmt1 from "update t3 set a=a+2"; +execute stmt1; +FLUSH TABLES; +execute stmt1; +FLUSH TABLES; +execute stmt1; +FLUSH TABLES; +deallocate prepare stmt1; +execute stmt2; +select * from t3; +call bug10100pd(level+1, lim); +else +execute stmt2; +end if; +end| +create procedure bug10100pc(level int, lim int) +begin +declare lv int; +declare c cursor for select a from t3; +open c; +if level < lim then +select level; +fetch c into lv; +select lv; +update t3 set a=level+lv; +FLUSH TABLES; +call bug10100pc(level+1, lim); +else +select * from t3; +end if; +close c; +end| +set @@max_sp_recursion_depth=4| +select @@max_sp_recursion_depth| +@@max_sp_recursion_depth +4 +select bug10100f(3)| +ERROR HY000: Recursive stored functions and triggers are not allowed. +select bug10100f(6)| +ERROR HY000: Recursive stored functions and triggers are not allowed. +call bug10100t(5)| +res +120 +call bug10100pt(1,5)| +a +4 +call bug10100pv(1,5)| +a +4 +update t3 set a=1| +call bug10100pd(1,5)| +level +1 +a +7 +a +7 +level +2 +a +13 +a +13 +level +3 +a +19 +a +19 +level +4 +a +25 +a +25 +a +25 +select * from t3| +a +25 +update t3 set a=1| +call bug10100pc(1,5)| +level +1 +lv +1 +level +2 +lv +2 +level +3 +lv +4 +level +4 +lv +7 +a +11 +select * from t3| +a +11 +set @@max_sp_recursion_depth=0| +select @@max_sp_recursion_depth| +@@max_sp_recursion_depth +0 +select bug10100f(5)| +ERROR HY000: Recursive stored functions and triggers are not allowed. +call bug10100t(5)| +ERROR HY000: Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine bug10100p +set @@max_sp_recursion_depth=255| +set @var=1| +call bug10100p(255, @var)| +call bug10100pt(1,255)| +call bug10100pv(1,255)| +call bug10100pd(1,255)| +call bug10100pc(1,255)| +set @@max_sp_recursion_depth=0| +deallocate prepare stmt2| +drop function bug10100f| +drop procedure bug10100p| +drop procedure bug10100t| +drop procedure bug10100pt| +drop procedure bug10100pv| +drop procedure bug10100pd| +drop procedure bug10100pc| +drop view v1| +drop table t3| drop table t1,t2; diff --git a/mysql-test/r/sp_trans.result b/mysql-test/r/sp_trans.result index 6077087ab87..bb742d0d3d7 100644 --- a/mysql-test/r/sp_trans.result +++ b/mysql-test/r/sp_trans.result @@ -174,3 +174,198 @@ ERROR HY000: Explicit or implicit commit is not allowed in stored function or tr drop procedure bug10015_8| drop function bug10015_7| drop table t1, t2| +drop function if exists bug13825_0| +drop function if exists bug13825_1| +drop function if exists bug13825_2| +drop function if exists bug13825_3| +drop function if exists bug13825_4| +drop function if exists bug13825_5| +drop procedure if exists bug13825_0| +drop procedure if exists bug13825_1| +drop procedure if exists bug13825_2| +drop table if exists t1| +create table t1 (i int) engine=innodb| +create table t2 (i int) engine=innodb| +create function bug13825_0() returns int +begin +rollback to savepoint x; +return 1; +end| +create function bug13825_1() returns int +begin +release savepoint x; +return 1; +end| +create function bug13825_2() returns int +begin +insert into t1 values (2); +savepoint x; +insert into t1 values (3); +rollback to savepoint x; +insert into t1 values (4); +return 1; +end| +create procedure bug13825_0() +begin +rollback to savepoint x; +end| +create procedure bug13825_1() +begin +release savepoint x; +end| +create procedure bug13825_2() +begin +savepoint x; +end| +insert into t2 values (1)| +create trigger t2_bi before insert on t2 for each row +rollback to savepoint x| +create trigger t2_bu before update on t2 for each row +release savepoint x| +create trigger t2_bd before delete on t2 for each row +begin +insert into t1 values (2); +savepoint x; +insert into t1 values (3); +rollback to savepoint x; +insert into t1 values (4); +end| +create function bug13825_3(rb int) returns int +begin +insert into t1 values(1); +savepoint x; +insert into t1 values(2); +if rb then +rollback to savepoint x; +end if; +insert into t1 values(3); +return rb; +end| +create function bug13825_4() returns int +begin +savepoint x; +insert into t1 values(2); +rollback to savepoint x; +return 0; +end| +create function bug13825_5(p int) returns int +begin +savepoint x; +insert into t2 values(p); +rollback to savepoint x; +insert into t2 values(p+1); +return p; +end| +set autocommit= 0| +begin | +insert into t1 values (1)| +savepoint x| +set @a:= bug13825_0()| +ERROR 42000: SAVEPOINT x does not exist +insert into t2 values (2)| +ERROR 42000: SAVEPOINT x does not exist +set @a:= bug13825_1()| +ERROR 42000: SAVEPOINT x does not exist +update t2 set i = 2| +ERROR 42000: SAVEPOINT x does not exist +set @a:= bug13825_2()| +select * from t1| +i +1 +2 +4 +rollback to savepoint x| +select * from t1| +i +1 +delete from t2| +select * from t1| +i +1 +2 +4 +rollback to savepoint x| +select * from t1| +i +1 +release savepoint x| +set @a:= bug13825_2()| +select * from t1| +i +1 +2 +4 +rollback to savepoint x| +ERROR 42000: SAVEPOINT x does not exist +delete from t1| +commit| +begin| +insert into t1 values (5)| +savepoint x| +insert into t1 values (6)| +call bug13825_0()| +select * from t1| +i +5 +call bug13825_1()| +rollback to savepoint x| +ERROR 42000: SAVEPOINT x does not exist +savepoint x| +insert into t1 values (7)| +call bug13825_2()| +rollback to savepoint x| +select * from t1| +i +5 +7 +delete from t1| +commit| +set autocommit= 1| +select bug13825_3(0)| +bug13825_3(0) +0 +select * from t1| +i +1 +2 +3 +delete from t1| +select bug13825_3(1)| +bug13825_3(1) +1 +select * from t1| +i +1 +3 +delete from t1| +set autocommit= 0| +begin| +insert into t1 values (1)| +set @a:= bug13825_4()| +select * from t1| +i +1 +delete from t1| +commit| +set autocommit= 1| +drop table t2| +create table t2 (i int) engine=innodb| +insert into t1 values (1), (bug13825_5(2)), (3)| +select * from t1| +i +1 +2 +3 +select * from t2| +i +3 +drop function bug13825_0| +drop function bug13825_1| +drop function bug13825_2| +drop function bug13825_3| +drop function bug13825_4| +drop function bug13825_5| +drop procedure bug13825_0| +drop procedure bug13825_1| +drop procedure bug13825_2| +drop table t1, t2| diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index af99dea58b9..ff92fc543d4 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -703,8 +703,11 @@ create trigger t1_ai after insert on t1 for each row insert into t2 values (new.f1+1); create trigger t2_ai after insert on t2 for each row insert into t1 values (new.f2+1); +set @SAVE_SP_RECURSION_LEVELS=@@max_sp_recursion_depth; +set @@max_sp_recursion_depth=100; insert into t1 values (1); ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +set @@max_sp_recursion_depth=@SAVE_SP_RECURSION_LEVELS; select * from t1; f1 1 @@ -763,3 +766,17 @@ ERROR HY000: Table 't3' was not locked with LOCK TABLES deallocate prepare stmt1; drop procedure p1; drop table t1, t2, t3; +create table t1 (a int); +drop procedure if exists p2; +CREATE PROCEDURE `p2`() +begin +insert into t1 values (1); +end// +create trigger trg before insert on t1 for each row +begin +declare done int default 0; +set done= not done; +end// +CALL p2(); +drop procedure p2; +drop table t1; diff --git a/mysql-test/r/type_binary.result b/mysql-test/r/type_binary.result index 49fd7ba5633..1c60bf46608 100644 --- a/mysql-test/r/type_binary.result +++ b/mysql-test/r/type_binary.result @@ -111,3 +111,6 @@ select count(distinct s1) from t1; count(distinct s1) 3 drop table t1; +select hex(cast(0x10 as binary(2))); +hex(cast(0x10 as binary(2))) +1000 diff --git a/mysql-test/r/type_newdecimal-big.result b/mysql-test/r/type_newdecimal-big.result new file mode 100644 index 00000000000..e95f2f3f781 --- /dev/null +++ b/mysql-test/r/type_newdecimal-big.result @@ -0,0 +1,11 @@ +drop procedure if exists sp1; +create procedure sp1 () 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 sp1()// +v1 v2 v3 * 0.000000000001 v4 * 0.000000000001 +1.000000100000 1.999999900000 1.000000100000 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/variables.result b/mysql-test/r/variables.result index 5b91e02e39b..d192ee6fe1c 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -351,6 +351,14 @@ set global rpl_recovery_rank=100; set global server_id=100; set global slow_launch_time=100; set sort_buffer_size=100; +set @@max_sp_recursion_depth=10; +select @@max_sp_recursion_depth; +@@max_sp_recursion_depth +10 +set @@max_sp_recursion_depth=0; +select @@max_sp_recursion_depth; +@@max_sp_recursion_depth +0 set sql_auto_is_null=1; select @@sql_auto_is_null; @@sql_auto_is_null diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 89067ec23a2..e2ee02351d7 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -501,3 +501,20 @@ drop user test14256; insert into mysql.user select * from t1; flush privileges; drop table t1; +create database mysqltest; +use mysqltest; +CREATE TABLE t1 (i INT); +CREATE VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` +GRANT SELECT, LOCK TABLES ON mysqltest.* TO mysqltest_1@localhost; +use mysqltest; +LOCK TABLES v1 READ; +SHOW CREATE TABLE v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' +UNLOCK TABLES; +use test; +use test; +drop user mysqltest_1@localhost; +drop database mysqltest; diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 70eb87131df..dc7f695e38e 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -64,7 +64,7 @@ select cast(_latin1'a ' AS char) as c2, cast(_latin1'abc' AS char(2)) as c3, cast(_latin1'a ' AS char(2)) as c4, - cast(_latin1'a' AS char(2)) as c5; + hex(cast(_latin1'a' AS char(2))) as c5; select cast(1000 as CHAR(3)); create table t1 select @@ -73,7 +73,7 @@ create table t1 select cast(_latin1'abc' AS char(2)) as c3, cast(_latin1'a ' AS char(2)) as c4, cast(_latin1'a' AS char(2)) as c5; -select * from t1; +select c1,c2,c3,c4,hex(c5) from t1; show create table t1; drop table t1; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index be59e336739..65c4dcb6df5 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -16,3 +16,4 @@ rpl_until : Unstable test case, bug#12429 rpl_deadlock : Unstable test case, bug#12429 kill : Unstable test case, bug#9712 compress : Magnus will fix +ndb_alter_table : Martin will fix diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 83085823729..5666f23f5aa 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -999,3 +999,27 @@ drop view v2; drop view v0; drop view v1; drop table t1; + +# +# BUG#14554 - mysqldump does not separate words "ROW" and "BEGIN" +# for tables with trigger created in the IGNORE_SPACE sql mode. +# + +SET @old_sql_mode = @@SQL_MODE; +SET SQL_MODE = IGNORE_SPACE; + +CREATE TABLE t1 (a INT); +DELIMITER |; +CREATE TRIGGER tr1 BEFORE INSERT ON t1 + FOR EACH ROW + BEGIN + SET new.a = 0; + END| +DELIMITER ;| + +SET SQL_MODE = @old_sql_mode; + +--exec $MYSQL_DUMP --skip-comments --databases test + +DROP TRIGGER tr1; +DROP TABLE t1; diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 75ab245a352..58e3e002b2a 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -142,6 +142,7 @@ INSERT INTO t1 VALUES (1,2,0),(18,19,4),(20,21,0); select c from t1 order by c; drop table t1; +--disable_ps_protocol create table t1 ( a int primary key, b varchar(10), c varchar(10), index (b) ) engine=ndb; insert into t1 values (1,'one','one'), (2,'two','two'), (3,'three','three'); @@ -151,10 +152,13 @@ select * from t1 where b = 'two'; connection server1; alter table t1 drop index c; connection server2; +# This should fail since index information is not automatically refreshed +--error 1412 select * from t1 where b = 'two'; select * from t1 where b = 'two'; connection server1; drop table t1; +--enable_ps_protocol #--disable_warnings #DROP TABLE IF EXISTS t2; diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test new file mode 100644 index 00000000000..6644bc3ab43 --- /dev/null +++ b/mysql-test/t/sp-code.test @@ -0,0 +1,49 @@ +# +# Test the debugging feature "show procedure/function code <name>" +# + +-- source include/is_debug_build.inc + +create procedure empty() +begin +end; +show procedure code empty; +drop procedure empty; + +create function almost_empty() + returns int + return 0; +show function code almost_empty; +drop function almost_empty; + +delimiter //; +create procedure code_sample(x int, out err int, out nulls int) +begin + declare count int default 0; + + set nulls = 0; + begin + declare c cursor for select name from t1; + declare exit handler for not found close c; + + open c; + loop + begin + declare n varchar(20); + declare continue handler for sqlexception set err=1; + + fetch c into n; + if isnull(n) then + set nulls = nulls + 1; + else + set count = count + 1; + update t2 set idx = count where name=n; + end if; + end; + end loop; + end; + select t.name, t.idx from t2 t order by idx asc; +end// +delimiter ;// +show procedure code code_sample; +drop procedure code_sample; diff --git a/mysql-test/t/sp-dynamic.test b/mysql-test/t/sp-dynamic.test index e9816ee3ef0..5416f5931ff 100644 --- a/mysql-test/t/sp-dynamic.test +++ b/mysql-test/t/sp-dynamic.test @@ -26,18 +26,29 @@ begin execute stmt; end| prepare stmt from "call p1()"| +# Allow SP resursion to be show that it has not influence here +set @SAVE_SP_RECURSION_LEVELS=@@max_sp_recursion_depth| +set @@max_sp_recursion_depth=100| --error ER_PS_NO_RECURSION execute stmt| --error ER_PS_NO_RECURSION execute stmt| --error ER_PS_NO_RECURSION execute stmt| ---error ER_SP_NO_RECURSION +--error ER_PS_NO_RECURSION +call p1()| +--error ER_PS_NO_RECURSION call p1()| ---error ER_SP_NO_RECURSION +--error ER_PS_NO_RECURSION call p1()| ---error ER_SP_NO_RECURSION +set @@max_sp_recursion_depth=@SAVE_SP_RECURSION_LEVELS| +--error ER_SP_RECURSION_LIMIT call p1()| +--error ER_SP_RECURSION_LIMIT +call p1()| +--error ER_SP_RECURSION_LIMIT +call p1()| + drop procedure p1| # # C. Create/drop a stored procedure in Dynamic SQL. diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 5057dd0d9f8..69e5f73817b 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1044,10 +1044,11 @@ begin call bug11394(i - 1,(select 1)); end if; end| -# Again if we allow recursion for stored procedures (without -# additional efforts) the following statement will crash the server. ---error 1424 +--error ER_SP_RECURSION_LIMIT +call bug11394(2, 1)| +set @@max_sp_recursion_depth=10| call bug11394(2, 1)| +set @@max_sp_recursion_depth=default| drop procedure bug11394| delimiter ;| diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 5ad2b9287aa..def6afc000e 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4291,6 +4291,9 @@ call bug12589_1()| # No warnings here call bug12589_2()| call bug12589_3()| +drop procedure bug12589_1| +drop procedure bug12589_2| +drop procedure bug12589_3| # # BUG#7049: Stored procedure CALL errors are ignored @@ -4595,6 +4598,185 @@ call bug14845()| drop procedure bug14845| # +# BUG#13549 "Server crash with nested stored procedures". +# Server should not crash when during execution of stored procedure +# we have to parse trigger/function definition and this new trigger/ +# function has more local variables declared than invoking stored +# procedure and last of these variables is used in argument of NOT +# operator. +# +--disable_warnings +drop procedure if exists bug13549_1| +drop procedure if exists bug13549_2| +--enable_warnings +CREATE PROCEDURE `bug13549_2`() +begin + call bug13549_1(); +end| +CREATE PROCEDURE `bug13549_1`() +begin + declare done int default 0; + set done= not done; +end| +CALL bug13549_2()| +drop procedure bug13549_2| +drop procedure bug13549_1| + +# +# BUG#10100: function (and stored procedure?) recursivity problem +# +--disable_warnings +drop function if exists bug10100f| +drop procedure if exists bug10100p| +drop procedure if exists bug10100t| +drop procedure if exists bug10100pt| +drop procedure if exists bug10100pv| +drop procedure if exists bug10100pd| +drop procedure if exists bug10100pc| +--enable_warnings +# routines with simple recursion +create function bug10100f(prm int) returns int +begin + if prm > 1 then + return prm * bug10100f(prm - 1); + end if; + return 1; +end| +create procedure bug10100p(prm int, inout res int) +begin + set res = res * prm; + if prm > 1 then + call bug10100p(prm - 1, res); + end if; +end| +create procedure bug10100t(prm int) +begin + declare res int; + set res = 1; + call bug10100p(prm, res); + select res; +end| + +# a procedure which use tables and recursion +create table t3 (a int)| +insert into t3 values (0)| +create view v1 as select a from t3; +create procedure bug10100pt(level int, lim int) +begin + if level < lim then + update t3 set a=level; + FLUSH TABLES; + call bug10100pt(level+1, lim); + else + select * from t3; + end if; +end| +# view & recursion +create procedure bug10100pv(level int, lim int) +begin + if level < lim then + update v1 set a=level; + FLUSH TABLES; + call bug10100pv(level+1, lim); + else + select * from v1; + end if; +end| +# dynamic sql & recursion +prepare stmt2 from "select * from t3;"; +create procedure bug10100pd(level int, lim int) +begin + if level < lim then + select level; + prepare stmt1 from "update t3 set a=a+2"; + execute stmt1; + FLUSH TABLES; + execute stmt1; + FLUSH TABLES; + execute stmt1; + FLUSH TABLES; + deallocate prepare stmt1; + execute stmt2; + select * from t3; + call bug10100pd(level+1, lim); + else + execute stmt2; + end if; +end| +# cursor & recursion +create procedure bug10100pc(level int, lim int) +begin + declare lv int; + declare c cursor for select a from t3; + open c; + if level < lim then + select level; + fetch c into lv; + select lv; + update t3 set a=level+lv; + FLUSH TABLES; + call bug10100pc(level+1, lim); + else + select * from t3; + end if; + close c; +end| + +set @@max_sp_recursion_depth=4| +select @@max_sp_recursion_depth| +-- error ER_SP_NO_RECURSION +select bug10100f(3)| +-- error ER_SP_NO_RECURSION +select bug10100f(6)| +call bug10100t(5)| +call bug10100pt(1,5)| +call bug10100pv(1,5)| +update t3 set a=1| +call bug10100pd(1,5)| +select * from t3| +update t3 set a=1| +call bug10100pc(1,5)| +select * from t3| +set @@max_sp_recursion_depth=0| +select @@max_sp_recursion_depth| +-- error ER_SP_NO_RECURSION +select bug10100f(5)| +-- error ER_SP_RECURSION_LIMIT +call bug10100t(5)| + +#end of the stack checking +set @@max_sp_recursion_depth=255| +set @var=1| +#disable log because error about stack overrun contains numbers which +#depend on a system +-- disable_result_log +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100p(255, @var)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pt(1,255)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pv(1,255)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pd(1,255)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pc(1,255)| +-- enable_result_log +set @@max_sp_recursion_depth=0| + +deallocate prepare stmt2| + +drop function bug10100f| +drop procedure bug10100p| +drop procedure bug10100t| +drop procedure bug10100pt| +drop procedure bug10100pv| +drop procedure bug10100pd| +drop procedure bug10100pc| +drop view v1| +drop table t3| + + +# # BUG#NNNN: New bug synopsis # #--disable_warnings diff --git a/mysql-test/t/sp_trans.test b/mysql-test/t/sp_trans.test index 82e1cd2f1c9..d72eaf5dca0 100644 --- a/mysql-test/t/sp_trans.test +++ b/mysql-test/t/sp_trans.test @@ -176,6 +176,186 @@ drop table t1, t2| # +# BUG#13825 "Triggers: crash if release savepoint". +# Also general test for handling of savepoints in stored routines. +# +# According to SQL standard we should establish new savepoint +# level before executing stored function/trigger and destroy +# this savepoint level after execution. Stored procedures by +# default should be executed using the same savepoint level +# as their caller (to execute stored procedure using new +# savepoint level one should explicitly specify NEW SAVEPOINT +# LEVEL clause in procedure creation statement which MySQL +# does not support yet). +--disable_warnings +drop function if exists bug13825_0| +drop function if exists bug13825_1| +drop function if exists bug13825_2| +drop function if exists bug13825_3| +drop function if exists bug13825_4| +drop function if exists bug13825_5| +drop procedure if exists bug13825_0| +drop procedure if exists bug13825_1| +drop procedure if exists bug13825_2| +drop table if exists t1| +--enable_warnings +create table t1 (i int) engine=innodb| +create table t2 (i int) engine=innodb| +create function bug13825_0() returns int +begin + rollback to savepoint x; + return 1; +end| +create function bug13825_1() returns int +begin + release savepoint x; + return 1; +end| +create function bug13825_2() returns int +begin + insert into t1 values (2); + savepoint x; + insert into t1 values (3); + rollback to savepoint x; + insert into t1 values (4); + return 1; +end| +create procedure bug13825_0() +begin + rollback to savepoint x; +end| +create procedure bug13825_1() +begin + release savepoint x; +end| +create procedure bug13825_2() +begin + savepoint x; +end| +insert into t2 values (1)| +create trigger t2_bi before insert on t2 for each row + rollback to savepoint x| +create trigger t2_bu before update on t2 for each row + release savepoint x| +create trigger t2_bd before delete on t2 for each row +begin + insert into t1 values (2); + savepoint x; + insert into t1 values (3); + rollback to savepoint x; + insert into t1 values (4); +end| +create function bug13825_3(rb int) returns int +begin + insert into t1 values(1); + savepoint x; + insert into t1 values(2); + if rb then + rollback to savepoint x; + end if; + insert into t1 values(3); + return rb; +end| +create function bug13825_4() returns int +begin + savepoint x; + insert into t1 values(2); + rollback to savepoint x; + return 0; +end| +create function bug13825_5(p int) returns int +begin + savepoint x; + insert into t2 values(p); + rollback to savepoint x; + insert into t2 values(p+1); + return p; +end| +set autocommit= 0| +# Test of savepoint level handling for stored functions and triggers +begin | +insert into t1 values (1)| +savepoint x| +--error ER_SP_DOES_NOT_EXIST +set @a:= bug13825_0()| +--error ER_SP_DOES_NOT_EXIST +insert into t2 values (2)| +--error ER_SP_DOES_NOT_EXIST +set @a:= bug13825_1()| +--error ER_SP_DOES_NOT_EXIST +update t2 set i = 2| +set @a:= bug13825_2()| +select * from t1| +rollback to savepoint x| +select * from t1| +delete from t2| +select * from t1| +rollback to savepoint x| +select * from t1| +# Of course savepoints set in function should not be visible from its caller +release savepoint x| +set @a:= bug13825_2()| +select * from t1| +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint x| +delete from t1| +commit| +# Test of savepoint level handling for stored procedures +begin| +insert into t1 values (5)| +savepoint x| +insert into t1 values (6)| +call bug13825_0()| +select * from t1| +call bug13825_1()| +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint x| +savepoint x| +insert into t1 values (7)| +call bug13825_2()| +rollback to savepoint x| +select * from t1| +delete from t1| +commit| +set autocommit= 1| +# Let us test that savepoints work inside of functions +# even in auto-commit mode +select bug13825_3(0)| +select * from t1| +delete from t1| +select bug13825_3(1)| +select * from t1| +delete from t1| +# Curious case: rolling back to savepoint which is set by first +# statement in function should not rollback whole transaction. +set autocommit= 0| +begin| +insert into t1 values (1)| +set @a:= bug13825_4()| +select * from t1| +delete from t1| +commit| +set autocommit= 1| +# Other curious case: savepoint in the middle of statement +drop table t2| +create table t2 (i int) engine=innodb| +insert into t1 values (1), (bug13825_5(2)), (3)| +select * from t1| +select * from t2| +# Cleanup +drop function bug13825_0| +drop function bug13825_1| +drop function bug13825_2| +drop function bug13825_3| +drop function bug13825_4| +drop function bug13825_5| +drop procedure bug13825_0| +drop procedure bug13825_1| +drop procedure bug13825_2| +drop table t1, t2| + + +# # BUG#NNNN: New bug synopsis # #--disable_warnings diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 02d994128e2..d4fa5268762 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -743,8 +743,12 @@ create trigger t1_ai after insert on t1 for each row insert into t2 values (new.f1+1); create trigger t2_ai after insert on t2 for each row insert into t1 values (new.f2+1); +# Allow SP resursion to be show that it has not influence here +set @SAVE_SP_RECURSION_LEVELS=@@max_sp_recursion_depth; +set @@max_sp_recursion_depth=100; --error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG insert into t1 values (1); +set @@max_sp_recursion_depth=@SAVE_SP_RECURSION_LEVELS; select * from t1; select * from t2; drop trigger t1_ai; @@ -914,3 +918,31 @@ call p1(); deallocate prepare stmt1; drop procedure p1; drop table t1, t2, t3; + +# +# BUG#13549 "Server crash with nested stored procedures". +# Server should not crash when during execution of stored procedure +# we have to parse trigger/function definition and this new trigger/ +# function has more local variables declared than invoking stored +# procedure and last of these variables is used in argument of NOT +# operator. +# +create table t1 (a int); +--disable_warnings +drop procedure if exists p2; +--enable_warnings +DELIMITER //; +CREATE PROCEDURE `p2`() +begin + insert into t1 values (1); +end// +create trigger trg before insert on t1 for each row +begin + declare done int default 0; + set done= not done; +end// +DELIMITER ;// +CALL p2(); +drop procedure p2; +drop table t1; + diff --git a/mysql-test/t/type_binary.test b/mysql-test/t/type_binary.test index b5928cb14c4..451363c1ae4 100644 --- a/mysql-test/t/type_binary.test +++ b/mysql-test/t/type_binary.test @@ -65,3 +65,6 @@ select hex(s1) from t1 where s1=0x0120; select hex(s1) from t1 where s1=0x0100; select count(distinct s1) from t1; drop table t1; + +# check that cast appends trailing zeros +select hex(cast(0x10 as binary(2))); diff --git a/mysql-test/t/type_newdecimal-big.test b/mysql-test/t/type_newdecimal-big.test new file mode 100644 index 00000000000..e200017f2ba --- /dev/null +++ b/mysql-test/t/type_newdecimal-big.test @@ -0,0 +1,31 @@ +--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(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 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/variables.test b/mysql-test/t/variables.test index a1b4bc552eb..76761f9177d 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -237,6 +237,10 @@ set global rpl_recovery_rank=100; set global server_id=100; set global slow_launch_time=100; set sort_buffer_size=100; +set @@max_sp_recursion_depth=10; +select @@max_sp_recursion_depth; +set @@max_sp_recursion_depth=0; +select @@max_sp_recursion_depth; set sql_auto_is_null=1; select @@sql_auto_is_null; set @@sql_auto_is_null=0; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index b4f367c2065..04d6d2f323b 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -664,3 +664,39 @@ insert into mysql.user select * from t1; flush privileges; drop table t1; + +# +# BUG#14726: freeing stack variable in case of an error of opening +# a view when we have locked tables with LOCK TABLES statement. +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +use mysqltest; +CREATE TABLE t1 (i INT); +CREATE VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +GRANT SELECT, LOCK TABLES ON mysqltest.* TO mysqltest_1@localhost; + +connection user1; + +use mysqltest; +LOCK TABLES v1 READ; +-- error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE TABLE v1; +UNLOCK TABLES; +use test; + +connection root; +use test; +drop user mysqltest_1@localhost; +drop database mysqltest; + +# +# switch to default connaction +# +disconnect user1; +disconnect root; +connection default; diff --git a/netware/Makefile.am b/netware/Makefile.am index be59efd1deb..ab88d97f9bc 100644 --- a/netware/Makefile.am +++ b/netware/Makefile.am @@ -40,10 +40,10 @@ netware_build_files = client/mysql.def client/mysqladmin.def \ link_sources: set -x; \ for f in $(netware_build_files); do \ - rm -f $(srcdir)/../$$f; \ + rm -f ../$$f; \ org=`echo $$f | sed -e 's/.*\/\(.*\)/\1/g'`; \ - @LN_CP_F@ $(srcdir)/$$org $(srcdir)/../$$f; \ - done; + @LN_CP_F@ $(srcdir)/$$org ../$$f; \ + done else EXTRA_DIST= comp_err.def init_db.sql install_test_db.ncf \ libmysql.def libmysql.imp \ diff --git a/netware/mysql_test_run.c b/netware/mysql_test_run.c index 92ed89b4770..98b7ab7fd8c 100644 --- a/netware/mysql_test_run.c +++ b/netware/mysql_test_run.c @@ -1173,6 +1173,9 @@ void setup(char *file) setenv("MYSQL",file_path,1); snprintf(file_path, PATH_MAX*2, "%s/mysqlshow --no-defaults --user=root --port=%u", bin_dir, master_port); setenv("MYSQL_SHOW",file_path,1); + snprintf(file_path, PATH_MAX*2, "%s/mysqlcheck --no-defaults -uroot --port=%u", bin_dir, master_port); + setenv("MYSQL_CHECK",file_path,1); + } /****************************************************************************** diff --git a/pstack/Makefile.am b/pstack/Makefile.am index 77f84d212cd..20d5d8314ce 100644 --- a/pstack/Makefile.am +++ b/pstack/Makefile.am @@ -20,7 +20,7 @@ # SUBDIRS = aout -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include noinst_HEADERS = bucomm.h debug.h ieee.h budbg.h demangle.h \ linuxthreads.h pstack.h pstacktrace.h SRC= bucomm.c filemode.c linuxthreads.c rddbg.c \ diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 2d7f18b676b..56a2d4a7bc6 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -83,9 +83,10 @@ CLEANFILES = @server_scripts@ \ mysql_find_rows \ mysqlhotcopy \ mysqldumpslow \ + mysql_explain_log \ + mysql_tableinfo \ mysqld_multi \ make_win_src_distribution \ - make_win_binary_distribution \ mysql_create_system_tables DISTCLEANFILES = mysqlbug diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 5767728fe4f..ea78133cc5e 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -308,7 +308,7 @@ fi # NDB Cluster if [ x$NDBCLUSTER = x1 ]; then - ( cd ndb ; @MAKE@ DESTDIR=$BASE/ndb-stage install ) + ( cd storage/ndb ; @MAKE@ DESTDIR=$BASE/ndb-stage install ) ( cd mysql-test/ndb ; @MAKE@ DESTDIR=$BASE/ndb-stage install ) $CP $BASE/ndb-stage@bindir@/* $BASE/bin/. $CP $BASE/ndb-stage@libexecdir@/* $BASE/bin/. diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am index 4fa2a0da405..7449735f0bf 100644 --- a/server-tools/instance-manager/Makefile.am +++ b/server-tools/instance-manager/Makefile.am @@ -53,12 +53,12 @@ libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \ CLEANFILES= net_serv.cc client_settings.h net_serv.cc: - rm -f $(srcdir)/net_serv.cc - @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc $(srcdir)/net_serv.cc + rm -f net_serv.cc + @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc net_serv.cc client_settings.h: - rm -f $(srcdir)/client_settings.h - @LN_CP_F@ $(top_srcdir)/sql/client_settings.h $(srcdir)/client_settings.h + rm -f client_settings.h + @LN_CP_F@ $(top_srcdir)/sql/client_settings.h client_settings.h libexec_PROGRAMS= mysqlmanager diff --git a/sql-bench/Makefile.am b/sql-bench/Makefile.am index 579a2a9f7fe..12f3d5550b3 100644 --- a/sql-bench/Makefile.am +++ b/sql-bench/Makefile.am @@ -60,6 +60,8 @@ install-data-local: for i in $(srcdir)/limits/*.* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/limits; done for i in $(srcdir)/Comments/*.* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/Comments; done +uninstall-local: + @RM@ -f -r $(DESTDIR)$(benchdir) SUFFIXES = .sh diff --git a/sql/Makefile.am b/sql/Makefile.am index 9dcd4487080..78d5e262fde 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -62,7 +62,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ parse_file.h sql_view.h sql_trigger.h \ sql_array.h sql_cursor.h \ - sql_plugin.h + sql_plugin.h authors.h mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ @@ -124,17 +124,17 @@ AM_YFLAGS = -d mysql_tzinfo_to_sql.cc: rm -f mysql_tzinfo_to_sql.cc - @LN_CP_F@ tztime.cc mysql_tzinfo_to_sql.cc + @LN_CP_F@ $(srcdir)/tztime.cc mysql_tzinfo_to_sql.cc link_sources: mysql_tzinfo_to_sql.cc rm -f mini_client_errors.c - @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c + @LN_CP_F@ $(top_srcdir)/libmysql/errmsg.c mini_client_errors.c rm -f pack.c - @LN_CP_F@ ../sql-common/pack.c pack.c + @LN_CP_F@ $(top_srcdir)/sql-common/pack.c pack.c rm -f client.c - @LN_CP_F@ ../sql-common/client.c client.c + @LN_CP_F@ $(top_srcdir)/sql-common/client.c client.c rm -f my_time.c - @LN_CP_F@ ../sql-common/my_time.c my_time.c + @LN_CP_F@ $(top_srcdir)/sql-common/my_time.c my_time.c mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES) $(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $< diff --git a/sql/authors.h b/sql/authors.h index d2ec9350b98..ab5e367d707 100644 --- a/sql/authors.h +++ b/sql/authors.h @@ -29,5 +29,6 @@ struct show_table_authors_st show_table_authors[]= { { "Petr Chardin", "Moscow, Russia", "Instance Manager (5.0)" }, { "Sergey Vojtovich", "Izhevsk, Russia", "Plugins infrastructure (5.1)" }, { "Alexander Nozdrin", "Moscow, Russia", "Bugfixing (Stored Procedures, 5.0)" }, + { "Per-Erik Martin", "Uppsala, Sweden", "Stored Procedures (5.0)" }, {NULL, NULL, NULL} }; diff --git a/sql/field.cc b/sql/field.cc index db8be782ac6..ea1f0f3f984 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1268,9 +1268,9 @@ my_decimal *Field::val_decimal(my_decimal *decimal) void Field_num::add_zerofill_and_unsigned(String &res) const { if (unsigned_flag) - res.append(" unsigned"); + res.append(STRING_WITH_LEN(" unsigned")); if (zerofill) - res.append(" zerofill"); + res.append(STRING_WITH_LEN(" zerofill")); } @@ -1665,7 +1665,7 @@ Field *Field::clone(MEM_ROOT *root, struct st_table *new_table) void Field_null::sql_type(String &res) const { - res.set_ascii("null", 4); + res.set_ascii(STRING_WITH_LEN("null")); } @@ -1677,7 +1677,7 @@ void Field_null::sql_type(String &res) const void Field_decimal::reset(void) { - Field_decimal::store("0",1,&my_charset_bin); + Field_decimal::store(STRING_WITH_LEN("0"),&my_charset_bin); } void Field_decimal::overflow(bool negative) @@ -2386,7 +2386,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) #ifndef DBUG_OFF { char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; - DBUG_PRINT("info", ("saving with precision %d, scale: %d, value %s", + DBUG_PRINT("info", ("saving with precision %d scale: %d value %s", (int)precision, (int)dec, dbug_decimal_as_string(dbug_buff, decimal_value))); } @@ -2401,7 +2401,8 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec); error= 1; } - DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, bin_size);); + DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, + bin_size);); DBUG_RETURN(error); } @@ -4117,7 +4118,7 @@ void Field_float::sql_type(String &res) const { if (dec == NOT_FIXED_DEC) { - res.set_ascii("float", 5); + res.set_ascii(STRING_WITH_LEN("float")); } else { @@ -4388,7 +4389,7 @@ void Field_double::sql_type(String &res) const CHARSET_INFO *cs=res.charset(); if (dec == NOT_FIXED_DEC) { - res.set_ascii("double",6); + res.set_ascii(STRING_WITH_LEN("double")); } else { @@ -4676,7 +4677,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) if (temp == 0L) { /* Zero time is "000000" */ - val_ptr->set("0000-00-00 00:00:00", 19, &my_charset_bin); + val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin); return val_ptr; } val_buffer->set_charset(&my_charset_bin); // Safety @@ -4808,7 +4809,7 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) void Field_timestamp::sql_type(String &res) const { - res.set_ascii("timestamp", 9); + res.set_ascii(STRING_WITH_LEN("timestamp")); } @@ -5077,7 +5078,7 @@ void Field_time::sort_string(char *to,uint length __attribute__((unused))) void Field_time::sql_type(String &res) const { - res.set_ascii("time", 4); + res.set_ascii(STRING_WITH_LEN("time")); } /**************************************************************************** @@ -5384,7 +5385,7 @@ void Field_date::sort_string(char *to,uint length __attribute__((unused))) void Field_date::sql_type(String &res) const { - res.set_ascii("date", 4); + res.set_ascii(STRING_WITH_LEN("date")); } @@ -5567,7 +5568,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused))) void Field_newdate::sql_type(String &res) const { - res.set_ascii("date", 4); + res.set_ascii(STRING_WITH_LEN("date")); } @@ -5841,7 +5842,7 @@ void Field_datetime::sort_string(char *to,uint length __attribute__((unused))) void Field_datetime::sql_type(String &res) const { - res.set_ascii("datetime", 8); + res.set_ascii(STRING_WITH_LEN("datetime")); } /**************************************************************************** @@ -6084,7 +6085,7 @@ void Field_string::sql_type(String &res) const res.length(length); if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_charset() && (charset()->state & MY_CS_BINSORT)) - res.append(" binary"); + res.append(STRING_WITH_LEN(" binary")); } @@ -6486,7 +6487,7 @@ void Field_varstring::sql_type(String &res) const res.length(length); if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_charset() && (charset()->state & MY_CS_BINSORT)) - res.append(" binary"); + res.append(STRING_WITH_LEN(" binary")); } @@ -7224,10 +7225,10 @@ void Field_blob::sql_type(String &res) const } res.set_ascii(str,length); if (charset() == &my_charset_bin) - res.append("blob"); + res.append(STRING_WITH_LEN("blob")); else { - res.append("text"); + res.append(STRING_WITH_LEN("text")); } } @@ -7447,28 +7448,28 @@ void Field_geom::sql_type(String &res) const switch (geom_type) { case GEOM_POINT: - res.set("point", 5, cs); + res.set(STRING_WITH_LEN("point"), cs); break; case GEOM_LINESTRING: - res.set("linestring", 10, cs); + res.set(STRING_WITH_LEN("linestring"), cs); break; case GEOM_POLYGON: - res.set("polygon", 7, cs); + res.set(STRING_WITH_LEN("polygon"), cs); break; case GEOM_MULTIPOINT: - res.set("multipoint", 10, cs); + res.set(STRING_WITH_LEN("multipoint"), cs); break; case GEOM_MULTILINESTRING: - res.set("multilinestring", 15, cs); + res.set(STRING_WITH_LEN("multilinestring"), cs); break; case GEOM_MULTIPOLYGON: - res.set("multipolygon", 12, cs); + res.set(STRING_WITH_LEN("multipolygon"), cs); break; case GEOM_GEOMETRYCOLLECTION: - res.set("geometrycollection", 18, cs); + res.set(STRING_WITH_LEN("geometrycollection"), cs); break; default: - res.set("geometry", 8, cs); + res.set(STRING_WITH_LEN("geometry"), cs); } } @@ -7745,7 +7746,7 @@ void Field_enum::sql_type(String &res) const String enum_item(buffer, sizeof(buffer), res.charset()); res.length(0); - res.append("enum("); + res.append(STRING_WITH_LEN("enum(")); bool flag=0; uint *len= typelib->type_lengths; @@ -7859,7 +7860,7 @@ void Field_set::sql_type(String &res) const String set_item(buffer, sizeof(buffer), res.charset()); res.length(0); - res.append("set("); + res.append(STRING_WITH_LEN("set(")); bool flag=0; uint *len= typelib->type_lengths; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index e50961a5700..70d84514b80 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2608,7 +2608,7 @@ int ha_federated::stash_remote_error() { DBUG_ENTER("ha_federated::stash_remote_error()"); remote_error_number= mysql_errno(mysql); - my_snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE, + my_snprintf(remote_error_buf, sizeof(remote_error_buf), "%s", mysql_error(mysql)); DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM); } @@ -2620,10 +2620,10 @@ bool ha_federated::get_error_message(int error, String* buf) DBUG_PRINT("enter", ("error: %d", error)); if (error == HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM) { - buf->append("Error on remote system: "); + buf->append(STRING_WITH_LEN("Error on remote system: ")); buf->qs_append(remote_error_number); - buf->append(": "); - buf->append(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE); + buf->append(STRING_WITH_LEN(": ")); + buf->append(remote_error_buf); remote_error_number= 0; remote_error_buf[0]= '\0'; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index deb8f0d9812..1562803aed7 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2219,11 +2219,13 @@ innobase_savepoint( DBUG_ENTER("innobase_savepoint"); - if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - /* In the autocommit state there is no sense to set a - savepoint: we return immediate success */ - DBUG_RETURN(0); - } + /* + In the autocommit mode there is no sense to set a savepoint + (unless we are in sub-statement), so SQL layer ensures that + this method is never called in such situation. + */ + DBUG_ASSERT(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) || + thd->in_sub_stmt); trx = check_trx_exists(thd); diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index ba2ded85d33..37dfe34b40c 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -506,10 +506,10 @@ void ha_myisammrg::append_create_info(String *packet) if (file->merge_insert_method != MERGE_INSERT_DISABLED) { - packet->append(" INSERT_METHOD=",15); + packet->append(STRING_WITH_LEN(" INSERT_METHOD=")); packet->append(get_type(&merge_insert_method,file->merge_insert_method-1)); } - packet->append(" UNION=(",8); + packet->append(STRING_WITH_LEN(" UNION=(")); current_db= table->s->db.str; db_length= table->s->db.length; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 848ae1f92f1..2ab036ee1a0 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -101,6 +101,8 @@ static handler *ndbcluster_create_handler(TABLE_SHARE *table) #define NDB_FAILED_AUTO_INCREMENT ~(Uint64)0 #define NDB_AUTO_INCREMENT_RETRIES 10 +#define NDB_INVALID_SCHEMA_OBJECT 241 + #define ERR_PRINT(err) \ DBUG_PRINT("error", ("%d message: %s", err.code, err.message)) @@ -368,7 +370,21 @@ Thd_ndb::Thd_ndb() Thd_ndb::~Thd_ndb() { if (ndb) + { +#ifndef DBUG_OFF + Ndb::Free_list_usage tmp; tmp.m_name= 0; + while (ndb->get_free_list_usage(&tmp)) + { + uint leaked= (uint) tmp.m_created - tmp.m_free; + if (leaked) + fprintf(stderr, "NDB: Found %u %s%s that %s not been released\n", + leaked, tmp.m_name, + (leaked == 1)?"":"'s", + (leaked == 1)?"has":"have"); + } +#endif delete ndb; + } ndb= NULL; changed_tables.empty(); } @@ -3419,15 +3435,18 @@ 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_version < tab->getObjectVersion()) + if (m_table != (void *)tab) { - /* - The table has been altered, refresh the index list - */ - build_index_list(ndb, table, ILBP_OPEN); m_table= (void *)tab; m_table_version = tab->getObjectVersion(); } + else if (m_table_version < tab->getObjectVersion()) + { + /* + The table has been altered, caller has to retry + */ + DBUG_RETURN(my_errno= HA_ERR_TABLE_DEF_CHANGED); + } m_table_info= tab_info; } no_uncommitted_rows_init(thd); @@ -5130,7 +5149,21 @@ int ndbcluster_end(ha_panic_function type) (void) pthread_mutex_unlock(&LOCK_ndb_util_thread); if (g_ndb) + { +#ifndef DBUG_OFF + Ndb::Free_list_usage tmp; tmp.m_name= 0; + while (g_ndb->get_free_list_usage(&tmp)) + { + uint leaked= (uint) tmp.m_created - tmp.m_free; + if (leaked) + fprintf(stderr, "NDB: Found %u %s%s that %s not been released\n", + leaked, tmp.m_name, + (leaked == 1)?"":"'s", + (leaked == 1)?"has":"have"); + } +#endif delete g_ndb; + } g_ndb= NULL; if (g_ndb_cluster_connection) delete g_ndb_cluster_connection; diff --git a/sql/handler.cc b/sql/handler.cc index 2688b117318..7e9825c9d0d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1027,10 +1027,10 @@ int ha_update_statistics() int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; - THD_TRANS *trans=&thd->transaction.all; + THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : + &thd->transaction.all); handlerton **ht=trans->ht, **end_ht; DBUG_ENTER("ha_rollback_to_savepoint"); - DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0); trans->nht=sv->nht; trans->no_2pc=0; @@ -1059,7 +1059,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) for (; *ht ; ht++) { int err; - if ((err= (*(*ht)->rollback)(thd, 1))) + if ((err= (*(*ht)->rollback)(thd, !thd->in_sub_stmt))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; @@ -1079,10 +1079,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) int ha_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; - THD_TRANS *trans=&thd->transaction.all; + THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : + &thd->transaction.all); handlerton **ht=trans->ht; DBUG_ENTER("ha_savepoint"); - DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0); #ifdef USING_TRANSACTIONS for (; *ht; ht++) { @@ -1108,9 +1108,10 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv) int ha_release_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; - handlerton **ht=thd->transaction.all.ht, **end_ht; + THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : + &thd->transaction.all); + handlerton **ht=trans->ht, **end_ht; DBUG_ENTER("ha_release_savepoint"); - DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0); end_ht=ht+sv->nht; for (; ht < end_ht; ht++) @@ -1677,7 +1678,7 @@ void handler::print_error(int error, myf errflag) if (str.length() >= max_length) { str.length(max_length-4); - str.append("..."); + str.append(STRING_WITH_LEN("...")); } my_error(ER_DUP_ENTRY, MYF(0), str.c_ptr(), key_nr+1); DBUG_VOID_RETURN; diff --git a/sql/item.cc b/sql/item.cc index df1cc7ea7ed..1c2016049ad 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -383,7 +383,7 @@ void Item::print_item_w_name(String *str) if (name) { THD *thd= current_thd; - str->append(" AS ", 4); + str->append(STRING_WITH_LEN(" AS ")); append_identifier(thd, str, name, (uint) strlen(name)); } } @@ -894,6 +894,7 @@ bool Item_splocal::is_null() Item * Item_splocal::this_item() { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset); } @@ -901,12 +902,14 @@ Item_splocal::this_item() Item ** Item_splocal::this_item_addr(THD *thd, Item **addr) { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item_addr(m_offset); } Item * Item_splocal::this_const_item() const { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset); } @@ -914,7 +917,10 @@ Item::Type Item_splocal::type() const { 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 } @@ -1031,7 +1037,7 @@ void Item_name_const::cleanup() void Item_name_const::print(String *str) { - str->append("NAME_CONST("); + str->append(STRING_WITH_LEN("NAME_CONST(")); name_item->print(str); str->append(','); value_item->print(str); @@ -4887,7 +4893,7 @@ void Item_ref::make_field(Send_field *field) void Item_ref_null_helper::print(String *str) { - str->append("<ref_null_helper>(", 18); + str->append(STRING_WITH_LEN("<ref_null_helper>(")); if (ref) (*ref)->print(str); else @@ -5013,7 +5019,7 @@ bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const void Item_null_helper::print(String *str) { - str->append("<null_helper>(", 14); + str->append(STRING_WITH_LEN("<null_helper>(")); store->print(str); str->append(')'); } @@ -5074,10 +5080,10 @@ void Item_default_value::print(String *str) { if (!arg) { - str->append("default", 7); + str->append(STRING_WITH_LEN("default")); return; } - str->append("default(", 8); + str->append(STRING_WITH_LEN("default(")); arg->print(str); str->append(')'); } @@ -5177,7 +5183,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) void Item_insert_value::print(String *str) { - str->append("values(", 7); + str->append(STRING_WITH_LEN("values(")); arg->print(str); str->append(')'); } @@ -5438,7 +5444,7 @@ Item_cache* Item_cache::get_cache(Item_result type) void Item_cache::print(String *str) { - str->append("<cache>(", 8); + str->append(STRING_WITH_LEN("<cache>(")); if (example) example->print(str); else diff --git a/sql/item.h b/sql/item.h index db42396f528..711050395de 100644 --- a/sql/item.h +++ b/sql/item.h @@ -704,6 +704,8 @@ public: }; +class sp_head; + /* A reference to local SP variable (incl. reference to SP parameter), used in runtime. @@ -721,6 +723,13 @@ class Item_splocal : public Item uint m_offset; public: +#ifndef DBUG_OFF + /* + Routine to which this Item_splocal belongs. Used for checking if correct + runtime context is used for variable handling. + */ + sp_head *owner; +#endif LEX_STRING m_name; THD *thd; @@ -1055,7 +1064,7 @@ public: bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } - void print(String *str) { str->append("NULL", 4); } + void print(String *str) { str->append(STRING_WITH_LEN("NULL")); } Item *safe_charset_converter(CHARSET_INFO *tocs); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index ba530a71bb8..a8ccc8771c9 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1175,10 +1175,10 @@ void Item_func_between::print(String *str) str->append('('); args[0]->print(str); if (negated) - str->append(" not", 4); - str->append(" between ", 9); + str->append(STRING_WITH_LEN(" not")); + str->append(STRING_WITH_LEN(" between ")); args[1]->print(str); - str->append(" and ", 5); + str->append(STRING_WITH_LEN(" and ")); args[2]->print(str); str->append(')'); } @@ -1793,7 +1793,7 @@ uint Item_func_case::decimal_precision() const void Item_func_case::print(String *str) { - str->append("(case ", 6); + str->append(STRING_WITH_LEN("(case ")); if (first_expr_num != -1) { args[first_expr_num]->print(str); @@ -1801,19 +1801,19 @@ void Item_func_case::print(String *str) } for (uint i=0 ; i < ncases ; i+=2) { - str->append("when ", 5); + str->append(STRING_WITH_LEN("when ")); args[i]->print(str); - str->append(" then ", 6); + str->append(STRING_WITH_LEN(" then ")); args[i+1]->print(str); str->append(' '); } if (else_expr_num != -1) { - str->append("else ", 5); + str->append(STRING_WITH_LEN("else ")); args[else_expr_num]->print(str); str->append(' '); } - str->append("end)", 4); + str->append(STRING_WITH_LEN("end)")); } /* @@ -2419,10 +2419,10 @@ void Item_func_in::print(String *str) str->append('('); args[0]->print(str); if (negated) - str->append(" not", 4); - str->append(" in (", 5); + str->append(STRING_WITH_LEN(" not")); + str->append(STRING_WITH_LEN(" in (")); print_args(str, 1); - str->append("))", 2); + str->append(STRING_WITH_LEN("))")); } @@ -2894,7 +2894,7 @@ void Item_func_isnotnull::print(String *str) { str->append('('); args[0]->print(str); - str->append(" is not null)", 13); + str->append(STRING_WITH_LEN(" is not null)")); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 4869dc0d95b..b9e0ea59d84 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -796,9 +796,9 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) void Item_func_signed::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as signed)", 11); + str->append(STRING_WITH_LEN(" as signed)")); } @@ -857,9 +857,9 @@ longlong Item_func_signed::val_int() void Item_func_unsigned::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as unsigned)", 13); + str->append(STRING_WITH_LEN(" as unsigned)")); } @@ -929,9 +929,9 @@ my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) void Item_decimal_typecast::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as decimal)", 12); + str->append(STRING_WITH_LEN(" as decimal)")); } @@ -2236,7 +2236,7 @@ longlong Item_func_locate::val_int() void Item_func_locate::print(String *str) { - str->append("locate(", 7); + str->append(STRING_WITH_LEN("locate(")); args[1]->print(str); str->append(','); args[0]->print(str); @@ -3299,7 +3299,7 @@ longlong Item_func_benchmark::val_int() void Item_func_benchmark::print(String *str) { - str->append("benchmark(", 10); + str->append(STRING_WITH_LEN("benchmark(")); char buffer[20]; // my_charset_bin is good enough for numbers String st(buffer, sizeof(buffer), &my_charset_bin); @@ -3813,9 +3813,9 @@ my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val) void Item_func_set_user_var::print(String *str) { - str->append("(@", 2); + str->append(STRING_WITH_LEN("(@")); str->append(name.str, name.length); - str->append(":=", 2); + str->append(STRING_WITH_LEN(":=")); args[0]->print(str); str->append(')'); } @@ -3823,9 +3823,9 @@ void Item_func_set_user_var::print(String *str) void Item_func_set_user_var::print_as_stmt(String *str) { - str->append("set @", 5); + str->append(STRING_WITH_LEN("set @")); str->append(name.str, name.length); - str->append(":=", 2); + str->append(STRING_WITH_LEN(":=")); args[0]->print(str); str->append(')'); } @@ -4056,7 +4056,7 @@ enum Item_result Item_func_get_user_var::result_type() const void Item_func_get_user_var::print(String *str) { - str->append("(@", 2); + str->append(STRING_WITH_LEN("(@")); str->append(name.str,name.length); str->append(')'); } @@ -4481,15 +4481,15 @@ double Item_func_match::val_real() void Item_func_match::print(String *str) { - str->append("(match ", 7); + str->append(STRING_WITH_LEN("(match ")); print_args(str, 1); - str->append(" against (", 10); + str->append(STRING_WITH_LEN(" against (")); args[0]->print(str); if (flags & FT_BOOL) - str->append(" in boolean mode", 16); + str->append(STRING_WITH_LEN(" in boolean mode")); else if (flags & FT_EXPAND) - str->append(" with query expansion", 21); - str->append("))", 2); + str->append(STRING_WITH_LEN(" with query expansion")); + str->append(STRING_WITH_LEN("))")); } longlong Item_func_bit_xor::val_int() @@ -4695,10 +4695,16 @@ Item_func_sp::sp_result_field(void) const { Field *field; DBUG_ENTER("Item_func_sp::sp_result_field"); + DBUG_PRINT("info", ("sp: %s, flags: %x, level: %lu", + (m_sp ? "YES" : "NO"), + (m_sp ? m_sp->m_flags : (uint)0), + (m_sp ? m_sp->m_recursion_level : (ulong)0))); if (!m_sp) { - if (!(m_sp= sp_find_function(current_thd, m_name, TRUE))) + THD *thd= current_thd; + if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name, + &thd->sp_func_cache, TRUE))) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); DBUG_RETURN(0); @@ -4923,7 +4929,8 @@ Item_func_sp::find_and_check_access(THD *thd, ulong want_access, bool res= TRUE; *save= 0; // Safety if error - if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) + if (! m_sp && ! (m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name, + &thd->sp_func_cache, TRUE))) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); goto error; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1e8fe2e695f..a8c51bb6662 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1790,7 +1790,7 @@ String *Item_func_format::val_str(String *str) void Item_func_format::print(String *str) { - str->append("format(", 7); + str->append(STRING_WITH_LEN("format(")); args[0]->print(str); str->append(','); // my_charset_bin is good enough for numbers @@ -1950,7 +1950,7 @@ String *Item_func_make_set::val_str(String *str) void Item_func_make_set::print(String *str) { - str->append("make_set(", 9); + str->append(STRING_WITH_LEN("make_set(")); item->print(str); if (arg_count) { @@ -2331,9 +2331,9 @@ void Item_func_conv_charset::fix_length_and_dec() void Item_func_conv_charset::print(String *str) { - str->append("convert(", 8); + str->append(STRING_WITH_LEN("convert(")); args[0]->print(str); - str->append(" using ", 7); + str->append(STRING_WITH_LEN(" using ")); str->append(conv_charset->csname); str->append(')'); } @@ -2403,7 +2403,7 @@ void Item_func_set_collation::print(String *str) { str->append('('); args[0]->print(str); - str->append(" collate ", 9); + str->append(STRING_WITH_LEN(" collate ")); DBUG_ASSERT(args[1]->basic_const_item() && args[1]->type() == Item::STRING_ITEM); args[1]->str_value.print(str); @@ -2523,9 +2523,9 @@ String *Item_func_unhex::val_str(String *str) void Item_func_binary::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as binary)", 11); + str->append(STRING_WITH_LEN(" as binary)")); } @@ -2630,7 +2630,7 @@ String* Item_func_export_set::val_str(String* str) } break; case 3: - sep_buf.set(",", 1, default_charset()); + sep_buf.set(STRING_WITH_LEN(","), default_charset()); sep = &sep_buf; break; default: @@ -2745,7 +2745,8 @@ String *Item_func_quote::val_str(String *str) uint arg_length, new_length; if (!arg) // Null argument { - str->copy("NULL", 4, collation.collation); // Return the string 'NULL' + /* Return the string 'NULL' */ + str->copy(STRING_WITH_LEN("NULL"), collation.collation); null_value= 0; return str; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 36865b4b8b4..3f87af4038d 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -536,7 +536,7 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): void Item_exists_subselect::print(String *str) { - str->append("exists", 6); + str->append(STRING_WITH_LEN("exists")); Item_subselect::print(str); } @@ -1342,11 +1342,11 @@ err: void Item_in_subselect::print(String *str) { if (transformed) - str->append("<exists>", 8); + str->append(STRING_WITH_LEN("<exists>")); else { left_expr->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); } Item_subselect::print(str); } @@ -1365,7 +1365,7 @@ Item_allany_subselect::select_transformer(JOIN *join) void Item_allany_subselect::print(String *str) { if (transformed) - str->append("<exists>", 8); + str->append(STRING_WITH_LEN("<exists>")); else { left_expr->print(str); @@ -1797,16 +1797,16 @@ void subselect_union_engine::print(String *str) void subselect_uniquesubquery_engine::print(String *str) { - str->append("<primary_index_lookup>(", 23); + str->append(STRING_WITH_LEN("<primary_index_lookup>(")); tab->ref.items[0]->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name.str, tab->table->s->table_name.length); KEY *key_info= tab->table->key_info+ tab->ref.key; - str->append(" on ", 4); + str->append(STRING_WITH_LEN(" on ")); str->append(key_info->name); if (cond) { - str->append(" where ", 7); + str->append(STRING_WITH_LEN(" where ")); cond->print(str); } str->append(')'); @@ -1815,18 +1815,18 @@ void subselect_uniquesubquery_engine::print(String *str) void subselect_indexsubquery_engine::print(String *str) { - str->append("<index_lookup>(", 15); + str->append(STRING_WITH_LEN("<index_lookup>(")); tab->ref.items[0]->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name.str, tab->table->s->table_name.length); KEY *key_info= tab->table->key_info+ tab->ref.key; - str->append(" on ", 4); + str->append(STRING_WITH_LEN(" on ")); str->append(key_info->name); if (check_null) - str->append(" checking NULL", 14); + str->append(STRING_WITH_LEN(" checking NULL")); if (cond) { - str->append(" where ", 7); + str->append(STRING_WITH_LEN(" where ")); cond->print(str); } str->append(')'); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 63d1493f833..03050a99ff1 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3179,9 +3179,9 @@ String* Item_func_group_concat::val_str(String* str) void Item_func_group_concat::print(String *str) { - str->append("group_concat(", 13); + str->append(STRING_WITH_LEN("group_concat(")); if (distinct) - str->append("distinct ", 9); + str->append(STRING_WITH_LEN("distinct ")); for (uint i= 0; i < arg_count_field; i++) { if (i) @@ -3190,19 +3190,19 @@ void Item_func_group_concat::print(String *str) } if (arg_count_order) { - str->append(" order by ", 10); + str->append(STRING_WITH_LEN(" order by ")); for (uint i= 0 ; i < arg_count_order ; i++) { if (i) str->append(','); (*order[i]->item)->print(str); if (order[i]->asc) - str->append(" ASC"); + str->append(STRING_WITH_LEN(" ASC")); else - str->append(" DESC"); + str->append(STRING_WITH_LEN(" DESC")); } } - str->append(" separator \'", 12); + str->append(STRING_WITH_LEN(" separator \'")); str->append(*separator); - str->append("\')", 2); + str->append(STRING_WITH_LEN("\')")); } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 38d3356a29f..f62ad42bb95 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -506,7 +506,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, str->set_charset(&my_charset_bin); if (l_time->neg) - str->append("-", 1); + str->append('-'); end= (ptr= format->format.str) + format->format.length; for (; ptr != end ; ptr++) @@ -546,21 +546,21 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, length= int10_to_str(l_time->day, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); if (l_time->day >= 10 && l_time->day <= 19) - str->append("th", 2); + str->append(STRING_WITH_LEN("th")); else { switch (l_time->day %10) { case 1: - str->append("st",2); + str->append(STRING_WITH_LEN("st")); break; case 2: - str->append("nd",2); + str->append(STRING_WITH_LEN("nd")); break; case 3: - str->append("rd",2); + str->append(STRING_WITH_LEN("rd")); break; default: - str->append("th",2); + str->append(STRING_WITH_LEN("th")); break; } } @@ -2142,9 +2142,9 @@ void Item_date_add_interval::print(String *str) void Item_extract::print(String *str) { - str->append("extract(", 8); + str->append(STRING_WITH_LEN("extract(")); str->append(interval_names[int_type]); - str->append(" from ", 6); + str->append(STRING_WITH_LEN(" from ")); args[0]->print(str); str->append(')'); } @@ -2286,9 +2286,9 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const void Item_typecast::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as ", 4); + str->append(STRING_WITH_LEN(" as ")); str->append(cast_type()); str->append(')'); } @@ -2296,9 +2296,9 @@ void Item_typecast::print(String *str) void Item_char_typecast::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as char", 8); + str->append(STRING_WITH_LEN(" as char")); if (cast_length >= 0) { str->append('('); @@ -2311,7 +2311,7 @@ void Item_char_typecast::print(String *str) } if (cast_cs) { - str->append(" charset ", 9); + str->append(STRING_WITH_LEN(" charset ")); str->append(cast_cs->csname); } str->append(')'); @@ -2352,22 +2352,37 @@ String *Item_char_typecast::val_str(String *str) and the result is longer than cast length, e.g. CAST('string' AS CHAR(1)) */ - if (cast_length >= 0 && - (res->length() > (length= (uint32) res->charpos(cast_length)))) - { // Safe even if const arg - char char_type[40]; - my_snprintf(char_type, sizeof(char_type), "CHAR(%lu)", length); - - if (!res->alloced_length()) - { // Don't change const str - str_value= *res; // Not malloced string - res= &str_value; + if (cast_length >= 0) + { + if (res->length() > (length= (uint32) res->charpos(cast_length))) + { // Safe even if const arg + char char_type[40]; + my_snprintf(char_type, sizeof(char_type), "%s(%lu)", + cast_cs == &my_charset_bin ? "BINARY" : "CHAR", length); + + if (!res->alloced_length()) + { // Don't change const str + str_value= *res; // Not malloced string + res= &str_value; + } + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), char_type, + res->c_ptr_safe()); + res->length((uint) length); + } + else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length) + { + if (res->alloced_length() < (uint) cast_length) + { + str->alloc(cast_length); + str->copy(*res); + res= str; + } + bzero((char*) res->ptr() + res->length(), + (uint) cast_length - res->length()); + res->length(cast_length); } - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER(ER_TRUNCATED_WRONG_VALUE), char_type, - res->c_ptr_safe()); - res->length((uint) length); } null_value= 0; return res; @@ -2609,14 +2624,14 @@ void Item_func_add_time::print(String *str) if (is_date) { DBUG_ASSERT(sign > 0); - str->append("timestamp(", 10); + str->append(STRING_WITH_LEN("timestamp(")); } else { if (sign > 0) - str->append("addtime(", 8); + str->append(STRING_WITH_LEN("addtime(")); else - str->append("subtime(", 8); + str->append(STRING_WITH_LEN("subtime(")); } args[0]->print(str); str->append(','); @@ -2825,31 +2840,31 @@ void Item_func_timestamp_diff::print(String *str) switch (int_type) { case INTERVAL_YEAR: - str->append("YEAR"); + str->append(STRING_WITH_LEN("YEAR")); break; case INTERVAL_QUARTER: - str->append("QUARTER"); + str->append(STRING_WITH_LEN("QUARTER")); break; case INTERVAL_MONTH: - str->append("MONTH"); + str->append(STRING_WITH_LEN("MONTH")); break; case INTERVAL_WEEK: - str->append("WEEK"); + str->append(STRING_WITH_LEN("WEEK")); break; case INTERVAL_DAY: - str->append("DAY"); + str->append(STRING_WITH_LEN("DAY")); break; case INTERVAL_HOUR: - str->append("HOUR"); + str->append(STRING_WITH_LEN("HOUR")); break; case INTERVAL_MINUTE: - str->append("MINUTE"); + str->append(STRING_WITH_LEN("MINUTE")); break; case INTERVAL_SECOND: - str->append("SECOND"); + str->append(STRING_WITH_LEN("SECOND")); break; case INTERVAL_MICROSECOND: - str->append("SECOND_FRAC"); + str->append(STRING_WITH_LEN("SECOND_FRAC")); break; default: break; @@ -2905,13 +2920,13 @@ void Item_func_get_format::print(String *str) switch (type) { case MYSQL_TIMESTAMP_DATE: - str->append("DATE, "); + str->append(STRING_WITH_LEN("DATE, ")); break; case MYSQL_TIMESTAMP_DATETIME: - str->append("DATETIME, "); + str->append(STRING_WITH_LEN("DATETIME, ")); break; case MYSQL_TIMESTAMP_TIME: - str->append("TIME, "); + str->append(STRING_WITH_LEN("TIME, ")); break; default: DBUG_ASSERT(0); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index c884c454dac..a0aa0b96cc6 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -29,7 +29,7 @@ public: :Item_real_func(list) {} double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } void fix_length_and_dec() { decimals=0; max_length=6; } - void print(String *str) { str->append("0.0", 3); } + void print(String *str) { str->append(STRING_WITH_LEN("0.0")); } const char *func_name() const { return "unique_users"; } }; @@ -57,7 +57,7 @@ public: { return new Item_sum_unique_users(thd, this); } - void print(String *str) { str->append("0.0", 3); } + void print(String *str) { str->append(STRING_WITH_LEN("0.0")); } Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); const char *func_name() const { return "sum_unique_users"; } }; diff --git a/sql/key.cc b/sql/key.cc index e804fb65654..4001c6177a1 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -322,7 +322,7 @@ void key_unpack(String *to,TABLE *table,uint idx) { if (table->record[0][key_part->null_offset] & key_part->null_bit) { - to->append("NULL", 4); + to->append(STRING_WITH_LEN("NULL")); continue; } } @@ -334,7 +334,7 @@ void key_unpack(String *to,TABLE *table,uint idx) to->append(tmp); } else - to->append("???", 3); + to->append(STRING_WITH_LEN("???")); } DBUG_VOID_RETURN; } diff --git a/sql/lex.h b/sql/lex.h index ba290e9b646..e3cbebf4629 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -112,6 +112,7 @@ static SYMBOL symbols[] = { { "CLIENT", SYM(CLIENT_SYM)}, { "CLOSE", SYM(CLOSE_SYM)}, { "COALESCE", SYM(COALESCE)}, + { "CODE", SYM(CODE_SYM)}, { "COLLATE", SYM(COLLATE_SYM)}, { "COLLATION", SYM(COLLATION_SYM)}, { "COLUMN", SYM(COLUMN_SYM)}, diff --git a/sql/log.cc b/sql/log.cc index 593a5ab2bdc..1fc7ba1f1fd 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -142,7 +142,7 @@ static int binlog_commit(THD *thd, bool all) // we're here because trans_log was flushed in MYSQL_LOG::log() DBUG_RETURN(0); } - Query_log_event qev(thd, "COMMIT", 6, TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev)); } @@ -166,7 +166,7 @@ static int binlog_rollback(THD *thd, bool all) */ if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE)) { - Query_log_event qev(thd, "ROLLBACK", 8, TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE); error= binlog_end_trans(thd, trans_log, &qev); } else @@ -1833,7 +1833,7 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) */ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - Query_log_event qinfo(thd, "BEGIN", 5, TRUE, FALSE); + Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE); /* Imagine this is rollback due to net timeout, after all statements of the transaction succeeded. Then we want a zero-error code in BEGIN. diff --git a/sql/log_event.cc b/sql/log_event.cc index 081b498f01e..c8f8ff40700 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -161,7 +161,7 @@ static void cleanup_load_tmpdir() we cannot meet Start_log event in the middle of events from one LOAD DATA. */ - p= strmake(prefbuf,"SQL_LOAD-",9); + p= strmake(prefbuf, STRING_WITH_LEN("SQL_LOAD-")); p= int10_to_str(::server_id, p, 10); *(p++)= '-'; *p= 0; @@ -902,14 +902,16 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) /* Pretty-print event common header if header is exactly 19 bytes */ if (print_event_info->common_header_len == LOG_EVENT_MINIMAL_HEADER_LEN) { + DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); fprintf(file, "# Position Timestamp Type Master ID " "Size Master Pos Flags \n"); fprintf(file, "# %8.8lx %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x\n", - hexdump_from, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], - ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], - ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18]); + (unsigned long) hexdump_from, + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], + ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], + ptr[14], ptr[15], ptr[16], ptr[17], ptr[18]); ptr += LOG_EVENT_MINIMAL_HEADER_LEN; hexdump_from += LOG_EVENT_MINIMAL_HEADER_LEN; } @@ -926,8 +928,10 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) if (i % 16 == 15) { + DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); fprintf(file, "# %8.8lx %-48.48s |%16s|\n", - hexdump_from + (i & 0xfffffff0), hex_string, char_string); + (unsigned long) (hexdump_from + (i & 0xfffffff0)), + hex_string, char_string); hex_string[0]= 0; char_string[0]= 0; c= char_string; @@ -939,8 +943,10 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) /* Non-full last line */ if (hex_string[0]) { - printf("# %8.8lx %-48.48s |%s|\n# ", - hexdump_from + (i & 0xfffffff0), hex_string, char_string); + DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); + fprintf(file, "# %8.8lx %-48.48s |%s|\n# ", + (unsigned long) (hexdump_from + (i & 0xfffffff0)), + hex_string, char_string); } } } @@ -2992,7 +2998,7 @@ void Rotate_log_event::pack_info(Protocol *protocol) String tmp(buf1, sizeof(buf1), log_cs); tmp.length(0); tmp.append(new_log_ident, ident_len); - tmp.append(";pos="); + tmp.append(STRING_WITH_LEN(";pos=")); tmp.append(llstr(pos,buf)); protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin); } @@ -4164,7 +4170,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) bzero((char*)&file, sizeof(file)); p = slave_load_file_stem(fname_buf, file_id, server_id); strmov(p, ".info"); // strmov takes less code than memcpy - strnmov(proc_info, "Making temp file ", 17); // no end 0 + strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0 thd->proc_info= proc_info; my_delete(fname_buf, MYF(0)); // old copy may exist already if ((fd= my_create(fname_buf, CREATE_MODE, @@ -4333,7 +4339,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) DBUG_ENTER("Append_block_log_event::exec_event"); memcpy(p, ".data", 6); - strnmov(proc_info, "Making temp file ", 17); // no end 0 + strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0 thd->proc_info= proc_info; if (get_create_or_append()) { @@ -4817,23 +4823,23 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli) p= buf; memcpy(p, query, fn_pos_start); p+= fn_pos_start; - fname= (p= strmake(p, " INFILE \'", 9)); + fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'"))); p= slave_load_file_stem(p, file_id, server_id); - fname_end= (p= strmake(p, ".data", 5)); + fname_end= (p= strmake(p, STRING_WITH_LEN(".data"))); *(p++)='\''; switch (dup_handling) { case LOAD_DUP_IGNORE: - p= strmake(p, " IGNORE", 7); + p= strmake(p, STRING_WITH_LEN(" IGNORE")); break; case LOAD_DUP_REPLACE: - p= strmake(p, " REPLACE", 8); + p= strmake(p, STRING_WITH_LEN(" REPLACE")); break; default: /* Ordinary load data */ break; } - p= strmake(p, " INTO", 5); + p= strmake(p, STRING_WITH_LEN(" INTO")); p= strmake(p, query+fn_pos_end, q_len-fn_pos_end); error= Query_log_event::exec_event(rli, buf, p-buf); diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 1bd16940b47..89607129026 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -193,16 +193,23 @@ int str2my_decimal(uint mask, const char *from, uint length, #ifndef DBUG_OFF /* routines for debugging print */ +#define DIG_PER_DEC1 9 +#define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1) + /* print decimal */ void print_decimal(const my_decimal *dec) { - fprintf(DBUG_FILE, - "\nDecimal: sign: %d intg: %d frac: %d \n\ -%09d,%09d,%09d,%09d,%09d,%09d,%09d,%09d\n", - dec->sign(), dec->intg, dec->frac, - dec->buf[0], dec->buf[1], dec->buf[2], dec->buf[3], - dec->buf[4], dec->buf[5], dec->buf[6], dec->buf[7]); + int i, end; + char buff[512], *pos; + pos= buff; + pos+= my_sprintf(buff, (buff, "Decimal: sign: %d intg: %d frac: %d { ", + dec->sign(), dec->intg, dec->frac)); + end= ROUND_UP(dec->frac)+ROUND_UP(dec->intg)-1; + for (i=0; i < end; i++) + pos+= my_sprintf(pos, (pos, "%09d, ", dec->buf[i])); + pos+= my_sprintf(pos, (pos, "%09d }\n", dec->buf[i])); + fputs(buff, DBUG_FILE); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8385d177f81..2850fc8173d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -390,6 +390,9 @@ extern ulong srv_commit_concurrency; } #endif #ifdef WITH_BERKELEY_STORAGE_ENGINE +#ifndef HAVE_U_INT32_T +typedef unsigned int u_int32_t; +#endif extern const u_int32_t bdb_DB_TXN_NOSYNC, bdb_DB_RECOVER, bdb_DB_PRIVATE; extern bool berkeley_shared_data; extern u_int32_t berkeley_init_flags,berkeley_env_flags, berkeley_lock_type, @@ -548,6 +551,8 @@ pthread_cond_t COND_server_started; int mysqld_server_started= 0; +File_parser_dummy_hook file_parser_dummy_hook; + /* replication parameters, if master_host is not NULL, we are a slave */ uint master_port= MYSQL_PORT, master_connect_retry = 60; uint report_port= MYSQL_PORT; @@ -4621,6 +4626,7 @@ enum options_mysqld OPT_OPTIMIZER_PRUNE_LEVEL, OPT_UPDATABLE_VIEWS_WITH_LIMIT, OPT_SP_AUTOMATIC_PRIVILEGES, + OPT_MAX_SP_RECURSION_DEPTH, OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET, OPT_ENABLE_LARGE_PAGES, OPT_TIMED_MUTEXES, @@ -5876,6 +5882,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.read_buff_size, (gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0}, + {"max_sp_recursion_depth", OPT_MAX_SP_RECURSION_DEPTH, + "Maximum stored procedure recursion depth. (discussed with docs).", + (gptr*) &global_system_variables.max_sp_recursion_depth, + (gptr*) &max_system_variables.max_sp_recursion_depth, 0, GET_ULONG, + OPT_ARG, 0, 0, 255, 0, 1, 0 }, #ifdef HAVE_REPLICATION {"relay_log_purge", OPT_RELAY_LOG_PURGE, "0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.", diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2e7ee5964b7..9d555c3f512 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6706,7 +6706,7 @@ void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str) QUICK_RANGE_SELECT *quick; bool first= TRUE; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); - str->append("sort_union("); + str->append(STRING_WITH_LEN("sort_union(")); while ((quick= it++)) { if (!first) @@ -6728,7 +6728,7 @@ void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str) bool first= TRUE; QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); - str->append("intersect("); + str->append(STRING_WITH_LEN("intersect(")); while ((quick= it++)) { KEY *key_info= head->key_info + quick->index; @@ -6752,7 +6752,7 @@ void QUICK_ROR_UNION_SELECT::add_info_string(String *str) bool first= TRUE; QUICK_SELECT_I *quick; List_iterator_fast<QUICK_SELECT_I> it(quick_selects); - str->append("union("); + str->append(STRING_WITH_LEN("union(")); while ((quick= it++)) { if (!first) @@ -8892,7 +8892,7 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, } } if (!tmp.length()) - tmp.append("(empty)"); + tmp.append(STRING_WITH_LEN("(empty)")); DBUG_PRINT("info", ("SEL_TREE %p (%s) scans:%s", tree, msg, tmp.ptr())); @@ -8918,7 +8918,7 @@ static void print_ror_scans_arr(TABLE *table, const char *msg, tmp.append(table->key_info[(*start)->keynr].name); } if (!tmp.length()) - tmp.append("(empty)"); + tmp.append(STRING_WITH_LEN("(empty)")); DBUG_PRINT("info", ("ROR key scans (%s): %s", msg, tmp.ptr())); DBUG_VOID_RETURN; } diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 4633261e4ed..fe82054c528 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -50,23 +50,23 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s) */ switch(*ptr) { case '\\': // escape character - if (my_b_append(file, (const byte *)"\\\\", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\\"))) return TRUE; break; case '\n': // parameter value delimiter - if (my_b_append(file, (const byte *)"\\n", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\n"))) return TRUE; break; case '\0': // problem for some string processing utilities - if (my_b_append(file, (const byte *)"\\0", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\0"))) return TRUE; break; case 26: // problem for windows utilities (Ctrl-Z) - if (my_b_append(file, (const byte *)"\\z", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\z"))) return TRUE; break; case '\'': // list of string delimiter - if (my_b_append(file, (const byte *)"\\\'", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\'"))) return TRUE; break; default: @@ -155,10 +155,10 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, while ((str= it++)) { // We need ' ' after string to detect list continuation - if ((!first && my_b_append(file, (const byte *)" ", 1)) || - my_b_append(file, (const byte *)"\'", 1) || + if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) || + my_b_append(file, (const byte *)STRING_WITH_LEN("\'")) || write_escaped_string(file, str) || - my_b_append(file, (const byte *)"\'", 1)) + my_b_append(file, (const byte *)STRING_WITH_LEN("\'"))) { DBUG_RETURN(TRUE); } @@ -176,7 +176,7 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, { num.set(*val, &my_charset_bin); // We need ' ' after string to detect list continuation - if ((!first && my_b_append(file, (const byte *)" ", 1)) || + if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) || my_b_append(file, (const byte *)num.ptr(), num.length())) { DBUG_RETURN(TRUE); @@ -242,9 +242,9 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, goto err_w_file; // write header (file signature) - if (my_b_append(&file, (const byte *)"TYPE=", 5) || + if (my_b_append(&file, (const byte *)STRING_WITH_LEN("TYPE=")) || my_b_append(&file, (const byte *)type->str, type->length) || - my_b_append(&file, (const byte *)"\n", 1)) + my_b_append(&file, (const byte *)STRING_WITH_LEN("\n"))) goto err_w_file; // write parameters to temporary file @@ -252,9 +252,9 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, { if (my_b_append(&file, (const byte *)param->name.str, param->name.length) || - my_b_append(&file, (const byte *)"=", 1) || + my_b_append(&file, (const byte *)STRING_WITH_LEN("=")) || write_parameter(&file, base, param, &old_version) || - my_b_append(&file, (const byte *)"\n", 1)) + my_b_append(&file, (const byte *)STRING_WITH_LEN("\n"))) goto err_w_cache; } @@ -664,6 +664,61 @@ parse_quoted_escaped_string(char *ptr, char *end, /* + Parser for FILE_OPTIONS_ULLLIST type value. + + SYNOPSIS + get_file_options_ulllist() + ptr [in/out] pointer to parameter + end [in] end of the configuration + line [in] pointer to the line begining + base [in] base address for parameter writing (structure + like TABLE) + parameter [in] description + mem_root [in] MEM_ROOT for parameters allocation +*/ + +bool get_file_options_ulllist(char *&ptr, char *end, char *line, + gptr base, File_option *parameter, + MEM_ROOT *mem_root) +{ + List<ulonglong> *nlist= (List<ulonglong>*)(base + parameter->offset); + ulonglong *num; + nlist->empty(); + // list parsing + while (ptr < end) + { + int not_used; + char *num_end= end; + if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) || + nlist->push_back(num, mem_root)) + goto nlist_err; + *num= my_strtoll10(ptr, &num_end, ¬_used); + ptr= num_end; + switch (*ptr) { + case '\n': + goto end_of_nlist; + case ' ': + // we cant go over buffer bounds, because we have \0 at the end + ptr++; + break; + default: + goto nlist_err_w_message; + } + } + +end_of_nlist: + if (*(ptr++) != '\n') + goto nlist_err; + return FALSE; + +nlist_err_w_message: + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), parameter->name.str, line); +nlist_err: + return TRUE; +} + + +/* parse parameters SYNOPSIS @@ -673,6 +728,8 @@ parse_quoted_escaped_string(char *ptr, char *end, mem_root MEM_ROOT for parameters allocation parameters parameters description required number of required parameters in above list + hook hook called for unknown keys + hook_data some data specific for the hook RETURN FALSE - OK @@ -681,15 +738,15 @@ parse_quoted_escaped_string(char *ptr, char *end, my_bool File_parser::parse(gptr base, MEM_ROOT *mem_root, - struct File_option *parameters, uint required) + struct File_option *parameters, uint required, + Unknown_key_hook *hook) { uint first_param= 0, found= 0; - register char *ptr= start; + char *ptr= start; char *eol; LEX_STRING *str; List<LEX_STRING> *list; ulonglong *num; - List<ulonglong> *nlist; DBUG_ENTER("File_parser::parse"); while (ptr < end && found < required) @@ -829,58 +886,64 @@ list_err: DBUG_RETURN(TRUE); } case FILE_OPTIONS_ULLLIST: - { - nlist= (List<ulonglong>*)(base + parameter->offset); - nlist->empty(); - // list parsing - while (ptr < end) - { - int not_used; - char *num_end= end; - if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) || - nlist->push_back(num, mem_root)) - goto nlist_err; - *num= my_strtoll10(ptr, &num_end, ¬_used); - ptr= num_end; - switch (*ptr) { - case '\n': - goto end_of_nlist; - case ' ': - // we cant go over buffer bounds, because we have \0 at the end - ptr++; - break; - default: - goto nlist_err_w_message; - } - } - -end_of_nlist: - if (*(ptr++) != '\n') - goto nlist_err; + if (get_file_options_ulllist(ptr, end, line, base, + parameter, mem_root)) + DBUG_RETURN(TRUE); break; - -nlist_err_w_message: - my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), - parameter->name.str, line); -nlist_err: - DBUG_RETURN(TRUE); - - } default: DBUG_ASSERT(0); // never should happened } } else { - // skip unknown parameter - if (!(ptr= strchr(ptr, '\n'))) - { - my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0), line); - DBUG_RETURN(TRUE); - } - ptr++; + ptr= line; + if (hook->process_unknown_string(ptr, base, mem_root, end)) + { + DBUG_RETURN(TRUE); + } + // skip unknown parameter + if (!(ptr= strchr(ptr, '\n'))) + { + my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0), line); + DBUG_RETURN(TRUE); + } + ptr++; } } } DBUG_RETURN(FALSE); } + + +/* + Dummy unknown key hook + + SYNOPSIS + File_parser_dummy_hook::process_unknown_string() + unknown_key [in/out] reference on the line with unknown + parameter and the parsing point + base [in] base address for parameter writing (structure like + TABLE) + mem_root [in] MEM_ROOT for parameters allocation + end [in] the end of the configuration + + NOTE + This hook used to catch no longer supported keys and process them for + backward compatibility, but it will not slow down processing of modern + format files. + This hook does nothing except debug output. + + RETURN + FALSE OK + TRUE Error +*/ + +bool +File_parser_dummy_hook::process_unknown_string(char *&unknown_key, + gptr base, MEM_ROOT *mem_root, + char *end) +{ + DBUG_ENTER("file_parser_dummy_hook::process_unknown_string"); + DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + DBUG_RETURN(FALSE); +} diff --git a/sql/parse_file.h b/sql/parse_file.h index b4199e4fbf1..afa88da2ead 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -40,6 +40,35 @@ struct File_option file_opt_type type; /* Option type */ }; + +/* + This hook used to catch no longer supported keys and process them for + backward compatibility. +*/ + +class Unknown_key_hook +{ +public: + virtual bool process_unknown_string(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, char *end)= 0; +}; + + +/* Dummy hook for parsers which do not need hook for unknown keys */ + +class File_parser_dummy_hook: public Unknown_key_hook +{ +public: + virtual bool process_unknown_string(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, char *end); +}; + +extern File_parser_dummy_hook file_parser_dummy_hook; + +bool get_file_options_ulllist(char *&ptr, char *end, char *line, + gptr base, File_option *parameter, + MEM_ROOT *mem_root); + class File_parser; File_parser *sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root, bool bad_format_errors); @@ -64,7 +93,8 @@ public: my_bool ok() { return content_ok; } LEX_STRING *type() { return &file_type; } my_bool parse(gptr base, MEM_ROOT *mem_root, - struct File_option *parameters, uint required); + struct File_option *parameters, uint required, + Unknown_key_hook *hook); friend File_parser *sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root, diff --git a/sql/protocol.cc b/sql/protocol.cc index 8c3e5a62820..0a1b42f5236 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -498,7 +498,7 @@ void Protocol::init(THD *thd_arg) thd=thd_arg; packet= &thd->packet; convert= &thd->convert_buffer; -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_types= 0; #endif } @@ -551,7 +551,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); } -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_types= (enum_field_types*) thd->alloc(sizeof(field_types) * list->elements); uint count= 0; @@ -572,7 +572,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (prot.store("def", 3, cs, thd_charset) || + if (prot.store(STRING_WITH_LEN("def"), cs, thd_charset) || prot.store(field.db_name, (uint) strlen(field.db_name), cs, thd_charset) || prot.store(field.table_name, (uint) strlen(field.table_name), @@ -648,7 +648,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) item->send(&prot, &tmp); // Send default value if (prot.write()) break; /* purecov: inspected */ -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_types[count++]= field.type; #endif } @@ -732,14 +732,14 @@ bool Protocol::store(I_List<i_string>* str_list) void Protocol_simple::prepare_for_resend() { packet->length(0); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_pos= 0; #endif } bool Protocol_simple::store_null() { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_pos++; #endif char buff[1]; @@ -773,7 +773,7 @@ bool Protocol::store_string_aux(const char *from, uint length, bool Protocol_simple::store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || @@ -790,7 +790,7 @@ bool Protocol_simple::store(const char *from, uint length, CHARSET_INFO *fromcs) { CHARSET_INFO *tocs= this->thd->variables.character_set_results; -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || @@ -805,7 +805,7 @@ bool Protocol_simple::store(const char *from, uint length, bool Protocol_simple::store_tiny(longlong from) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY); field_pos++; #endif @@ -817,7 +817,7 @@ bool Protocol_simple::store_tiny(longlong from) bool Protocol_simple::store_short(longlong from) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_YEAR || field_types[field_pos] == MYSQL_TYPE_SHORT); @@ -831,7 +831,7 @@ bool Protocol_simple::store_short(longlong from) bool Protocol_simple::store_long(longlong from) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_INT24 || field_types[field_pos] == MYSQL_TYPE_LONG); @@ -845,7 +845,7 @@ bool Protocol_simple::store_long(longlong from) bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_LONGLONG); field_pos++; @@ -860,7 +860,7 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) bool Protocol_simple::store_decimal(const my_decimal *d) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; @@ -874,7 +874,7 @@ bool Protocol_simple::store_decimal(const my_decimal *d) bool Protocol_simple::store(float from, uint32 decimals, String *buffer) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_FLOAT); field_pos++; @@ -886,7 +886,7 @@ bool Protocol_simple::store(float from, uint32 decimals, String *buffer) bool Protocol_simple::store(double from, uint32 decimals, String *buffer) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DOUBLE); field_pos++; @@ -900,7 +900,7 @@ bool Protocol_simple::store(Field *field) { if (field->is_null()) return store_null(); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_pos++; #endif char buff[MAX_FIELD_WIDTH]; @@ -921,7 +921,7 @@ bool Protocol_simple::store(Field *field) bool Protocol_simple::store(TIME *tm) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DATETIME || field_types[field_pos] == MYSQL_TYPE_TIMESTAMP); @@ -944,7 +944,7 @@ bool Protocol_simple::store(TIME *tm) bool Protocol_simple::store_date(TIME *tm) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DATE); field_pos++; @@ -963,7 +963,7 @@ bool Protocol_simple::store_date(TIME *tm) bool Protocol_simple::store_time(TIME *tm) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TIME); field_pos++; @@ -1088,7 +1088,7 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag) bool Protocol_prep::store_decimal(const my_decimal *d) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; diff --git a/sql/protocol.h b/sql/protocol.h index c00bbba4cc9..8d9da5774b2 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -31,7 +31,7 @@ protected: String *packet; String *convert; uint field_pos; -#ifndef DEBUG_OFF +#ifndef DBUG_OFF enum enum_field_types *field_types; #endif uint field_count; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 823930121fe..960e0ac86cc 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -503,7 +503,7 @@ int update_slave_list(MYSQL* mysql, MASTER_INFO* mi) int port_ind; DBUG_ENTER("update_slave_list"); - if (mysql_real_query(mysql,"SHOW SLAVE HOSTS",16) || + if (mysql_real_query(mysql, STRING_WITH_LEN("SHOW SLAVE HOSTS")) || !(res = mysql_store_result(mysql))) { error= mysql_error(mysql); @@ -796,7 +796,7 @@ bool load_master_data(THD* thd) MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res; uint num_dbs; - if (mysql_real_query(&mysql, "SHOW DATABASES", 14) || + if (mysql_real_query(&mysql, STRING_WITH_LEN("SHOW DATABASES")) || !(db_res = mysql_store_result(&mysql))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); @@ -822,8 +822,9 @@ bool load_master_data(THD* thd) we wait to issue FLUSH TABLES WITH READ LOCK for as long as we can to minimize the lock time. */ - if (mysql_real_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) || - mysql_real_query(&mysql, "SHOW MASTER STATUS",18) || + if (mysql_real_query(&mysql, + STRING_WITH_LEN("FLUSH TABLES WITH READ LOCK")) || + mysql_real_query(&mysql, STRING_WITH_LEN("SHOW MASTER STATUS")) || !(master_status_res = mysql_store_result(&mysql))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); @@ -876,7 +877,7 @@ bool load_master_data(THD* thd) } if (mysql_select_db(&mysql, db) || - mysql_real_query(&mysql, "SHOW TABLES", 11) || + mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) || !(*cur_table_res = mysql_store_result(&mysql))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); @@ -934,7 +935,7 @@ bool load_master_data(THD* thd) mysql_free_result(master_status_res); } - if (mysql_real_query(&mysql, "UNLOCK TABLES", 13)) + if (mysql_real_query(&mysql, STRING_WITH_LEN("UNLOCK TABLES"))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); goto err; diff --git a/sql/set_var.cc b/sql/set_var.cc index 0505d36e0e4..b505f8cdc2a 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -298,6 +298,8 @@ sys_var_long_ptr sys_max_relay_log_size("max_relay_log_size", fix_max_relay_log_size); sys_var_thd_ulong sys_max_sort_length("max_sort_length", &SV::max_sort_length); +sys_var_thd_ulong sys_max_sp_recursion_depth("max_sp_recursion_depth", + &SV::max_sp_recursion_depth); sys_var_max_user_conn sys_max_user_connections("max_user_connections"); sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables", &SV::max_tmp_tables); @@ -772,6 +774,8 @@ struct show_var_st init_vars[]= { {sys_max_relay_log_size.name, (char*) &sys_max_relay_log_size, SHOW_SYS}, {sys_max_seeks_for_key.name, (char*) &sys_max_seeks_for_key, SHOW_SYS}, {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS}, + {sys_max_sp_recursion_depth.name, + (char*) &sys_max_sp_recursion_depth, SHOW_SYS}, {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS}, diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index 2e23027f1f5..6d905ba35dc 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -49,5 +49,15 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README $(INSTALL_DATA) $(srcdir)/charsets/*.xml $(DESTDIR)$(pkgdatadir)/charsets +# FIXME maybe shouldn't remove, could be needed by other installation? +uninstall-local: + @RM@ -f -r $(DESTDIR)$(pkgdatadir) + +distclean-local: + @RM@ -f */errmsg.sys + +# Do nothing +link_sources: + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7b2b03f9cb9..f922f7a08ba 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5361,7 +5361,7 @@ ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG ER_NO_DEFAULT_FOR_VIEW_FIELD eng "Field of view '%-.64s.%-.64s' underlying table doesn't have a default value" ER_SP_NO_RECURSION - eng "Recursive stored routines are not allowed." + eng "Recursive stored functions and triggers are not allowed." ER_TOO_BIG_SCALE 42000 S1009 eng "Too big scale %d specified for column '%-.64s'. Maximum is %d." ER_TOO_BIG_PRECISION 42000 S1009 @@ -5423,6 +5423,10 @@ ER_SP_BAD_VAR_SHADOW 42000 eng "Variable '%-.64s' must be quoted with `...`, or renamed" 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." +ER_OLD_FILE_FORMAT + eng "'%-.64s' has an old format, you should re-create the '%s' object(s)" +ER_SP_RECURSION_LIMIT + eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.64s" ER_PARTITION_REQUIRES_VALUES_ERROR eng "%s PARTITIONING requires definition of VALUES %s for each partition" swe "%s PARTITIONering kräver definition av VALUES %s för varje partition" diff --git a/sql/slave.cc b/sql/slave.cc index e354d4fcf8d..9e4c3b08256 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1068,7 +1068,7 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi) MYSQL_RES *master_res= 0; MYSQL_ROW master_row; - if (!mysql_real_query(mysql, "SELECT UNIX_TIMESTAMP()", 23) && + if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT UNIX_TIMESTAMP()")) && (master_res= mysql_store_result(mysql)) && (master_row= mysql_fetch_row(master_res))) { @@ -1094,7 +1094,8 @@ do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS"); Note: we could have put a @@SERVER_ID in the previous SELECT UNIX_TIMESTAMP() instead, but this would not have worked on 3.23 masters. */ - if (!mysql_real_query(mysql, "SHOW VARIABLES LIKE 'SERVER_ID'", 31) && + if (!mysql_real_query(mysql, + STRING_WITH_LEN("SHOW VARIABLES LIKE 'SERVER_ID'")) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -1129,7 +1130,8 @@ not always make sense; please check the manual before using it)."; goto err; if ((*mysql->server_version == '4') && - !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) && + !mysql_real_query(mysql, + STRING_WITH_LEN("SELECT @@GLOBAL.COLLATION_SERVER")) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -1156,7 +1158,7 @@ be equal for replication to work"; those were alpha). */ if ((*mysql->server_version == '4') && - !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && + !mysql_real_query(mysql, STRING_WITH_LEN("SELECT @@GLOBAL.TIME_ZONE")) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && diff --git a/sql/sp.cc b/sql/sp.cc index ac79f02ba3d..e9deb9b73c4 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -28,6 +28,11 @@ create_string(THD *thd, String *buf, const char *returns, ulong returnslen, const char *body, ulong bodylen, st_sp_chistics *chistics); +static int +db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, + ulong sql_mode, const char *params, const char *returns, + const char *body, st_sp_chistics &chistics, + const char *definer, longlong created, longlong modified); /* * @@ -376,83 +381,80 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) close_proc_table(thd, &open_tables_state_backup); table= 0; - { - String defstr; - LEX *oldlex= thd->lex; - char olddb[128]; - bool dbchanged; - enum enum_sql_command oldcmd= thd->lex->sql_command; - ulong old_sql_mode= thd->variables.sql_mode; - ha_rows select_limit= thd->variables.select_limit; - - thd->variables.sql_mode= sql_mode; - thd->variables.select_limit= HA_POS_ERROR; - - defstr.set_charset(system_charset_info); - if (!create_string(thd, &defstr, - type, - name, - params, strlen(params), - returns, strlen(returns), - body, strlen(body), - &chistics)) - { - ret= SP_INTERNAL_ERROR; - goto done; - } + ret= db_load_routine(thd, type, name, sphp, + sql_mode, params, returns, body, chistics, + definer, created, modified); + + done: + if (table) + close_proc_table(thd, &open_tables_state_backup); + DBUG_RETURN(ret); +} - dbchanged= FALSE; - if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), - 1, &dbchanged))) - goto done; - { - /* This is something of a kludge. We need to initialize some fields - * in thd->lex (the unit and master stuff), and the easiest way to - * do it is, is to call mysql_init_query(), but this unfortunately - * resets teh value_list where we keep the CALL parameters. So we - * copy the list and then restore it. (... and found_semicolon too). - */ - List<Item> tmpvals= thd->lex->value_list; - char *tmpfsc= thd->lex->found_semicolon; - - lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length()); - thd->lex->value_list= tmpvals; - thd->lex->found_semicolon= tmpfsc; - } +static int +db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, + ulong sql_mode, const char *params, const char *returns, + const char *body, st_sp_chistics &chistics, + const char *definer, longlong created, longlong modified) +{ + LEX *oldlex= thd->lex, newlex; + sp_rcontext *save_spcont= thd->spcont; + String defstr; + char olddb[128]; + bool dbchanged; + ulong old_sql_mode= thd->variables.sql_mode; + ha_rows select_limit= thd->variables.select_limit; + int ret= SP_INTERNAL_ERROR; + + thd->variables.sql_mode= sql_mode; + thd->variables.select_limit= HA_POS_ERROR; + + thd->lex= &newlex; + newlex.current_select= NULL; + + defstr.set_charset(system_charset_info); + if (!create_string(thd, &defstr, + type, + name, + params, strlen(params), + returns, strlen(returns), + body, strlen(body), + &chistics)) + goto end; - if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL) - { - LEX *newlex= thd->lex; - sp_head *sp= newlex->sphead; + dbchanged= FALSE; + if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), + 1, &dbchanged))) + goto end; - if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) - goto done; - if (sp) - { - delete sp; - newlex->sphead= NULL; - } - ret= SP_PARSE_ERROR; - } - else - { - if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) - goto done; - *sphp= thd->lex->sphead; - (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); - (*sphp)->set_info(created, modified, &chistics, sql_mode); - (*sphp)->optimize(); - } - thd->lex->sql_command= oldcmd; - thd->variables.sql_mode= old_sql_mode; - thd->variables.select_limit= select_limit; - } + lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length()); - done: - if (table) - close_proc_table(thd, &open_tables_state_backup); - DBUG_RETURN(ret); + thd->spcont= 0; + if (yyparse(thd) || thd->is_fatal_error || newlex.sphead == NULL) + { + sp_head *sp= newlex.sphead; + + if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) + goto end; + delete sp; + ret= SP_PARSE_ERROR; + } + else + { + if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) + goto end; + *sphp= newlex.sphead; + (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); + (*sphp)->set_info(created, modified, &chistics, sql_mode); + (*sphp)->optimize(); + } +end: + thd->spcont= save_spcont; + thd->variables.sql_mode= old_sql_mode; + thd->variables.select_limit= select_limit; + thd->lex= oldlex; + return ret; } @@ -900,45 +902,106 @@ err: ******************************************************************************/ /* - Obtain object representing stored procedure by its name from + Obtain object representing stored procedure/function by its name from stored procedures cache and looking into mysql.proc if needed. SYNOPSIS - sp_find_procedure() + sp_find_routine() thd - thread context + type - type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE) name - name of procedure + cp - hash to look routine in cache_only - if true perform cache-only lookup (Don't look in mysql.proc). - TODO - We should consider merging of sp_find_procedure() and - sp_find_function() into one sp_find_routine() function - (the same applies to other similarly paired functions). - RETURN VALUE Non-0 pointer to sp_head object for the procedure, or 0 - in case of error. */ sp_head * -sp_find_procedure(THD *thd, sp_name *name, bool cache_only) +sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, + bool cache_only) { sp_head *sp; - DBUG_ENTER("sp_find_procedure"); - DBUG_PRINT("enter", ("name: %.*s.%.*s", - name->m_db.length, name->m_db.str, - name->m_name.length, name->m_name.str)); + ulong depth= (type == TYPE_ENUM_PROCEDURE ? + thd->variables.max_sp_recursion_depth : + 0); + + DBUG_ENTER("sp_find_routine"); + DBUG_PRINT("enter", ("name: %.*s.%.*s, type: %d, cache only %d", + name->m_db.length, name->m_db.str, + name->m_name.length, name->m_name.str, + type, cache_only)); - if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)) && !cache_only) + if ((sp= sp_cache_lookup(cp, name))) + { + ulong level; + DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); + if (sp->m_first_free_instance) + { + DBUG_PRINT("info", ("first free: 0x%lx, level: %lu, flags %x", + (ulong)sp->m_first_free_instance, + sp->m_first_free_instance->m_recursion_level, + sp->m_first_free_instance->m_flags)); + DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED)); + if (sp->m_first_free_instance->m_recursion_level > depth) + { + sp->recursion_level_error(); + DBUG_RETURN(0); + } + DBUG_RETURN(sp->m_first_free_instance); + } + level= sp->m_last_cached_sp->m_recursion_level + 1; + if (level > depth) + { + sp->recursion_level_error(); + DBUG_RETURN(0); + } + { + sp_head *new_sp; + const char *returns= ""; + char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + String retstr(64); + strxmov(definer, sp->m_definer_user.str, "@", + sp->m_definer_host.str, NullS); + if (type == TYPE_ENUM_FUNCTION) + { + sp_returns_type(thd, retstr, sp); + returns= retstr.ptr(); + } + if (db_load_routine(thd, type, name, &new_sp, + sp->m_sql_mode, sp->m_params.str, returns, + sp->m_body.str, *sp->m_chistics, definer, + sp->m_created, sp->m_modified) == SP_OK) + { + sp->m_last_cached_sp->m_next_cached_sp= new_sp; + new_sp->m_recursion_level= level; + new_sp->m_first_instance= sp; + sp->m_last_cached_sp= sp->m_first_free_instance= new_sp; + DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x", + (ulong)new_sp, new_sp->m_recursion_level, + new_sp->m_flags)); + DBUG_RETURN(new_sp); + } + DBUG_RETURN(0); + } + } + if (!cache_only) { - if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK) - sp_cache_insert(&thd->sp_proc_cache, sp); + if (db_find_routine(thd, type, name, &sp) == SP_OK) + { + sp_cache_insert(cp, sp); + DBUG_PRINT("info", ("added new: 0x%lx, level: %lu, flags %x", + (ulong)sp, sp->m_recursion_level, + sp->m_flags)); + } } - DBUG_RETURN(sp); } + int sp_exists_routine(THD *thd, TABLE_LIST *tables, bool any, bool no_error) { @@ -956,8 +1019,10 @@ sp_exists_routine(THD *thd, TABLE_LIST *tables, bool any, bool no_error) lex_name.str= thd->strmake(table->table_name, lex_name.length); name= new sp_name(lex_db, lex_name); name->init_qname(thd); - if (sp_find_procedure(thd, name) != NULL || - sp_find_function(thd, name) != NULL) + if (sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name, + &thd->sp_proc_cache, FALSE) != NULL || + sp_find_routine(thd, TYPE_ENUM_FUNCTION, name, + &thd->sp_func_cache, FALSE) != NULL) { if (any) DBUG_RETURN(1); @@ -1025,7 +1090,8 @@ sp_show_create_procedure(THD *thd, sp_name *name) DBUG_ENTER("sp_show_create_procedure"); DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); - if ((sp= sp_find_procedure(thd, name))) + if ((sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name, + &thd->sp_proc_cache, FALSE))) { int ret= sp->show_create_procedure(thd); @@ -1051,42 +1117,6 @@ sp_show_status_procedure(THD *thd, const char *wild) FUNCTION ******************************************************************************/ -/* - Obtain object representing stored function by its name from - stored functions cache and looking into mysql.proc if needed. - - SYNOPSIS - sp_find_function() - thd - thread context - name - name of function - cache_only - if true perform cache-only lookup - (Don't look in mysql.proc). - - NOTE - See TODO section for sp_find_procedure(). - - RETURN VALUE - Non-0 pointer to sp_head object for the function, or - 0 - in case of error. -*/ - -sp_head * -sp_find_function(THD *thd, sp_name *name, bool cache_only) -{ - sp_head *sp; - DBUG_ENTER("sp_find_function"); - DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); - - if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) && - !cache_only) - { - if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) == SP_OK) - sp_cache_insert(&thd->sp_func_cache, sp); - } - DBUG_RETURN(sp); -} - - int sp_create_function(THD *thd, sp_head *sp) { @@ -1134,7 +1164,8 @@ sp_show_create_function(THD *thd, sp_name *name) DBUG_ENTER("sp_show_create_function"); DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); - if ((sp= sp_find_function(thd, name))) + if ((sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, name, + &thd->sp_func_cache, FALSE))) { int ret= sp->show_create_function(thd); @@ -1444,10 +1475,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, &thd->sp_func_cache : &thd->sp_proc_cache), &name))) { - LEX *oldlex= thd->lex; - LEX *newlex= new st_lex; - thd->lex= newlex; - newlex->current_select= NULL; name.m_name.str= strchr(name.m_qname.str, '.'); name.m_db.length= name.m_name.str - name.m_qname.str; name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str, @@ -1462,8 +1489,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, else sp_cache_insert(&thd->sp_proc_cache, sp); } - delete newlex; - thd->lex= oldlex; } if (sp) { @@ -1586,30 +1611,30 @@ create_string(THD *thd, String *buf, chistics->comment.length)) return FALSE; - buf->append("CREATE ", 7); + buf->append(STRING_WITH_LEN("CREATE ")); if (type == TYPE_ENUM_FUNCTION) - buf->append("FUNCTION ", 9); + buf->append(STRING_WITH_LEN("FUNCTION ")); else - buf->append("PROCEDURE ", 10); + buf->append(STRING_WITH_LEN("PROCEDURE ")); append_identifier(thd, buf, name->m_name.str, name->m_name.length); buf->append('('); buf->append(params, paramslen); buf->append(')'); if (type == TYPE_ENUM_FUNCTION) { - buf->append(" RETURNS ", 9); + buf->append(STRING_WITH_LEN(" RETURNS ")); buf->append(returns, returnslen); } buf->append('\n'); switch (chistics->daccess) { case SP_NO_SQL: - buf->append(" NO SQL\n"); + buf->append(STRING_WITH_LEN(" NO SQL\n")); break; case SP_READS_SQL_DATA: - buf->append(" READS SQL DATA\n"); + buf->append(STRING_WITH_LEN(" READS SQL DATA\n")); break; case SP_MODIFIES_SQL_DATA: - buf->append(" MODIFIES SQL DATA\n"); + buf->append(STRING_WITH_LEN(" MODIFIES SQL DATA\n")); break; case SP_DEFAULT_ACCESS: case SP_CONTAINS_SQL: @@ -1617,12 +1642,12 @@ create_string(THD *thd, String *buf, break; } if (chistics->detistic) - buf->append(" DETERMINISTIC\n", 18); + buf->append(STRING_WITH_LEN(" DETERMINISTIC\n")); if (chistics->suid == SP_IS_NOT_SUID) - buf->append(" SQL SECURITY INVOKER\n", 25); + buf->append(STRING_WITH_LEN(" SQL SECURITY INVOKER\n")); if (chistics->comment.length) { - buf->append(" COMMENT "); + buf->append(STRING_WITH_LEN(" COMMENT ")); append_unescaped(buf, chistics->comment.str, chistics->comment.length); buf->append('\n'); } @@ -36,7 +36,8 @@ int sp_drop_db_routines(THD *thd, char *db); sp_head * -sp_find_procedure(THD *thd, sp_name *name, bool cache_only = 0); +sp_find_routine(THD *thd, int type, sp_name *name, + sp_cache **cp, bool cache_only); int sp_exists_routine(THD *thd, TABLE_LIST *procs, bool any, bool no_error); @@ -57,9 +58,6 @@ sp_show_create_procedure(THD *thd, sp_name *name); int sp_show_status_procedure(THD *thd, const char *wild); -sp_head * -sp_find_function(THD *thd, sp_name *name, bool cache_only = 0); - int sp_create_function(THD *thd, sp_head *sp); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8406e83850c..0800089209c 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -105,6 +105,8 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_WARNS: + case SQLCOM_SHOW_PROC_CODE: + case SQLCOM_SHOW_FUNC_CODE: flags= sp_head::MULTI_RESULTS; break; /* @@ -480,7 +482,8 @@ 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_flags(0), m_returns_cs(NULL), m_recursion_level(0), m_next_cached_sp(0), + m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); @@ -661,6 +664,7 @@ sp_head::create(THD *thd) sp_head::~sp_head() { destroy(); + delete m_next_cached_sp; if (m_thd) restore_thd_mem_root(m_thd); } @@ -864,9 +868,9 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length; /* append the spvar substitute */ - res|= qbuf.append(" NAME_CONST('"); + res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('")); res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length); - res|= qbuf.append("',"); + res|= qbuf.append(STRING_WITH_LEN("',")); val= (*splocal)->this_item(); DBUG_PRINT("info", ("print %p", val)); val->print(&qbuf); @@ -889,6 +893,31 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) /* + Return appropriate error about recursion limit reaching + + SYNOPSIS + sp_head::recursion_level_error() + + NOTE + For functions and triggers we return error about prohibited recursion. + For stored procedures we return about reaching recursion limit. +*/ + +void sp_head::recursion_level_error() +{ + if (m_type == TYPE_ENUM_PROCEDURE) + { + THD *thd= current_thd; + my_error(ER_SP_RECURSION_LIMIT, MYF(0), + thd->variables.max_sp_recursion_depth, + m_name); + } + else + my_error(ER_SP_NO_RECURSION, MYF(0)); +} + + +/* Execute the routine. The main instruction jump loop is there Assume the parameters already set. @@ -917,37 +946,31 @@ int sp_head::execute(THD *thd) Item_change_list old_change_list; String old_packet; - /* init per-instruction memroot */ - init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - - /* Use some extra margin for possible SP recursion and functions */ - if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb)) + if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char*)&old_packet)) { DBUG_RETURN(-1); } - if (m_flags & IS_INVOKED) - { - /* - We have to disable recursion for stored routines since in - many cases LEX structure and many Item's can't be used in - reentrant way now. - - TODO: We can circumvent this problem by using separate - sp_head instances for each recursive invocation. - - NOTE: Theoretically arguments of procedure can be evaluated - before its invocation so there should be no problem with - recursion. But since we perform cleanup for CALL statement - as for any other statement only after its execution, its LEX - structure is not reusable for recursive calls. Thus we have - to prohibit recursion for stored procedures too. - */ - my_error(ER_SP_NO_RECURSION, MYF(0)); - DBUG_RETURN(-1); - } + /* init per-instruction memroot */ + init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + + DBUG_ASSERT(!(m_flags & IS_INVOKED)); m_flags|= IS_INVOKED; + m_first_instance->m_first_free_instance= m_next_cached_sp; + DBUG_PRINT("info", ("first free for 0x%lx ++: 0x%lx->0x%lx, level: %lu, flags %x", + (ulong)m_first_instance, this, m_next_cached_sp, + m_next_cached_sp->m_recursion_level, + m_next_cached_sp->m_flags)); + /* + Check that if there are not any instances after this one then + pointer to the last instance points on this instance or if there are + some instances after this one then recursion level of next instance + greater then recursion level of current instance on 1 + */ + DBUG_ASSERT((m_next_cached_sp == 0 && + m_first_instance->m_last_cached_sp == this) || + (m_recursion_level + 1 == m_next_cached_sp->m_recursion_level)); dbchanged= FALSE; if (m_db.length && @@ -1122,6 +1145,29 @@ int sp_head::execute(THD *thd) ret= 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, + m_first_instance->m_first_free_instance, this, + m_recursion_level, m_flags)); + /* + Check that we have one of following: + + 1) there are not free instances which means that this instance is last + in the list of instances (pointer to the last instance point on it and + ther are not other instances after this one in the list) + + 2) There are some free instances which mean that first free instance + should go just after this one and recursion level of that free instance + should be on 1 more then recursion leven of this instance. + */ + DBUG_ASSERT((m_first_instance->m_first_free_instance == 0 && + this == m_first_instance->m_last_cached_sp && + m_next_cached_sp == 0) || + (m_first_instance->m_first_free_instance != 0 && + m_first_instance->m_first_free_instance == m_next_cached_sp && + 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); } @@ -1179,6 +1225,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) // QQ Should have some error checking here? (types, etc...) if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax))) goto end; +#ifndef DBUG_OFF + nctx->owner= this; +#endif for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); @@ -1221,7 +1270,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) char buf[256]; String bufstr(buf, sizeof(buf), &my_charset_bin); bufstr.length(0); - bufstr.append("DO ", 3); + bufstr.append(STRING_WITH_LEN("DO ")); append_identifier(thd, &bufstr, m_name.str, m_name.length); bufstr.append('('); for (uint i=0; i < argcount; i++) @@ -1323,6 +1372,9 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) { // Create a temporary old context if (!(octx= new sp_rcontext(octx, csize, hmax, cmax))) DBUG_RETURN(-1); +#ifndef DBUG_OFF + octx->owner= 0; +#endif thd->spcont= octx; /* set callers_arena to thd, for upper-level function to work */ @@ -1334,6 +1386,9 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) thd->spcont= save_spcont; DBUG_RETURN(-1); } +#ifndef DBUG_OFF + nctx->owner= this; +#endif if (csize > 0 || hmax > 0 || cmax > 0) { @@ -1746,7 +1801,7 @@ sp_head::show_create_procedure(THD *thd) LINT_INIT(sql_mode_len); if (check_show_routine_access(thd, this, &full_access)) - return 1; + DBUG_RETURN(1); sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, @@ -1759,10 +1814,7 @@ sp_head::show_create_procedure(THD *thd) max(buffer.length(), 1024))); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - { - res= 1; - goto done; - } + DBUG_RETURN(1); protocol->prepare_for_resend(); protocol->store(m_name.str, m_name.length, system_charset_info); protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); @@ -1771,7 +1823,6 @@ sp_head::show_create_procedure(THD *thd) res= protocol->write(); send_eof(thd); - done: DBUG_RETURN(res); } @@ -1816,7 +1867,7 @@ sp_head::show_create_function(THD *thd) LINT_INIT(sql_mode_len); if (check_show_routine_access(thd, this, &full_access)) - return 1; + DBUG_RETURN(1); sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, @@ -1828,10 +1879,7 @@ sp_head::show_create_function(THD *thd) max(buffer.length(),1024))); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - { - res= 1; - goto done; - } + DBUG_RETURN(1); protocol->prepare_for_resend(); protocol->store(m_name.str, m_name.length, system_charset_info); protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); @@ -1840,7 +1888,6 @@ sp_head::show_create_function(THD *thd) res= protocol->write(); send_eof(thd); - done: DBUG_RETURN(res); } @@ -1900,6 +1947,50 @@ sp_head::opt_mark(uint ip) } +#ifndef DBUG_OFF +int +sp_head::show_routine_code(THD *thd) +{ + Protocol *protocol= thd->protocol; + char buff[2048]; + String buffer(buff, sizeof(buff), system_charset_info); + List<Item> field_list; + sp_instr *i; + bool full_access; + int res= 0; + uint ip; + DBUG_ENTER("sp_head::show_routine_code"); + DBUG_PRINT("info", ("procedure: %s", m_name.str)); + + if (check_show_routine_access(thd, this, &full_access) || !full_access) + DBUG_RETURN(1); + + field_list.push_back(new Item_uint("Pos", 9)); + // 1024 is for not to confuse old clients + field_list.push_back(new Item_empty_string("Instruction", + max(buffer.length(), 1024))); + if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | + Protocol::SEND_EOF)) + DBUG_RETURN(1); + + for (ip= 0; (i = get_instr(ip)) ; ip++) + { + protocol->prepare_for_resend(); + protocol->store((longlong)ip); + + buffer.set("", 0, system_charset_info); + i->print(&buffer); + protocol->store(buffer.ptr(), buffer.length(), system_charset_info); + if ((res= protocol->write())) + break; + } + send_eof(thd); + + DBUG_RETURN(res); +} +#endif // ifndef DBUG_OFF + + /* Prepare LEX and thread for execution of instruction, if requested open and lock LEX's tables, execute instruction's core function, perform @@ -2058,14 +2149,43 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } +/* + Sufficient max length of printed destinations and frame offsets (all uints). +*/ +#define SP_INSTR_UINT_MAXLEN 8 + +#define SP_STMT_PRINT_MAXLEN 40 void sp_instr_stmt::print(String *str) { - str->reserve(12); - str->append("stmt "); + uint i, len; + + /* stmt CMD "..." */ + if (str->reserve(SP_STMT_PRINT_MAXLEN+SP_INSTR_UINT_MAXLEN+8)) + return; + str->qs_append(STRING_WITH_LEN("stmt ")); str->qs_append((uint)m_lex_keeper.sql_command()); + str->qs_append(STRING_WITH_LEN(" \"")); + len= m_query.length; + /* + Print the query string (but not too much of it), just to indicate which + statement it is. + */ + if (len > SP_STMT_PRINT_MAXLEN) + len= SP_STMT_PRINT_MAXLEN-3; + /* Copy the query string and replace '\n' with ' ' in the process */ + for (i= 0 ; i < len ; i++) + { + if (m_query.str[i] == '\n') + str->qs_append(' '); + else + str->qs_append(m_query.str[i]); + } + if (m_query.length > SP_STMT_PRINT_MAXLEN) + str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */ + str->qs_append('"'); } - +#undef SP_STMT_PRINT_MAXLEN int sp_instr_stmt::exec_core(THD *thd, uint *nextp) @@ -2102,10 +2222,23 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) void sp_instr_set::print(String *str) { - str->reserve(12); - str->append("set "); + /* set name@offset ... */ + int rsrv = SP_INSTR_UINT_MAXLEN+6; + sp_pvar_t *var = m_ctx->find_pvar(m_offset); + + /* 'var' should always be non-null, but just in case... */ + if (var) + rsrv+= var->name.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("set ")); + if (var) + { + str->qs_append(var->name.str, var->name.length); + str->qs_append('@'); + } str->qs_append(m_offset); - str->append(' '); + str->qs_append(' '); m_value->print(str); } @@ -2138,9 +2271,9 @@ sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) void sp_instr_set_trigger_field::print(String *str) { - str->append("set ", 4); + str->append(STRING_WITH_LEN("set_trigger_field ")); trigger_field->print(str); - str->append(":=", 2); + str->append(STRING_WITH_LEN(":=")); value->print(str); } @@ -2162,8 +2295,10 @@ sp_instr_jump::execute(THD *thd, uint *nextp) void sp_instr_jump::print(String *str) { - str->reserve(12); - str->append("jump "); + /* jump dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) + return; + str->qs_append(STRING_WITH_LEN("jump ")); str->qs_append(m_dest); } @@ -2244,10 +2379,12 @@ sp_instr_jump_if::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if::print(String *str) { - str->reserve(12); - str->append("jump_if "); + /* jump_if dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too + return; + str->qs_append(STRING_WITH_LEN("jump_if ")); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2305,10 +2442,12 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if_not::print(String *str) { - str->reserve(16); - str->append("jump_if_not "); + /* jump_if_not dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too + return; + str->qs_append(STRING_WITH_LEN("jump_if_not ")); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2363,10 +2502,12 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) void sp_instr_freturn::print(String *str) { - str->reserve(12); - str->append("freturn "); + /* freturn type expr... */ + if (str->reserve(UINT_MAX+8+32)) // Add some for the expr. too + return; + str->qs_append(STRING_WITH_LEN("freturn ")); str->qs_append((uint)m_type); - str->append(' '); + str->qs_append(' '); m_value->print(str); } @@ -2391,15 +2532,31 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) void sp_instr_hpush_jump::print(String *str) { - str->reserve(32); - str->append("hpush_jump "); + /* hpush_jump dest fsize type */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21)) + return; + str->qs_append(STRING_WITH_LEN("hpush_jump ")); str->qs_append(m_dest); - str->append(" t="); - str->qs_append(m_type); - str->append(" f="); + str->qs_append(' '); str->qs_append(m_frame); - str->append(" h="); - str->qs_append(m_ip+1); + switch (m_type) + { + case SP_HANDLER_NONE: + str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug + break; + case SP_HANDLER_EXIT: + str->qs_append(STRING_WITH_LEN(" EXIT")); + break; + case SP_HANDLER_CONTINUE: + str->qs_append(STRING_WITH_LEN(" CONTINUE")); + break; + case SP_HANDLER_UNDO: + str->qs_append(STRING_WITH_LEN(" UNDO")); + break; + default: + str->qs_append(STRING_WITH_LEN(" UNKNOWN:")); // This would be a bug as well + str->qs_append(m_type); + } } uint @@ -2434,8 +2591,10 @@ sp_instr_hpop::execute(THD *thd, uint *nextp) void sp_instr_hpop::print(String *str) { - str->reserve(12); - str->append("hpop "); + /* hpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) + return; + str->qs_append(STRING_WITH_LEN("hpop ")); str->qs_append(m_count); } @@ -2469,12 +2628,14 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) void sp_instr_hreturn::print(String *str) { - str->reserve(16); - str->append("hreturn "); + /* hreturn framesize dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9)) + return; + str->qs_append(STRING_WITH_LEN("hreturn ")); str->qs_append(m_frame); if (m_dest) { - str->append(' '); + str->qs_append(' '); str->qs_append(m_dest); } } @@ -2522,7 +2683,22 @@ sp_instr_cpush::execute(THD *thd, uint *nextp) void sp_instr_cpush::print(String *str) { - str->append("cpush"); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cpush name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+7; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("cpush ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } + str->qs_append(m_cursor); } @@ -2543,8 +2719,10 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) void sp_instr_cpop::print(String *str) { - str->reserve(12); - str->append("cpop "); + /* cpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) + return; + str->qs_append(STRING_WITH_LEN("cpop ")); str->qs_append(m_count); } @@ -2618,8 +2796,21 @@ sp_instr_copen::exec_core(THD *thd, uint *nextp) void sp_instr_copen::print(String *str) { - str->reserve(12); - str->append("copen "); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* copen name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+7; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("copen ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } str->qs_append(m_cursor); } @@ -2647,8 +2838,21 @@ sp_instr_cclose::execute(THD *thd, uint *nextp) void sp_instr_cclose::print(String *str) { - str->reserve(12); - str->append("cclose "); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cclose name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+8; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("cclose ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } str->qs_append(m_cursor); } @@ -2677,14 +2881,29 @@ sp_instr_cfetch::print(String *str) { List_iterator_fast<struct sp_pvar> li(m_varlist); sp_pvar_t *pv; - - str->reserve(12); - str->append("cfetch "); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cfetch name@offset vars... */ + uint rsrv= SP_INSTR_UINT_MAXLEN+8; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("cfetch ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } str->qs_append(m_cursor); while ((pv= li++)) { - str->reserve(8); - str->append(' '); + if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2)) + return; + str->qs_append(' '); + str->qs_append(pv->name.str, pv->name.length); + str->qs_append('@'); str->qs_append(pv->offset); } } @@ -2708,8 +2927,10 @@ sp_instr_error::execute(THD *thd, uint *nextp) void sp_instr_error::print(String *str) { - str->reserve(12); - str->append("error "); + /* error code */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+6)) + return; + str->qs_append(STRING_WITH_LEN("error ")); str->qs_append(m_errcode); } diff --git a/sql/sp_head.h b/sql/sp_head.h index f70c43c2b03..90ce53db9db 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -143,6 +143,32 @@ public: LEX_STRING m_definer_host; longlong m_created; longlong m_modified; + /* Recursion level of the current SP instance. The levels are numbered from 0 */ + ulong m_recursion_level; + /* + A list of diferent recursion level instances for the same procedure. + For every recursion level we have a sp_head instance. This instances + connected in the list. The list ordered by increasing recursion level + (m_recursion_level). + */ + sp_head *m_next_cached_sp; + /* + Pointer to the first element of the above list + */ + sp_head *m_first_instance; + /* + Pointer to the first free (non-INVOKED) routine in the list of + cached instances for this SP. This pointer is set only for the first + SP in the list of instences (see above m_first_cached_sp pointer). + The pointer equal to 0 if we have no free instances. + For non-first instance value of this pointer meanless (point to itself); + */ + sp_head *m_first_free_instance; + /* + Pointer to the last element in the list of instances of the SP. + For non-first instance value of this pointer meanless (point to itself); + */ + sp_head *m_last_cached_sp; /* Set containing names of stored routines used by this routine. Note that unlike elements of similar set for statement elements of this @@ -266,6 +292,8 @@ public: void optimize(); void opt_mark(uint ip); + void recursion_level_error(); + inline sp_instr * get_instr(uint i) { @@ -304,6 +332,12 @@ public: return test(m_flags & (CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT)); } + +#ifndef DBUG_OFF + int show_routine_code(THD *thd); +#endif + + private: MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root @@ -865,8 +899,8 @@ class sp_instr_cpush : public sp_instr public: - sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex) - : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE) + sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex, uint offset) + : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE), m_cursor(offset) {} virtual ~sp_instr_cpush() @@ -885,6 +919,7 @@ public: private: sp_lex_keeper m_lex_keeper; + uint m_cursor; /* Frame offset (for debugging) */ }; // class sp_instr_cpush : public sp_instr diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index f873b676925..147173ab4d8 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -169,6 +169,28 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) return NULL; } +/* + Find a variable by offset from the top. + This used for two things: + - When evaluating parameters at the beginning, and setting out parameters + at the end, of invokation. (Top frame only, so no recursion then.) + - For printing of sp_instr_set. (Debug mode only.) + */ +sp_pvar_t * +sp_pcontext::find_pvar(uint offset) +{ + if (m_poffset <= offset && offset < m_poffset + m_pvar.elements) + { // This frame + sp_pvar_t *p; + + get_dynamic(&m_pvar, (gptr)&p, offset - m_poffset); + return p; + } + if (m_parent) + return m_parent->find_pvar(offset); // Some previous frame + return NULL; // index out of bounds +} + void sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode) @@ -331,3 +353,21 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped) return m_parent->find_cursor(name, poff, scoped); return FALSE; } + +/* + Find a cursor by offset from the top. + This is only used for debugging. + */ +my_bool +sp_pcontext::find_cursor(uint offset, LEX_STRING *n) +{ + if (m_coffset <= offset && offset < m_coffset + m_cursor.elements) + { // This frame + get_dynamic(&m_cursor, (gptr)n, offset - m_coffset); + return TRUE; + } + if (m_parent) + return m_parent->find_cursor(offset, n); // Some previous frame + return FALSE; // index out of bounds +} + diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index bd2259cb6fb..b8dd1742f7e 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -170,18 +170,9 @@ class sp_pcontext : public Sql_alloc sp_pvar_t * find_pvar(LEX_STRING *name, my_bool scoped=0); - // Find by index + // Find by offset sp_pvar_t * - find_pvar(uint i) - { - sp_pvar_t *p; - - if (i < m_pvar.elements) - get_dynamic(&m_pvar, (gptr)&p, i); - else - p= NULL; - return p; - } + find_pvar(uint offset); // // Labels @@ -261,6 +252,10 @@ class sp_pcontext : public Sql_alloc my_bool find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0); + /* Find by offset (for debugging only) */ + my_bool + find_cursor(uint offset, LEX_STRING *n); + inline uint max_cursors() { diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index cae5c5467c9..d54188aa96f 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -66,6 +66,14 @@ class sp_rcontext : public Sql_alloc */ Query_arena *callers_arena; +#ifndef DBUG_OFF + /* + Routine to which this Item_splocal belongs. Used for checking if correct + runtime context is used for variable handling. + */ + sp_head *owner; +#endif + sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax); ~sp_rcontext() diff --git a/sql/spatial.cc b/sql/spatial.cc index ca9615236e0..e91653f79d5 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1793,7 +1793,7 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt, geom->set_data_ptr(data, (uint) (m_data_end - data)); if (geom->as_wkt(txt, &data)) return 1; - if (txt->append(",", 1, 512)) + if (txt->append(STRING_WITH_LEN(","), 512)) return 1; } txt->length(txt->length() - 1); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index abd32585444..3c00a4630e9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1810,19 +1810,22 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, /* We write down SSL related ACL stuff */ switch (lex->ssl_type) { case SSL_TYPE_ANY: - table->field[next_field]->store("ANY", 3, &my_charset_latin1); + table->field[next_field]->store(STRING_WITH_LEN("ANY"), + &my_charset_latin1); table->field[next_field+1]->store("", 0, &my_charset_latin1); table->field[next_field+2]->store("", 0, &my_charset_latin1); table->field[next_field+3]->store("", 0, &my_charset_latin1); break; case SSL_TYPE_X509: - table->field[next_field]->store("X509", 4, &my_charset_latin1); + table->field[next_field]->store(STRING_WITH_LEN("X509"), + &my_charset_latin1); table->field[next_field+1]->store("", 0, &my_charset_latin1); table->field[next_field+2]->store("", 0, &my_charset_latin1); table->field[next_field+3]->store("", 0, &my_charset_latin1); break; case SSL_TYPE_SPECIFIED: - table->field[next_field]->store("SPECIFIED", 9, &my_charset_latin1); + table->field[next_field]->store(STRING_WITH_LEN("SPECIFIED"), + &my_charset_latin1); table->field[next_field+1]->store("", 0, &my_charset_latin1); table->field[next_field+2]->store("", 0, &my_charset_latin1); table->field[next_field+3]->store("", 0, &my_charset_latin1); @@ -4056,13 +4059,13 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { String global(buff,sizeof(buff),system_charset_info); global.length(0); - global.append("GRANT ",6); + global.append(STRING_WITH_LEN("GRANT ")); want_access= acl_user->access; if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL))) - global.append("ALL PRIVILEGES",14); + global.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!(want_access & ~GRANT_ACL)) - global.append("USAGE",5); + global.append(STRING_WITH_LEN("USAGE")); else { bool found=0; @@ -4072,16 +4075,16 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_access & j) { if (found) - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); found=1; global.append(command_array[counter],command_lengths[counter]); } } } - global.append (" ON *.* TO '",12); + global.append (STRING_WITH_LEN(" ON *.* TO '")); global.append(lex_user->user.str, lex_user->user.length, system_charset_info); - global.append ("'@'",3); + global.append (STRING_WITH_LEN("'@'")); global.append(lex_user->host.str,lex_user->host.length, system_charset_info); global.append ('\''); @@ -4092,23 +4095,23 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) make_password_from_salt(passwd_buff, acl_user->salt); else make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt); - global.append(" IDENTIFIED BY PASSWORD '",25); + global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); global.append(passwd_buff); global.append('\''); } /* "show grants" SSL related stuff */ if (acl_user->ssl_type == SSL_TYPE_ANY) - global.append(" REQUIRE SSL",12); + global.append(STRING_WITH_LEN(" REQUIRE SSL")); else if (acl_user->ssl_type == SSL_TYPE_X509) - global.append(" REQUIRE X509",13); + global.append(STRING_WITH_LEN(" REQUIRE X509")); else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) { int ssl_options = 0; - global.append(" REQUIRE ",9); + global.append(STRING_WITH_LEN(" REQUIRE ")); if (acl_user->x509_issuer) { ssl_options++; - global.append("ISSUER \'",8); + global.append(STRING_WITH_LEN("ISSUER \'")); global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); global.append('\''); } @@ -4116,7 +4119,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { if (ssl_options++) global.append(' '); - global.append("SUBJECT \'",9); + global.append(STRING_WITH_LEN("SUBJECT \'")); global.append(acl_user->x509_subject,strlen(acl_user->x509_subject), system_charset_info); global.append('\''); @@ -4125,7 +4128,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { if (ssl_options++) global.append(' '); - global.append("CIPHER '",8); + global.append(STRING_WITH_LEN("CIPHER '")); global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), system_charset_info); global.append('\''); @@ -4137,9 +4140,9 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) acl_user->user_resource.conn_per_hour || acl_user->user_resource.user_conn)) { - global.append(" WITH",5); + global.append(STRING_WITH_LEN(" WITH")); if (want_access & GRANT_ACL) - global.append(" GRANT OPTION",13); + global.append(STRING_WITH_LEN(" GRANT OPTION")); add_user_option(&global, acl_user->user_resource.questions, "MAX_QUERIES_PER_HOUR"); add_user_option(&global, acl_user->user_resource.updates, @@ -4177,12 +4180,12 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { String db(buff,sizeof(buff),system_charset_info); db.length(0); - db.append("GRANT ",6); + db.append(STRING_WITH_LEN("GRANT ")); if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL))) - db.append("ALL PRIVILEGES",14); + db.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!(want_access & ~GRANT_ACL)) - db.append("USAGE",5); + db.append(STRING_WITH_LEN("USAGE")); else { int found=0, cnt; @@ -4192,23 +4195,23 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_access & j) { if (found) - db.append(", ",2); + db.append(STRING_WITH_LEN(", ")); found = 1; db.append(command_array[cnt],command_lengths[cnt]); } } } - db.append (" ON ",4); + db.append (STRING_WITH_LEN(" ON ")); append_identifier(thd, &db, acl_db->db, strlen(acl_db->db)); - db.append (".* TO '",7); + db.append (STRING_WITH_LEN(".* TO '")); db.append(lex_user->user.str, lex_user->user.length, system_charset_info); - db.append ("'@'",3); + db.append (STRING_WITH_LEN("'@'")); db.append(lex_user->host.str, lex_user->host.length, system_charset_info); db.append ('\''); if (want_access & GRANT_ACL) - db.append(" WITH GRANT OPTION",18); + db.append(STRING_WITH_LEN(" WITH GRANT OPTION")); protocol->prepare_for_resend(); protocol->store(db.ptr(),db.length(),db.charset()); if (protocol->write()) @@ -4241,12 +4244,12 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL; global.length(0); - global.append("GRANT ",6); + global.append(STRING_WITH_LEN("GRANT ")); if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL))) - global.append("ALL PRIVILEGES",14); + global.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!test_access) - global.append("USAGE",5); + global.append(STRING_WITH_LEN("USAGE")); else { /* Add specific column access */ @@ -4258,7 +4261,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_access & j) { if (found) - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); found= 1; global.append(command_array[counter],command_lengths[counter]); @@ -4282,14 +4285,14 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) */ if (table_access & j) { - global.append(", ", 2); + global.append(STRING_WITH_LEN(", ")); global.append(command_array[counter], command_lengths[counter]); } - global.append(" (",2); + global.append(STRING_WITH_LEN(" (")); } else - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); global.append(grant_column->column, grant_column->key_length, system_charset_info); @@ -4301,21 +4304,21 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } } } - global.append(" ON ",4); + global.append(STRING_WITH_LEN(" ON ")); append_identifier(thd, &global, grant_table->db, strlen(grant_table->db)); global.append('.'); append_identifier(thd, &global, grant_table->tname, strlen(grant_table->tname)); - global.append(" TO '",5); + global.append(STRING_WITH_LEN(" TO '")); global.append(lex_user->user.str, lex_user->user.length, system_charset_info); - global.append("'@'",3); + global.append(STRING_WITH_LEN("'@'")); global.append(lex_user->host.str,lex_user->host.length, system_charset_info); global.append('\''); if (table_access & GRANT_ACL) - global.append(" WITH GRANT OPTION",18); + global.append(STRING_WITH_LEN(" WITH GRANT OPTION")); protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); if (protocol->write()) @@ -4328,14 +4331,14 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } if (show_routine_grants(thd, lex_user, &proc_priv_hash, - "PROCEDURE", 9, buff, sizeof(buff))) + STRING_WITH_LEN("PROCEDURE"), buff, sizeof(buff))) { error= -1; goto end; } if (show_routine_grants(thd, lex_user, &func_priv_hash, - "FUNCTION", 8, buff, sizeof(buff))) + STRING_WITH_LEN("FUNCTION"), buff, sizeof(buff))) { error= -1; goto end; @@ -4376,10 +4379,10 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, ulong test_access= proc_access & ~GRANT_ACL; global.length(0); - global.append("GRANT ",6); + global.append(STRING_WITH_LEN("GRANT ")); if (!test_access) - global.append("USAGE",5); + global.append(STRING_WITH_LEN("USAGE")); else { /* Add specific procedure access */ @@ -4391,13 +4394,13 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, if (test_access & j) { if (found) - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); found= 1; global.append(command_array[counter],command_lengths[counter]); } } } - global.append(" ON ",4); + global.append(STRING_WITH_LEN(" ON ")); global.append(type,typelen); global.append(' '); append_identifier(thd, &global, grant_proc->db, @@ -4405,15 +4408,15 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, global.append('.'); append_identifier(thd, &global, grant_proc->tname, strlen(grant_proc->tname)); - global.append(" TO '",5); + global.append(STRING_WITH_LEN(" TO '")); global.append(lex_user->user.str, lex_user->user.length, system_charset_info); - global.append("'@'",3); + global.append(STRING_WITH_LEN("'@'")); global.append(lex_user->host.str,lex_user->host.length, system_charset_info); global.append('\''); if (proc_access & GRANT_ACL) - global.append(" WITH GRANT OPTION",18); + global.append(STRING_WITH_LEN(" WITH GRANT OPTION")); protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); if (protocol->write()) @@ -5068,7 +5071,7 @@ static void append_user(String *str, LEX_USER *user) str->append(','); str->append('\''); str->append(user->user.str); - str->append("'@'"); + str->append(STRING_WITH_LEN("'@'")); str->append(user->host.str); str->append('\''); } @@ -5650,7 +5653,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff,"'",user,"'@'",host,"'",NullS); if (!(want_access & ~GRANT_ACL)) - update_schema_privilege(table, buff, 0, 0, 0, 0, "USAGE", 5, is_grantable); + update_schema_privilege(table, buff, 0, 0, 0, 0, + STRING_WITH_LEN("USAGE"), is_grantable); else { uint priv_id; @@ -5708,7 +5712,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff,"'",user,"'@'",host,"'",NullS); if (!(want_access & ~GRANT_ACL)) update_schema_privilege(table, buff, acl_db->db, 0, 0, - 0, "USAGE", 5, is_grantable); + 0, STRING_WITH_LEN("USAGE"), is_grantable); else { int cnt; @@ -5768,7 +5772,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS); if (!test_access) update_schema_privilege(table, buff, grant_table->db, grant_table->tname, - 0, 0, "USAGE", 5, is_grantable); + 0, 0, STRING_WITH_LEN("USAGE"), is_grantable); else { ulong j; diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index e1f4b8f6076..0e4198a5114 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -733,13 +733,13 @@ bool analyse::end_of_records() tree_info.found = 0; tree_info.item = (*f)->item; - tmp_str.set("ENUM(", 5,&my_charset_bin); + tmp_str.set(STRING_WITH_LEN("ENUM("),&my_charset_bin); tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info, left_root_right); tmp_str.append(')'); if (!(*f)->nulls) - tmp_str.append(" NOT NULL"); + tmp_str.append(STRING_WITH_LEN(" NOT NULL")); output_str_length = tmp_str.length(); func_items[9]->set(tmp_str.ptr(), tmp_str.length(), tmp_str.charset()); if (result->send_data(result_fields)) @@ -749,35 +749,35 @@ bool analyse::end_of_records() ans.length(0); if (!(*f)->treemem && !(*f)->tree_elements) - ans.append("CHAR(0)", 7); + ans.append(STRING_WITH_LEN("CHAR(0)")); else if ((*f)->item->type() == Item::FIELD_ITEM) { switch (((Item_field*) (*f)->item)->field->real_type()) { case FIELD_TYPE_TIMESTAMP: - ans.append("TIMESTAMP", 9); + ans.append(STRING_WITH_LEN("TIMESTAMP")); break; case FIELD_TYPE_DATETIME: - ans.append("DATETIME", 8); + ans.append(STRING_WITH_LEN("DATETIME")); break; case FIELD_TYPE_DATE: case FIELD_TYPE_NEWDATE: - ans.append("DATE", 4); + ans.append(STRING_WITH_LEN("DATE")); break; case FIELD_TYPE_SET: - ans.append("SET", 3); + ans.append(STRING_WITH_LEN("SET")); break; case FIELD_TYPE_YEAR: - ans.append("YEAR", 4); + ans.append(STRING_WITH_LEN("YEAR")); break; case FIELD_TYPE_TIME: - ans.append("TIME", 4); + ans.append(STRING_WITH_LEN("TIME")); break; case FIELD_TYPE_DECIMAL: - ans.append("DECIMAL", 7); + ans.append(STRING_WITH_LEN("DECIMAL")); // if item is FIELD_ITEM, it _must_be_ Field_num in this case if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill) - ans.append(" ZEROFILL"); + ans.append(STRING_WITH_LEN(" ZEROFILL")); break; default: (*f)->get_opt_type(&ans, rows); @@ -785,7 +785,7 @@ bool analyse::end_of_records() } } if (!(*f)->nulls) - ans.append(" NOT NULL"); + ans.append(STRING_WITH_LEN(" NOT NULL")); func_items[9]->set(ans.ptr(), ans.length(), ans.charset()); if (result->send_data(result_fields)) return -1; @@ -829,18 +829,18 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) sprintf(buff, "BIGINT(%d)", num_info.integers); answer->append(buff, (uint) strlen(buff)); if (ev_num_info.llval >= 0 && ev_num_info.min_dval >= 0) - answer->append(" UNSIGNED"); + answer->append(STRING_WITH_LEN(" UNSIGNED")); if (num_info.zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } else if (max_length < 256) { if (must_be_blob) { if (item->collation.collation == &my_charset_bin) - answer->append("TINYBLOB", 8); + answer->append(STRING_WITH_LEN("TINYBLOB")); else - answer->append("TINYTEXT", 8); + answer->append(STRING_WITH_LEN("TINYTEXT")); } else if ((max_length * (total_rows - nulls)) < (sum + total_rows)) { @@ -856,23 +856,23 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) else if (max_length < (1L << 16)) { if (item->collation.collation == &my_charset_bin) - answer->append("BLOB", 4); + answer->append(STRING_WITH_LEN("BLOB")); else - answer->append("TEXT", 4); + answer->append(STRING_WITH_LEN("TEXT")); } else if (max_length < (1L << 24)) { if (item->collation.collation == &my_charset_bin) - answer->append("MEDIUMBLOB", 10); + answer->append(STRING_WITH_LEN("MEDIUMBLOB")); else - answer->append("MEDIUMTEXT", 10); + answer->append(STRING_WITH_LEN("MEDIUMTEXT")); } else { if (item->collation.collation == &my_charset_bin) - answer->append("LONGBLOB", 8); + answer->append(STRING_WITH_LEN("LONGBLOB")); else - answer->append("LONGTEXT", 8); + answer->append(STRING_WITH_LEN("LONGTEXT")); } } // field_str::get_opt_type @@ -902,14 +902,14 @@ void field_real::get_opt_type(String *answer, sprintf(buff, "BIGINT(%d)", len); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) - answer->append(" UNSIGNED"); + answer->append(STRING_WITH_LEN(" UNSIGNED")); } else if (item->decimals == NOT_FIXED_DEC) { if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX) - answer->append("FLOAT", 5); + answer->append(STRING_WITH_LEN("FLOAT")); else - answer->append("DOUBLE", 6); + answer->append(STRING_WITH_LEN("DOUBLE")); } else { @@ -926,7 +926,7 @@ void field_real::get_opt_type(String *answer, // a single number shouldn't be zerofill (max_length - (item->decimals + 1)) != 1 && ((Field_num*) ((Item_field*) item)->field)->zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } // field_real::get_opt_type @@ -950,14 +950,14 @@ void field_longlong::get_opt_type(String *answer, sprintf(buff, "BIGINT(%d)", (int) max_length); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) - answer->append(" UNSIGNED"); + answer->append(STRING_WITH_LEN(" UNSIGNED")); // if item is FIELD_ITEM, it _must_be_ Field_num in this class if ((item->type() == Item::FIELD_ITEM) && // a single number shouldn't be zerofill max_length != 1 && ((Field_num*) ((Item_field*) item)->field)->zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } // field_longlong::get_opt_type @@ -982,7 +982,7 @@ void field_ulonglong::get_opt_type(String *answer, // a single number shouldn't be zerofill max_length != 1 && ((Field_num*) ((Item_field*) item)->field)->zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } //field_ulonglong::get_opt_type diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cfeb78b2c31..1b06d59cc18 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1691,6 +1691,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, /* find a unused table in the open table cache */ if (refresh) *refresh=0; + + /* an open table operation needs a lot of the stack space */ + if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char *)&alias)) + return 0; + if (thd->killed) DBUG_RETURN(0); @@ -1803,7 +1808,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, (void) unpack_filename(path, path); if (mysql_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW) { - TABLE tab;// will not be used (because it's VIEW) but have to be passed + /* + Will not be used (because it's VIEW) but has to be passed. + Also we will not free it (because it is a stack variable). + */ + TABLE tab; table= &tab; VOID(pthread_mutex_lock(&LOCK_open)); if (!open_unireg_entry(thd, table, table_list, alias, diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 880bf74e67f..b7531696150 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -412,7 +412,7 @@ protected: /* The following functions are only used when debugging - We don't protect these with ifndef DEBUG_OFF to not have to recompile + We don't protect these with ifndef DBUG_OFF to not have to recompile everything if we want to add checks of the cache at some places. */ void wreck(uint line, const char *message); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 59f82de7013..8672180b66a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1497,7 +1497,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) { my_var *mv= gl++; if (mv->local) - (void)local_vars.push_back(new Item_splocal(mv->s, mv->offset)); + { + Item_splocal *var; + (void)local_vars.push_back(var= new Item_splocal(mv->s, mv->offset)); +#ifndef DBUG_OFF + var->owner= mv->owner; +#endif + } else { Item_func_set_user_var *var= new Item_func_set_user_var(mv->s, item); @@ -1918,6 +1924,7 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) - Value for found_rows() is reset and restored - examined_row_count is added to the total - cuted_fields is added to the total + - new savepoint level is created and destroyed NOTES: Seed for random() is saved for the first! usage of RAND() @@ -1941,6 +1948,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, backup->sent_row_count= sent_row_count; backup->cuted_fields= cuted_fields; backup->client_capabilities= client_capabilities; + backup->savepoints= transaction.savepoints; if (!lex->requires_prelocking() || is_update_query(lex->sql_command)) options&= ~OPTION_BIN_LOG; @@ -1953,6 +1961,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, examined_row_count= 0; sent_row_count= 0; cuted_fields= 0; + transaction.savepoints= 0; #ifndef EMBEDDED_LIBRARY /* Surpress OK packets in case if we will execute statements */ @@ -1963,6 +1972,21 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { + /* + To save resources we want to release savepoints which were created + during execution of function or trigger before leaving their savepoint + level. It is enough to release first savepoint set on this level since + all later savepoints will be released automatically. + */ + if (transaction.savepoints) + { + SAVEPOINT *sv; + for (sv= transaction.savepoints; sv->prev; sv= sv->prev) + {} + /* ha_release_savepoint() never returns error. */ + (void)ha_release_savepoint(this, sv); + } + transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; net.no_send_ok= backup->no_send_ok; diff --git a/sql/sql_class.h b/sql/sql_class.h index 381efe977f4..e075e46fb03 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -533,6 +533,7 @@ struct system_variables ulong completion_type; /* Determines which non-standard SQL behaviour should be enabled */ ulong sql_mode; + ulong max_sp_recursion_depth; /* check of key presence in updatable view */ ulong updatable_views_with_limit; ulong default_week_format; @@ -1102,6 +1103,7 @@ public: uint in_sub_stmt; bool enable_slow_log, insert_id_used; my_bool no_send_ok; + SAVEPOINT *savepoints; }; @@ -2095,6 +2097,13 @@ public: class my_var : public Sql_alloc { public: LEX_STRING s; +#ifndef DBUG_OFF + /* + Routine to which this Item_splocal belongs. Used for checking if correct + runtime context is used for variable handling. + */ + sp_head *owner; +#endif bool local; uint offset; enum_field_types type; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4f62a9c2864..4d32e26f1b7 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1529,9 +1529,9 @@ void st_select_lex_unit::print(String *str) { if (sl != first_select()) { - str->append(" union ", 7); + str->append(STRING_WITH_LEN(" union ")); if (union_all) - str->append("all ", 4); + str->append(STRING_WITH_LEN("all ")); else if (union_distinct == sl) union_all= TRUE; } @@ -1545,7 +1545,7 @@ void st_select_lex_unit::print(String *str) { if (fake_select_lex->order_list.elements) { - str->append(" order by ", 10); + str->append(STRING_WITH_LEN(" order by ")); fake_select_lex->print_order(str, (ORDER *) fake_select_lex-> order_list.first); @@ -1568,7 +1568,7 @@ void st_select_lex::print_order(String *str, ORDER *order) else (*order->item)->print(str); if (!order->asc) - str->append(" desc", 5); + str->append(STRING_WITH_LEN(" desc")); if (order->next) str->append(','); } @@ -1591,7 +1591,7 @@ void st_select_lex::print_limit(THD *thd, String *str) if (explicit_limit) { - str->append(" limit ", 7); + str->append(STRING_WITH_LEN(" limit ")); if (offset_limit) { offset_limit->print(str); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 2900df7982e..d7ad28a95f5 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -91,6 +91,7 @@ enum enum_sql_command { SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE, SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, + SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN, SQLCOM_SHOW_AUTHORS, /* This should be the last !!! */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index d86a28b1581..09bcb9cb9fe 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -691,7 +691,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, length=(uint) (read_info.row_end-pos); if (!read_info.enclosed && - (enclosed_length && length == 4 && !memcmp(pos,"NULL",4)) || + (enclosed_length && length == 4 && + !memcmp(pos, STRING_WITH_LEN("NULL"))) || (length == 1 && read_info.found_null)) { if (item->type() == Item::FIELD_ITEM) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 60941b306be..07535bd6c27 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3672,7 +3672,8 @@ end_with_restore_list: if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0)) break; #ifdef HAVE_DLOPEN - if (sp_find_function(thd, lex->spname)) + if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE)) { my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str); goto error; @@ -4023,8 +4024,8 @@ end_with_restore_list: break; } case SQLCOM_SAVEPOINT: - if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) || - !opt_using_transactions) + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) || + thd->in_sub_stmt) || !opt_using_transactions) send_ok(thd); else { @@ -4206,7 +4207,8 @@ end_with_restore_list: By this moment all needed SPs should be in cache so no need to look into DB. */ - if (!(sp= sp_find_procedure(thd, lex->spname, TRUE))) + if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, TRUE))) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", lex->spname->m_qname.str); @@ -4330,9 +4332,11 @@ end_with_restore_list: memcpy(&chistics, &lex->sp_chistics, sizeof(chistics)); if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) - sp= sp_find_procedure(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, FALSE); else - sp= sp_find_function(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE); mysql_reset_errors(thd, 0); if (! sp) { @@ -4408,9 +4412,11 @@ end_with_restore_list: char *db, *name; if (lex->sql_command == SQLCOM_DROP_PROCEDURE) - sp= sp_find_procedure(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, FALSE); else - sp= sp_find_function(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE); mysql_reset_errors(thd, 0); if (sp) { @@ -4538,6 +4544,33 @@ end_with_restore_list: lex->wild->ptr() : NullS)); break; } +#ifndef DBUG_OFF + case SQLCOM_SHOW_PROC_CODE: + case SQLCOM_SHOW_FUNC_CODE: + { + sp_head *sp; + + if (lex->spname->m_name.length > NAME_LEN) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str); + goto error; + } + if (lex->sql_command == SQLCOM_SHOW_PROC_CODE) + sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, FALSE); + else + sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE); + if (!sp || !sp->show_routine_code(thd)) + { + /* We don't distinguish between errors for now */ + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), + SP_COM_STRING(lex), lex->spname->m_name.str); + goto error; + } + break; + } +#endif // ifndef DBUG_OFF case SQLCOM_CREATE_VIEW: { if (end_active_trans(thd)) @@ -4556,7 +4589,7 @@ end_with_restore_list: buff.append(command[thd->lex->create_view_mode].str, command[thd->lex->create_view_mode].length); view_store_options(thd, first_table, &buff); - buff.append("VIEW ", 5); + buff.append(STRING_WITH_LEN("VIEW ")); /* Test if user supplied a db (ie: we did not use thd->db) */ if (first_table->db != thd->db && first_table->db[0]) { @@ -4566,7 +4599,7 @@ end_with_restore_list: } append_identifier(thd, &buff, first_table->table_name, first_table->table_name_length); - buff.append(" AS ", 4); + buff.append(STRING_WITH_LEN(" AS ")); buff.append(first_table->source.str, first_table->source.length); Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d5282ef6b7f..2f08583d974 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1931,7 +1931,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len) variable absent or equal to NULL, so we need to set variable to something reasonable to get a readable error message during parsing */ - str.set("NULL", 4, &my_charset_latin1); + str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1); } needs_conversion= String::needs_conversion(var_value->length(), diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8f5cc817c0e..c6f0ca03538 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13722,7 +13722,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, { SELECT_LEX *sl= join->unit->first_select(); uint len= 6, lastop= 0; - memcpy(table_name_buffer, "<union", 6); + memcpy(table_name_buffer, STRING_WITH_LEN("<union")); for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select()) { len+= lastop; @@ -13731,7 +13731,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, } if (sl || len + lastop >= NAME_LEN) { - memcpy(table_name_buffer + len, "...>", 5); + memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1); len+= 4; } else @@ -13910,7 +13910,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) { - extra.append("; Using "); + extra.append(STRING_WITH_LEN("; Using ")); tab->select->quick->add_info_string(&extra); } if (tab->select) @@ -13918,7 +13918,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (tab->use_quick == 2) { char buf[MAX_KEY/8+1]; - extra.append("; Range checked for each record (index map: 0x"); + extra.append(STRING_WITH_LEN("; Range checked for each " + "record (index map: 0x")); extra.append(tab->keys.print(buf)); extra.append(')'); } @@ -13928,38 +13929,39 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (thd->variables.engine_condition_pushdown && pushed_cond) { - extra.append("; Using where with pushed condition"); + extra.append(STRING_WITH_LEN("; Using where with pushed " + "condition")); if (thd->lex->describe & DESCRIBE_EXTENDED) { - extra.append(": "); + extra.append(STRING_WITH_LEN(": ")); ((COND *)pushed_cond)->print(&extra); } } else - extra.append("; Using where"); + extra.append(STRING_WITH_LEN("; Using where")); } } if (key_read) { if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) - extra.append("; Using index for group-by"); + extra.append(STRING_WITH_LEN("; Using index for group-by")); else - extra.append("; Using index"); + extra.append(STRING_WITH_LEN("; Using index")); } if (table->reginfo.not_exists_optimize) - extra.append("; Not exists"); + extra.append(STRING_WITH_LEN("; Not exists")); if (need_tmp_table) { need_tmp_table=0; - extra.append("; Using temporary"); + extra.append(STRING_WITH_LEN("; Using temporary")); } if (need_order) { need_order=0; - extra.append("; Using filesort"); + extra.append(STRING_WITH_LEN("; Using filesort")); } if (distinct & test_all_bits(used_tables,thd->used_tables)) - extra.append("; Distinct"); + extra.append(STRING_WITH_LEN("; Distinct")); /* Skip initial "; "*/ const char *str= extra.ptr(); @@ -14076,15 +14078,18 @@ static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables) { TABLE_LIST *curr= *tbl; if (curr->outer_join) - str->append(" left join ", 11); // MySQL converts right to left joins + { + /* MySQL converts right to left joins */ + str->append(STRING_WITH_LEN(" left join ")); + } else if (curr->straight) - str->append(" straight_join ", 15); + str->append(STRING_WITH_LEN(" straight_join ")); else - str->append(" join ", 6); + str->append(STRING_WITH_LEN(" join ")); curr->print(thd, str); if (curr->on_expr) { - str->append(" on(", 4); + str->append(STRING_WITH_LEN(" on(")); curr->on_expr->print(str); str->append(')'); } @@ -14169,28 +14174,28 @@ void st_select_lex::print(THD *thd, String *str) if (!thd) thd= current_thd; - str->append("select ", 7); + str->append(STRING_WITH_LEN("select ")); /* First add options */ if (options & SELECT_STRAIGHT_JOIN) - str->append("straight_join ", 14); + str->append(STRING_WITH_LEN("straight_join ")); if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) && (this == &thd->lex->select_lex)) - str->append("high_priority ", 14); + str->append(STRING_WITH_LEN("high_priority ")); if (options & SELECT_DISTINCT) - str->append("distinct ", 9); + str->append(STRING_WITH_LEN("distinct ")); if (options & SELECT_SMALL_RESULT) - str->append("sql_small_result ", 17); + str->append(STRING_WITH_LEN("sql_small_result ")); if (options & SELECT_BIG_RESULT) - str->append("sql_big_result ", 15); + str->append(STRING_WITH_LEN("sql_big_result ")); if (options & OPTION_BUFFER_RESULT) - str->append("sql_buffer_result ", 18); + str->append(STRING_WITH_LEN("sql_buffer_result ")); if (options & OPTION_FOUND_ROWS) - str->append("sql_calc_found_rows ", 20); + str->append(STRING_WITH_LEN("sql_calc_found_rows ")); if (!thd->lex->safe_to_cache_query) - str->append("sql_no_cache ", 13); + str->append(STRING_WITH_LEN("sql_no_cache ")); if (options & OPTION_TO_QUERY_CACHE) - str->append("sql_cache ", 10); + str->append(STRING_WITH_LEN("sql_cache ")); //Item List bool first= 1; @@ -14211,7 +14216,7 @@ void st_select_lex::print(THD *thd, String *str) */ if (table_list.elements) { - str->append(" from ", 6); + str->append(STRING_WITH_LEN(" from ")); /* go through join tree */ print_join(thd, str, &top_join_list); } @@ -14222,22 +14227,22 @@ void st_select_lex::print(THD *thd, String *str) cur_where= join->conds; if (cur_where) { - str->append(" where ", 7); + str->append(STRING_WITH_LEN(" where ")); cur_where->print(str); } // group by & olap if (group_list.elements) { - str->append(" group by ", 10); + str->append(STRING_WITH_LEN(" group by ")); print_order(str, (ORDER *) group_list.first); switch (olap) { case CUBE_TYPE: - str->append(" with cube", 10); + str->append(STRING_WITH_LEN(" with cube")); break; case ROLLUP_TYPE: - str->append(" with rollup", 12); + str->append(STRING_WITH_LEN(" with rollup")); break; default: ; //satisfy compiler @@ -14251,13 +14256,13 @@ void st_select_lex::print(THD *thd, String *str) if (cur_having) { - str->append(" having ", 8); + str->append(STRING_WITH_LEN(" having ")); cur_having->print(str); } if (order_list.elements) { - str->append(" order by ", 10); + str->append(STRING_WITH_LEN(" order by ")); print_order(str, (ORDER *) order_list.first); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0bda1e65413..e33fc2e1c56 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -540,22 +540,22 @@ bool mysqld_show_create_db(THD *thd, char *dbname, protocol->prepare_for_resend(); protocol->store(dbname, strlen(dbname), system_charset_info); buffer.length(0); - buffer.append("CREATE DATABASE ", 16); + buffer.append(STRING_WITH_LEN("CREATE DATABASE ")); if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS) - buffer.append("/*!32312 IF NOT EXISTS*/ ", 25); + buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ ")); append_identifier(thd, &buffer, dbname, strlen(dbname)); if (create.default_table_charset) { - buffer.append(" /*!40100", 9); - buffer.append(" DEFAULT CHARACTER SET ", 23); + buffer.append(STRING_WITH_LEN(" /*!40100")); + buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET ")); buffer.append(create.default_table_charset->csname); if (!(create.default_table_charset->state & MY_CS_PRIMARY)) { - buffer.append(" COLLATE ", 9); + buffer.append(STRING_WITH_LEN(" COLLATE ")); buffer.append(create.default_table_charset->name); } - buffer.append(" */", 3); + buffer.append(STRING_WITH_LEN(" */")); } protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); @@ -743,7 +743,7 @@ static void append_directory(THD *thd, String *packet, const char *dir_type, uint length= dirname_length(filename); packet->append(' '); packet->append(dir_type); - packet->append(" DIRECTORY='", 12); + packet->append(STRING_WITH_LEN(" DIRECTORY='")); #ifdef __WIN__ /* Convert \ to / to be able to create table on unix */ char *winfilename= (char*) thd->memdup(filename, length); @@ -792,16 +792,16 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) restore_record(table, s->default_values); // Get empty record if (share->tmp_table) - packet->append("CREATE TEMPORARY TABLE ", 23); + packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE ")); else - packet->append("CREATE TABLE ", 13); + packet->append(STRING_WITH_LEN("CREATE TABLE ")); if (table_list->schema_table) alias= table_list->schema_table->table_name; else alias= (lower_case_table_names == 2 ? table->alias : share->table_name.str); append_identifier(thd, packet, alias, strlen(alias)); - packet->append(" (\n", 3); + packet->append(STRING_WITH_LEN(" (\n")); for (ptr=table->field ; (field= *ptr); ptr++) { @@ -810,9 +810,9 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) uint flags = field->flags; if (ptr != table->field) - packet->append(",\n", 2); + packet->append(STRING_WITH_LEN(",\n")); - packet->append(" ", 2); + packet->append(STRING_WITH_LEN(" ")); append_identifier(thd,packet,field->field_name, strlen(field->field_name)); packet->append(' '); // check for surprises from the previous call to Field::sql_type() @@ -829,7 +829,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) { if (field->charset() != share->table_charset) { - packet->append(" character set ", 15); + packet->append(STRING_WITH_LEN(" character set ")); packet->append(field->charset()->csname); } /* @@ -838,20 +838,20 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) */ if (!(field->charset()->state & MY_CS_PRIMARY)) { - packet->append(" collate ", 9); + packet->append(STRING_WITH_LEN(" collate ")); packet->append(field->charset()->name); } } if (flags & NOT_NULL_FLAG) - packet->append(" NOT NULL", 9); + packet->append(STRING_WITH_LEN(" NOT NULL")); else if (field->type() == FIELD_TYPE_TIMESTAMP) { /* TIMESTAMP field require explicit NULL flag, because unlike all other fields they are treated as NOT NULL by default. */ - packet->append(" NULL", 5); + packet->append(STRING_WITH_LEN(" NULL")); } /* @@ -869,9 +869,9 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (has_default) { - packet->append(" default ", 9); + packet->append(STRING_WITH_LEN(" default ")); if (has_now_default) - packet->append("CURRENT_TIMESTAMP",17); + packet->append(STRING_WITH_LEN("CURRENT_TIMESTAMP")); else if (!field->is_null()) { // Not null by default type.set(tmp, sizeof(tmp), field->charset()); @@ -886,10 +886,10 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) append_unescaped(packet, def_val.ptr(), def_val.length()); } else - packet->append("''",2); + packet->append(STRING_WITH_LEN("''")); } else if (field->maybe_null()) - packet->append("NULL", 4); // Null as default + packet->append(STRING_WITH_LEN("NULL")); // Null as default else packet->append(tmp); } @@ -897,15 +897,15 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (!(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS) && table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD) - packet->append(" on update CURRENT_TIMESTAMP",28); + packet->append(STRING_WITH_LEN(" on update CURRENT_TIMESTAMP")); if (field->unireg_check == Field::NEXT_NUMBER && !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS)) - packet->append(" auto_increment", 15 ); + packet->append(STRING_WITH_LEN(" auto_increment")); if (field->comment.length) { - packet->append(" COMMENT ",9); + packet->append(STRING_WITH_LEN(" COMMENT ")); append_unescaped(packet, field->comment.str, field->comment.length); } } @@ -920,20 +920,20 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) { KEY_PART_INFO *key_part= key_info->key_part; bool found_primary=0; - packet->append(",\n ", 4); + packet->append(STRING_WITH_LEN(",\n ")); if (i == primary_key && !strcmp(key_info->name, primary_key_name)) { found_primary=1; - packet->append("PRIMARY ", 8); + packet->append(STRING_WITH_LEN("PRIMARY ")); } else if (key_info->flags & HA_NOSAME) - packet->append("UNIQUE ", 7); + packet->append(STRING_WITH_LEN("UNIQUE ")); else if (key_info->flags & HA_FULLTEXT) - packet->append("FULLTEXT ", 9); + packet->append(STRING_WITH_LEN("FULLTEXT ")); else if (key_info->flags & HA_SPATIAL) - packet->append("SPATIAL ", 8); - packet->append("KEY ", 4); + packet->append(STRING_WITH_LEN("SPATIAL ")); + packet->append(STRING_WITH_LEN("KEY ")); if (!found_primary) append_identifier(thd, packet, key_info->name, strlen(key_info->name)); @@ -942,19 +942,19 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) !limited_mysql_mode && !foreign_db_mode) { if (key_info->algorithm == HA_KEY_ALG_BTREE) - packet->append(" USING BTREE", 12); + packet->append(STRING_WITH_LEN(" USING BTREE")); if (key_info->algorithm == HA_KEY_ALG_HASH) - packet->append(" USING HASH", 11); + packet->append(STRING_WITH_LEN(" USING HASH")); // +BAR: send USING only in non-default case: non-spatial rtree if ((key_info->algorithm == HA_KEY_ALG_RTREE) && !(key_info->flags & HA_SPATIAL)) - packet->append(" USING RTREE", 12); + packet->append(STRING_WITH_LEN(" USING RTREE")); // No need to send USING FULLTEXT, it is sent as FULLTEXT KEY } - packet->append(" (", 2); + packet->append(STRING_WITH_LEN(" (")); for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) { @@ -997,13 +997,13 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) file->free_foreign_key_create_info(for_str); } - packet->append("\n)", 2); + packet->append(STRING_WITH_LEN("\n)")); if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode) { if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) - packet->append(" TYPE=", 6); + packet->append(STRING_WITH_LEN(" TYPE=")); else - packet->append(" ENGINE=", 8); + packet->append(STRING_WITH_LEN(" ENGINE=")); #ifdef WITH_PARTITION_STORAGE_ENGINE if (table->part_info) packet->append(ha_get_storage_engine(table->part_info-> @@ -1018,58 +1018,58 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) !(thd->variables.sql_mode & MODE_MYSQL323) && !(thd->variables.sql_mode & MODE_MYSQL40)) { - packet->append(" DEFAULT CHARSET=", 17); + packet->append(STRING_WITH_LEN(" DEFAULT CHARSET=")); packet->append(share->table_charset->csname); if (!(share->table_charset->state & MY_CS_PRIMARY)) { - packet->append(" COLLATE=", 9); + packet->append(STRING_WITH_LEN(" COLLATE=")); packet->append(table->s->table_charset->name); } } if (share->min_rows) { - packet->append(" MIN_ROWS=", 10); + packet->append(STRING_WITH_LEN(" MIN_ROWS=")); end= longlong10_to_str(share->min_rows, buff, 10); packet->append(buff, (uint) (end- buff)); } if (share->max_rows && !table_list->schema_table) { - packet->append(" MAX_ROWS=", 10); + packet->append(STRING_WITH_LEN(" MAX_ROWS=")); end= longlong10_to_str(share->max_rows, buff, 10); packet->append(buff, (uint) (end - buff)); } if (share->avg_row_length) { - packet->append(" AVG_ROW_LENGTH=", 16); + packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH=")); end= longlong10_to_str(share->avg_row_length, buff,10); packet->append(buff, (uint) (end - buff)); } if (share->db_create_options & HA_OPTION_PACK_KEYS) - packet->append(" PACK_KEYS=1", 12); + packet->append(STRING_WITH_LEN(" PACK_KEYS=1")); if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) - packet->append(" PACK_KEYS=0", 12); + packet->append(STRING_WITH_LEN(" PACK_KEYS=0")); if (share->db_create_options & HA_OPTION_CHECKSUM) - packet->append(" CHECKSUM=1", 11); + packet->append(STRING_WITH_LEN(" CHECKSUM=1")); if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) - packet->append(" DELAY_KEY_WRITE=1",18); + packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1")); if (share->row_type != ROW_TYPE_DEFAULT) { - packet->append(" ROW_FORMAT=",12); + packet->append(STRING_WITH_LEN(" ROW_FORMAT=")); packet->append(ha_row_type[(uint) share->row_type]); } table->file->append_create_info(packet); if (share->comment && share->comment[0]) { - packet->append(" COMMENT=", 9); + packet->append(STRING_WITH_LEN(" COMMENT=")); append_unescaped(packet, share->comment, strlen(share->comment)); } if (share->connect_string.length) { - packet->append(" CONNECTION=", 12); + packet->append(STRING_WITH_LEN(" CONNECTION=")); append_unescaped(packet, share->connect_string.str, share->connect_string.length); } if (file->raid_type) @@ -1107,25 +1107,25 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) void view_store_options(THD *thd, TABLE_LIST *table, String *buff) { - buff->append("ALGORITHM=", 10); + buff->append(STRING_WITH_LEN("ALGORITHM=")); switch ((int8)table->algorithm) { case VIEW_ALGORITHM_UNDEFINED: - buff->append("UNDEFINED ", 10); + buff->append(STRING_WITH_LEN("UNDEFINED ")); break; case VIEW_ALGORITHM_TMPTABLE: - buff->append("TEMPTABLE ", 10); + buff->append(STRING_WITH_LEN("TEMPTABLE ")); break; case VIEW_ALGORITHM_MERGE: - buff->append("MERGE ", 6); + buff->append(STRING_WITH_LEN("MERGE ")); break; default: DBUG_ASSERT(0); // never should happen } append_definer(thd, buff, &table->definer.user, &table->definer.host); if (table->view_suid) - buff->append("SQL SECURITY DEFINER ", 21); + buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER ")); else - buff->append("SQL SECURITY INVOKER ", 21); + buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER ")); } @@ -1183,19 +1183,19 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) } } - buff->append("CREATE ", 7); + buff->append(STRING_WITH_LEN("CREATE ")); if (!foreign_db_mode) { view_store_options(thd, table, buff); } - buff->append("VIEW ", 5); + buff->append(STRING_WITH_LEN("VIEW ")); if (!table->compact_view_format) { append_identifier(thd, buff, table->view_db.str, table->view_db.length); buff->append('.'); } append_identifier(thd, buff, table->view_name.str, table->view_name.length); - buff->append(" AS ", 4); + buff->append(STRING_WITH_LEN(" AS ")); /* We can't just use table->query, because our SQL_MODE may trigger @@ -1206,9 +1206,9 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) if (table->with_check != VIEW_CHECK_NONE) { if (table->with_check == VIEW_CHECK_LOCAL) - buff->append(" WITH LOCAL CHECK OPTION", 24); + buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION")); else - buff->append(" WITH CASCADED CHECK OPTION", 27); + buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION")); } return 0; } @@ -2198,20 +2198,24 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) { if (with_i_schema) { - table->field[3]->store("SYSTEM VIEW", 11, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), + system_charset_info); } else { my_snprintf(end, len, "/%s%s", file_name, reg_ext); switch (mysql_frm_type(thd, path, ¬_used)) { case FRMTYPE_ERROR: - table->field[3]->store("ERROR", 5, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("ERROR"), + system_charset_info); break; case FRMTYPE_TABLE: - table->field[3]->store("BASE TABLE", 10, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), + system_charset_info); break; case FRMTYPE_VIEW: - table->field[3]->store("VIEW", 4, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("VIEW"), + system_charset_info); break; default: DBUG_ASSERT(0); @@ -2364,8 +2368,8 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, } else if (tables->view) { - table->field[3]->store("VIEW", 4, cs); - table->field[20]->store("VIEW", 4, cs); + table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); + table->field[20]->store(STRING_WITH_LEN("VIEW"), cs); } else { @@ -2376,11 +2380,11 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO | HA_STATUS_NO_LOCK); if (share->tmp_table == SYSTEM_TMP_TABLE) - table->field[3]->store("SYSTEM VIEW", 11, cs); + table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else if (share->tmp_table) - table->field[3]->store("LOCAL TEMPORARY", 15, cs); + table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs); else - table->field[3]->store("BASE TABLE", 10, cs); + table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); for (int i= 4; i < 20; i++) { @@ -2616,7 +2620,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, if (show_table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_UN_FIELD) { - table->field[5]->store("CURRENT_TIMESTAMP", 17, cs); + table->field[5]->store(STRING_WITH_LEN("CURRENT_TIMESTAMP"), cs); table->field[5]->set_notnull(); } else if (field->unireg_check != Field::NEXT_NUMBER && @@ -2878,8 +2882,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, get_field(thd->mem_root, proc_table->field[10], &tmp_string); table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs); } - table->field[6]->store("SQL", 3, cs); - table->field[10]->store("SQL", 3, cs); + table->field[6]->store(STRING_WITH_LEN("SQL"), cs); + table->field[10]->store(STRING_WITH_LEN("SQL"), cs); get_field(thd->mem_root, proc_table->field[6], &tmp_string); table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs); table->field[12]->store(sp_data_access_name[enum_idx].str, @@ -3034,7 +3038,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, pos= show_table->file->index_type(i); table->field[13]->store(pos, strlen(pos), cs); if (!show_table->s->keys_in_use.is_set(i)) - table->field[14]->store("disabled", 8, cs); + table->field[14]->store(STRING_WITH_LEN("disabled"), cs); else table->field[14]->store("", 0, cs); table->field[14]->set_notnull(); @@ -3144,13 +3148,15 @@ static int get_schema_constraints_record(THD *thd, struct st_table_list *tables, if (i == primary_key && !strcmp(key_info->name, primary_key_name)) { if (store_constraints(thd, table, base_name, file_name, key_info->name, - strlen(key_info->name), "PRIMARY KEY", 11)) + strlen(key_info->name), + STRING_WITH_LEN("PRIMARY KEY"))) DBUG_RETURN(1); } else if (key_info->flags & HA_NOSAME) { if (store_constraints(thd, table, base_name, file_name, key_info->name, - strlen(key_info->name), "UNIQUE", 6)) + strlen(key_info->name), + STRING_WITH_LEN("UNIQUE"))) DBUG_RETURN(1); } } @@ -3191,11 +3197,11 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db, table->field[5]->store(db, strlen(db), cs); table->field[6]->store(tname, strlen(tname), cs); table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs); - table->field[10]->store("ROW", 3, cs); + table->field[10]->store(STRING_WITH_LEN("ROW"), cs); table->field[11]->store(trg_action_time_type_names[timing].str, trg_action_time_type_names[timing].length, cs); - table->field[14]->store("OLD", 3, cs); - table->field[15]->store("NEW", 3, cs); + table->field[14]->store(STRING_WITH_LEN("OLD"), cs); + table->field[15]->store(STRING_WITH_LEN("NEW"), cs); sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, @@ -3586,9 +3592,9 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(field_info->old_name); if (lex->wild && lex->wild->ptr()) { - buffer.append(" ("); + buffer.append(STRING_WITH_LEN(" (")); buffer.append(lex->wild->ptr()); - buffer.append(")"); + buffer.append(')'); } field->set_name(buffer.ptr(), buffer.length(), system_charset_info); } @@ -3609,9 +3615,9 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(lex->select_lex.db); if (lex->wild && lex->wild->ptr()) { - buffer.append(" ("); + buffer.append(STRING_WITH_LEN(" (")); buffer.append(lex->wild->ptr()); - buffer.append(")"); + buffer.append(')'); } Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 51f802e7465..fd7bca7ec21 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -848,22 +848,22 @@ void String::print(String *str) switch (c) { case '\\': - str->append("\\\\", 2); + str->append(STRING_WITH_LEN("\\\\")); break; case '\0': - str->append("\\0", 2); + str->append(STRING_WITH_LEN("\\0")); break; case '\'': - str->append("\\'", 2); + str->append(STRING_WITH_LEN("\\'")); break; case '\n': - str->append("\\n", 2); + str->append(STRING_WITH_LEN("\\n")); break; case '\r': - str->append("\\r", 2); + str->append(STRING_WITH_LEN("\\r")); break; case 26: //Ctrl-Z - str->append("\\z", 2); + str->append(STRING_WITH_LEN("\\z")); break; default: str->append(c); diff --git a/sql/sql_string.h b/sql/sql_string.h index ddae6368228..67c3e0c62f2 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -24,6 +24,8 @@ #define NOT_FIXED_DEC 31 #endif +#define STRING_WITH_LEN(X) ((char*) X), (sizeof(X)-1) + class String; int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 90f498f42dd..c8775ebc923 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -779,7 +779,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, MY_CS_BINSORT,MYF(0)))) { char tmp[64]; - strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), "_bin", 4); + strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), + STRING_WITH_LEN("_bin")); my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp); DBUG_RETURN(-1); } @@ -2121,7 +2122,7 @@ static int send_check_errmsg(THD *thd, TABLE_LIST* table, protocol->prepare_for_resend(); protocol->store(table->alias, system_charset_info); protocol->store((char*) operator_name, system_charset_info); - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); protocol->store(errmsg, system_charset_info); thd->clear_error(); if (protocol->write()) @@ -2432,7 +2433,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); - protocol->store("error",5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); if (!(err_msg=thd->net.last_error)) err_msg=ER(ER_CHECK_NO_SUCH_TABLE); /* if it was a view will check md5 sum */ @@ -2469,7 +2470,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY), table_name); protocol->store(buff, length, system_charset_info); @@ -2504,8 +2505,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); - protocol->store("warning", 7, system_charset_info); - protocol->store("Table is marked as crashed", 26, system_charset_info); + protocol->store(STRING_WITH_LEN("warning"), system_charset_info); + protocol->store(STRING_WITH_LEN("Table is marked as crashed"), + system_charset_info); if (protocol->write()) goto err; } @@ -2529,7 +2531,7 @@ send_result_message: char buf[ERRMSGSIZE+20]; uint length=my_snprintf(buf, ERRMSGSIZE, ER(ER_CHECK_NOT_IMPLEMENTED), operator_name); - protocol->store("note", 4, system_charset_info); + protocol->store(STRING_WITH_LEN("note"), system_charset_info); protocol->store(buf, length, system_charset_info); } break; @@ -2539,41 +2541,45 @@ send_result_message: char buf[ERRMSGSIZE+20]; uint length= my_snprintf(buf, ERRMSGSIZE, ER(ER_BAD_TABLE_ERROR), table_name); - protocol->store("note", 4, system_charset_info); + protocol->store(STRING_WITH_LEN("note"), system_charset_info); protocol->store(buf, length, system_charset_info); } break; case HA_ADMIN_OK: - protocol->store("status", 6, system_charset_info); - protocol->store("OK",2, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("OK"), system_charset_info); break; case HA_ADMIN_FAILED: - protocol->store("status", 6, system_charset_info); - protocol->store("Operation failed",16, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("Operation failed"), + system_charset_info); break; case HA_ADMIN_REJECT: - protocol->store("status", 6, system_charset_info); - protocol->store("Operation need committed state",30, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("Operation need committed state"), + system_charset_info); open_for_modify= FALSE; break; case HA_ADMIN_ALREADY_DONE: - protocol->store("status", 6, system_charset_info); - protocol->store("Table is already up to date", 27, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("Table is already up to date"), + system_charset_info); break; case HA_ADMIN_CORRUPT: - protocol->store("error", 5, system_charset_info); - protocol->store("Corrupt", 7, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); + protocol->store(STRING_WITH_LEN("Corrupt"), system_charset_info); fatal_error=1; break; case HA_ADMIN_INVALID: - protocol->store("error", 5, system_charset_info); - protocol->store("Invalid argument",16, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); + protocol->store(STRING_WITH_LEN("Invalid argument"), + system_charset_info); break; case HA_ADMIN_TRY_ALTER: @@ -2609,7 +2615,7 @@ send_result_message: else { /* Hijack the row already in-progress. */ - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); protocol->store(err_msg, system_charset_info); (void)protocol->write(); /* Start off another row for HA_ADMIN_FAILED */ @@ -2626,7 +2632,7 @@ send_result_message: } case HA_ADMIN_WRONG_CHECKSUM: { - protocol->store("note", 4, system_charset_info); + protocol->store(STRING_WITH_LEN("note"), system_charset_info); protocol->store(ER(ER_VIEW_CHECKSUM), strlen(ER(ER_VIEW_CHECKSUM)), system_charset_info); break; @@ -2638,7 +2644,7 @@ send_result_message: uint length=my_snprintf(buf, ERRMSGSIZE, "Unknown - internal error %d during operation", result_code); - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); protocol->store(buf, length, system_charset_info); fatal_error=1; break; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 7695911c9e8..8f8d292f2e2 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -20,7 +20,8 @@ #include "sql_trigger.h" #include "parse_file.h" -static const LEX_STRING triggers_file_type= {(char *)"TRIGGERS", 8}; +static const LEX_STRING triggers_file_type= + {STRING_WITH_LEN("TRIGGERS")}; const char * const triggers_file_ext= ".TRG"; @@ -33,21 +34,17 @@ const char * const triggers_file_ext= ".TRG"; static File_option triggers_file_parameters[]= { { - { (char *) STRING_WITH_LEN("triggers") }, + {STRING_WITH_LEN("triggers") }, offsetof(class Table_triggers_list, definitions_list), FILE_OPTIONS_STRLIST }, { - /* - FIXME: Length specified for "sql_modes" key is erroneous, problem caused - by this are reported as BUG#14090 and should be fixed ASAP. - */ - { (char *) "sql_modes", 13 }, + {STRING_WITH_LEN("sql_modes") }, offsetof(class Table_triggers_list, definition_modes_list), FILE_OPTIONS_ULLLIST }, { - { (char *) STRING_WITH_LEN("definers") }, + {STRING_WITH_LEN("definers") }, offsetof(class Table_triggers_list, definers_list), FILE_OPTIONS_STRLIST }, @@ -73,7 +70,8 @@ struct st_trigname LEX_STRING trigger_table; }; -static const LEX_STRING trigname_file_type= {(char *)"TRIGGERNAME", 11}; +static const LEX_STRING trigname_file_type= + {STRING_WITH_LEN("TRIGGERNAME")}; const char * const trigname_file_ext= ".TRN"; @@ -84,7 +82,7 @@ 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. */ - { (char *) "trigger_table", 15 }, + {STRING_WITH_LEN("trigger_table")}, offsetof(struct st_trigname, trigger_table), FILE_OPTIONS_ESTRING }, @@ -108,6 +106,21 @@ const LEX_STRING trg_event_type_names[]= static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig); +bool handle_old_incorrect_sql_modes(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, + char *end, gptr hook_data); + +class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook +{ +private: + char *path; +public: + Handle_old_incorrect_sql_modes_hook(char *file_path) + :path(file_path) + {}; + virtual bool process_unknown_string(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, char *end); +}; /* Create or drop trigger for table. @@ -237,7 +250,7 @@ end: { log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */ - log_query.append("CREATE "); + log_query.append(STRING_WITH_LEN("CREATE ")); append_definer(thd, &log_query, &definer_user, &definer_host); log_query.append(thd->lex->trigger_definition_begin); } @@ -691,6 +704,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, { Table_triggers_list *triggers= new (&table->mem_root) Table_triggers_list(table); + Handle_old_incorrect_sql_modes_hook sql_modes_hook(path.str); if (!triggers) DBUG_RETURN(1); @@ -705,7 +719,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, triggers->definers_list.empty(); if (parser->parse((gptr)triggers, &table->mem_root, - triggers_file_parameters, TRG_NUM_REQUIRED_PARAMETERS)) + triggers_file_parameters, + TRG_NUM_REQUIRED_PARAMETERS, + &sql_modes_hook)) DBUG_RETURN(1); List_iterator_fast<LEX_STRING> it(triggers->definitions_list); @@ -800,6 +816,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, List_iterator_fast<LEX_STRING> it_definer(triggers-> definers_list); LEX *old_lex= thd->lex, lex; + sp_rcontext *save_spcont= thd->spcont; ulong save_sql_mode= thd->variables.sql_mode; thd->lex= &lex; @@ -815,6 +832,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->variables.sql_mode= (ulong)*trg_sql_mode; lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length); + thd->spcont= 0; if (yyparse((void *)thd) || thd->is_fatal_error) { /* @@ -895,6 +913,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->db= save_db.str; thd->db_length= save_db.length; thd->lex= old_lex; + thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; DBUG_RETURN(0); @@ -903,6 +922,7 @@ err_with_lex_cleanup: // QQ: anything else ? lex_end(&lex); thd->lex= old_lex; + thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; thd->db= save_db.str; thd->db_length= save_db.length; @@ -1020,7 +1040,8 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig) } if (parser->parse((gptr)&trigname, thd->mem_root, - trigname_file_parameters, 1)) + trigname_file_parameters, 1, + &file_parser_dummy_hook)) DBUG_RETURN(0); /* We need to reset statement table list to be PS/SP friendly. */ @@ -1172,3 +1193,65 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, return res; } + + +/* + Trigger BUG#14090 compatibility hook + + SYNOPSIS + Handle_old_incorrect_sql_modes_hook::process_unknown_string() + unknown_key [in/out] reference on the line with unknown + parameter and the parsing point + base [in] base address for parameter writing (structure + like TABLE) + mem_root [in] MEM_ROOT for parameters allocation + end [in] the end of the configuration + + NOTE: this hook process back compatibility for incorrectly written + sql_modes parameter (see BUG#14090). + + RETURN + FALSE OK + TRUE Error +*/ + +bool +Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key, + gptr base, + MEM_ROOT *mem_root, + char *end) +{ +#define INVALID_SQL_MODES_LENGTH 13 + DBUG_ENTER("handle_old_incorrect_sql_modes"); + DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + if (unknown_key + INVALID_SQL_MODES_LENGTH + 1 < end && + unknown_key[INVALID_SQL_MODES_LENGTH] == '=' && + !memcmp(unknown_key, STRING_WITH_LEN("sql_modes"))) + { + DBUG_PRINT("info", ("sql_modes affected by BUG#14090 detected")); + push_warning_printf(current_thd, + MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_OLD_FILE_FORMAT, + ER(ER_OLD_FILE_FORMAT), + (char *)path, "TRIGGER"); + File_option sql_modes_parameters= + { + {STRING_WITH_LEN("sql_modes") }, + offsetof(class Table_triggers_list, definition_modes_list), + FILE_OPTIONS_ULLLIST + }; + char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1; + if (get_file_options_ulllist(ptr, end, unknown_key, base, + &sql_modes_parameters, mem_root)) + { + DBUG_RETURN(TRUE); + } + /* + Set parsing pointer to the last symbol of string (\n) + 1) to avoid problem with \0 in the junk after sql_modes + 2) to speed up skipping this line by parser. + */ + unknown_key= ptr-1; + } + DBUG_RETURN(FALSE); +} diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 38c3974ce56..c3ce543da54 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -623,7 +623,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, TODO: special cascade/restrict procedure for alter? */ if (parser->parse((gptr)view, thd->mem_root, - view_parameters + revision_number_position, 1)) + view_parameters + revision_number_position, 1, + &file_parser_dummy_hook)) { DBUG_RETURN(thd->net.report_error? -1 : 0); } @@ -792,7 +793,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) be used here */ if (parser->parse((gptr)table, thd->mem_root, view_parameters, - required_view_parameters)) + required_view_parameters, &file_parser_dummy_hook)) goto err; /* @@ -1517,7 +1518,8 @@ mysql_rename_view(THD *thd, /* get view definition and source */ if (parser->parse((gptr)&view_def, thd->mem_root, view_parameters, - array_elements(view_parameters)-1)) + array_elements(view_parameters)-1, + &file_parser_dummy_hook)) goto err; /* rename view and it's backups */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 092d73a6ccd..c79ad97be4e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -177,6 +177,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CLIENT_SYM %token CLOSE_SYM %token COALESCE +%token CODE_SYM %token COLLATE_SYM %token COLLATION_SYM %token COLUMNS @@ -1631,13 +1632,14 @@ sp_decl: for (uint i = max-$2 ; i < max ; i++) { sp_instr_set *in; + uint off= ctx->pvar_context2index(i); - ctx->set_type(i, type); + 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, - ctx->pvar_context2index(i), + off, it, type, lex, (i == max - 1)); @@ -1646,7 +1648,7 @@ sp_decl: freeing LEX. */ lex->sphead->add_instr(in); - ctx->set_default(i, it); + ctx->set_default(off, it); } lex->sphead->restore_lex(YYTHD); $$.vars= $2; @@ -1720,7 +1722,8 @@ sp_decl: delete $5; YYABORT; } - i= new sp_instr_cpush(sp->instructions(), ctx, $5); + i= new sp_instr_cpush(sp->instructions(), ctx, $5, + ctx->current_cursors()); sp->add_instr(i); ctx->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; @@ -2310,8 +2313,12 @@ sp_case: ivar.str= (char *)"_tmp_"; ivar.length= 5; - Item *var= (Item*) new Item_splocal(ivar, - ctx->current_pvars()-1); + Item_splocal *var= new Item_splocal(ivar, + ctx->current_pvars()-1); +#ifndef DBUG_OFF + if (var) + var->owner= sp; +#endif Item *expr= new Item_func_eq(var, $2); i= new sp_instr_jump_if_not(ip, ctx, expr, lex); @@ -6488,7 +6495,13 @@ select_var_ident: YYABORT; else { - ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset,t->type)); + my_var *var; + ((select_dumpvar *)lex->result)-> + var_list.push_back(var= new my_var($1,1,t->offset,t->type)); +#ifndef DBUG_OFF + if (var) + var->owner= lex->sphead; +#endif } } ; @@ -7238,7 +7251,28 @@ show_param: YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) YYABORT; - }; + } + | PROCEDURE CODE_SYM sp_name + { +#ifdef DBUG_OFF + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#else + Lex->sql_command= SQLCOM_SHOW_PROC_CODE; + Lex->spname= $3; +#endif + } + | FUNCTION_SYM CODE_SYM sp_name + { +#ifdef DBUG_OFF + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#else + Lex->sql_command= SQLCOM_SHOW_FUNC_CODE; + Lex->spname= $3; +#endif + } + ; show_engine_param: STATUS_SYM @@ -7779,6 +7813,10 @@ simple_ident: Item_splocal *splocal; splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev - lex->sphead->m_tmp_query); +#ifndef DBUG_OFF + if (splocal) + splocal->owner= lex->sphead; +#endif $$ = (Item*) splocal; lex->variables_used= 1; lex->safe_to_cache_query=0; @@ -8136,6 +8174,7 @@ keyword_sp: | CIPHER_SYM {} | CLIENT_SYM {} | COALESCE {} + | CODE_SYM {} | COLLATION_SYM {} | COLUMNS {} | COMMITTED_SYM {} diff --git a/sql/structs.h b/sql/structs.h index a3903e945e9..85af73794ae 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -20,8 +20,6 @@ struct st_table; class Field; -#define STRING_WITH_LEN(X) ((char*) X), (sizeof(X)-1) - typedef struct st_lex_string { char *str; diff --git a/sql/table.cc b/sql/table.cc index 5c5a2962373..9fc840f7a3d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -252,7 +252,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags) goto err; } } - else if (memcmp(head, "TYPE=", 5) == 0) + else if (memcmp(head, STRING_WITH_LEN("TYPE=")) == 0) { error= 5; if (memcmp(head+5,"VIEW",4) == 0) diff --git a/sql/tztime.cc b/sql/tztime.cc index ccef8fe8d7a..afdbebea547 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1558,7 +1558,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) sql_print_error("Fatal error: OOM while initializing time zones"); goto end_with_cleanup; } - tmp_tzname->name.set("SYSTEM", 6, &my_charset_latin1); + tmp_tzname->name.set(STRING_WITH_LEN("SYSTEM"), &my_charset_latin1); tmp_tzname->tz= my_tz_SYSTEM; if (my_hash_insert(&tz_names, (const byte *)tmp_tzname)) { diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index b3d95d21eb7..e2c8b446322 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -165,7 +165,7 @@ static struct my_option my_long_options[] = "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"block-search", 'b', diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c index 114e80d8f1a..d691c24e890 100644 --- a/storage/myisam/myisampack.c +++ b/storage/myisam/myisampack.c @@ -254,7 +254,7 @@ enum options_mp {OPT_CHARSETS_DIR_MP=256, OPT_AUTO_CLOSE}; static struct my_option my_long_options[] = { #ifdef __NETWARE__ - {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", + {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"backup", 'b', "Make a backup of the table as table_name.OLD.", diff --git a/storage/ndb/docs/Makefile.am b/storage/ndb/docs/Makefile.am index d10228d419d..d67db4a6392 100644 --- a/storage/ndb/docs/Makefile.am +++ b/storage/ndb/docs/Makefile.am @@ -1,7 +1,7 @@ DOXYDIR = doxygen noinst_HEADERS = $(DOXYDIR)/predoxy.pl $(DOXYDIR)/postdoxy.pl $(DOXYDIR)/Doxyfile.ndbapi $(DOXYDIR)/Doxyfile.mgmapi $(DOXYDIR)/header.ndbapi.tex $(DOXYDIR)/header.mgmapi.tex -all: do-check-html ndbapidoc-html mgmapidoc-html +all-local: do-check-html ndbapidoc-html mgmapidoc-html all-pdf: do-check-pdf ndbapidoc-pdf mgmapidoc-pdf DOXYTMP = .doxytmp diff --git a/storage/ndb/src/common/portlib/NdbThread.c b/storage/ndb/src/common/portlib/NdbThread.c index d501ea2559a..b91e9c6a5b3 100644 --- a/storage/ndb/src/common/portlib/NdbThread.c +++ b/storage/ndb/src/common/portlib/NdbThread.c @@ -91,13 +91,15 @@ ndb_thread_wrapper(void* _ss){ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, NDB_THREAD_ARG *p_thread_arg, - const NDB_THREAD_STACKSIZE thread_stack_size, + const NDB_THREAD_STACKSIZE _thread_stack_size, const char* p_thread_name, NDB_THREAD_PRIO thread_prio) { struct NdbThread* tmpThread; int result; pthread_attr_t thread_attr; + NDB_THREAD_STACKSIZE thread_stack_size= _thread_stack_size * SIZEOF_CHARP/4; + DBUG_ENTER("NdbThread_Create"); (void)thread_prio; /* remove warning for unused parameter */ @@ -114,11 +116,11 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, strnmov(tmpThread->thread_name,p_thread_name,sizeof(tmpThread->thread_name)); pthread_attr_init(&thread_attr); -#if (SIZEOF_CHARP == 8) - pthread_attr_setstacksize(&thread_attr, 2*thread_stack_size); -#else - pthread_attr_setstacksize(&thread_attr, thread_stack_size); +#ifdef PTHREAD_STACK_MIN + if (thread_stack_size < PTHREAD_STACK_MIN) + thread_stack_size = PTHREAD_STACK_MIN; #endif + pthread_attr_setstacksize(&thread_attr, thread_stack_size); #ifdef USE_PTHREAD_EXTRAS /* Guard stack overflow with a 2k databuffer */ pthread_attr_setguardsize(&thread_attr, 2048); @@ -133,7 +135,11 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, &thread_attr, ndb_thread_wrapper, tmpThread); - assert(result==0); + if (result != 0) + { + NdbMem_Free((char *)tmpThread); + tmpThread = 0; + } pthread_attr_destroy(&thread_attr); DBUG_PRINT("exit",("ret: %lx", tmpThread)); diff --git a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index 8a60c26b4ef..a9fef297bef 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -250,6 +250,7 @@ class Dbtup: public SimulatedBlock { friend class Suma; public: struct KeyReqStruct; +friend struct KeyReqStruct; // CC typedef bool (Dbtup::* ReadFunction)(Uint32*, KeyReqStruct*, AttributeHeader*, @@ -2345,14 +2346,15 @@ private: //--------------------------------------------------------------- // // Public methods - Uint32* alloc_var_rec(Fragrecord*, Tablerec*, Uint32, Local_key*, Uint32*, - Uint32 base); + Uint32* alloc_var_rec(Fragrecord*const, Tablerec*const, Uint32, Local_key*, + Uint32*, Uint32 base); void free_var_part(Fragrecord*, Tablerec*, Var_part_ref, Uint32 chain); void free_var_part(Fragrecord*, Tablerec*, Local_key*, Var_page*, Uint32 chain); void validate_page(Tablerec*, Var_page* page); - Uint32* alloc_fix_rec(Fragrecord*, Tablerec*, Local_key*, Uint32 *); + Uint32* alloc_fix_rec(Fragrecord*const, Tablerec*const, Local_key*, + Uint32*); void free_fix_rec(Fragrecord*, Tablerec*, Local_key*, Fix_page*); // Private methods diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index fe6197a5bba..cd9307321e1 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -113,22 +113,25 @@ Dbtup::setUpQueryRoutines(Tablerec* const regTabPtr) } if(AttributeDescriptor::getDiskBased(attrDescr)) { - ReadFunction r[] = { - &Dbtup::readDiskBitsNotNULL, - &Dbtup::readDiskBitsNULLable, - &Dbtup::readDiskFixedSizeNotNULL, - &Dbtup::readDiskFixedSizeNULLable, - &Dbtup::readDiskVarSizeNULLable, - &Dbtup::readDiskVarSizeNotNULL - }; - UpdateFunction u[] = { - &Dbtup::updateDiskBitsNotNULL, - &Dbtup::updateDiskBitsNULLable, - &Dbtup::updateDiskFixedSizeNotNULL, - &Dbtup::updateDiskFixedSizeNULLable, - &Dbtup::updateDiskVarSizeNULLable, - &Dbtup::updateDiskVarSizeNotNULL - }; + // array initializer crashes gcc-2.95.3 + ReadFunction r[6]; + { + r[0] = &Dbtup::readDiskBitsNotNULL; + r[1] = &Dbtup::readDiskBitsNULLable; + r[2] = &Dbtup::readDiskFixedSizeNotNULL; + r[3] = &Dbtup::readDiskFixedSizeNULLable; + r[4] = &Dbtup::readDiskVarSizeNULLable; + r[5] = &Dbtup::readDiskVarSizeNotNULL; + } + UpdateFunction u[6]; + { + u[0] = &Dbtup::updateDiskBitsNotNULL; + u[1] = &Dbtup::updateDiskBitsNULLable; + u[2] = &Dbtup::updateDiskFixedSizeNotNULL; + u[3] = &Dbtup::updateDiskFixedSizeNULLable; + u[4] = &Dbtup::updateDiskVarSizeNULLable; + u[5] = &Dbtup::updateDiskVarSizeNotNULL; + } Uint32 a= AttributeDescriptor::getArrayType(attrDescr) == NDB_ARRAYTYPE_FIXED ? 2 : 4; diff --git a/storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp b/storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp index 6f3586ddfd2..31811ecfafb 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp @@ -123,3 +123,7 @@ main(void) } template class Vector<Record>; + +// hp3750 +struct Signal { Signal(); int foo; }; +Signal::Signal(){} diff --git a/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index 89fe83f6bf4..b6ca421064f 100644 --- a/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -66,13 +66,13 @@ struct BlockInfo { }; static BlockInfo ALL_BLOCKS[] = { + { NDBFS_REF, 0 , 2000, 2999 }, { DBTC_REF, 1 , 8000, 8035 }, { DBDIH_REF, 1 , 7000, 7173 }, { DBLQH_REF, 1 , 5000, 5030 }, { DBACC_REF, 1 , 3000, 3999 }, { DBTUP_REF, 1 , 4000, 4007 }, { DBDICT_REF, 1 , 6000, 6003 }, - { NDBFS_REF, 0 , 2000, 2999 }, { NDBCNTR_REF, 0 , 1000, 1999 }, { QMGR_REF, 1 , 1, 999 }, { CMVMI_REF, 1 , 9000, 9999 }, diff --git a/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp b/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp index c371b1cd890..75ab83b2e98 100644 --- a/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp +++ b/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp @@ -122,6 +122,8 @@ AsyncFile::doStart() stackSize, (char*)&buf, NDB_THREAD_PRIO_MEAN); + if (theThreadPtr == 0) + ERROR_SET(fatal, NDBD_EXIT_MEMALLOC, "","Could not allocate file system thread"); NdbCondition_Wait(theStartConditionPtr, theStartMutexPtr); diff --git a/storage/ndb/src/kernel/blocks/pgman.hpp b/storage/ndb/src/kernel/blocks/pgman.hpp index 276cc60ee4c..da59afa5794 100644 --- a/storage/ndb/src/kernel/blocks/pgman.hpp +++ b/storage/ndb/src/kernel/blocks/pgman.hpp @@ -243,6 +243,9 @@ public: private: friend class Page_cache_client; + struct Page_entry; // CC + friend struct Page_entry; + struct Page_request { enum Flags { OP_MASK = 0x000F // 4 bits for TUP operation diff --git a/storage/ndb/src/kernel/blocks/print_file.cpp b/storage/ndb/src/kernel/blocks/print_file.cpp index 70441553671..14b83cccaee 100644 --- a/storage/ndb/src/kernel/blocks/print_file.cpp +++ b/storage/ndb/src/kernel/blocks/print_file.cpp @@ -368,3 +368,6 @@ print_undo_page(int count, void* ptr, Uint32 sz){ return 0; } + +// hp3750 +Signal::Signal(){} diff --git a/storage/ndb/src/kernel/blocks/restore.hpp b/storage/ndb/src/kernel/blocks/restore.hpp index 5654bcebd0e..12d093b4593 100644 --- a/storage/ndb/src/kernel/blocks/restore.hpp +++ b/storage/ndb/src/kernel/blocks/restore.hpp @@ -72,6 +72,9 @@ public: }; private: + struct File; // CC + friend struct File; + struct File { File() {} diff --git a/storage/ndb/src/ndbapi/Ndb.cpp b/storage/ndb/src/ndbapi/Ndb.cpp index 50f2123a811..8bfedc2f96f 100644 --- a/storage/ndb/src/ndbapi/Ndb.cpp +++ b/storage/ndb/src/ndbapi/Ndb.cpp @@ -1300,7 +1300,12 @@ Uint64 Ndb::getLatestGCI() void Ndb::setReportThreshEventGCISlip(unsigned thresh) { - theEventBuffer->m_gci_slip_thresh= thresh; + if (theEventBuffer->m_free_thresh != thresh) + { + theEventBuffer->m_free_thresh= thresh; + theEventBuffer->m_min_free_thresh= thresh; + theEventBuffer->m_max_free_thresh= 100; + } } void Ndb::setReportThreshEventFreeMem(unsigned thresh) diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index a1fc6e87c0d..1fa0c6386be 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -539,6 +539,8 @@ NdbEventBuffer::NdbEventBuffer(Ndb *ndb) : m_latestGCI(0), m_total_alloc(0), m_free_thresh(10), + m_min_free_thresh(10), + m_max_free_thresh(100), m_gci_slip_thresh(3), m_dropped_ev_op(0), m_active_op_count(0) @@ -635,8 +637,6 @@ int NdbEventBuffer::expand(unsigned sz) EventBufData_chunk *chunk_data= (EventBufData_chunk *)NdbMem_Allocate(alloc_size); - m_total_alloc+= alloc_size; - chunk_data->sz= sz; m_allocated_data.push_back(chunk_data); @@ -902,8 +902,8 @@ NdbEventBuffer::execSUB_GCP_COMPLETE_REP(const SubGcpCompleteRep * const rep) assert(bucket->m_data.m_count); #endif m_complete_data.m_data.append(bucket->m_data); - reportStatus(); } + reportStatus(); bzero(bucket, sizeof(Gci_container)); bucket->m_gci = gci + ACTIVE_GCI_DIRECTORY_SIZE; bucket->m_gcp_complete_rep_count = m_system_nodes; @@ -1356,23 +1356,47 @@ NdbEventBuffer::reportStatus() else apply_gci= latest_gci; - if (100*m_free_data_sz < m_free_thresh*m_total_alloc || - latest_gci-apply_gci >= m_gci_slip_thresh) + if (100*m_free_data_sz < m_min_free_thresh*m_total_alloc && + m_total_alloc > 1024*1024) + { + /* report less free buffer than m_free_thresh, + next report when more free than 2 * m_free_thresh + */ + m_min_free_thresh= 0; + m_max_free_thresh= 2 * m_free_thresh; + goto send_report; + } + + if (100*m_free_data_sz > m_max_free_thresh*m_total_alloc && + m_total_alloc > 1024*1024) + { + /* report more free than 2 * m_free_thresh + next report when less free than m_free_thresh + */ + m_min_free_thresh= m_free_thresh; + m_max_free_thresh= 100; + goto send_report; + } + if (latest_gci-apply_gci >= m_gci_slip_thresh) { - Uint32 data[8]; - data[0]= NDB_LE_EventBufferStatus; - data[1]= m_total_alloc-m_free_data_sz; - data[2]= m_total_alloc; - data[3]= 0; - data[4]= apply_gci & ~(Uint32)0; - data[5]= apply_gci >> 32; - data[6]= latest_gci & ~(Uint32)0; - data[7]= latest_gci >> 32; - m_ndb->theImpl->send_event_report(data,8); + goto send_report; + } + return; + +send_report: + Uint32 data[8]; + data[0]= NDB_LE_EventBufferStatus; + data[1]= m_total_alloc-m_free_data_sz; + data[2]= m_total_alloc; + data[3]= 0; + data[4]= apply_gci & ~(Uint32)0; + data[5]= apply_gci >> 32; + data[6]= latest_gci & ~(Uint32)0; + data[7]= latest_gci >> 32; + m_ndb->theImpl->send_event_report(data,8); #ifdef VM_TRACE - assert(m_total_alloc >= m_free_data_sz); + assert(m_total_alloc >= m_free_data_sz); #endif - } } template class Vector<Gci_container>; diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp index 0436cea66ce..542a4a594a5 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp @@ -271,7 +271,7 @@ public: unsigned m_total_alloc; // total allocated memory // threshholds to report status - unsigned m_free_thresh; + unsigned m_free_thresh, m_min_free_thresh, m_max_free_thresh; unsigned m_gci_slip_thresh; NdbError m_error; diff --git a/storage/ndb/test/ndbapi/bank/BankLoad.cpp b/storage/ndb/test/ndbapi/bank/BankLoad.cpp index 34947019a51..78fd6c7d678 100644 --- a/storage/ndb/test/ndbapi/bank/BankLoad.cpp +++ b/storage/ndb/test/ndbapi/bank/BankLoad.cpp @@ -23,7 +23,7 @@ */ struct AccountTypesStruct { int id; - const char* descr; + const char descr[64]; }; const AccountTypesStruct accountTypes[] = { { 0, "KASSA"}, diff --git a/storage/ndb/test/ndbapi/testNdbApi.cpp b/storage/ndb/test/ndbapi/testNdbApi.cpp index f456d852898..dd0628bb1b1 100644 --- a/storage/ndb/test/ndbapi/testNdbApi.cpp +++ b/storage/ndb/test/ndbapi/testNdbApi.cpp @@ -1141,6 +1141,21 @@ int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runBug_WritePartialIgnoreError(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + const NdbDictionary::Table* pTab = ctx->getTab(); + + HugoOperations hugoOps(*pTab); + + Ndb* pNdb = GETNDB(step); + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkWritePartialRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_Commit(pNdb, AO_IgnoreError) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + + return result; +} + int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; const Uint32 max= 5; @@ -1317,6 +1332,11 @@ TESTCASE("Bug_11133", INITIALIZER(runBug_11133); FINALIZER(runClearTable); } +TESTCASE("Bug_WritePartialIgnoreError", + "Test WritePartialIgnoreError\n"){ + INITIALIZER(runBug_WritePartialIgnoreError); + FINALIZER(runClearTable); +} TESTCASE("Scan_4006", "Check that getNdbScanOperation does not get 4006\n"){ INITIALIZER(runLoadTable); diff --git a/storage/ndb/test/run-test/daily-basic-tests.txt b/storage/ndb/test/run-test/daily-basic-tests.txt index ca4cc10f8cd..12f4a7bd6e5 100644 --- a/storage/ndb/test/run-test/daily-basic-tests.txt +++ b/storage/ndb/test/run-test/daily-basic-tests.txt @@ -528,6 +528,10 @@ max-time: 500 cmd: testNdbApi args: -n Scan_4006 T1 D1 D2 +max-time: 500 +cmd: testNdbApi +args: -n Bug_WritePartialIgnoreError T1 + #max-time: 500 #cmd: testInterpreter #args: T1 diff --git a/storage/ndb/test/run-test/make-config.sh b/storage/ndb/test/run-test/make-config.sh index e82acb8a7dd..a5ea2e58ae6 100755 --- a/storage/ndb/test/run-test/make-config.sh +++ b/storage/ndb/test/run-test/make-config.sh @@ -44,7 +44,7 @@ add_proc (){ ;; mysqld) echo "$proc_no.mysqld" >> $dir_file - echo "[ndb_mgmd]" >> $config_file + echo "[mysqld]" >> $config_file echo "Id: $node_id" >> $config_file echo "HostName: $2" >> $config_file node_id=`expr $node_id + 1` diff --git a/storage/ndb/test/tools/listen.cpp b/storage/ndb/test/tools/listen.cpp index 05edb012fdb..cffe256bf40 100644 --- a/storage/ndb/test/tools/listen.cpp +++ b/storage/ndb/test/tools/listen.cpp @@ -64,7 +64,6 @@ main(int argc, const char** argv){ ndbout << "Waiting for ndb to become ready..." << endl; int result = 0; - Uint64 last_gci= 0, cnt= 0; NdbDictionary::Dictionary *myDict = MyNdb.getDictionary(); Vector<NdbDictionary::Event*> events; @@ -91,7 +90,7 @@ main(int argc, const char** argv){ { if(myDict->getNdbError().classification == NdbError::SchemaObjectExists) { - g_info << "Event creation failed event exists\n"; + g_info << "Event creation failed event exists. Removing...\n"; if (myDict->dropEvent(name.c_str())) { g_err << "Failed to drop event: " << myDict->getNdbError() << endl; @@ -146,19 +145,37 @@ main(int argc, const char** argv){ { while(MyNdb.pollEvents(100) == 0); - NdbEventOperation* pOp; - while((pOp= MyNdb.nextEvent()) != 0) + NdbEventOperation* pOp= MyNdb.nextEvent(); + while(pOp) { - if(pOp->getGCI() != last_gci) + Uint64 gci= pOp->getGCI(); + Uint64 cnt_i= 0, cnt_u= 0, cnt_d= 0; + do { - if(cnt) ndbout_c("GCI: %lld events: %lld", last_gci, cnt); - cnt= 1; - last_gci= pOp->getGCI(); - } - else - { - cnt++; - } + switch(pOp->getEventType()) + { + case NdbDictionary::Event::TE_INSERT: + cnt_i++; + break; + case NdbDictionary::Event::TE_DELETE: + cnt_d++; + break; + case NdbDictionary::Event::TE_UPDATE: + cnt_u++; + break; + case NdbDictionary::Event::TE_CLUSTER_FAILURE: + break; + case NdbDictionary::Event::TE_ALTER: + break; + case NdbDictionary::Event::TE_DROP: + break; + default: + /* We should REALLY never get here. */ + ndbout_c("Error: unknown event type"); + abort(); + } + } while ((pOp= MyNdb.nextEvent()) && gci == pOp->getGCI()); + ndbout_c("GCI: %lld events: %lld(I) %lld(U) %lld(D)", gci, cnt_i, cnt_u, cnt_d); } } end: diff --git a/strings/decimal.c b/strings/decimal.c index 0c1f03016e0..9cf4a281be2 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -972,12 +972,18 @@ int decimal2double(decimal_t *from, double *to) int double2decimal(double from, decimal_t *to) { /* TODO: fix it, when we'll have dtoa */ - char s[400], *end; - sprintf(s, "%.16G", from); - end= strend(s); - return string2decimal(s, to, &end); + char buff[400], *end; + int length, res; + DBUG_ENTER("double2decimal"); + length= my_sprintf(buff, (buff, "%.16G", from)); + DBUG_PRINT("info",("from: %g from_as_str: %s", from, buff)); + end= buff+length; + res= string2decimal(buff, to, &end); + DBUG_PRINT("exit", ("res: %d", res)); + DBUG_RETURN(res); } + static int ull2dec(ulonglong from, decimal_t *to) { int intg1, error=E_DEC_OK; diff --git a/support-files/Makefile.am b/support-files/Makefile.am index 972d1dc7038..26d51438a1b 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -107,7 +107,5 @@ SUFFIXES = .sh $< > $@-t @MV@ $@-t $@ -all: binary-configure - # Don't update the files from bitkeeper %::SCCS/s.% |