From 095efe48a5eee7e25d0cbed551c70c3d24bd3855 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Sat, 24 Sep 2005 15:51:45 +0200 Subject: Makefile.am, configure.in: Enable "make distcheck" to work --- Docs/Makefile.am | 24 ++++++++++++++---------- Makefile.am | 31 +++++++++++++++---------------- client/Makefile.am | 4 ++-- cmd-line-utils/libedit/Makefile.am | 16 ++++++++-------- configure.in | 11 ++++++++--- include/Makefile.am | 16 ++++------------ libmysql/Makefile.am | 32 ++++++++++++++++---------------- libmysql_r/Makefile.am | 4 ++-- libmysqld/Makefile.am | 16 ++++++++-------- libmysqld/examples/Makefile.am | 15 ++++++++------- mysql-test/Makefile.am | 3 +++ ndb/docs/Makefile.am | 4 +--- netware/Makefile.am | 6 +++--- pstack/Makefile.am | 2 +- scripts/Makefile.am | 5 +++-- sql-bench/Makefile.am | 2 ++ sql/Makefile.am | 12 ++++++------ sql/share/Makefile.am | 7 +++++++ support-files/Makefile.am | 2 -- 19 files changed, 111 insertions(+), 101 deletions(-) diff --git a/Docs/Makefile.am b/Docs/Makefile.am index b1f69381774..685eaeef7d1 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,32 @@ 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 + +# 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 9025251ff2a..7b397189aee 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@ \ @readline_topdir@ sql-common \ @thread_dirs@ pstack \ @@ -34,16 +35,19 @@ DIST_SUBDIRS = . include @docs_dirs@ zlib \ BUILD netware os2 @libmysqld_dirs@ \ @bench_dirs@ support-files @fs_dirs@ @tools_dirs@ -# 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 @@ -73,13 +77,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 @@ -91,7 +90,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 1e8851fb3b9..c0569d5fa6f 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -41,8 +41,8 @@ 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; # Don't update the files from bitkeeper 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/configure.in b/configure.in index 97eb0cb0edf..bce2aaef302 100644 --- a/configure.in +++ b/configure.in @@ -37,7 +37,7 @@ romanian russian serbian slovak spanish swedish ukrainian" # Generate make rules for all error messages AVAILABLE_LANGUAGES_ERRORS= -AVAILABLE_LANGUAGES_ERRORS_RULES=$srcdir/ac_available_languages_fragment +AVAILABLE_LANGUAGES_ERRORS_RULES=ac_available_languages_fragment rm -f $AVAILABLE_LANGUAGES_ERRORS_RULES for i in $AVAILABLE_LANGUAGES do @@ -2310,6 +2310,7 @@ then echo "Warning: extra-tools disabled because --enable-thread-safe-client wasn't used" else tools_dirs="tools" + AC_CONFIG_FILES(tools/Makefile) fi fi AC_SUBST(tools_dirs) @@ -2320,9 +2321,12 @@ MYSQL_CHECK_VIO MYSQL_CHECK_OPENSSL 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 @@ -2331,6 +2335,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, @@ -2921,6 +2926,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 @@ -3275,12 +3281,11 @@ AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl myisam/Makefile 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-common/Makefile SSL/Makefile dnl dbug/Makefile scripts/Makefile dnl - include/Makefile sql-bench/Makefile tools/Makefile dnl + include/Makefile sql-bench/Makefile dnl tests/Makefile Docs/Makefile support-files/Makefile dnl support-files/MacOSX/Makefile mysql-test/Makefile dnl netware/Makefile dnl diff --git a/include/Makefile.am b/include/Makefile.am index 0c845900a4f..3fa7b04d69a 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -38,23 +38,15 @@ SUPERCLEANFILES = mysql_version.h my_config.h # Some include files that may be moved and patched by configure DISTCLEANFILES = sched.h $(SUPERCLEANFILES) -clean: +clean-local: $(RM) -fr readline -distclean: +distclean-local: $(RM) -fr readline -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 + +link_sources: -$(RM) -fr readline @readline_h_ln_cmd@ diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index 4bd9eddafb0..8e76d0f125d 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 a76ef675189..f7cf00321cb 100644 --- a/libmysql_r/Makefile.am +++ b/libmysql_r/Makefile.am @@ -41,6 +41,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 f4e9d4e6b39..d6f68047296 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -122,19 +122,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 $(sqlexamplessources); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ $(srcdir)/../sql/examples/$$f $(srcdir)/$$f; \ + rm -f $$f; \ + @LN_CP_F@ $(top_srcdir)/sql/examples/$$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 d19023c100f..588a6153a3b 100644 --- a/libmysqld/examples/Makefile.am +++ b/libmysqld/examples/Makefile.am @@ -20,14 +20,15 @@ client_sources = $(mysqltest_embedded_SOURCES) $(mysql_SOURCES) tests_sources= $(mysql_client_test_embedded_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 = @MT_INCLUDES@ \ @@ -48,7 +49,7 @@ mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) mysql_client_test_embedded_LINK = $(CXXLINK) mysql_client_test_embedded_SOURCES = mysql_client_test.c -clean: +clean-local: rm -f $(client_sources) rm -f $(tests_sources) diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index e7abcd3fc95..f2a780cc550 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -82,6 +82,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/ndb/docs/Makefile.am b/ndb/docs/Makefile.am index 1399ce3b6a5..9b7ec213e26 100644 --- a/ndb/docs/Makefile.am +++ b/ndb/docs/Makefile.am @@ -1,14 +1,12 @@ 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 ndbapidoc mgmapidoc - DOXYTMP = .doxytmp DOXYOUT = .doxyout NDB_RELEASE = @NDB_VERSION_MAJOR@.@NDB_VERSION_MINOR@.@NDB_VERSION_BUILD@-@NDB_VERSION_STATUS@ -clean: +clean-local: rm -rf ndbapi.pdf ndbapi.html mgmapi.pdf mgmapi.html rm -rf $(DOXYTMP) $(DOXYOUT) diff --git a/netware/Makefile.am b/netware/Makefile.am index aeb93d1575d..0588e6b1ade 100644 --- a/netware/Makefile.am +++ b/netware/Makefile.am @@ -42,10 +42,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 \ isamchk.def isamlog.def libmysql.def libmysql.imp \ 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 27b42314273..30ba75c551d 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -85,12 +85,13 @@ 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 -SUPERCLEANFILES = mysqlbug +DISTCLEANFILES = mysqlbug # We want the right version and configure comand line in mysqlbug mysqlbug: ${top_builddir}/config.status mysqlbug.sh 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 ea7cea9c7b9..218cf5dbca5 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -111,17 +111,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 $< @@ -145,7 +145,7 @@ lex_hash.h: gen_lex_hash$(EXEEXT) udf_example.so: udf_example.cc $(CXXCOMPILE) -shared -o $@ $< -distclean: +distclean-local: rm -f lex_hash.h # Don't update the files from bitkeeper diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index f0207fdef03..3b13d73e8da 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -43,6 +43,13 @@ 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) + +# Do nothing +link_sources: + fix_errors: for lang in @AVAILABLE_LANGUAGES@; \ do \ 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.% -- cgit v1.2.1 From c7db18719e06fc3330216032a05c2e66453d9169 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Tue, 25 Oct 2005 15:36:39 +0500 Subject: Bug#14255 CAST(x AS BINARY(N)) does not pad type_binary.result, type_binary.test: Adding test case. item_timefunc.cc: Padding code was added. --- mysql-test/r/type_binary.result | 3 +++ mysql-test/t/type_binary.test | 3 +++ sql/item_timefunc.cc | 44 +++++++++++++++++++++++++++-------------- 3 files changed, 35 insertions(+), 15 deletions(-) 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/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/sql/item_timefunc.cc b/sql/item_timefunc.cc index 7f94c19647e..e43b0cdf46e 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2327,22 +2327,36 @@ 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), "CHAR(%lu)", 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; -- cgit v1.2.1 From b269caecb12b6b7da093f6924e5a7326cc1b75e9 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Wed, 9 Nov 2005 11:56:04 +0200 Subject: Additional "make distcheck" changes specific to 5.0 --- Docs/Makefile.am | 5 +++++ client/Makefile.am | 2 +- configure.in | 3 +-- extra/Makefile.am | 3 +++ extra/yassl/Makefile.am | 2 +- extra/yassl/src/Makefile.am | 2 +- extra/yassl/taocrypt/src/Makefile.am | 2 +- server-tools/instance-manager/Makefile.am | 8 ++++---- sql/share/Makefile.am | 3 +++ 9 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 685eaeef7d1..542c82d8f58 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -33,6 +33,11 @@ install-data-hook: mysql.info 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) diff --git a/client/Makefile.am b/client/Makefile.am index b1821c54b60..804f194085f 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -61,7 +61,7 @@ link_sources: 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/configure.in b/configure.in index de162cdcd54..fa03aa08508 100644 --- a/configure.in +++ b/configure.in @@ -71,7 +71,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) AC_SUBST([NDB_VERSION_MAJOR]) AC_SUBST([NDB_VERSION_MINOR]) @@ -2753,7 +2752,7 @@ AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl pstack/Makefile pstack/aout/Makefile sql/Makefile sql/share/Makefile dnl 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 457fddce673..a60656cb5c6 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/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/share/Makefile.am b/sql/share/Makefile.am index d860b2b40c1..6d905ba35dc 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -53,6 +53,9 @@ install-data-local: uninstall-local: @RM@ -f -r $(DESTDIR)$(pkgdatadir) +distclean-local: + @RM@ -f */errmsg.sys + # Do nothing link_sources: -- cgit v1.2.1 From a035c96c0fe600206113c7fb5cb2957a16cc39eb Mon Sep 17 00:00:00 2001 From: "SergeyV@selena." <> Date: Mon, 14 Nov 2005 18:10:16 +0300 Subject: Import patch for bug #13377 from current 5.0 bk tree. --- include/my_global.h | 9 +++ include/my_sys.h | 1 + mysys/my_create.c | 5 +- mysys/my_open.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/log.cc | 62 +----------------- sql/sql_class.h | 6 +- sql/sql_repl.cc | 39 ++--------- 7 files changed, 207 insertions(+), 99 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index b32a8fe6baa..33cdfa2d03c 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -553,6 +553,15 @@ typedef SOCKET_SIZE_TYPE size_socket; #define O_NOFOLLOW 0 #endif +/* additional file share flags for win32 */ +#ifdef __WIN__ +#define _SH_DENYRWD 0x110 /* deny read/write mode & delete */ +#define _SH_DENYWRD 0x120 /* deny write mode & delete */ +#define _SH_DENYRDD 0x130 /* deny read mode & delete */ +#define _SH_DENYDEL 0x140 /* deny delete only */ +#endif /* __WIN__ */ + + /* #define USE_RECORD_LOCK */ /* Unsigned types supported by the compiler */ diff --git a/include/my_sys.h b/include/my_sys.h index 76031806b82..44fe383bf4f 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -601,6 +601,7 @@ extern char *_my_strdup_with_length(const byte *from, uint length, #ifdef __WIN__ extern int my_access(const char *path, int amode); +extern File my_sopen(const char *path, int oflag, int shflag, int pmode); #else #define my_access access #endif diff --git a/mysys/my_create.c b/mysys/my_create.c index 5fa97a9ca78..a85417c7701 100644 --- a/mysys/my_create.c +++ b/mysys/my_create.c @@ -47,13 +47,16 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, #elif defined(VMS) fd = open((my_string) FileName, access_flags | O_CREAT, 0, "ctx=stm","ctx=bin"); -#elif defined(MSDOS) || defined(__WIN__) || defined(__EMX__) || defined(OS2) +#elif defined(MSDOS) || defined(__EMX__) || defined(OS2) if (access_flags & O_SHARE) fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY, SH_DENYNO, MY_S_IREAD | MY_S_IWRITE); else fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY, MY_S_IREAD | MY_S_IWRITE); +#elif defined(__WIN__) + fd= my_sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY, + SH_DENYNO, MY_S_IREAD | MY_S_IWRITE); #else fd = open(FileName, access_flags); #endif diff --git a/mysys/my_open.c b/mysys/my_open.c index 69d63c49554..baca97450b7 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -56,12 +56,18 @@ File my_open(const char *FileName, int Flags, myf MyFlags) DBUG_RETURN(my_register_filename(-1, FileName, FILE_BY_OPEN, EE_FILENOTFOUND, MyFlags)); } +#ifndef __WIN__ if (Flags & O_SHARE) fd = sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO, MY_S_IREAD | MY_S_IWRITE); else fd = open((my_string) FileName, Flags | O_BINARY, MY_S_IREAD | MY_S_IWRITE); +#else + fd= my_sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO, + MY_S_IREAD | MY_S_IWRITE); +#endif + #elif !defined(NO_OPEN_3) fd = open(FileName, Flags, my_umask); /* Normal unix */ #else @@ -167,3 +173,181 @@ File my_register_filename(File fd, const char *FileName, enum file_type FileName, my_errno); return(fd); } + +#ifdef __WIN__ + +extern void __cdecl _dosmaperr(unsigned long); + +/* + Open a file with sharing. Similar to _sopen() from libc, but allows managing + share delete on win32 + + SYNOPSIS + my_sopen() + path fully qualified file name + oflag operation flags + shflag share flag + pmode permission flags + + RETURN VALUE + File descriptor of opened file if success + -1 and sets errno if fails. +*/ + +File my_sopen(const char *path, int oflag, int shflag, int pmode) +{ + int fh; /* handle of opened file */ + int mask; + HANDLE osfh; /* OS handle of opened file */ + DWORD fileaccess; /* OS file access (requested) */ + DWORD fileshare; /* OS file sharing mode */ + DWORD filecreate; /* OS method of opening/creating */ + DWORD fileattrib; /* OS file attribute flags */ + SECURITY_ATTRIBUTES SecurityAttributes; + + SecurityAttributes.nLength= sizeof(SecurityAttributes); + SecurityAttributes.lpSecurityDescriptor= NULL; + SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT); + + /* + * decode the access flags + */ + switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: /* read access */ + fileaccess= GENERIC_READ; + break; + case _O_WRONLY: /* write access */ + fileaccess= GENERIC_WRITE; + break; + case _O_RDWR: /* read and write access */ + fileaccess= GENERIC_READ | GENERIC_WRITE; + break; + default: /* error, bad oflag */ + errno= EINVAL; + _doserrno= 0L; /* not an OS error */ + return -1; + } + + /* + * decode sharing flags + */ + switch (shflag) { + case _SH_DENYRW: /* exclusive access except delete */ + fileshare= FILE_SHARE_DELETE; + break; + case _SH_DENYWR: /* share read and delete access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE; + break; + case _SH_DENYRD: /* share write and delete access */ + fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _SH_DENYNO: /* share read, write and delete access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _SH_DENYRWD: /* exclusive access */ + fileshare= 0L; + break; + case _SH_DENYWRD: /* share read access */ + fileshare= FILE_SHARE_READ; + break; + case _SH_DENYRDD: /* share write access */ + fileshare= FILE_SHARE_WRITE; + break; + case _SH_DENYDEL: /* share read and write access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + default: /* error, bad shflag */ + errno= EINVAL; + _doserrno= 0L; /* not an OS error */ + return -1; + } + + /* + * decode open/create method flags + */ + switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: // ignore EXCL w/o CREAT + filecreate= OPEN_EXISTING; + break; + + case _O_CREAT: + filecreate= OPEN_ALWAYS; + break; + + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + filecreate= CREATE_NEW; + break; + + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT + filecreate= TRUNCATE_EXISTING; + break; + + case _O_CREAT | _O_TRUNC: + filecreate= CREATE_ALWAYS; + break; + + default: + // this can't happen ... all cases are covered + errno= EINVAL; + _doserrno= 0L; + return -1; + } + + /* + * decode file attribute flags if _O_CREAT was specified + */ + fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */ + if (oflag & _O_CREAT) + { + _umask((mask= _umask(0))); + + if (!((pmode & ~mask) & _S_IWRITE)) + fileattrib= FILE_ATTRIBUTE_READONLY; + } + + /* + * Set temporary file (delete-on-close) attribute if requested. + */ + if (oflag & _O_TEMPORARY) + { + fileattrib|= FILE_FLAG_DELETE_ON_CLOSE; + fileaccess|= DELETE; + } + + /* + * Set temporary file (delay-flush-to-disk) attribute if requested. + */ + if (oflag & _O_SHORT_LIVED) + fileattrib|= FILE_ATTRIBUTE_TEMPORARY; + + /* + * Set sequential or random access attribute if requested. + */ + if (oflag & _O_SEQUENTIAL) + fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN; + else if (oflag & _O_RANDOM) + fileattrib|= FILE_FLAG_RANDOM_ACCESS; + + /* + * try to open/create the file + */ + if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes, + filecreate, fileattrib, NULL)) == (HANDLE)0xffffffff) + { + /* + * OS call to open/create file failed! map the error, release + * the lock, and return -1. note that it's not necessary to + * call _free_osfhnd (it hasn't been used yet). + */ + _dosmaperr(GetLastError()); /* map error */ + return -1; /* return error to caller */ + } + + fh= _open_osfhandle((long)osfh, oflag & (_O_APPEND | _O_RDONLY | _O_TEXT)); + + return fh; /* return handle */ +} +#endif /* __WIN__ */ diff --git a/sql/log.cc b/sql/log.cc index 7ea2dba2144..eeb181253e0 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -357,8 +357,7 @@ static int find_uniq_filename(char *name) MYSQL_LOG::MYSQL_LOG() :bytes_written(0), last_time(0), query_start(0), name(0), prepared_xids(0), log_type(LOG_CLOSED), file_id(1), open_count(1), - readers_count(0), reset_pending(FALSE), write_error(FALSE), inited(FALSE), - need_start_event(TRUE), + write_error(FALSE), inited(FALSE), need_start_event(TRUE), description_event_for_exec(0), description_event_for_queue(0) { /* @@ -385,9 +384,7 @@ void MYSQL_LOG::cleanup() delete description_event_for_exec; (void) pthread_mutex_destroy(&LOCK_log); (void) pthread_mutex_destroy(&LOCK_index); - (void) pthread_mutex_destroy(&LOCK_readers); (void) pthread_cond_destroy(&update_cond); - (void) pthread_cond_destroy(&reset_cond); } DBUG_VOID_RETURN; } @@ -432,9 +429,7 @@ void MYSQL_LOG::init_pthread_objects() inited= 1; (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_readers, MY_MUTEX_INIT_SLOW); (void) pthread_cond_init(&update_cond, 0); - (void) pthread_cond_init(&reset_cond, 0); } const char *MYSQL_LOG::generate_name(const char *log_name, @@ -938,12 +933,6 @@ bool MYSQL_LOG::reset_logs(THD* thd) pthread_mutex_lock(&LOCK_log); pthread_mutex_lock(&LOCK_index); - /* - we need one more lock to block attempts to open a log while - we are waiting untill all log files will be closed - */ - pthread_mutex_lock(&LOCK_readers); - /* The following mutex is needed to ensure that no threads call 'delete thd' as we would then risk missing a 'rollback' from this @@ -966,19 +955,6 @@ bool MYSQL_LOG::reset_logs(THD* thd) goto err; } - reset_pending= TRUE; - /* - send update signal just in case so that all reader threads waiting - for log update will leave wait condition - */ - signal_update(); - /* - if there are active readers wait until all of them will - release opened files - */ - while (readers_count) - pthread_cond_wait(&reset_cond, &LOCK_log); - for (;;) { my_delete(linfo.log_file_name, MYF(MY_WME)); @@ -997,10 +973,7 @@ bool MYSQL_LOG::reset_logs(THD* thd) my_free((gptr) save_name, MYF(0)); err: - reset_pending= FALSE; - (void) pthread_mutex_unlock(&LOCK_thread_count); - pthread_mutex_unlock(&LOCK_readers); pthread_mutex_unlock(&LOCK_index); pthread_mutex_unlock(&LOCK_log); DBUG_RETURN(error); @@ -2073,12 +2046,6 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave) { const char *old_msg; DBUG_ENTER("wait_for_update"); - - if (reset_pending) - { - pthread_mutex_unlock(&LOCK_log); - DBUG_VOID_RETURN; - } old_msg= thd->enter_cond(&update_cond, &LOCK_log, is_slave ? @@ -2330,33 +2297,6 @@ void MYSQL_LOG::signal_update() DBUG_VOID_RETURN; } -void MYSQL_LOG::readers_addref() -{ - /* - There is no necessity for reference counting on *nix, since it allows to - delete opened files, however it is more clean way to wait - untill all files will be closed on *nix as well. - */ - DBUG_ENTER("MYSQL_LOG::reader_addref"); - pthread_mutex_lock(&LOCK_log); - pthread_mutex_lock(&LOCK_readers); - readers_count++; - pthread_mutex_unlock(&LOCK_readers); - pthread_mutex_unlock(&LOCK_log); - DBUG_VOID_RETURN; -} - -void MYSQL_LOG::readers_release() -{ - DBUG_ENTER("MYSQL_LOG::reader_release"); - pthread_mutex_lock(&LOCK_log); - readers_count--; - if (!readers_count) - pthread_cond_broadcast(&reset_cond); - pthread_mutex_unlock(&LOCK_log); - DBUG_VOID_RETURN; -} - #ifdef __NT__ void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, uint length, int buffLen) diff --git a/sql/sql_class.h b/sql/sql_class.h index 2d1880a6d9d..eaa8291e697 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -189,11 +189,10 @@ class MYSQL_LOG: public TC_LOG { private: /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ - pthread_mutex_t LOCK_log, LOCK_index, LOCK_readers; + pthread_mutex_t LOCK_log, LOCK_index; pthread_mutex_t LOCK_prep_xids; pthread_cond_t COND_prep_xids; pthread_cond_t update_cond; - pthread_cond_t reset_cond; ulonglong bytes_written; time_t last_time,query_start; IO_CACHE log_file; @@ -335,9 +334,6 @@ public: int purge_logs_before_date(time_t purge_time); int purge_first_log(struct st_relay_log_info* rli, bool included); bool reset_logs(THD* thd); - inline bool is_reset_pending() { return reset_pending; } - void readers_addref(); - void readers_release(); void close(uint exiting); // iterating through the log index file diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index b5865fa8816..cd293fc21c7 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -372,11 +372,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, goto err; } - /* - Call readers_addref before opening log to track count - of binlog readers - */ - mysql_bin_log.readers_addref(); if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; @@ -574,8 +569,7 @@ impossible position"; goto err; if (!(flags & BINLOG_DUMP_NON_BLOCK) && - mysql_bin_log.is_active(log_file_name) && - !mysql_bin_log.is_reset_pending()) + mysql_bin_log.is_active(log_file_name)) { /* Block until there is more data in the log @@ -688,13 +682,7 @@ impossible position"; else { bool loop_breaker = 0; - // need this to break out of the for loop from switch - - // if we are going to switch log file anyway, close current log first - end_io_cache(&log); - (void) my_close(file, MYF(MY_WME)); - // decrease reference count of binlog readers - mysql_bin_log.readers_release(); + /* need this to break out of the for loop from switch */ thd->proc_info = "Finished reading one binlog; switching to next binlog"; switch (mysql_bin_log.find_next_log(&linfo, 1)) { @@ -704,25 +692,16 @@ impossible position"; case 0: break; default: - // need following call to do release on err label - mysql_bin_log.readers_addref(); errmsg = "could not find next log"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - if (loop_breaker) - { - // need following call to do release on end label - mysql_bin_log.readers_addref(); - break; - } - - /* - Call readers_addref before opening log to track count - of binlog readers - */ - mysql_bin_log.readers_addref(); + if (loop_breaker) + break; + + end_io_cache(&log); + (void) my_close(file, MYF(MY_WME)); /* Call fake_rotate_event() in case the previous log (the one which @@ -755,8 +734,6 @@ end: end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); - // decrease reference count of binlog readers - mysql_bin_log.readers_release(); send_eof(thd); thd->proc_info = "Waiting to finalize termination"; @@ -783,8 +760,6 @@ err: pthread_mutex_unlock(&LOCK_thread_count); if (file >= 0) (void) my_close(file, MYF(MY_WME)); - // decrease reference count of binlog readers - mysql_bin_log.readers_release(); my_message(my_errno, errmsg, MYF(0)); DBUG_VOID_RETURN; -- cgit v1.2.1 From 88b6d28abad7a23690e9688245853fdccc4577eb Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Mon, 14 Nov 2005 19:53:41 +0100 Subject: Bug#13707 - Server crash with INSERT DELAYED on MyISAM table After push fix. Must not access new_field if it is NULL. --- sql/field.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 381a13c3263..e7dff9500ad 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6194,6 +6194,8 @@ uint Field_string::max_packed_col_length(uint max_length) Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table) { + Field *new_field; + if (type() != MYSQL_TYPE_VAR_STRING || table == new_table) return Field::new_field(root, new_table); @@ -6202,15 +6204,16 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table) This is done to ensure that ALTER TABLE will convert old VARCHAR fields to now VARCHAR fields. */ - Field *new_field= new Field_varstring(field_length, maybe_null(), - field_name, new_table, - charset()); - /* - delayed_insert::get_local_table() needs a ptr copied from old table. - This is what other new_field() methods do too. The above method of - Field_varstring sets ptr to NULL. - */ - new_field->ptr= ptr; + if (new_field= new Field_varstring(field_length, maybe_null(), + field_name, new_table, charset())) + { + /* + delayed_insert::get_local_table() needs a ptr copied from old table. + This is what other new_field() methods do too. The above method of + Field_varstring sets ptr to NULL. + */ + new_field->ptr= ptr; + } return new_field; } -- cgit v1.2.1 From a316a30d5eef679106c9067307cfb0d8610f09e5 Mon Sep 17 00:00:00 2001 From: "eric@mysql.com" <> Date: Wed, 16 Nov 2005 08:22:25 -0800 Subject: BUG#12659 error handling in federated needs improvement. Sanja pointed out that we were copying an entire buffer, most of which was probably garbage, and possibly hidden by null termination in the middle of the buffer. Now we are only copying the error message. --- sql/ha_federated.cc | 10 +++++++--- sql/ha_federated.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index d6d6b5980f6..00516bef5a3 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2615,8 +2615,11 @@ int ha_federated::stash_remote_error() { DBUG_ENTER("ha_federated::stash_remote_error()"); remote_error_number= mysql_errno(mysql); - my_snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE, - mysql_error(mysql)); + const char *remote_error= mysql_error(mysql); + remote_error_len= strlen(remote_error); + if(remote_error_len > (sizeof(remote_error_buf) - 1)) + remote_error_len= (sizeof(remote_error_buf) - 1); + my_snprintf(remote_error_buf, remote_error_len + 1, remote_error); DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM); } @@ -2630,10 +2633,11 @@ bool ha_federated::get_error_message(int error, String* buf) buf->append("Error on remote system: "); buf->qs_append(remote_error_number); buf->append(": "); - buf->append(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE); + buf->append(remote_error_buf, remote_error_len); remote_error_number= 0; remote_error_buf[0]= '\0'; + remote_error_len= 0; } DBUG_PRINT("exit", ("message: %s", buf->ptr())); DBUG_RETURN(FALSE); diff --git a/sql/ha_federated.h b/sql/ha_federated.h index b25071dda16..769a8c9eef8 100644 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -159,6 +159,7 @@ class ha_federated: public handler MYSQL_ROW_OFFSET current_position; // Current position used by ::position() int remote_error_number; char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE]; + uint remote_error_len; private: /* -- cgit v1.2.1 From c518a2405fefd175030a0e9ff019dedb064f28e5 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Thu, 17 Nov 2005 11:11:48 +0100 Subject: Background: Since long, the compiled code of stored routines has been printed in the trace file when starting mysqld with the "--debug" flag. (At creation time only, and only in debug builds of course.) This has been helpful when debugging stored procedure execution, but it's a bit awkward to use. Also, the printing of some of the instructions is a bit terse, in particular for sp_instr_stmt where only the command code was printed. This improves the printout of several of the instructions, and adds the debugging- only commands "show procedure code " and "show function code ". (In non-debug builds they are not available.) --- sql/lex.h | 1 + sql/sp_head.cc | 169 +++++++++++++++++++++++++++++++++++++++++++++-------- sql/sp_head.h | 11 +++- sql/sp_pcontext.cc | 42 +++++++++++++ sql/sp_pcontext.h | 15 ++--- sql/sql_lex.h | 1 + sql/sql_parse.cc | 24 ++++++++ sql/sql_yacc.yy | 28 ++++++++- 8 files changed, 252 insertions(+), 39 deletions(-) diff --git a/sql/lex.h b/sql/lex.h index a5366742fd9..efcb9b84f81 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -110,6 +110,7 @@ static SYMBOL symbols[] = { { "CIPHER", SYM(CIPHER_SYM)}, { "CLIENT", SYM(CLIENT_SYM)}, { "CLOSE", SYM(CLOSE_SYM)}, + { "CODE", SYM(CODE_SYM)}, { "COLLATE", SYM(COLLATE_SYM)}, { "COLLATION", SYM(COLLATION_SYM)}, { "COLUMN", SYM(COLUMN_SYM)}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 08a189165b5..1ab562b53fc 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; /* @@ -1698,7 +1700,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, @@ -1711,10 +1713,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); @@ -1723,7 +1722,6 @@ sp_head::show_create_procedure(THD *thd) res= protocol->write(); send_eof(thd); - done: DBUG_RETURN(res); } @@ -1768,7 +1766,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, @@ -1780,10 +1778,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); @@ -1792,7 +1787,6 @@ sp_head::show_create_function(THD *thd) res= protocol->write(); send_eof(thd); - done: DBUG_RETURN(res); } @@ -1852,6 +1846,51 @@ 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); + int res; + List field_list; + bool full_access; + uint ip; + sp_instr *i; + + 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.c_ptr_quick(), 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 @@ -2010,14 +2049,34 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } +#define STMT_PRINT_MAXLEN 40 void sp_instr_stmt::print(String *str) { - str->reserve(12); + uint i, len; + + str->reserve(STMT_PRINT_MAXLEN+20); str->append("stmt "); str->qs_append((uint)m_lex_keeper.sql_command()); + str->append(" \""); + len= m_query.length; + /* + Print the query string (but not too much of it), just to indicate which + statement it is. + */ + if (len > STMT_PRINT_MAXLEN) + len= 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->append(' '); + else + str->append(m_query.str[i]); + if (m_query.length > STMT_PRINT_MAXLEN) + str->append("..."); /* Indicate truncated string */ + str->append('"'); } - +#undef STMT_PRINT_MAXLEN int sp_instr_stmt::exec_core(THD *thd, uint *nextp) @@ -2054,8 +2113,19 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) void sp_instr_set::print(String *str) { - str->reserve(12); + int rsrv = 16; + 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; + str->reserve(rsrv); str->append("set "); + if (var) + { + str->append(var->name.str, var->name.length); + str->append('@'); + } str->qs_append(m_offset); str->append(' '); m_value->print(str); @@ -2346,12 +2416,26 @@ sp_instr_hpush_jump::print(String *str) str->reserve(32); str->append("hpush_jump "); str->qs_append(m_dest); - str->append(" t="); - str->qs_append(m_type); - str->append(" f="); + str->append(' '); str->qs_append(m_frame); - str->append(" h="); - str->qs_append(m_ip+1); + switch (m_type) + { + case SP_HANDLER_NONE: + str->append(" NONE"); // This would be a bug + break; + case SP_HANDLER_EXIT: + str->append(" EXIT"); + break; + case SP_HANDLER_CONTINUE: + str->append(" CONTINUE"); + break; + case SP_HANDLER_UNDO: + str->append(" UNDO"); + break; + default: + str->append(" UNKNOWN:"); // This would be a bug as well + str->qs_append(m_type); + } } uint @@ -2474,7 +2558,17 @@ 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); + + str->reserve(32); + str->append("cpush "); + if (found) + { + str->append(n.str, n.length); + str->append('@'); + } + str->qs_append(m_cursor); } @@ -2570,8 +2664,16 @@ sp_instr_copen::exec_core(THD *thd, uint *nextp) void sp_instr_copen::print(String *str) { - str->reserve(12); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + + str->reserve(32); str->append("copen "); + if (found) + { + str->append(n.str, n.length); + str->append('@'); + } str->qs_append(m_cursor); } @@ -2599,8 +2701,16 @@ sp_instr_cclose::execute(THD *thd, uint *nextp) void sp_instr_cclose::print(String *str) { - str->reserve(12); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + + str->reserve(32); str->append("cclose "); + if (found) + { + str->append(n.str, n.length); + str->append('@'); + } str->qs_append(m_cursor); } @@ -2629,14 +2739,23 @@ sp_instr_cfetch::print(String *str) { List_iterator_fast li(m_varlist); sp_pvar_t *pv; + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(12); + str->reserve(32); str->append("cfetch "); + if (found) + { + str->append(n.str, n.length); + str->append('@'); + } str->qs_append(m_cursor); while ((pv= li++)) { - str->reserve(8); + str->reserve(16); str->append(' '); + str->append(pv->name.str, pv->name.length); + str->append('@'); str->qs_append(pv->offset); } } diff --git a/sql/sp_head.h b/sql/sp_head.h index d1a122fd410..8055a04151f 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -295,6 +295,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 @@ -856,8 +862,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() @@ -876,6 +882,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..32824b75847 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -169,6 +169,29 @@ 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 i) +{ + if (m_poffset <= i && i < m_poffset + m_pvar.elements) + { // This frame + sp_pvar_t *p; + + get_dynamic(&m_pvar, (gptr)&p, i - m_poffset); + return p; + } + else if (m_parent) + return m_parent->find_pvar(i); // Some previous frame + else + 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 +354,22 @@ 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 i, LEX_STRING *n) +{ + if (m_coffset <= i && i < m_coffset + m_cursor.elements) + { // This frame + get_dynamic(&m_cursor, (gptr)n, i - m_poffset); + return TRUE; + } + else if (m_parent) + return m_parent->find_cursor(i, n); // Some previous frame + else + return FALSE; // index out of bounds +} + diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index bd2259cb6fb..77e749fe3ad 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -172,16 +172,7 @@ class sp_pcontext : public Sql_alloc // Find by index 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 i); // // 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 index (for debugging only) */ + my_bool + find_cursor(uint i, LEX_STRING *n); + inline uint max_cursors() { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0e836b6e9b9..372bbc5576b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -90,6 +90,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, /* This should be the last !!! */ SQLCOM_END diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c19d54feda5..f46f0d3e5a1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4560,6 +4560,30 @@ 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_procedure(thd, lex->spname); + else + sp= sp_find_function(thd, lex->spname); + 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)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 55002def5e9..2901698dd70 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -175,6 +175,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 @@ -1698,7 +1699,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; @@ -6625,7 +6627,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 @@ -7534,6 +7557,7 @@ keyword_sp: | CHANGED {} | CIPHER_SYM {} | CLIENT_SYM {} + | CODE_SYM {} | COLLATION_SYM {} | COLUMNS {} | COMMITTED_SYM {} -- cgit v1.2.1 From 77cbf5d3ffafe5a1244815dd7248ac42f43847ea Mon Sep 17 00:00:00 2001 From: "mskold@mysql.com" <> Date: Thu, 17 Nov 2005 12:45:23 +0100 Subject: Fixed incorrectly use if table with wrong schema version --- mysql-test/r/ndb_alter_table.result | 3 +-- mysql-test/t/ndb_alter_table.test | 2 ++ sql/ha_ndbcluster.cc | 44 ++++++++++++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result index 3714ea14e16..62e8455ae9f 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/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 5c792f76316..3cd363fb6e8 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -147,6 +147,8 @@ 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 1105 select * from t1 where b = 'two'; select * from t1 where b = 'two'; connection server1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 608dc3eaa54..6760208488f 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -50,6 +50,8 @@ static const char *ha_ndb_ext=".ndb"; #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)) @@ -212,7 +214,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= 0; } @@ -3269,15 +3285,19 @@ 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 + */ + NdbError err= ndb->getNdbError(NDB_INVALID_SCHEMA_OBJECT); + DBUG_RETURN(ndb_to_mysql_error(&err)); + } m_table_info= tab_info; } no_uncommitted_rows_init(thd); @@ -4657,7 +4677,21 @@ bool ndbcluster_end() { DBUG_ENTER("ndbcluster_end"); 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; -- cgit v1.2.1 From c15c270437ea4fdd0eec9e0bbeedc2d6bc2f1110 Mon Sep 17 00:00:00 2001 From: "eric@mysql.com" <> Date: Thu, 17 Nov 2005 06:05:09 -0800 Subject: fix potential security hole, pointed out by Sergei. Also simplify code per Sergei's suggestion. --- sql/ha_federated.cc | 9 +++------ sql/ha_federated.h | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 00516bef5a3..015ad185a24 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2616,10 +2616,8 @@ int ha_federated::stash_remote_error() DBUG_ENTER("ha_federated::stash_remote_error()"); remote_error_number= mysql_errno(mysql); const char *remote_error= mysql_error(mysql); - remote_error_len= strlen(remote_error); - if(remote_error_len > (sizeof(remote_error_buf) - 1)) - remote_error_len= (sizeof(remote_error_buf) - 1); - my_snprintf(remote_error_buf, remote_error_len + 1, remote_error); + my_snprintf(remote_error_buf, sizeof(remote_error_buf), "%s", + mysql_error(mysql)); DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM); } @@ -2633,11 +2631,10 @@ bool ha_federated::get_error_message(int error, String* buf) buf->append("Error on remote system: "); buf->qs_append(remote_error_number); buf->append(": "); - buf->append(remote_error_buf, remote_error_len); + buf->append(remote_error_buf); remote_error_number= 0; remote_error_buf[0]= '\0'; - remote_error_len= 0; } DBUG_PRINT("exit", ("message: %s", buf->ptr())); DBUG_RETURN(FALSE); diff --git a/sql/ha_federated.h b/sql/ha_federated.h index 769a8c9eef8..b25071dda16 100644 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -159,7 +159,6 @@ class ha_federated: public handler MYSQL_ROW_OFFSET current_position; // Current position used by ::position() int remote_error_number; char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE]; - uint remote_error_len; private: /* -- cgit v1.2.1 From 76ddbf2fd35f878abd32a26e93953403e497ede2 Mon Sep 17 00:00:00 2001 From: "eric@mysql.com" <> Date: Thu, 17 Nov 2005 06:28:11 -0800 Subject: removed superfluous local variable --- sql/ha_federated.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 015ad185a24..c3ab5f11952 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2615,7 +2615,6 @@ int ha_federated::stash_remote_error() { DBUG_ENTER("ha_federated::stash_remote_error()"); remote_error_number= mysql_errno(mysql); - const char *remote_error= mysql_error(mysql); my_snprintf(remote_error_buf, sizeof(remote_error_buf), "%s", mysql_error(mysql)); DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM); -- cgit v1.2.1 From 96413a44d1654bb6045a250a61666fe3ce716f57 Mon Sep 17 00:00:00 2001 From: "mskold@mysql.com" <> Date: Fri, 18 Nov 2005 09:54:49 +0100 Subject: Using new error code HA_ERR_TABLE_DEF_CHANGED to signal wrong schema version of table --- mysql-test/t/ndb_alter_table.test | 2 +- sql/ha_ndbcluster.cc | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 86086ac54e5..4f76380f94c 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -152,7 +152,7 @@ connection server1; alter table t1 drop index c; connection server2; # This should fail since index information is not automatically refreshed ---error 1105 +--error 1412 select * from t1 where b = 'two'; select * from t1 where b = 'two'; connection server1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b8794c67301..cdd406d473c 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3342,8 +3342,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) /* The table has been altered, caller has to retry */ - NdbError err= ndb->getNdbError(NDB_INVALID_SCHEMA_OBJECT); - DBUG_RETURN(ndb_to_mysql_error(&err)); + DBUG_RETURN(my_errno= HA_ERR_TABLE_DEF_CHANGED); } m_table_info= tab_info; } -- cgit v1.2.1 From 16fcccce1ad3ee078e837f4bc3738aaadde8a87f Mon Sep 17 00:00:00 2001 From: "mskold@mysql.com" <> Date: Fri, 18 Nov 2005 12:20:22 +0100 Subject: Disabled --ps-protocol during autodiscover test --- mysql-test/t/ndb_alter_table.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 3cd363fb6e8..d89b81859e7 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -138,6 +138,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'); @@ -153,6 +154,7 @@ 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; -- cgit v1.2.1 From 3a832faafecefdd0b83b8ba0be8ea28528f04b8d Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Fri, 18 Nov 2005 16:30:27 +0100 Subject: Post-review fixes, mainly fixing all print() methods for sp_instr* classes. Also added mysql-test files: include/is_debug_build.inc r/is_debug_build.require r/sp-code.result t/sp-code.test --- mysql-test/include/is_debug_build.inc | 4 + mysql-test/r/is_debug_build.require | 2 + mysql-test/r/sp-code.result | 65 ++++++++++++++ mysql-test/t/sp-code.test | 50 +++++++++++ sql/sp_head.cc | 160 ++++++++++++++++++++-------------- sql/sp_pcontext.cc | 26 +++--- sql/sp_pcontext.h | 8 +- sql/sql_parse.cc | 3 +- 8 files changed, 234 insertions(+), 84 deletions(-) create mode 100644 mysql-test/include/is_debug_build.inc create mode 100644 mysql-test/r/is_debug_build.require create mode 100644 mysql-test/r/sp-code.result create mode 100644 mysql-test/t/sp-code.test 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/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/sp-code.result b/mysql-test/r/sp-code.result new file mode 100644 index 00000000000..e9597af10ee --- /dev/null +++ b/mysql-test/r/sp-code.result @@ -0,0 +1,65 @@ +select version(), substring_index(version(), "-", -1); +version() substring_index(version(), "-", -1) +5.0.17-debug-log log +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/t/sp-code.test b/mysql-test/t/sp-code.test new file mode 100644 index 00000000000..a40d86f9d4a --- /dev/null +++ b/mysql-test/t/sp-code.test @@ -0,0 +1,50 @@ +# +# Test the debugging feature "show procedure/function code " +# + +-- source include/is_debug_build.inc +select version(), substring_index(version(), "-", -1); + +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/sql/sp_head.cc b/sql/sp_head.cc index 1ab562b53fc..b11260ab999 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1853,14 +1853,13 @@ sp_head::show_routine_code(THD *thd) Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); - int res; List field_list; + sp_instr *i; bool full_access; + int res; uint ip; - sp_instr *i; - DBUG_ENTER("sp_head::show_routine_code"); - DBUG_PRINT("info", ("procedure %s", m_name.str)); + DBUG_PRINT("info", ("procedure: %s", m_name.str)); if (check_show_routine_access(thd, this, &full_access) || !full_access) DBUG_RETURN(1); @@ -1880,7 +1879,7 @@ sp_head::show_routine_code(THD *thd) buffer.set("", 0, system_charset_info); i->print(&buffer); - protocol->store(buffer.c_ptr_quick(), buffer.length(), system_charset_info); + protocol->store(buffer.ptr(), buffer.length(), system_charset_info); if ((res= protocol->write())) break; } @@ -2055,10 +2054,12 @@ sp_instr_stmt::print(String *str) { uint i, len; - str->reserve(STMT_PRINT_MAXLEN+20); - str->append("stmt "); + /* Reserve enough space for 'stmt CMD "..."'; max+20 is more than enough. */ + if (str->reserve(STMT_PRINT_MAXLEN+20)) + return; + str->qs_append("stmt ", 5); str->qs_append((uint)m_lex_keeper.sql_command()); - str->append(" \""); + str->qs_append(" \"", 2); len= m_query.length; /* Print the query string (but not too much of it), just to indicate which @@ -2068,13 +2069,15 @@ sp_instr_stmt::print(String *str) len= 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->append(' '); + str->qs_append(' '); else - str->append(m_query.str[i]); + str->qs_append(m_query.str[i]); + } if (m_query.length > STMT_PRINT_MAXLEN) - str->append("..."); /* Indicate truncated string */ - str->append('"'); + str->qs_append("...", 3); /* Indicate truncated string */ + str->qs_append('"'); } #undef STMT_PRINT_MAXLEN @@ -2119,15 +2122,16 @@ sp_instr_set::print(String *str) /* 'var' should always be non-null, but just in case... */ if (var) rsrv+= var->name.length; - str->reserve(rsrv); - str->append("set "); + if (str->reserve(rsrv)) + return; + str->qs_append("set ", 4); if (var) { - str->append(var->name.str, var->name.length); - str->append('@'); + 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); } @@ -2184,8 +2188,9 @@ sp_instr_jump::execute(THD *thd, uint *nextp) void sp_instr_jump::print(String *str) { - str->reserve(12); - str->append("jump "); + if (str->reserve(12)) + return; + str->qs_append("jump ", 5); str->qs_append(m_dest); } @@ -2266,10 +2271,11 @@ 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 "); + if (str->reserve(32)) + return; + str->qs_append("jump_if ", 8); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2327,10 +2333,11 @@ 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 "); + if (str->reserve(32)) + return; + str->qs_append("jump_if_not ", 12); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2385,10 +2392,11 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) void sp_instr_freturn::print(String *str) { - str->reserve(12); - str->append("freturn "); + if (str->reserve(32)) + return; + str->qs_append("freturn ", 8); str->qs_append((uint)m_type); - str->append(' '); + str->qs_append(' '); m_value->print(str); } @@ -2413,27 +2421,28 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) void sp_instr_hpush_jump::print(String *str) { - str->reserve(32); - str->append("hpush_jump "); + if (str->reserve(32)) + return; + str->qs_append("hpush_jump ", 11); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); str->qs_append(m_frame); switch (m_type) { case SP_HANDLER_NONE: - str->append(" NONE"); // This would be a bug + str->qs_append(" NONE", 5); // This would be a bug break; case SP_HANDLER_EXIT: - str->append(" EXIT"); + str->qs_append(" EXIT", 5); break; case SP_HANDLER_CONTINUE: - str->append(" CONTINUE"); + str->qs_append(" CONTINUE", 9); break; case SP_HANDLER_UNDO: - str->append(" UNDO"); + str->qs_append(" UNDO", 5); break; default: - str->append(" UNKNOWN:"); // This would be a bug as well + str->qs_append(" UNKNOWN:", 9); // This would be a bug as well str->qs_append(m_type); } } @@ -2470,8 +2479,9 @@ sp_instr_hpop::execute(THD *thd, uint *nextp) void sp_instr_hpop::print(String *str) { - str->reserve(12); - str->append("hpop "); + if (str->reserve(12)) + return; + str->qs_append("hpop ", 5); str->qs_append(m_count); } @@ -2505,12 +2515,13 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) void sp_instr_hreturn::print(String *str) { - str->reserve(16); - str->append("hreturn "); + if (str->reserve(20)) + return; + str->qs_append("hreturn ", 8); str->qs_append(m_frame); if (m_dest) { - str->append(' '); + str->qs_append(' '); str->qs_append(m_dest); } } @@ -2559,14 +2570,18 @@ void sp_instr_cpush::print(String *str) { LEX_STRING n; + uint rsrv= 12; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("cpush "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("cpush ", 6); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); } @@ -2589,8 +2604,9 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) void sp_instr_cpop::print(String *str) { - str->reserve(12); - str->append("cpop "); + if (str->reserve(12)) + return; + str->qs_append("cpop ", 5); str->qs_append(m_count); } @@ -2665,14 +2681,18 @@ void sp_instr_copen::print(String *str) { LEX_STRING n; + uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("copen "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("copen ", 6); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); } @@ -2702,14 +2722,18 @@ void sp_instr_cclose::print(String *str) { LEX_STRING n; + uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("cclose "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("cclose ", 7); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); } @@ -2740,22 +2764,27 @@ sp_instr_cfetch::print(String *str) List_iterator_fast li(m_varlist); sp_pvar_t *pv; LEX_STRING n; + uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("cfetch "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("cfetch ", 7); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); while ((pv= li++)) { - str->reserve(16); - str->append(' '); - str->append(pv->name.str, pv->name.length); - str->append('@'); + if (str->reserve(pv->name.length+10)) + return; + str->qs_append(' '); + str->qs_append(pv->name.str, pv->name.length); + str->qs_append('@'); str->qs_append(pv->offset); } } @@ -2779,8 +2808,9 @@ sp_instr_error::execute(THD *thd, uint *nextp) void sp_instr_error::print(String *str) { - str->reserve(12); - str->append("error "); + if (str->reserve(12)) + return; + str->qs_append("error ", 6); str->qs_append(m_errcode); } diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 32824b75847..147173ab4d8 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -177,19 +177,18 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) - For printing of sp_instr_set. (Debug mode only.) */ sp_pvar_t * -sp_pcontext::find_pvar(uint i) +sp_pcontext::find_pvar(uint offset) { - if (m_poffset <= i && i < m_poffset + m_pvar.elements) + if (m_poffset <= offset && offset < m_poffset + m_pvar.elements) { // This frame sp_pvar_t *p; - get_dynamic(&m_pvar, (gptr)&p, i - m_poffset); + get_dynamic(&m_pvar, (gptr)&p, offset - m_poffset); return p; } - else if (m_parent) - return m_parent->find_pvar(i); // Some previous frame - else - return NULL; // index out of bounds + if (m_parent) + return m_parent->find_pvar(offset); // Some previous frame + return NULL; // index out of bounds } void @@ -360,16 +359,15 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped) This is only used for debugging. */ my_bool -sp_pcontext::find_cursor(uint i, LEX_STRING *n) +sp_pcontext::find_cursor(uint offset, LEX_STRING *n) { - if (m_coffset <= i && i < m_coffset + m_cursor.elements) + if (m_coffset <= offset && offset < m_coffset + m_cursor.elements) { // This frame - get_dynamic(&m_cursor, (gptr)n, i - m_poffset); + get_dynamic(&m_cursor, (gptr)n, offset - m_coffset); return TRUE; } - else if (m_parent) - return m_parent->find_cursor(i, n); // Some previous frame - else - return FALSE; // index out of bounds + 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 77e749fe3ad..b8dd1742f7e 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -170,9 +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); + find_pvar(uint offset); // // Labels @@ -252,9 +252,9 @@ class sp_pcontext : public Sql_alloc my_bool find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0); - /* Find by index (for debugging only) */ + /* Find by offset (for debugging only) */ my_bool - find_cursor(uint i, LEX_STRING *n); + find_cursor(uint offset, LEX_STRING *n); inline uint max_cursors() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f46f0d3e5a1..5eafda5f685 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4576,7 +4576,8 @@ end_with_restore_list: else sp= sp_find_function(thd, lex->spname); if (!sp || !sp->show_routine_code(thd)) - { /* We don't distinguish between errors for now */ + { + /* 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; -- cgit v1.2.1 From 4513ffd109f2687e0c8ed575e31d197b15a7beeb Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Fri, 18 Nov 2005 18:05:04 +0100 Subject: Removed forgotten test line in sp-code.test. --- mysql-test/r/sp-code.result | 3 --- mysql-test/t/sp-code.test | 1 - 2 files changed, 4 deletions(-) diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index e9597af10ee..e6c4ffe1731 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -1,6 +1,3 @@ -select version(), substring_index(version(), "-", -1); -version() substring_index(version(), "-", -1) -5.0.17-debug-log log create procedure empty() begin end; diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test index a40d86f9d4a..6644bc3ab43 100644 --- a/mysql-test/t/sp-code.test +++ b/mysql-test/t/sp-code.test @@ -3,7 +3,6 @@ # -- source include/is_debug_build.inc -select version(), substring_index(version(), "-", -1); create procedure empty() begin -- cgit v1.2.1 From a50cc250ffff75eb1a52f9dfeb90a391e1a04cf9 Mon Sep 17 00:00:00 2001 From: "jamppa@suse9-x86.mysql.com" <> Date: Fri, 18 Nov 2005 18:25:46 +0100 Subject: Netware specific changes for 5.0.16a --- client/mysql.cc | 2 +- client/mysqladmin.cc | 2 +- client/mysqlbinlog.cc | 2 +- client/mysqlcheck.c | 2 +- client/mysqldump.c | 2 +- client/mysqlimport.c | 2 +- client/mysqlshow.c | 2 +- configure.in | 2 +- myisam/myisamchk.c | 2 +- myisam/myisampack.c | 2 +- netware/mysql_test_run.c | 3 +++ 11 files changed, 13 insertions(+), 10 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 441687e2e4e..bcd0c2453f7 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..d3676362da4 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, 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/configure.in b/configure.in index c36d24a5bc5..c6c3f1236e6 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.16) +AM_INIT_AUTOMAKE(mysql, 5.0.16a) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index b3d95d21eb7..e2c8b446322 100644 --- a/myisam/myisamchk.c +++ b/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/myisam/myisampack.c b/myisam/myisampack.c index 114e80d8f1a..d691c24e890 100644 --- a/myisam/myisampack.c +++ b/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/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); + } /****************************************************************************** -- cgit v1.2.1 From 133c00beb4f17b96e9e6cf77d870726de61958e4 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Sat, 19 Nov 2005 12:58:22 +0100 Subject: configure.in: Corrected "include/readline" link for "make distcheck" --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 9894426b581..41475ffcd4a 100644 --- a/configure.in +++ b/configure.in @@ -2442,7 +2442,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) @@ -2452,7 +2452,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 -- cgit v1.2.1 From 574e711209496b26b8e923127d6b616b569c2d20 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Sat, 19 Nov 2005 15:09:23 +0300 Subject: Fix for bug #13825 "Triggers: crash if release savepoint" and for general handling of savepoints in stored routines. Fixed ha_rollback_to_savepoint()/ha_savepoint()/ha_release_savepoint() functions to properly handle savepoints inside of stored functions and triggers. Also now when we invoke stored function or trigger we create new savepoint level. We destroy it at the end of function/trigger execution and return back to old savepoint level. --- mysql-test/r/sp_trans.result | 195 +++++++++++++++++++++++++++++++++++++++++++ mysql-test/t/sp_trans.test | 180 +++++++++++++++++++++++++++++++++++++++ sql/ha_innodb.cc | 12 +-- sql/handler.cc | 15 ++-- sql/sql_class.cc | 18 ++++ sql/sql_class.h | 1 + sql/sql_parse.cc | 4 +- 7 files changed, 411 insertions(+), 14 deletions(-) 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/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 @@ -175,6 +175,186 @@ drop function bug10015_7| 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 # diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 61af1afb2be..c092b83215a 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2178,11 +2178,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/handler.cc b/sql/handler.cc index 81e94af5dc7..a9ca40902c8 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1145,10 +1145,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; @@ -1176,7 +1176,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; @@ -1196,10 +1196,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++) { @@ -1225,9 +1225,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++) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index fc9df020b6c..849e1f45b03 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1916,6 +1916,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() @@ -1939,6 +1940,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; @@ -1951,6 +1953,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 */ @@ -1961,6 +1964,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 7ca168ec518..0cc4aca1812 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1097,6 +1097,7 @@ public: uint in_sub_stmt; bool enable_slow_log, insert_id_used; my_bool no_send_ok; + SAVEPOINT *savepoints; }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1882965fd1e..d529279eaed 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4016,8 +4016,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 { -- cgit v1.2.1 From 806f9e24ff1e9409d6b833c4ec1c07d3e45272c3 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Sun, 20 Nov 2005 20:47:07 +0200 Subject: Inefficient usage of String::append() fixed. Bad examples of usage of a string with its length fixed. The incorrect length in the trigger file configuration descriptor fixed (BUG#14090). A hook for unknown keys added to the parser to support old .TRG files. --- sql/field.cc | 52 +++++++-------- sql/ha_berkeley.cc | 2 +- sql/ha_federated.cc | 4 +- sql/ha_myisammrg.cc | 4 +- sql/handler.cc | 2 +- sql/item.cc | 16 ++--- sql/item.h | 2 +- sql/item_cmpfunc.cc | 24 +++---- sql/item_func.cc | 36 +++++----- sql/item_strfunc.cc | 19 +++--- sql/item_subselect.cc | 26 ++++---- sql/item_sum.cc | 14 ++-- sql/item_timefunc.cc | 56 ++++++++-------- sql/item_uniq.h | 4 +- sql/key.cc | 4 +- sql/log.cc | 6 +- sql/log_event.cc | 18 ++--- sql/mysqld.cc | 2 + sql/opt_range.cc | 10 +-- sql/parse_file.cc | 181 ++++++++++++++++++++++++++++++++++---------------- sql/parse_file.h | 32 ++++++++- sql/protocol.cc | 2 +- sql/repl_failsafe.cc | 13 ++-- sql/share/errmsg.txt | 2 + sql/slave.cc | 10 +-- sql/sp.cc | 20 +++--- sql/sp_head.cc | 46 ++++++------- sql/spatial.cc | 2 +- sql/sql_acl.cc | 104 +++++++++++++++-------------- sql/sql_analyse.cc | 58 ++++++++-------- sql/sql_lex.cc | 10 +-- sql/sql_load.cc | 3 +- sql/sql_parse.cc | 4 +- sql/sql_prepare.cc | 2 +- sql/sql_select.cc | 73 ++++++++++---------- sql/sql_show.cc | 168 ++++++++++++++++++++++++---------------------- sql/sql_string.cc | 12 ++-- sql/sql_string.h | 2 + sql/sql_table.cc | 52 ++++++++------- sql/sql_trigger.cc | 105 +++++++++++++++++++++++++---- sql/sql_view.cc | 8 ++- sql/structs.h | 2 - sql/table.cc | 2 +- sql/tztime.cc | 2 +- 44 files changed, 710 insertions(+), 506 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 381a13c3263..f9457886dfb 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1272,9 +1272,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")); } @@ -1655,7 +1655,7 @@ bool Field::needs_quotes(void) void Field_null::sql_type(String &res) const { - res.set_ascii("null", 4); + res.set_ascii(STRING_WITH_LEN("null")); } @@ -1667,7 +1667,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) @@ -4113,7 +4113,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 { @@ -4384,7 +4384,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 { @@ -4673,7 +4673,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 @@ -4805,7 +4805,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")); } @@ -5074,7 +5074,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")); } /**************************************************************************** @@ -5381,7 +5381,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")); } @@ -5564,7 +5564,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")); } @@ -5838,7 +5838,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")); } /**************************************************************************** @@ -6061,7 +6061,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")); } @@ -6454,7 +6454,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")); } @@ -7174,10 +7174,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")); } } @@ -7397,28 +7397,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); } } @@ -7695,7 +7695,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; @@ -7809,7 +7809,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_berkeley.cc b/sql/ha_berkeley.cc index 3a2bdf3ef9a..72af402a0dc 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -308,7 +308,7 @@ int berkeley_show_logs(Protocol *protocol) { protocol->prepare_for_resend(); protocol->store(*a, system_charset_info); - protocol->store("BDB", 3, system_charset_info); + protocol->store(STRING_WITH_LEN("BDB"), system_charset_info); if (f && *f && strcmp(*a, *f) == 0) { f++; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index d6d6b5980f6..11a301a14db 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2627,9 +2627,9 @@ 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(STRING_WITH_LEN(": ")); buf->append(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE); remote_error_number= 0; diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 5911d6c0fbc..da4136def68 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -490,10 +490,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=(")); MYRG_TABLE *open_table,*first; current_db= table->s->db; diff --git a/sql/handler.cc b/sql/handler.cc index 7724b27949e..4f49b13c01e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1684,7 +1684,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 1850b7d05c3..015d796b755 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)); } } @@ -1031,7 +1031,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); @@ -4852,7 +4852,7 @@ void Item_ref::make_field(Send_field *field) void Item_ref_null_helper::print(String *str) { - str->append("(", 18); + str->append(STRING_WITH_LEN("(")); if (ref) (*ref)->print(str); else @@ -4969,7 +4969,7 @@ bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const void Item_null_helper::print(String *str) { - str->append("(", 14); + str->append(STRING_WITH_LEN("(")); store->print(str); str->append(')'); } @@ -5029,10 +5029,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(')'); } @@ -5126,7 +5126,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(')'); } @@ -5387,7 +5387,7 @@ Item_cache* Item_cache::get_cache(Item_result type) void Item_cache::print(String *str) { - str->append("(", 8); + str->append(STRING_WITH_LEN("(")); if (example) example->print(str); else diff --git a/sql/item.h b/sql/item.h index 8bc659c3060..6af53e0daa8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1055,7 +1055,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 06cb83a7101..2a7754c0217 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 7598865fbb7..c20a774e57e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -794,9 +794,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)")); } @@ -855,9 +855,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)")); } @@ -927,9 +927,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)")); } @@ -2234,7 +2234,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); @@ -3297,7 +3297,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); @@ -3811,9 +3811,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(')'); } @@ -3821,9 +3821,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(')'); } @@ -4054,7 +4054,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(')'); } @@ -4479,15 +4479,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() 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 8afc885e59b..f2d6f2b5899 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -533,7 +533,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); } @@ -1339,11 +1339,11 @@ err: void Item_in_subselect::print(String *str) { if (transformed) - str->append("", 8); + str->append(STRING_WITH_LEN("")); else { left_expr->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); } Item_subselect::print(str); } @@ -1362,7 +1362,7 @@ Item_allany_subselect::select_transformer(JOIN *join) void Item_allany_subselect::print(String *str) { if (transformed) - str->append("", 8); + str->append(STRING_WITH_LEN("")); else { left_expr->print(str); @@ -1794,16 +1794,16 @@ void subselect_union_engine::print(String *str) void subselect_uniquesubquery_engine::print(String *str) { - str->append("(", 23); + str->append(STRING_WITH_LEN("(")); tab->ref.items[0]->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name); 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(')'); @@ -1812,18 +1812,18 @@ void subselect_uniquesubquery_engine::print(String *str) void subselect_indexsubquery_engine::print(String *str) { - str->append("(", 15); + str->append(STRING_WITH_LEN("(")); tab->ref.items[0]->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name); 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 b2eaf39d624..506d2a16108 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3156,9 +3156,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) @@ -3167,19 +3167,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 2b0314bb287..a9559e35d92 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(')'); @@ -2609,14 +2609,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 +2825,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 +2905,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 4bd71d2fa47..9d86095f33e 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/log.cc b/sql/log.cc index 4b3d6698051..6099aaf8223 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -131,7 +131,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)); } @@ -155,7 +155,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 @@ -1848,7 +1848,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 2390ebd4214..b31f26d6058 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -160,7 +160,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; @@ -2991,7 +2991,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); } @@ -4163,7 +4163,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, @@ -4332,7 +4332,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()) { @@ -4816,23 +4816,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/mysqld.cc b/sql/mysqld.cc index 890b1716212..d85cd209c09 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -496,6 +496,8 @@ pthread_cond_t COND_refresh,COND_thread_count; pthread_t signal_thread; pthread_attr_t connection_attrib; +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; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index de52811c12f..323e829f219 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6691,7 +6691,7 @@ void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str) QUICK_RANGE_SELECT *quick; bool first= TRUE; List_iterator_fast it(quick_selects); - str->append("sort_union("); + str->append(STRING_WITH_LEN("sort_union(")); while ((quick= it++)) { if (!first) @@ -6713,7 +6713,7 @@ void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str) bool first= TRUE; QUICK_RANGE_SELECT *quick; List_iterator_fast it(quick_selects); - str->append("intersect("); + str->append(STRING_WITH_LEN("intersect(")); while ((quick= it++)) { KEY *key_info= head->key_info + quick->index; @@ -6737,7 +6737,7 @@ void QUICK_ROR_UNION_SELECT::add_info_string(String *str) bool first= TRUE; QUICK_SELECT_I *quick; List_iterator_fast it(quick_selects); - str->append("union("); + str->append(STRING_WITH_LEN("union(")); while ((quick= it++)) { if (!first) @@ -8868,7 +8868,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())); @@ -8894,7 +8894,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 d3e5645bafc..69757e0be06 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; } @@ -663,6 +663,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 *nlist= (List*)(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 @@ -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 *list; ulonglong *num; - List *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*)(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..a165bac6d7e 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -572,7 +572,7 @@ bool Protocol::send_fields(List *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), diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 2f00e43deec..d76be2ec2e4 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -502,7 +502,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); @@ -795,7 +795,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)); @@ -821,8 +821,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)); @@ -875,7 +876,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)); @@ -933,7 +934,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/share/errmsg.txt b/sql/share/errmsg.txt index a25d1196904..d2da1d0a7a8 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5423,3 +5423,5 @@ 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)" diff --git a/sql/slave.cc b/sql/slave.cc index 82d9799fec9..065d9c787ce 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1397,7 +1397,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))) { @@ -1423,7 +1423,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)) && @@ -1458,7 +1459,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)) && @@ -1485,7 +1487,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 451cec75236..7228b4bc4ab 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1585,30 +1585,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: @@ -1616,12 +1616,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'); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 08a189165b5..101f8213a3d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -816,9 +816,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); @@ -1173,7 +1173,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++) @@ -2014,7 +2014,7 @@ void sp_instr_stmt::print(String *str) { str->reserve(12); - str->append("stmt "); + str->append(STRING_WITH_LEN("stmt ")); str->qs_append((uint)m_lex_keeper.sql_command()); } @@ -2055,7 +2055,7 @@ void sp_instr_set::print(String *str) { str->reserve(12); - str->append("set "); + str->append(STRING_WITH_LEN("set ")); str->qs_append(m_offset); str->append(' '); m_value->print(str); @@ -2090,9 +2090,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->print(str); - str->append(":=", 2); + str->append(STRING_WITH_LEN(":=")); value->print(str); } @@ -2115,7 +2115,7 @@ void sp_instr_jump::print(String *str) { str->reserve(12); - str->append("jump "); + str->append(STRING_WITH_LEN("jump ")); str->qs_append(m_dest); } @@ -2197,7 +2197,7 @@ void sp_instr_jump_if::print(String *str) { str->reserve(12); - str->append("jump_if "); + str->append(STRING_WITH_LEN("jump_if ")); str->qs_append(m_dest); str->append(' '); m_expr->print(str); @@ -2258,7 +2258,7 @@ void sp_instr_jump_if_not::print(String *str) { str->reserve(16); - str->append("jump_if_not "); + str->append(STRING_WITH_LEN("jump_if_not ")); str->qs_append(m_dest); str->append(' '); m_expr->print(str); @@ -2316,7 +2316,7 @@ void sp_instr_freturn::print(String *str) { str->reserve(12); - str->append("freturn "); + str->append(STRING_WITH_LEN("freturn ")); str->qs_append((uint)m_type); str->append(' '); m_value->print(str); @@ -2344,13 +2344,13 @@ void sp_instr_hpush_jump::print(String *str) { str->reserve(32); - str->append("hpush_jump "); + str->append(STRING_WITH_LEN("hpush_jump ")); str->qs_append(m_dest); - str->append(" t="); + str->append(STRING_WITH_LEN(" t=")); str->qs_append(m_type); - str->append(" f="); + str->append(STRING_WITH_LEN(" f=")); str->qs_append(m_frame); - str->append(" h="); + str->append(STRING_WITH_LEN(" h=")); str->qs_append(m_ip+1); } @@ -2387,7 +2387,7 @@ void sp_instr_hpop::print(String *str) { str->reserve(12); - str->append("hpop "); + str->append(STRING_WITH_LEN("hpop ")); str->qs_append(m_count); } @@ -2422,7 +2422,7 @@ void sp_instr_hreturn::print(String *str) { str->reserve(16); - str->append("hreturn "); + str->append(STRING_WITH_LEN("hreturn ")); str->qs_append(m_frame); if (m_dest) { @@ -2474,7 +2474,7 @@ sp_instr_cpush::execute(THD *thd, uint *nextp) void sp_instr_cpush::print(String *str) { - str->append("cpush"); + str->append(STRING_WITH_LEN("cpush")); } @@ -2496,7 +2496,7 @@ void sp_instr_cpop::print(String *str) { str->reserve(12); - str->append("cpop "); + str->append(STRING_WITH_LEN("cpop ")); str->qs_append(m_count); } @@ -2571,7 +2571,7 @@ void sp_instr_copen::print(String *str) { str->reserve(12); - str->append("copen "); + str->append(STRING_WITH_LEN("copen ")); str->qs_append(m_cursor); } @@ -2600,7 +2600,7 @@ void sp_instr_cclose::print(String *str) { str->reserve(12); - str->append("cclose "); + str->append(STRING_WITH_LEN("cclose ")); str->qs_append(m_cursor); } @@ -2631,7 +2631,7 @@ sp_instr_cfetch::print(String *str) sp_pvar_t *pv; str->reserve(12); - str->append("cfetch "); + str->append(STRING_WITH_LEN("cfetch ")); str->qs_append(m_cursor); while ((pv= li++)) { @@ -2661,7 +2661,7 @@ void sp_instr_error::print(String *str) { str->reserve(12); - str->append("error "); + str->append(STRING_WITH_LEN("error ")); str->qs_append(m_errcode); } diff --git a/sql/spatial.cc b/sql/spatial.cc index 5af1bec45ca..d33966df4e0 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1791,7 +1791,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 bc8b9ba2efb..a572f03b575 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1811,19 +1811,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_lex.cc b/sql/sql_lex.cc index a302db15736..ac2d7e82fcf 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1526,9 +1526,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; } @@ -1542,7 +1542,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); @@ -1565,7 +1565,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(','); } @@ -1588,7 +1588,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_load.cc b/sql/sql_load.cc index 568778c021d..2a0145af9c7 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -680,7 +680,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 e196a84d134..647cdc663b1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4578,7 +4578,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]) { @@ -4588,7 +4588,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 ced862170ec..3a11244002e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1927,7 +1927,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 44c4ec998bb..f10e3f2f2c1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13672,7 +13672,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, "next_select()) { len+= lastop; @@ -13681,7 +13681,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 @@ -13860,7 +13860,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) @@ -13868,7 +13868,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(')'); } @@ -13878,38 +13879,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(); @@ -14026,15 +14028,18 @@ static void print_join(THD *thd, String *str, 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(')'); } @@ -14119,28 +14124,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; @@ -14161,7 +14166,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); } @@ -14172,22 +14177,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 @@ -14201,13 +14206,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 09fd982bdab..afe88167bab 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -490,22 +490,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()); @@ -716,7 +716,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); @@ -765,16 +765,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); append_identifier(thd, packet, alias, strlen(alias)); - packet->append(" (\n", 3); + packet->append(STRING_WITH_LEN(" (\n")); for (ptr=table->field ; (field= *ptr); ptr++) { @@ -783,9 +783,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() @@ -802,7 +802,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); } /* @@ -811,20 +811,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")); } /* @@ -842,9 +842,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()); @@ -859,10 +859,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); } @@ -870,15 +870,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); } } @@ -893,20 +893,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)); @@ -915,19 +915,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++) { @@ -964,71 +964,71 @@ 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=")); packet->append(file->table_type()); if (share->table_charset && !(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) @@ -1049,25 +1049,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 ")); } @@ -1125,19 +1125,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 @@ -1148,9 +1148,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; } @@ -2134,20 +2134,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); @@ -2300,8 +2304,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 { @@ -2312,11 +2316,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++) { @@ -2552,7 +2556,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 && @@ -2814,8 +2818,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, @@ -2970,7 +2974,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(); @@ -3083,13 +3087,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); } } @@ -3130,11 +3136,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, @@ -3525,9 +3531,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); } @@ -3548,9 +3554,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 c0748abf333..203b80f2924 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -700,7 +700,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); } @@ -1946,7 +1947,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()) @@ -2237,7 +2238,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 */ @@ -2274,7 +2275,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); @@ -2309,8 +2310,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; } @@ -2334,7 +2336,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; @@ -2344,41 +2346,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: @@ -2414,7 +2420,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 */ @@ -2431,7 +2437,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; @@ -2443,7 +2449,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 84cc79ee4dc..ee597e6b7b8 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 it(triggers->definitions_list); @@ -1020,7 +1036,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 +1189,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 b642d24b30d..e30a0012015 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; /* @@ -1502,7 +1503,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/structs.h b/sql/structs.h index 3c651c491d3..9421ebdc2af 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 3bc5c9a242b..8068a839052 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -110,7 +110,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err; - if (memcmp(head, "TYPE=", 5) == 0) + if (memcmp(head, STRING_WITH_LEN("TYPE=")) == 0) { // new .frm my_close(file,MYF(MY_WME)); diff --git a/sql/tztime.cc b/sql/tztime.cc index 537050e94db..1d06d4d0b8e 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)) { -- cgit v1.2.1 From 9a7efe36c6687ae34f0e697e33c2598086b69f97 Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Mon, 21 Nov 2005 13:36:48 +0300 Subject: Fixed BUG #14554: mysqldump does not separate "ROW" and trigger statement for tables created in the IGNORE_SPACE sql mode. --- client/mysqldump.c | 3 ++- mysql-test/r/mysqldump.result | 56 +++++++++++++++++++++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 24 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index b92b971ea4f..c6a57959d6d 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -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/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/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; -- cgit v1.2.1 From 7b78489e2d0247191aa31d96a06961659bcf408d Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Mon, 21 Nov 2005 16:05:40 +0100 Subject: Check for zlib with a zzlibCompileFlags() function in config/ac-macros/zlib.m4. (Patch provided by serg) --- config/ac-macros/zlib.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ], - [return compress(0, (unsigned long*) 0, "", 0);], + [return zlibCompileFlags();], [mysql_cv_compress="yes" AC_MSG_RESULT([ok])], [mysql_cv_compress="no"]) -- cgit v1.2.1 From 435c2ba671baa3251befb6f70099313e29fbd65a Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Mon, 21 Nov 2005 19:59:58 +0400 Subject: Additional fix for Bug#14255 CAST(x AS BINARY(N)) does not pad cast.result: cast.test: Avoid 0x00 byte in test results, use HEX instead. --- mysql-test/r/cast.result | 10 +++++----- mysql-test/t/cast.test | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 817be3a2e7c..98beedc5b1c 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -165,9 +165,9 @@ 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 ' @@ -185,9 +185,9 @@ 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 +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` ( 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; -- cgit v1.2.1 From 3d1c1d7f686804504196351f6e96b6f5fc841d84 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Mon, 21 Nov 2005 21:11:28 +0400 Subject: cast.result: Fixing test results accordingly. item_timefunc.cc: Displaying BINARY or CHAR in error messages, depending on the character set. --- mysql-test/r/cast.result | 26 +++++++++++++------------- sql/item_timefunc.cc | 3 ++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 98beedc5b1c..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 @@ -169,13 +169,13 @@ hex(cast(_latin1'a' AS char(2))) as c5; c1 c2 c3 c4 c5 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,8 +183,8 @@ 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 ' +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 @@ -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/sql/item_timefunc.cc b/sql/item_timefunc.cc index 54513d93636..5efabbff726 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2357,7 +2357,8 @@ String *Item_char_typecast::val_str(String *str) 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), "CHAR(%lu)", length); + 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 -- cgit v1.2.1 From 87a199fc2a7ba6ec7da38267172eb2da754756ac Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Mon, 21 Nov 2005 21:11:02 +0200 Subject: Avoiding removing dummy TABLE allocated on the stack (BUG#14726). --- mysql-test/r/view_grant.result | 17 +++++++++++++++++ mysql-test/t/view_grant.test | 36 ++++++++++++++++++++++++++++++++++++ sql/sql_base.cc | 17 ++++++++--------- 3 files changed, 61 insertions(+), 9 deletions(-) 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/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/sql/sql_base.cc b/sql/sql_base.cc index 1e7fce9001f..9af3c7c9518 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1199,17 +1199,16 @@ 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->db, - table_list->table_name, - alias, table_list, mem_root)) - { - table->next=table->prev=table; - free_cache_entry(table); - } - else + if (!open_unireg_entry(thd, table, table_list->db, + table_list->table_name, + alias, table_list, mem_root)) { DBUG_ASSERT(table_list->view != 0); VOID(pthread_mutex_unlock(&LOCK_open)); -- cgit v1.2.1 From 9851469d128305122ab56ff0c18644ace64c05ab Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Tue, 22 Nov 2005 02:40:08 +0100 Subject: Added explicit casts, since on i686, the fprintf function does not cast my_off_t correctly. Changed wrong printf to fprintf. --- sql/log_event.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 2390ebd4214..1a192ffaf5b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -901,14 +901,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; } @@ -925,8 +927,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; @@ -938,8 +942,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); } } } -- cgit v1.2.1 From 962d2df6b00a5360c44bad5bf59c547b49c82b45 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 22 Nov 2005 13:06:52 +0100 Subject: Some final cleanup of the sp_instr print methods. --- sql/sp_head.cc | 65 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b11260ab999..c208840155d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2048,14 +2048,19 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } -#define STMT_PRINT_MAXLEN 40 +/* + 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) { uint i, len; - /* Reserve enough space for 'stmt CMD "..."'; max+20 is more than enough. */ - if (str->reserve(STMT_PRINT_MAXLEN+20)) + /* stmt CMD "..." */ + if (str->reserve(SP_STMT_PRINT_MAXLEN+SP_INSTR_UINT_MAXLEN+8)) return; str->qs_append("stmt ", 5); str->qs_append((uint)m_lex_keeper.sql_command()); @@ -2065,8 +2070,8 @@ sp_instr_stmt::print(String *str) Print the query string (but not too much of it), just to indicate which statement it is. */ - if (len > STMT_PRINT_MAXLEN) - len= STMT_PRINT_MAXLEN-3; + 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++) { @@ -2075,11 +2080,11 @@ sp_instr_stmt::print(String *str) else str->qs_append(m_query.str[i]); } - if (m_query.length > STMT_PRINT_MAXLEN) + if (m_query.length > SP_STMT_PRINT_MAXLEN) str->qs_append("...", 3); /* Indicate truncated string */ str->qs_append('"'); } -#undef STMT_PRINT_MAXLEN +#undef SP_STMT_PRINT_MAXLEN int sp_instr_stmt::exec_core(THD *thd, uint *nextp) @@ -2116,7 +2121,8 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) void sp_instr_set::print(String *str) { - int rsrv = 16; + /* 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... */ @@ -2164,7 +2170,7 @@ 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("set_trigger_field ", 18); trigger_field->print(str); str->append(":=", 2); value->print(str); @@ -2188,7 +2194,8 @@ sp_instr_jump::execute(THD *thd, uint *nextp) void sp_instr_jump::print(String *str) { - if (str->reserve(12)) + /* jump dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) return; str->qs_append("jump ", 5); str->qs_append(m_dest); @@ -2271,7 +2278,8 @@ sp_instr_jump_if::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if::print(String *str) { - if (str->reserve(32)) + /* jump_if dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too return; str->qs_append("jump_if ", 8); str->qs_append(m_dest); @@ -2333,7 +2341,8 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if_not::print(String *str) { - if (str->reserve(32)) + /* jump_if_not dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too return; str->qs_append("jump_if_not ", 12); str->qs_append(m_dest); @@ -2392,7 +2401,8 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) void sp_instr_freturn::print(String *str) { - if (str->reserve(32)) + /* freturn type expr... */ + if (str->reserve(UINT_MAX+8+32)) // Add some for the expr. too return; str->qs_append("freturn ", 8); str->qs_append((uint)m_type); @@ -2421,7 +2431,8 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) void sp_instr_hpush_jump::print(String *str) { - if (str->reserve(32)) + /* hpush_jump dest fsize type */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21)) return; str->qs_append("hpush_jump ", 11); str->qs_append(m_dest); @@ -2479,7 +2490,8 @@ sp_instr_hpop::execute(THD *thd, uint *nextp) void sp_instr_hpop::print(String *str) { - if (str->reserve(12)) + /* hpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) return; str->qs_append("hpop ", 5); str->qs_append(m_count); @@ -2515,7 +2527,8 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) void sp_instr_hreturn::print(String *str) { - if (str->reserve(20)) + /* hreturn framesize dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9)) return; str->qs_append("hreturn ", 8); str->qs_append(m_frame); @@ -2570,8 +2583,9 @@ void sp_instr_cpush::print(String *str) { LEX_STRING n; - uint rsrv= 12; 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; @@ -2604,7 +2618,8 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) void sp_instr_cpop::print(String *str) { - if (str->reserve(12)) + /* cpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) return; str->qs_append("cpop ", 5); str->qs_append(m_count); @@ -2681,8 +2696,9 @@ void sp_instr_copen::print(String *str) { LEX_STRING n; - uint rsrv= 16; 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; @@ -2722,8 +2738,9 @@ void sp_instr_cclose::print(String *str) { LEX_STRING n; - uint rsrv= 16; 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; @@ -2764,8 +2781,9 @@ sp_instr_cfetch::print(String *str) List_iterator_fast li(m_varlist); sp_pvar_t *pv; LEX_STRING n; - uint rsrv= 16; 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; @@ -2780,7 +2798,7 @@ sp_instr_cfetch::print(String *str) str->qs_append(m_cursor); while ((pv= li++)) { - if (str->reserve(pv->name.length+10)) + if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2)) return; str->qs_append(' '); str->qs_append(pv->name.str, pv->name.length); @@ -2808,7 +2826,8 @@ sp_instr_error::execute(THD *thd, uint *nextp) void sp_instr_error::print(String *str) { - if (str->reserve(12)) + /* error code */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+6)) return; str->qs_append("error ", 6); str->qs_append(m_errcode); -- cgit v1.2.1 From 6c2f6e29b96bb7089278206ee796eb6862d70065 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 22 Nov 2005 14:25:44 +0100 Subject: Post-merge fixes in sp_head.cc (print methods). --- sql/sp_head.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a3a7af7ab67..5161ad0f64b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1898,7 +1898,7 @@ sp_head::show_routine_code(THD *thd) List field_list; sp_instr *i; bool full_access; - int res; + int res= 0; uint ip; DBUG_ENTER("sp_head::show_routine_code"); DBUG_PRINT("info", ("procedure: %s", m_name.str)); @@ -2104,9 +2104,9 @@ sp_instr_stmt::print(String *str) /* 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(STRING_WITH_LEN("stmt ")); str->qs_append((uint)m_lex_keeper.sql_command()); - str->qs_append(" \"", 2); + str->qs_append(STRING_WITH_LEN(" \"")); len= m_query.length; /* Print the query string (but not too much of it), just to indicate which @@ -2123,7 +2123,7 @@ sp_instr_stmt::print(String *str) str->qs_append(m_query.str[i]); } if (m_query.length > SP_STMT_PRINT_MAXLEN) - str->qs_append("...", 3); /* Indicate truncated string */ + str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */ str->qs_append('"'); } #undef SP_STMT_PRINT_MAXLEN @@ -2483,19 +2483,19 @@ sp_instr_hpush_jump::print(String *str) switch (m_type) { case SP_HANDLER_NONE: - str->qs_append(" NONE", 5); // This would be a bug + str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug break; case SP_HANDLER_EXIT: - str->qs_append(" EXIT", 5); + str->qs_append(STRING_WITH_LEN(" EXIT")); break; case SP_HANDLER_CONTINUE: - str->qs_append(" CONTINUE", 9); + str->qs_append(STRING_WITH_LEN(" CONTINUE")); break; case SP_HANDLER_UNDO: - str->qs_append(" UNDO", 5); + str->qs_append(STRING_WITH_LEN(" UNDO")); break; default: - str->qs_append(" UNKNOWN:", 9); // This would be a bug as well + str->qs_append(STRING_WITH_LEN(" UNKNOWN:")); // This would be a bug as well str->qs_append(m_type); } } @@ -2633,7 +2633,7 @@ sp_instr_cpush::print(String *str) rsrv+= n.length; if (str->reserve(rsrv)) return; - str->qs_append(STRING_WITH_LENGTH("cpush ")); + str->qs_append(STRING_WITH_LEN("cpush ")); if (found) { str->qs_append(n.str, n.length); -- cgit v1.2.1 From 7827fec43e6ce7b213c3049c62b2077e8345149a Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 22 Nov 2005 16:01:04 +0100 Subject: Set type and default correctly for local SP variables during parsing. --- sql/sql_yacc.yy | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 76cd19dd741..8c7bcc31689 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1605,13 +1605,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)); @@ -1620,7 +1621,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; -- cgit v1.2.1 From 2bcd68973bb3ae278399a69b4642e76368edd31e Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 23 Nov 2005 00:50:37 +0200 Subject: Fix for BUG#13549 "Server crash with nested stored procedures if inner routine has more local variables than outer one, and one of its last variables was used as argument to NOT operator". THD::spcont was non-0 when we were parsing stored routine/trigger definition during execution of another stored routine. This confused methods of Item_splocal and forced them use wrong runtime context. Fix ensures that we always have THD::spcont equal to zero during routine/trigger body parsing. This also allows to avoid problems with errors which occur during parsing and SQL exception handlers. --- mysql-test/r/sp.result | 17 +++++++++++++++++ mysql-test/r/trigger.result | 14 ++++++++++++++ mysql-test/t/sp.test | 27 +++++++++++++++++++++++++++ mysql-test/t/trigger.test | 28 ++++++++++++++++++++++++++++ sql/item.cc | 7 ++++++- sql/item.h | 9 +++++++++ sql/protocol.cc | 38 +++++++++++++++++++------------------- sql/protocol.h | 2 +- sql/sp.cc | 6 +++++- sql/sp_head.cc | 9 +++++++++ sql/sp_rcontext.h | 8 ++++++++ sql/sql_cache.h | 2 +- sql/sql_class.cc | 8 +++++++- sql/sql_class.h | 7 +++++++ sql/sql_trigger.cc | 3 +++ sql/sql_yacc.yy | 20 +++++++++++++++++--- 16 files changed, 178 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1b8cde6d3db..bb20f77baa9 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3435,4 +3435,21 @@ 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 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 table t1,t2; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index b305691fa18..73f498d4133 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -738,3 +738,17 @@ f1 1 drop trigger t1_bi; drop tables t1, t2; +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/t/sp.test b/mysql-test/t/sp.test index e16e7456056..8c70bc9f6b1 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4313,7 +4313,34 @@ 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#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#NNNN: New bug synopsis diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index cd79eb82ace..e66f092e695 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -875,3 +875,31 @@ drop function f1; drop view v1; drop table t1, t2, t3; --enable_parsing + +# +# 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/sql/item.cc b/sql/item.cc index 966dbbaec53..7a8ce37ce63 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -868,7 +868,7 @@ Item * Item_splocal::this_item() { THD *thd= current_thd; - + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset); } @@ -876,6 +876,7 @@ 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); } @@ -884,6 +885,7 @@ Item_splocal::this_const_item() const { THD *thd= current_thd; + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset); } @@ -893,7 +895,10 @@ Item_splocal::type() const THD *thd= current_thd; if (thd->spcont) + { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset)->type(); + } return NULL_ITEM; // Anything but SUBSELECT_ITEM } diff --git a/sql/item.h b/sql/item.h index a8f013f60d4..516cb05c2a2 100644 --- a/sql/item.h +++ b/sql/item.h @@ -703,6 +703,8 @@ public: }; +class sp_head; + /* A reference to local SP variable (incl. reference to SP parameter), used in runtime. @@ -720,6 +722,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; /* diff --git a/sql/protocol.cc b/sql/protocol.cc index ade94a483a8..490f27ab548 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -494,7 +494,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 } @@ -547,7 +547,7 @@ bool Protocol::send_fields(List *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; @@ -644,7 +644,7 @@ bool Protocol::send_fields(List *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 } @@ -728,14 +728,14 @@ bool Protocol::store(I_List* 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]; @@ -769,7 +769,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 || @@ -786,7 +786,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 || @@ -801,7 +801,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 @@ -813,7 +813,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); @@ -827,7 +827,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); @@ -841,7 +841,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++; @@ -856,7 +856,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++; @@ -870,7 +870,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++; @@ -882,7 +882,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++; @@ -896,7 +896,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]; @@ -917,7 +917,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); @@ -940,7 +940,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++; @@ -959,7 +959,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++; @@ -1084,7 +1084,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/sp.cc b/sql/sp.cc index 4f7b544f5c7..4a2da1bb8e6 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -380,6 +380,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) { String defstr; LEX *oldlex= thd->lex; + sp_rcontext *save_spcont= thd->spcont; char olddb[128]; bool dbchanged; enum enum_sql_command oldcmd= thd->lex->sql_command; @@ -422,6 +423,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) thd->lex->found_semicolon= tmpfsc; } + thd->spcont= 0; if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL) { LEX *newlex= thd->lex; @@ -439,12 +441,14 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) else { if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) - goto done; + goto db_done; *sphp= thd->lex->sphead; (*sphp)->set_info((char *)definer, (uint)strlen(definer), created, modified, &chistics, sql_mode); (*sphp)->optimize(); } +db_done: + thd->spcont= save_spcont; thd->lex->sql_command= oldcmd; thd->variables.sql_mode= old_sql_mode; thd->variables.select_limit= select_limit; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 671acbc2a0c..3e25544839f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1112,6 +1112,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(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); @@ -1256,6 +1259,9 @@ int sp_head::execute_procedure(THD *thd, List *args) { // Create a temporary old context if (!(octx= new sp_rcontext(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 */ @@ -1267,6 +1273,9 @@ int sp_head::execute_procedure(THD *thd, List *args) thd->spcont= save_spcont; DBUG_RETURN(-1); } +#ifndef DBUG_OFF + nctx->owner= this; +#endif if (csize > 0 || hmax > 0 || cmax > 0) { diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 22fa4f6e865..2988793083e 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(uint fsize, uint hmax, uint cmax); ~sp_rcontext() diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 123d16b606d..69a0d6cd05d 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -410,7 +410,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 2917626ff35..32bbb456689 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1490,7 +1490,13 @@ int select_dumpvar::prepare(List &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 DEBUG_OFF + var->owner= mv->owner; +#endif + } else { Item_func_set_user_var *var= new Item_func_set_user_var(mv->s, item); diff --git a/sql/sql_class.h b/sql/sql_class.h index 7cbfc19123f..56cb606558d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2075,6 +2075,13 @@ public: class my_var : public Sql_alloc { public: LEX_STRING s; +#ifndef DEBUG_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_trigger.cc b/sql/sql_trigger.cc index df8de59508d..27bee87c012 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -646,6 +646,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, char *trg_name_buff; List_iterator_fast itm(triggers->definition_modes_list); LEX *old_lex= thd->lex, lex; + sp_rcontext *save_spcont= thd->spcont; ulong save_sql_mode= thd->variables.sql_mode; thd->lex= &lex; @@ -660,6 +661,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) { /* @@ -712,6 +714,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; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f28fbe5c803..298c282d625 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2351,8 +2351,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 DEBUG_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); @@ -5925,7 +5929,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 DEBUG_OFF + if (var) + var->owner= lex->sphead; +#endif } } ; @@ -7224,6 +7234,10 @@ simple_ident: Item_splocal *splocal; splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev - lex->sphead->m_tmp_query); +#ifndef DEBUG_OFF + if (splocal) + splocal->owner= lex->sphead; +#endif $$ = (Item*) splocal; lex->variables_used= 1; lex->safe_to_cache_query=0; -- cgit v1.2.1 From 7bd691f11e961060bb0a665936f6712cb7d7bb22 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 23 Nov 2005 01:11:19 +0200 Subject: Recursion support made for SP (BUG#10100). --- client/mysqltest.c | 40 +++--- mysql-test/r/sp-dynamic.result | 15 ++- mysql-test/r/sp-error.result | 9 +- mysql-test/r/sp.result | 185 ++++++++++++++++++++++++++ mysql-test/r/trigger.result | 3 + mysql-test/r/variables.result | 8 ++ mysql-test/t/sp-dynamic.test | 17 ++- mysql-test/t/sp-error.test | 7 +- mysql-test/t/sp.test | 154 ++++++++++++++++++++++ mysql-test/t/trigger.test | 4 + mysql-test/t/variables.test | 4 + sql/item_func.cc | 11 +- sql/mysqld.cc | 6 + sql/set_var.cc | 5 + sql/share/errmsg.txt | 4 +- sql/sp.cc | 290 ++++++++++++++++++++++------------------- sql/sp.h | 6 +- sql/sp_head.cc | 96 ++++++++++---- sql/sp_head.h | 28 ++++ sql/sql_base.cc | 5 + sql/sql_class.h | 1 + sql/sql_parse.cc | 18 ++- 22 files changed, 714 insertions(+), 202 deletions(-) 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/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 50ff7ea264a..ae539e1654c 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 d50e6dd3751..1665143d6d2 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3617,4 +3617,189 @@ count(*) drop table t3, t4| drop procedure bug14210| set @@session.max_heap_table_size=default| +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/trigger.result b/mysql-test/r/trigger.result index b305691fa18..66f7f682cec 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 diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 3ecc48620b1..df180218a09 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/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 e2343cd905c..c79f2294baf 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 eaf69c0ab03..bff5a9496b6 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4541,6 +4541,160 @@ drop table t3, t4| drop procedure bug14210| set @@session.max_heap_table_size=default| +# +# 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 # diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index cd79eb82ace..c17bee34130 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; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index f23cc0152c1..2d0e2dbc9c9 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/sql/item_func.cc b/sql/item_func.cc index f467981540b..7ff59478e1f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4690,10 +4690,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); @@ -4925,7 +4931,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/mysqld.cc b/sql/mysqld.cc index acad378353b..79e4f0a6ca9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4543,6 +4543,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, @@ -5745,6 +5746,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/set_var.cc b/sql/set_var.cc index 8cf7311265c..79443a05bfe 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -258,6 +258,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); @@ -628,6 +630,7 @@ sys_var *sys_variables[]= &sys_max_relay_log_size, &sys_max_seeks_for_key, &sys_max_sort_length, + &sys_max_sp_recursion_depth, &sys_max_tmp_tables, &sys_max_user_connections, &sys_max_write_lock_count, @@ -892,6 +895,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/errmsg.txt b/sql/share/errmsg.txt index f85bda90e81..8a2334f0033 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 @@ -5421,3 +5421,5 @@ ER_NO_REFERENCED_ROW_2 23000 eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)" ER_SP_BAD_VAR_SHADOW 42000 eng "Variable '%-.64s' must be quoted with `...`, or renamed" +ER_SP_RECURSION_LIMIT + eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.64s" diff --git a/sql/sp.cc b/sql/sp.cc index 8386c5d58a2..861a41d8501 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -29,6 +29,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); /* * @@ -377,83 +382,77 @@ 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 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; + 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_info((char *)definer, (uint)strlen(definer), - 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); + 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_info((char *)definer, (uint)strlen(definer), + created, modified, &chistics, sql_mode); + (*sphp)->optimize(); + } + thd->variables.sql_mode= old_sql_mode; + thd->variables.select_limit= select_limit; +end: + thd->lex= oldlex; + return ret; } @@ -898,45 +897,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) { @@ -954,8 +1014,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); @@ -1023,7 +1085,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); @@ -1049,42 +1112,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) { @@ -1132,7 +1159,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); @@ -1442,10 +1470,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, @@ -1460,8 +1484,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) { diff --git a/sql/sp.h b/sql/sp.h index 933e5793e4c..7f314b8903e 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -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 abc66ce0b21..cb0413947df 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -437,7 +437,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); @@ -615,6 +616,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); } @@ -840,6 +842,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. @@ -869,37 +896,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 && @@ -1074,6 +1095,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); } diff --git a/sql/sp_head.h b/sql/sp_head.h index ed0f3987e01..b9de19c0927 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -140,6 +140,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 @@ -262,6 +288,8 @@ public: void optimize(); void opt_mark(uint ip); + void recursion_level_error(); + inline sp_instr * get_instr(uint i) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1e7fce9001f..70960dbc25e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1087,6 +1087,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); key_length= (uint) (strmov(strmov(key, table_list->db)+1, diff --git a/sql/sql_class.h b/sql/sql_class.h index 2d1880a6d9d..dec24121fee 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -534,6 +534,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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4bbca55f6ba..4d926e62afe 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3694,7 +3694,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; @@ -4228,7 +4229,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); @@ -4364,9 +4366,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) { @@ -4435,9 +4439,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) { -- cgit v1.2.1 From e6b04edbb119c621781615df84d9ddd2f20ba897 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 23 Nov 2005 01:29:25 +0200 Subject: merge --- sql/sp.cc | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/sql/sp.cc b/sql/sp.cc index 861a41d8501..f98795c54a5 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -400,6 +400,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, 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; @@ -430,6 +431,9 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length()); + (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); + (*sphp)->set_info(created, modified, &chistics, sql_mode); + thd->spcont= 0; if (yyparse(thd) || thd->is_fatal_error || newlex.sphead == NULL) { sp_head *sp= newlex.sphead; @@ -442,12 +446,15 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, else { if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) - goto end; + goto db_end; *sphp= newlex.sphead; + (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); (*sphp)->set_info((char *)definer, (uint)strlen(definer), created, modified, &chistics, sql_mode); (*sphp)->optimize(); } +db_end: + thd->spcont= save_spcont; thd->variables.sql_mode= old_sql_mode; thd->variables.select_limit= select_limit; end: @@ -550,12 +557,13 @@ db_create_routine(THD *thd, int type, sp_head *sp) store(sp->m_chistics->comment.str, sp->m_chistics->comment.length, system_charset_info); - if (!trust_routine_creators && mysql_bin_log.is_open()) + if ((sp->m_type == TYPE_ENUM_FUNCTION) && + !trust_function_creators && mysql_bin_log.is_open()) { if (!sp->m_chistics->detistic) { /* - Note that for a _function_ this test is not enough; one could use + Note that this test is not perfect; one could use a non-deterministic read-only function in an update statement. */ enum enum_sp_data_access access= @@ -1606,30 +1614,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: @@ -1637,12 +1645,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'); } -- cgit v1.2.1 From 83d692da888281576b7f7dd4fee1faa5be7eff68 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 23 Nov 2005 02:49:44 +0200 Subject: postmerge fix --- mysql-test/r/sp.result | 134 ++++++++++++++++++++++++------------------------- sql/item.cc | 1 - sql/sp.cc | 12 ++--- sql/sql_parse.cc | 6 ++- sql/sql_trigger.cc | 1 + 5 files changed, 76 insertions(+), 78 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index b1216f94245..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| @@ -3617,6 +3620,70 @@ count(*) drop table t3, t4| drop procedure bug14210| set @@session.max_heap_table_size=default| +drop function if exists bug14723| +drop procedure if exists bug14723| +/*!50003 create function bug14723() +returns bigint(20) +main_loop: begin +return 42; +end */;; +show create function bug14723;; +Function sql_mode Create Function +bug14723 CREATE FUNCTION `bug14723`() RETURNS bigint(20) +main_loop: begin +return 42; +end +select bug14723();; +bug14723() +42 +/*!50003 create procedure bug14723() +main_loop: begin +select 42; +end */;; +show create procedure bug14723;; +Procedure sql_mode Create Procedure +bug14723 CREATE PROCEDURE `bug14723`() +main_loop: begin +select 42; +end +call bug14723();; +42 +42 +drop function bug14723| +drop procedure bug14723| +create procedure bug14845() +begin +declare a char(255); +declare done int default 0; +declare c cursor for select count(*) from t1 where 1 = 0; +declare continue handler for sqlstate '02000' set done = 1; +open c; +repeat +fetch c into a; +if not done then +select a; +end if; +until done end repeat; +close c; +end| +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| @@ -3802,71 +3869,4 @@ drop procedure bug10100pd| drop procedure bug10100pc| drop view v1| drop table t3| -drop function if exists bug14723| -drop procedure if exists bug14723| -/*!50003 create function bug14723() -returns bigint(20) -main_loop: begin -return 42; -end */;; -show create function bug14723;; -Function sql_mode Create Function -bug14723 CREATE FUNCTION `bug14723`() RETURNS bigint(20) -main_loop: begin -return 42; -end -select bug14723();; -bug14723() -42 -/*!50003 create procedure bug14723() -main_loop: begin -select 42; -end */;; -show create procedure bug14723;; -Procedure sql_mode Create Procedure -bug14723 CREATE PROCEDURE `bug14723`() -main_loop: begin -select 42; -end -call bug14723();; -42 -42 -drop function bug14723| -drop procedure bug14723| -create procedure bug14845() -begin -declare a char(255); -declare done int default 0; -declare c cursor for select count(*) from t1 where 1 = 0; -declare continue handler for sqlstate '02000' set done = 1; -open c; -repeat -fetch c into a; -if not done then -select a; -end if; -until done end repeat; -close c; -end| -call bug14845()| -a -0 -drop procedure bug14845| -drop procedure bug12589_1| -drop procedure bug12589_2| -drop procedure bug12589_3| -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 table t1,t2; diff --git a/sql/item.cc b/sql/item.cc index b7983b13766..6d5855cd0ca 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -921,7 +921,6 @@ Item_splocal::type() const DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset)->type(); } - } return NULL_ITEM; // Anything but SUBSELECT_ITEM } diff --git a/sql/sp.cc b/sql/sp.cc index f98795c54a5..8991cc78b5e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -400,7 +400,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, const char *definer, longlong created, longlong modified) { LEX *oldlex= thd->lex, newlex; - sp_rcontext *save_spcont= ;thd->spcont; + sp_rcontext *save_spcont= thd->spcont; String defstr; char olddb[128]; bool dbchanged; @@ -431,8 +431,6 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length()); - (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); - (*sphp)->set_info(created, modified, &chistics, sql_mode); thd->spcont= 0; if (yyparse(thd) || thd->is_fatal_error || newlex.sphead == NULL) { @@ -446,18 +444,16 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, else { if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) - goto db_end; + goto end; *sphp= newlex.sphead; (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); - (*sphp)->set_info((char *)definer, (uint)strlen(definer), - created, modified, &chistics, sql_mode); + (*sphp)->set_info(created, modified, &chistics, sql_mode); (*sphp)->optimize(); } -db_end: +end: thd->spcont= save_spcont; thd->variables.sql_mode= old_sql_mode; thd->variables.select_limit= select_limit; -end: thd->lex= oldlex; return ret; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 437e910d592..d06cceba77b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4566,9 +4566,11 @@ end_with_restore_list: goto error; } if (lex->sql_command == SQLCOM_SHOW_PROC_CODE) - 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); if (!sp || !sp->show_routine_code(thd)) { /* We don't distinguish between errors for now */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 224fa332d67..296b55679a3 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -913,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); -- cgit v1.2.1 From 1343975dda2e5dc3f8dac4217a0b63b6db9812d6 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 23 Nov 2005 12:26:07 +0200 Subject: A name of macro is fixed. --- sql/sql_class.cc | 2 +- sql/sql_class.h | 2 +- sql/sql_yacc.yy | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 82af1265a9d..a0d87b05e97 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1498,7 +1498,7 @@ int select_dumpvar::prepare(List &list, SELECT_LEX_UNIT *u) { Item_splocal *var; (void)local_vars.push_back(var= new Item_splocal(mv->s, mv->offset)); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF var->owner= mv->owner; #endif } diff --git a/sql/sql_class.h b/sql/sql_class.h index ee24d9e904b..0346801b0dc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2086,7 +2086,7 @@ public: class my_var : public Sql_alloc { public: LEX_STRING s; -#ifndef DEBUG_OFF +#ifndef DBUG_OFF /* Routine to which this Item_splocal belongs. Used for checking if correct runtime context is used for variable handling. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1c191cc2dc2..671e2b1740d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2288,7 +2288,7 @@ sp_case: ivar.length= 5; Item_splocal *var= new Item_splocal(ivar, ctx->current_pvars()-1); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF if (var) var->owner= sp; #endif @@ -5875,7 +5875,7 @@ select_var_ident: my_var *var; ((select_dumpvar *)lex->result)-> var_list.push_back(var= new my_var($1,1,t->offset,t->type)); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF if (var) var->owner= lex->sphead; #endif @@ -7181,7 +7181,7 @@ simple_ident: Item_splocal *splocal; splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev - lex->sphead->m_tmp_query); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF if (splocal) splocal->owner= lex->sphead; #endif -- cgit v1.2.1